blob: 11a51fc068951b2257aa1da16a26b971d699865e [file] [log] [blame] [view]
---
title: Development Tools
category: development
order: 4
---
Accumulo has several tools that can help developers test their code.
## MiniAccumuloCluster
[MiniAccumuloCluster] is a standalone instance of Apache Accumulo for testing. It will
create Zookeeper and Accumulo processes that write all of their data to a single local
directory. [MiniAccumuloCluster] makes it easy to code against a real Accumulo instance.
Developers can write realistic-to-end integration tests that mimic the use of a normal
Accumulo instance.
[MiniAccumuloCluster] is published in a separate jar that should be added to your pom.xml
as a test dependency:
```xml
<dependency>
<groupId>org.apache.accumulo</groupId>
<artifactId>accumulo-minicluster</artifactId>
<version>${accumulo.version}</version>
<scope>test</scope>
</dependency>
```
To start it up, you will need to supply an empty directory and a root password as arguments:
```java
File tempDirectory = // JUnit and Guava supply mechanisms for creating temp directories
MiniAccumuloCluster mac = new MiniAccumuloCluster(tempDirectory, "password");
mac.start();
```
Once we have our mini cluster running, we will want to interact with the Accumulo client API:
```java
AccumuloClient client = mac.getAccumuloClient("root", new PasswordToken("password"));
```
Upon completion of our development code, we will want to shutdown our MiniAccumuloCluster:
```java
mac.stop();
// delete your temporary folder
```
## Iterator Test Harness
Iterators, while extremely powerful, are notoriously difficult to test. While the API defines
the methods an Iterator must implement and each method's functionality, the actual invocation
of these methods by Accumulo TabletServers can be surprisingly difficult to mimic in unit tests.
The Apache Accumulo "Iterator Test Harness" is designed to provide a generalized testing framework
for all Accumulo Iterators to leverage to identify common pitfalls in user-created Iterators.
### Framework Use
The Iterator Test Harness is published in a separate jar that should be added to your pom.xml as
a test dependency:
```xml
<dependency>
<groupId>org.apache.accumulo</groupId>
<artifactId>accumulo-iterator-test-harness</artifactId>
<version>${accumulo.version}</version>
<scope>test</scope>
</dependency>
```
To use the Iterator test harness, create a class that extends the [IteratorTestBase] class
and defines the following:
* A `SortedMap` of input data (`Key`-`Value` pairs)
* A [Range] to use in tests
* A `Map` of options (`String` to `String` pairs)
* A `SortedMap` of output data (`Key`-`Value` pairs)
* A list of [IteratorTestCase]s (these can be automatically discovered)
The majority of effort a user must make is in creating the input dataset and the expected
output dataset for the iterator being tested.
### Normal Test Outline
Most iterator tests will follow the given outline:
```java
import java.util.List;
import java.util.SortedMap;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Range;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.iteratortest.IteratorTestBase;
import org.apache.accumulo.iteratortest.IteratorTestInput;
import org.apache.accumulo.iteratortest.IteratorTestOutput;
import org.apache.accumulo.iteratortest.IteratorTestParameters;
public class MyIteratorTest extends IteratorTestBase {
@Override
protected Stream<IteratorTestParameters> parameters() {
var input = new IteratorTestInput(MyIterator.class, Map.of(), createRange(), INPUT_DATA);
var expectedOutput = new IteratorTestOutput(OUTPUT_DATA);
return builtinTestCases().map(test -> test.toParameters(input, expectedOutput));
}
private static SortedMap<Key,Value> INPUT_DATA = createInputData();
private static SortedMap<Key,Value> OUTPUT_DATA = createOutputData();
private static SortedMap<Key,Value> createInputData() {
// TODO -- implement this method
}
private static SortedMap<Key,Value> createOutputData() {
// TODO -- implement this method
}
private static Map<String,String> createOpts() {
IteratorSetting setting = new IteratorSetting(50, MyIterator.class);
// TODO -- add iterator specific options
return setting.getOptions();
}
private static Range createRange() {
// TODO -- implement this method
}
}
```
### Limitations
While the classes that implement [IteratorTestCase]s should exercise common edge-cases in user iterators,
there are still many limitations to the existing test harness. Some of them are:
* Can only specify a single iterator, not many (a "stack")
* No control over provided IteratorEnvironment for tests
* Exercising delete keys (especially with major compactions that do not include all files)
These are left as future improvements to the harness.
[Range]: {% jurl org.apache.accumulo.core.data.Range %}
[IteratorTestCase]: {% jurl org.apache.accumulo.iteratortest.IteratorTestCase %}
[IteratorTestBase]: {% jurl org.apache.accumulo.iteratortest.IteratorTestBase %}
[MiniAccumuloCluster]: {% jurl org.apache.accumulo.minicluster.MiniAccumuloCluster %}