Skip to content

Commit

Permalink
DRILL-6249: Adding more unit testing documentation.
Browse files Browse the repository at this point in the history
close #1251
  • Loading branch information
ilooner authored and Aman Sinha committed May 11, 2018
1 parent 8a1a7c5 commit dc8d010
Show file tree
Hide file tree
Showing 30 changed files with 794 additions and 42 deletions.
5 changes: 4 additions & 1 deletion README.md
Expand Up @@ -20,7 +20,10 @@ Please see the [Apache Drill Website](http://drill.apache.org/) or the [Apache D




## Join the community! ## Join the community!
Apache Drill is an Apache Foundation project and is seeking all types of contributions. Please say hello on the Apache Drill mailing list or join our Google Hangouts for more information. (More information can be found at the Apache Drill website). Apache Drill is an Apache Foundation project and is seeking all types of contributions.
Please say hello on the [Apache Drill mailing list](http://drill.apache.org/mailinglists/)
or join our [Google Hangouts](http://drill.apache.org/community-resources/) for more information.
(More information can be found at the [Apache Drill website](http://drill.apache.org/)).


## Export Control ## Export Control
This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See <http://www.wassenaar.org/> for more information. This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See <http://www.wassenaar.org/> for more information.
Expand Down
14 changes: 7 additions & 7 deletions common/src/test/java/org/apache/drill/test/DirTestWatcher.java
Expand Up @@ -31,10 +31,10 @@
* </p> * </p>
* *
* <p> * <p>
* A {@link DirTestWatcher} is added to a test by declaring it as a JUnit {@link org.junit.Rule}. A {@link org.junit.Rule} is * A {@link DirTestWatcher} is added to a test by declaring it as a JUnit {@link org.junit.Rule}. A {@link org.junit.Rule Rule} is
* a piece of code that is run before and after every JUnit test marked with the {@link org.junit.Test} annotation. When the * a piece of code that is run before and after every JUnit test marked with the {@link org.junit.Test Test} annotation. When the
* {@link DirTestWatcher} is added to a test class the {@link DirTestWatcher} will create a temp directory before each of your * {@link DirTestWatcher} is added to a test class the {@link DirTestWatcher} will create a temp directory before each of your
* {@link org.junit.Test}s and optionally delete the temp directory after each of your {@link org.junit.Test}s. The temp directory * {@link org.junit.Test Test}s and optionally delete the temp directory after each of your {@link org.junit.Test Test}s. The <b>base temp directory</b>
* created by the {@link DirTestWatcher} is in the <b>target</b> folder of the maven project and has the form * created by the {@link DirTestWatcher} is in the <b>target</b> folder of the maven project and has the form
* <b>(my test class fully qualified name)/(my test method name)</b>. So in the context of the code example below, the temp directory created for * <b>(my test class fully qualified name)/(my test method name)</b>. So in the context of the code example below, the temp directory created for
* each test in <b>target</b> will be <b>my.proj.MyTestClass/myTestMethod1</b> and <b>my.proj.MyTestClass/myTestMethod2</b> respectively. * each test in <b>target</b> will be <b>my.proj.MyTestClass/myTestMethod1</b> and <b>my.proj.MyTestClass/myTestMethod2</b> respectively.
Expand All @@ -46,24 +46,24 @@
* </p> * </p>
* *
* <p> * <p>
* By default, the {@link DirTestWatcher} deletes the temp directory it creates at the end of each {@link org.junit.Test}. However, you can create a {@link DirTestWatcher} * By default, the {@link DirTestWatcher} deletes the temp directory it creates at the end of each {@link org.junit.Test Test}. However, you can create a {@link DirTestWatcher}
* by doing {@code new DirTestWatcher(false)} to disable the deletion of temp directories after a test. This is useful if you want to examine files after a test runs. * by doing {@code new DirTestWatcher(false)} to disable the deletion of temp directories after a test. This is useful if you want to examine files after a test runs.
* </p> * </p>
* *
* <pre> * <pre>
* package my.proj; * package my.proj;
* *
* public class MyTestClass { * public class MyTestClass {
* &#064;org.junit.Rule * &#064;Rule
* public final DirTestWatcher dirTestWatcher = new DirTestWatcher(); * public final DirTestWatcher dirTestWatcher = new DirTestWatcher();
* *
* &#064;org.junit.Test * &#064;Test
* public void myTestMethod1() { * public void myTestMethod1() {
* File dir = dirTestWatcher.getDir(); * File dir = dirTestWatcher.getDir();
* // Do stuff in the temp directory * // Do stuff in the temp directory
* } * }
* *
* &#064;org.junit.Test * &#064;Test
* public void myTestMethod2() { * public void myTestMethod2() {
* File dir = dirTestWatcher.getDir(); * File dir = dirTestWatcher.getDir();
* // Do stuff in the temp directory * // Do stuff in the temp directory
Expand Down
7 changes: 5 additions & 2 deletions common/src/test/java/org/apache/drill/test/TestTools.java
Expand Up @@ -34,10 +34,13 @@ public enum FileSource {
PROJECT PROJECT
} }


public static final Path TEST_RESOURCES = Paths.get("src", "test", "resources"); public static final Path TEST_RESOURCES_REL = Paths.get("src", "test", "resources");
public static final Path PROJECT_ROOT = Paths.get("..", ".."); public static final Path PROJECT_ROOT = Paths.get("..", "..");
public static final Path WORKING_PATH = new File(".").toPath(); public static final Path WORKING_PATH = new File(".").toPath();


public static final Path TEST_RESOURCES_ABS = WORKING_PATH.resolve(TEST_RESOURCES_REL);
public static final Path SAMPLE_DATA = PROJECT_ROOT.resolve("sample-data");

static final boolean IS_DEBUG = java.lang.management.ManagementFactory.getRuntimeMXBean() static final boolean IS_DEBUG = java.lang.management.ManagementFactory.getRuntimeMXBean()
.getInputArguments() .getInputArguments()
.toString() .toString()
Expand All @@ -56,7 +59,7 @@ public static TestRule getRepeatRule(final boolean enforce) {


public static File getResourceFile(Path relPath) { public static File getResourceFile(Path relPath) {
return WORKING_PATH return WORKING_PATH
.resolve(TEST_RESOURCES) .resolve(TEST_RESOURCES_REL)
.resolve(relPath) .resolve(relPath)
.toFile(); .toFile();
} }
Expand Down
4 changes: 4 additions & 0 deletions docs/dev/BaseTestQuery.md
@@ -0,0 +1,4 @@
# BaseTestQuery Deprecated. Use [ClusterTest](ClusterTest.md) Instead.

The [BaseTestQuery](../../exec/java-exec/src/test/java/org/apache/drill/test/BaseTestQuery.java) class is useful if you want start a local Drill cluster and run several
integration tests against the Drill cluster.
4 changes: 4 additions & 0 deletions docs/dev/ClusterTest.md
@@ -0,0 +1,4 @@
# ClusterTest

The [ClusterTest](../../exec/java-exec/src/test/java/org/apache/drill/test/ClusterTest.java) class is useful if you want start a local Drill cluster and run several integration
tests against the Drill cluster. Please read the [ClusterTest](../../exec/java-exec/src/test/java/org/apache/drill/test/ClusterTest.java) java doc for more details.
6 changes: 5 additions & 1 deletion docs/dev/DevDocs.md
Expand Up @@ -6,4 +6,8 @@ For information about configuring your development enviornment see [Environment.


## Testing ## Testing


For information about how to do Integration and Unit Testing in Drill see [Testing.md](Testing.md). For information about how to do integration and unit testing in Drill see [Testing.md](Testing.md).

## License Headers

For more information about working with license headers see [LicenseHeaders.md](LicenseHeaders.md)
51 changes: 51 additions & 0 deletions docs/dev/GeneratedCode.md
@@ -0,0 +1,51 @@
# Testing Generated Code

## Writing Unit Tests For Generated Code

An example of unit testing generated code without running all of Drill is the **priorityQueueOrderingTest()** test in
[TopNBatchTest](../../exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TopN/TopNBatchTest.java). That test tests the
[PriorityQueueTemplate](../../exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/TopN/PriorityQueueTemplate.java) class separately from the rest of Drill.

The testing of [PriorityQueueTemplate](../../exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/TopN/PriorityQueueTemplate.java) is mainly accomplished by creating
instances of the following classes:

* [FunctionLookupContext](../../exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionLookupContext.java)
* [CodeCompiler](../../exec/java-exec/src/main/java/org/apache/drill/exec/compile/CodeCompiler.java)

## Creating A [FunctionLookupContext](../../exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionLookupContext.java)

```
new FunctionImplementationRegistry(drillConfig)
```

## Creating A [CodeCompiler](../../exec/java-exec/src/main/java/org/apache/drill/exec/compile/CodeCompiler.java)

1. Create an [OperatorFixture](OperatorFixture.md).
1. Retrieve the [SystemOptionManager](../../exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SystemOptionManager.java) from the
[OperatorFixture](OperatorFixture.md).
```
operatorFixture.getOptionManager();
```
1. Create an instance of [CodeCompiler](../../exec/java-exec/src/main/java/org/apache/drill/exec/compile/CodeCompiler.java).
```
new CodeCompiler(drillConfig, optionManager)
```

## Debugging Generated Code

It is possible to set break points in generated code.

### Instructions For IntelliJ

1. File→Project structure…→Modules→distribution→Sources → Add content root
1. Chose /tmp/drill/codegen
1. Mark it as Sources directory.
1. Set saveCodeForDebugging(true) for the code generator of interest
1. Run the unit test of interest
1. Now some generated classes should appear in Intellij under the distribution module
1. Set a break point in a generated class and run the unit test in debug mode

### Instructions For Eclipse

1. To step into the generated code, set a breakpoint just before we call into the setup method.
1. Step into that method which will step into doSetup. This opens the generated code file.
107 changes: 107 additions & 0 deletions docs/dev/InstantiatingComponents.md
@@ -0,0 +1,107 @@
# Instantiating Components

There are a few techniques for creating instances classes in unit tests:

* Use a mocking library. **(Depracated)**
* Provide a simple impementation of an interface
* Build a real instance of class using the class's builders / constructors
* Use the [ClusterFixture](ClusterFixture.md) or [OperatorFixture](OperatorFixture.md) classes to create instances of objects.

## Mocking Libraries (Deprecated)

Drill uses two mocking libraries in order to mock classes.

* [Mockito](http://site.mockito.org)
* [JMockit](http://jmockit.github.io/tutorial.html)

These libraries were originally used to work around the lack of well defined interfaces and adequate testing tools. Drill has made significant improvements in these areas
so using mocking libraries are no longer required. Existing tests that use these libraries will be refactored to remove them, and new tests should NOT use these libraries.

## Instantiating Contexts

There are several contexts used throughout Drill, for a complete description of each and how
they are used please see [FragmentContextImpl](../../exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContextImpl.java).

When doing tests you can use the following mock contexts:

* [MockFragmentContext](../../exec/java-exec/src/test/java/org/apache/drill/test/OperatorFixture.java) is a simple mock implementation of
the [FragmentContext](../../exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java). A mock instance of the class can also be retrieved from an
[OperatorFixture](OperatorFixture.md).
```
FragmentContext context = operatorFixture.getFragmentContext();
```

## Creating An Instance of [QueryId](../../protocol/src/main/java/org/apache/drill/exec/proto/beans/QueryId.java)

```
UserBitShared.QueryId queryId = UserBitShared.QueryId.newBuilder()
.setPart1(1L)
.setPart2(2L)
.build();
```

## Creating [FragmentHandle](../../protocol/src/main/java/org/apache/drill/exec/proto/beans/FragmentHandle.java)

```
ExecProtos.FragmentHandle fragmentHandle = ExecProtos.FragmentHandle.newBuilder()
.setQueryId(queryId)
.setMinorFragmentId(1)
.setMajorFragmentId(2)
.build();
```

## Creating A [DrillConfig](../../common/src/main/java/org/apache/drill/common/config/DrillConfig.java)

There are a few ways to create a [DrillConfig](../../common/src/main/java/org/apache/drill/common/config/DrillConfig.java). The simplest way is to
create a [ClusterFixture](ClusterFixture.md) or [OperatorFixture](OperatorFixture.md) and then do the following:

```
DrillConfig drillConfig = clusterFixture.config();
```

or

```
DrillConfig drillConfig = operatorFixture.config();
```

If you need a [DrillConfig](../../common/src/main/java/org/apache/drill/common/config/DrillConfig.java) and don't want all the extra things provided
by [ClusterFixture](ClusterFixture.md) and [OperatorFixture](OperatorFixture.md), you can use
[ConfigBuilder](../../exec/java-exec/src/test/java/org/apache/drill/test/ConfigBuilder.java).

## Creating A [SpillSet](../../exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/spill/SpillSet.java)

1. Create a [PhysicalOperator](../../exec/java-exec/src/main/java/org/apache/drill/exec/physical/base/PhysicalOperator.java).
```
HashJoinPOP pop = new HashJoinPOP(null, null, null, JoinRelType.FULL);
```
1. Create a [DrillConfig](../../common/src/main/java/org/apache/drill/common/config/DrillConfig.java).
1. Create a [FragmentHandle](../../protocol/src/main/java/org/apache/drill/exec/proto/beans/FragmentHandle.java) as described above.
1. Create a [SpillSet](../../exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/spill/SpillSet.java).
```
SpillSet spillSet = new SpillSet(config, fragmentHandle, pop);
```

## Creating A [PersistentStoreProvider](../../exec/java-exec/src/main/java/org/apache/drill/exec/store/sys/PersistentStoreProvider.java)

```
LocalPersistentStoreProvider provider = new LocalPersistentStoreProvider(drillConfig);
provider.start();
```

## Creating A [LogicalPlanPersistence](../../logical/src/main/java/org/apache/drill/common/config/LogicalPlanPersistence.java)

```
LogicalPlanPersistence logicalPlanPersistence = PhysicalPlanReaderTestFactory.defaultLogicalPlanPersistence(drillConfig);
```

## Creating An Instance Of An Option Manager

You can create an instance of the [SystemOptionManager](../../exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SystemOptionManager.java) by leveraging the
[OperatorFixture](OperatorFixture.md).

1. Create an [OperatorFixture](OperatorFixture.md).
1. Retrieve the [SystemOptionManager](../../exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SystemOptionManager.java).
```
operatorFixture.getOptionManager();
```
34 changes: 34 additions & 0 deletions docs/dev/LicenseHeaders.md
@@ -0,0 +1,34 @@
# License Headers

Drill uses two license header checkers:

* [Apache RAT Plugin](http://creadur.apache.org/rat/apache-rat-plugin/)
* [License Maven Plugin](http://code.mycila.com/license-maven-plugin/)

## Why Two?

[Apache RAT Plugin](http://creadur.apache.org/rat/apache-rat-plugin/) is used because it is the standard license header
checker for Apache projects.

[License Maven Plugin](http://code.mycila.com/license-maven-plugin/) performs stricter license checks and supports disallowing license headers wrapped in `/**` and `**/`. This
allows us to inforce requiring all license headers to be wrapped only in `/*` and `*/`.

## Doing License Checks

The license checks are disabled locally by default and are enabled on Travis. If you'd like to perform
license checks locally you can do the following:

```
mvn license:check -Dlicense.skip=false
```

## Auto Formatting Headers

If the license checks fail and you can't figure out what's wrong with your headers, you can auto-format
your license headers with the following command:

```
mvn license:format -Dlicense.skip=false
```

This command will also add license headers to files without them.
31 changes: 31 additions & 0 deletions docs/dev/PhysicalOpUnitTestBase.md
@@ -0,0 +1,31 @@
# Single Operator Unit Test

It is possible to run an end to end test of an operator in isolation by extending
[PhysicalOpUnitTestBase](../../exec/java-exec/src/test/java/org/apache/drill/exec/physical/unit/PhysicalOpUnitTestBase.java).

A simple example of an operator level unit test is the following:

```
public class BasicPhysicalOpUnitTest extends PhysicalOpUnitTestBase {
@Test
public void testSimpleProject() {
Project projectConf = new Project(parseExprs("x+5", "x"), null);
List<String> jsonBatches = Lists.newArrayList(
"[{\"x\": 5 },{\"x\": 10 }]",
"[{\"x\": 20 },{\"x\": 30 },{\"x\": 40 }]");
opTestBuilder()
.physicalOperator(projectConf)
.inputDataStreamJson(jsonBatches)
.baselineColumns("x")
.baselineValues(10l)
.baselineValues(15l)
.baselineValues(25l)
.baselineValues(35l)
.baselineValues(45l)
.go();
}
}
```

0 comments on commit dc8d010

Please sign in to comment.