// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

= Kudu Java Developer Documentation

== System Requirements

- Runtime
    * Java 8+
- Build time
    * Java 8+
- Test time
    * Built Kudu Binaries
    * MIT Kerberos (krb5)

== Building Everything

[source,bash]
----
$ ./gradlew assemble
----

== Building Just the Client

[source,bash]
----
$ ./gradlew :kudu-client:assemble
----

The client jar can then be found at `kudu-client/build/libs`.

== Running the Tests

The tests may locate the master and tablet server
binaries by looking in `build/latest/bin` from the root of
the git repository. If you have recently built the C++ code
for Kudu, those should be present already.

If for some reason the binaries aren't in the expected location
as shown above, you can pass
`-DkuduBinDir=/path/to/directory`.

Once everything is setup correctly, run:

[source,bash]
----
$ ./gradlew test
----

If you would like to force tests that were already run to re-run
you can pass `-PrerunTests`. Another option is to run

[source,bash]
----
$ ./gradlew cleanTest test
----

The difference is that the latter spends extra time re-building test state,
while the former runs them again. Using -PrerunTests can be useful to quickly
loop on tests with less slowdown. See
https://docs.gradle.org/5.6.4/userguide/java_testing.html#sec:forcing_java_tests_to_run[here]
for more details.

If you would like to run a subset of the tests or a single test
you can pass the Gradle `--tests <pattern>` argument to filter
the tests ran.
See https://docs.gradle.org/current/userguide/java_testing.html#test_filtering[here]
for detailed documentation of all pattern options.

Single Test Class Example:

[source,bash]
----
$ ./gradlew :kudu-client:test --tests org.apache.kudu.TestColumnSchema
----

Single Test Method Example:

[source,bash]
----
$ ./gradlew :kudu-client:test --tests org.apache.kudu.TestColumnSchema.testEquals
----

Pattern Example:

[source,bash]
----
$ ./gradlew test --tests *IT*
----

== Additional Gradle Commands

=== Discovering Other Gradle Tasks

[source,bash]
----
$ ./gradlew tasks
----

=== Clearing Build State

[source,bash]
----
$ ./gradlew clean
----

Note: You generally don't need to run this task, but it can be useful
to rule out any build issues.

=== Installing Artifacts to the Local Maven Repository

[source,bash]
----
$ ./gradlew install
----

=== Checking for Dependency Updates

[source,bash]
----
./gradlew dependencyUpdates
----

NOTE: Additional Gradle command line flag options can be found
https://docs.gradle.org/current/userguide/command_line_interface.html[here].

== Tips for IDEs

=== IntelliJ

Follow the standard instructions as laid out
https://www.jetbrains.com/help/idea/gradle.html#gradle_import[here]
to import the Gradle project.

For the most consistent behavior on the command line and
in the IDE, be sure to enable `Delegate IDE build/run actions to gradle`
and run tests using the `Gradle Test Runner` as described
https://www.jetbrains.com/help/idea/gradle.html#delegate_build_gradle[here].

Some of the classes generated by Kudu Protobuf files are larger than the
default "intellisense" limit in Intellij. This means Intellij won't
provide code assistance for the classes in those files and may indicate
that the classes in those files are not found. Follow the instructions
https://intellij-support.jetbrains.com/hc/en-us/articles/206544869-Configuring-JVM-options-and-platform-properties[here]
to set "idea.max.intellisense.filesize=5000" in the `idea.properties` file
to work around this issue.

=== Eclipse

Follow the instructions as laid out
http://www.vogella.com/tutorials/EclipseGradle/article.html#eclipse-gradle-support[here]
to install the Eclipse Gradle (Buildship) tooling.
Then follow the instruction on the same page
http://www.vogella.com/tutorials/EclipseGradle/article.html#import-an-existing-gradle-project[here]
to import an existing project.
