This commit is contained in:
remco
2023-04-26 20:01:14 +02:00
parent 14e571d0e2
commit 4e6ea95bb6
302 changed files with 69669 additions and 1 deletions
@@ -0,0 +1,205 @@
# Java API Changelog
This document summarizes all important API changes in the Extraction Plugin API. This document only shows changes that
are important to plugin developers. For a full list of changes per version, please refer to the general
:ref:`changelog <changelog>`.
.. If present, remove `..` before `## |version|` if you create a new entry after a previous release.
.. ## |version|
## 0.6.1
* The JAVA SDK is now distributed through maven central instead of the Hansken community.
## 0.6.0
.. warning:: It is highly recommended to upgrade your plugin to this new version.
See the migration steps below.
* Extraction plugin container images are now labeled with PluginInfo. This
allows Hansken to efficiently load extraction plugins.
* By default, extraction plugin version is managed in the plugin's `pom.xml`.
The `.pluginVersion(..)` can be removed from the PluginInfo builder.
* **Migration steps from earlier versions** -- for plugins that use the Java
extraction plugin SuperPOM:
1. Update the SDK version in your `pom.xml`
2. If you come from a version prior to `0.4.0`, or if you use a plugin name
instead of a plugin id in your `pluginInfo()`, switch to the plugin id style
(read instructions for version `0.4.0`)
3. Set your plugin version in your project's `pom.xml`, and remove the
following from your `PluginInfo.Builder`:
```java
.pluginVersion(...)
```
4. Update your build scripts to build your plugin (Docker) container image.
You should build your plugin container image with the following command:
```bash
mvn package docker:build`
```
This will generate a plugin image:
* The extraction plugin is added to your local image registry
(`docker images`),
* The image name is `extraction-plugin/PLUGINID`, e.g.
`extraction-plugin/nfi.nl/extract/chat/whatsapp`,
* The image is tagged with two tags: `latest`, and your plugin version.
Nb. If Docker is not available in your environment, `podman` can be used
as an alternative. See :ref:`packaging <java_superpom_podman>` for more
details.
## 0.5.0
* Add new tracelet api `Trace.addTracelet(type, consumer)`.
It can be used like this:
```java
trace.addTracelet("prediction", tracelet -> tracelet
.set("type", "classification")
.set("label", "label")
.set("confidence", 0.8f)
.set("embedding", Vector.of(1,2,3))
.set("modelName", "yolo")
.set("modelVersion", "2.0"));
```
* Deprecate Trace.addTracelet(Trace)
* Support vector data type in trace properties.
## 0.4.13
* When writing input search traces for tests, it is no longer required to explicitly set an `id` property.
These are automatically generated when executing tests.
## 0.4.7
* A new convenience method `id(String, String, String)` is added to the PluginInfo builder. This removes some
boilerplate code when setting the pluginId. More details on the plugin naming conventions can be found at the
:doc:`../concepts/plugin_naming_convention` section.
```java
PluginInfo.builderFor(this)
.id("nfi.nl", "extract", "TestPlugin") // new style
.id(new PluginId("nfi.nl", "extract", "TestPlugin")) // old style, but also works
...
```
## 0.4.6
* It is now possible to specify maximum system resources in the `PluginInfo`. To run a plugin with 0.5 cpu (= 0.5
vCPU/Core/hyperthread) and 1 gb memory, for example, the following configuration can be added to `PluginInfo`:
```java
PluginInfo.builderFor(this)
...
.pluginResources(PluginResources.builder()
.maximumCpu(0.5f)
.maximumMemory(1000)
.build())
.build();
```
## 0.4.0
* Extraction Plugins are now identified with a `PluginInfo.PluginId` containing a domain, category and name. The
method `PluginInfo.name(pluginName)` has been replaced by `PluginInfo.id(new PluginId(domain, category, name)`. More
details on the plugin naming conventions can be found at the :doc:`../concepts/plugin_naming_convention` section.
* `PluginInfo.name()` is now deprecated (but will still work for backwards compatibility).
* A new license field `PluginInfo.license` has also been added in this release.
* The following example creates a PluginInfo for a plugin with the name `TestPlugin`, licensed under
the `Apache License 2.0` license:
```java
PluginInfo.builderFor(this)
.id(new PluginId("nfi.nl", "extract", "TestPlugin")) // id.domain: nfi.nl, id.category: extract, id.name: TestPlugin
// .name("TestPlugin") // no longer supported
.pluginVersion("0.4.1")
.author(Author.builder()...build())
.description("A plugin for testing.")
.maturityLevel(MaturityLevel.PROOF_OF_CONCEPT)
.hqlMatcher("*")
.webpageUrl("https://www.hansken.org")
.license("Apache License 2.0")
.build();
```
## 0.3.0
* Extraction Plugins can now create new datastreams on a Trace through data transformations. Data transformations
describe how data can be obtained from a source.
An example case is an extraction plugin that processes an archive file. The plugin creates a child trace per entry in
the archive file. Each child trace will have a datastream that is a transformation that marks the start and length of
the entry in the original archive data. By just describing the data instead of specifying the actual data, a lot of
space is saved.
Although Hansken supports various transformations, the Extraction Plugins SDK for now only supports ranged data
transformations. Ranged data transformations define data as a list of ranges, each range with an offset and length in
a bytearray.
The following example sets a new datastream with dataType `html` on a trace, by setting a ranged data transformation:
```java
trace.setData("html", RangedDataTransformation.builder().addRange(offset, length).build());
```
The following example creates a child trace and sets a new datastream with dataType `raw` on it, by setting a ranged
data transformation with two ranges:
```java
trace.newChild(format("lineNumber %d", lineNumber), child -> {
child.setData("raw", RangedDataTransformation.builder()
.addRange(10, 20)
.addRange(50, 30)
.build());
});
```
More detailed documentation will follow in an upcoming SDK release.
## 0.2.0
.. warning:: This is an API breaking change. Plugins created with an earlier version of the extraction plugin SDK are
not compatible with Hansken that uses `0.2.0` or later.
* Introduced a new extraction plugin type `DeferredExtractioPlugin`. Deferred Extraction plugins can be run at a
different extraction stage. This type of plugin also allows accessing other traces using the searcher.
* The class `ExtractionContext` has been renamed to `DataContext`. The new name `DataContext` represents the class
contents better. Plugins have to update matching import statements and the type in `ExtractionPlugin.process()`
implementation in the same way. This change has no functional side effects.
Old:
```java
import org.hansken.plugin.extraction.api.ExtractionContext;
@Override
public void process(final Trace trace, final ExtractionContext context) throws IOException {
}
```
New:
```java
import org.hansken.plugin.extraction.api.DataContext;
@Override
public void process(final Trace trace, final DataContext dataContext) throws IOException {
}
```
+134
View File
@@ -0,0 +1,134 @@
# How to debug an Extraction Plugin
Debugging is the art of removing bugs — hopefully quickly.
## Locally
To debug a plugin locally, it is recommended to start the plugin via the IDE by running the integration test. This has
the advantage that breakpoints can easily be put in the code instead of printing log statements, for example.
### Logging
The logging of the extraction plugin is displayed in the console.
## Locally with Docker
Debugging an extraction plugin via docker is a bit trickier. Java has the advantage that remote debugging is already
baked in.
Using Java Remote Debug with Docker containers requires 3 distinct steps:
1. Build a Docker image
2. Run the Docker image with specific Java tool options
3. Setting breakpoints in your code
### Build a Docker image
If the Docker image is not built, run the following command to build the Docker image:
```bash
mvn package docker:build
```
### Run the Docker image with specific Java tool options
In Java, the remote debug functionality is not enabled by default. To enable the remote debug functionality, the
following environments variable must be set in the Docker container:
```bash
JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"
```
This environment variable allows the debugger to connect to the debuggee (application being debugged). To start the
Docker image with the `JAVA_TOOL_OPTIONS` environment variable, the following command can be used:
```bash
docker run -p 5005:5005 -e JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" your_extraction_plugin_name
```
The next step is to attach the debugger to the debuggee.
For Intellij, the instructions are clearly described on the following
page: [Tutorial: Remote debug](https://www.jetbrains.com/help/idea/tutorial-remote-debug.html#49be7f04)
### Setting breakpoints in the code
The last step is to add breakpoints in the code.
### Logging in Docker
The logging of the extraction plugin is displayed in the console after running the `docker run` command. In addition,
the logging is also displayed in the IntelliJ console while debugging.
## Kubernetes
In kubernetes it is currently _not_ possible to debug via Java Remote Debug because:
* no debug ports are published;
* the container was not started with the environment variable `JAVA_TOOL_OPTIONS` so debugging is not enabled.
### Logging in Kubernetes
If there is authorization to the kubernetes cluster, the logging can be viewed with the following command:
```bash
kubectl logs -f hansken-extraction-plugins/your_extraction_plugin_pod
```
## Debug HQL
An HQL query can be debugged by overriding the `isVerboseLoggingEnabled()` method of the `ExtractionPluginFlits` class.
The example below shows an example of an embedded FLITS test with verbose logging enabled.
```java
public class TestPluginFlitsIT extends EmbeddedExtractionPluginFlits {
@Override
public Path testPath() {
return srcPath("integration/inputs/plugin");
}
@Override
public Path resultPath() {
return srcPath("integration/results/embedded/plugin");
}
@Override
protected ExtractionPlugin pluginToTest() {
return new TestPlugin();
}
@Override
public boolean regenerate() {
return true;
}
@Override
protected boolean isVerboseLoggingEnabled() {
return true;
}
}
```
The following output will then be displayed in the console:
```text
HQL match found for:
$data.type=jpg
With trace:
dataType=jpg
types={file, data}
properties={data.raw.mimeType=image/jpg, path=/test-input-trace, file.name=image.jpg, name=test-input-trace, id=0}
```
If the HQL query contains an error, it will be shown in the generated test results. An example of an invalid query
is ``$data.mimeType=image/jpg`` (slash not escaped). This query will produce an error like the one shown below.
```json
{
"class": "org.hansken.plugin.extraction.hql_lite.lang.ParseException",
"message": "HqlLiteHumanQueryParser: line 1:20 token recognition error at: '/jpg'"
}
```
.. note:: The error is only shown in the generated trace, so to find out the `ParseException` override
the `regenerate()` method from `Flits` and then let this method return `true`.
+3
View File
@@ -0,0 +1,3 @@
# Javadoc
Visit the `Javadoc of the Extraction Plugins SDK API <../../_static/javadoc/index.html>`_.
+42
View File
@@ -0,0 +1,42 @@
# Packaging
Extraction plugins are packaged as OCI images (also known as Docker images).
The OCI images are labeled with the PluginInfo.
To automate packaging of a Java plugin and labeling the OCI image, the Extraction Plugin SuperPom has been configured to automate this for you.
If your project uses the Extraction Plugin SuperPom (see [Prerequisites](prerequisites.md)), Packaging an extraction plugin is handled by Maven.
To package your plugin into a container image, the following command can be used:
```bash
mvn package docker:build
```
This will generate a plugin image:
* The extraction plugin is added to your local image registry
(`docker images`),
* The image name is `extraction-plugin/PLUGINID`, e.g.
`extraction-plugin/nfi.nl/extract/chat/whatsapp`,
* The image is labeled with two tags: `latest`, and your plugin version.
It is possible to apply extra arguments to the docker command [as described here](http://dmp.fabric8.io/#docker:build).
For example, to specify a proxy, use the following command:
```bash
mvn package docker:build -Ddocker.buildArg.https_proxy=https://proxy:8001
```
Once your plugin is packaged, it can be published or 'uploaded' to Hansken.
See ":ref:`upload_plugin`" for instructions.
.. _java_superpom_podman:
Note: if your build environment does not have Docker available, you can use
[podman](https://podman.io/) as an alternative. Install podman on your machine
or build agent, and run the following commands _before_ invoking the
`mvn package docker:build` command:
```bash
podman system service --time=0 unix:/run/user/$(id -u)/podman/podman.sock &
export DOCKER_HOST="unix:/run/user/$(id -u)/podman/podman.sock"
```
@@ -0,0 +1,41 @@
# Prerequisites
Required software:
* Java 11 or higher
* Docker for [packaging](packaging.md) and publishing plugins
(or use a Docker alternative such as `podman`)
* Maven (recommended, build automation tool)
Required dependencies:
* All required project dependencies to build extraction plugins are published on the public Maven Central, under `org.hansken.plugin.extraction:plugin-super-pom`.
For maven based extraction plugins, the following `pom.xml` snippet can be used as basis of a plugin:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.hansken.plugin.extraction</groupId>
<artifactId>plugin-super-pom</artifactId>
<version>SET_THE_SDK_VERSION_HERE</version>
</parent>
<artifactId>CHOOSE_YOUR_ARTIFACTID_HERE</artifactId>
<version>SET_THE_PLUGIN_VERSION_HERE</version>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<properties>
<mainClass>SET_THE_PLUGIN_MAIN_CLASS_HERE</mainClass>
</properties>
</project>
```
+246
View File
@@ -0,0 +1,246 @@
# Java code snippets
This page contains Java code snippets for common patterns that will be used when writing a plugin.
## RandomAccessData as InputStream
In Java, `InputStream` is a common type to pass data to another class or method. The SDK provides a simple utility to
use a `RandomAccessData` as `InputStream`.
Add the following import to your code:
```java
import org.hansken.plugin.extraction.core.data.RandomAccessDatas;
```
Next we can create an `InputStream` from the `RandomAccessData` as shown in the following snippet. Note that the
`InputStream` is created using a `try-with-resources`-statement. This ensures that the `InputStream` is correctly closed
when the `InputStream` is no longer required.
```java
RandomAccessData traceData=...;
try(InputStream asInputStream=RandomAccessDatas.asInputStream(traceData)){
// use the InputStream here
}
```
Notes:
* the created `InputStream` is *not* thread-safe,
* the created `InputStream` changes state in the provided `RandomAccessData`
(e.g. when data is read, the position updated in both the `InputStream` *and*
the `RandomAccessData` instances),
* for more details on the implementation of the `InputStream`, refer to the `RandomAccessDataInputStream` JavaDoc.
.. _tracelets java:
## Adding tracelets
In the following Java example, a "classification" :ref:`tracelet<tracelets>` is added to a trace. The tracelet consists
of a list of four properties, namely "class", "confidence", "modelName" and "modelVersion".
```java
trace.addTracelet("prediction", tracelet -> tracelet
.set("type", "classification")
.set("class", "telephone")
.set("label", "label")
.set("confidence", 0.8f)
.set("embedding", Vector.of(1,2,3))
.set("modelName", "yolo")
.set("modelVersion", "2.0"));
```
or
```java
trace.addTracelet(new Tracelet("prediction", List.of(
new TraceletProperty("prediction.type","classification"),
new TraceletProperty("prediction.class","telephone"),
new TraceletProperty("prediction.label","label"),
new TraceletProperty("prediction.confidence",0.8f))),
new TraceletProperty("prediction.embedding", Vector.of(1,2,3)),
new TraceletProperty("prediction.modelName","yolo"),
new TraceletProperty("prediction.modelVersion","2.0"));
```
.. _datastreams java:
## Adding data to a trace
Traces can have data attatched to them. See :ref:`datastreams` for more information.
The following two snippets demonstrate how to add data to a trace.
It is currently not possible to verify that a specific data stream is already set or not.
### Data Transformations
The most efficient way to add data to a trace is using data transformations.
See :doc:`../concepts/data_transformations` for more details.
The following example sets a new data stream with dataType `html` on a trace, by setting a ranged data transformation:
```java
trace.setData("html", RangedDataTransformation.builder().addRange(offset, length).build());
```
The following example creates a child trace and sets a new datastream with dataType `raw` on it, by setting a ranged
data transformation with two ranges:
```java
trace.newChild(format("lineNumber %d", lineNumber), child -> {
child.setData("raw", RangedDataTransformation.builder()
.addRange(10, 20)
.addRange(50, 30)
.build());
});
```
### Blobs
It is not always possible to create a transormation for the data that has to be
added to a trace. For example the data is a result of a computation, and not
a direct subset of another data stream..
The following examples show how to creates a new data stream of dataType `raw` on a trace.
In case all data is stored in a `byte[]`, we can add the byte array to the data stream with:
```java
final byte[] rawBytes = {.....};
trace.setData("raw", writer -> writer.write(rawBytes));
```
Alternatively, if the data is available in an `InputStream` the data can be added with:
```java
final InputStream inputStream = ...;
trace.setData("raw", inputStream);
```
## Specifying system resources
In the `PluginInfo` you can specify **maximum** system resource metrics for a plugin. These are used for scaling the
number of pods as described [here](../concepts/kubernetes_autoscaling.md#Autoscaling). To run a plugin with 0.5 cpu (=
0.5 vCPU/Core/hyperthread) and 1 gb memory, for example, the following configuration can be added to `PluginInfo`:
```java
PluginInfo.builderFor(this)
...
.pluginResources(PluginResources.builder()
.maximumCpu(0.5f)
.maximumMemory(1000)
.build())
.build();
```
.. _java_snippets_deferred:
## Deferred Extraction Plugins
Using a deferred plugin requires inheriting the `DeferredExtractionPlugin` base class. This allows access to
a ``TraceSearcher`` object in the process function to search for traces.
```java
public class ExampleDeferred extends DeferredExtractionPlugin {
@Override
public PluginInfo pluginInfo();
@Override
public void process(final Trace trace, final ExtractionContext context,
final TraceSearcher searcher) {
final SearchResult result = searcher.search("file.extension=asc", 10);
}
}
```
The ``search`` method accepts a HQL query and a count, which represents the maximum number of traces to return. It may
be useful to specifically search for traces from the image being extracted. Add ``"image:" + trace.get("image")`` to
your query. The query of the provided example could be extended like this:
`"file.extension = asc AND image:" + trace.get("image")`.
The traces contained in the ``SearchResult`` are returned as a stream.
```java
final Stream<Trace> stream = result.getTraces();
stream.limit(5);
```
## Logging
The logging is provided by Log4j 2 with a SLF4J binding. The Log4j 2 SLF4J binding allows applications coded to the
SLF4J API to use Log4j 2 as the implementation.
### Usage
Here is an example illustrating how to log something with SLF4J. It begins by getting a logger with the name "LOG". This
logger is in turn used to log the message `I'm logging a variable 1234!`.
```java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Example {
private static final Logger LOG = LoggerFactory.getLogger(Example.class);
public void example() {
final int aNumber = 1234;
// logs to console: I'm logging a variable 1234!
LOG.info("I'm logging a variable {}!", aNumber);
}
}
```
### Customize logging
It's easy to change the logging format with a file called `log4j2.xml`. If desired, this file must be in the `resources`
folder, for example `src/main/resources/log4j2.xml`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appenders>
<console name="stdout" target="SYSTEM_OUT">
<patternLayout
pattern="%-5p|%d{yyyy-MM-dd HH:mm:ss}|%-20.20t|%-32.32c{1}|%m%n"/>
</console>
</appenders>
<loggers>
<root level="info">
<appenderRef ref="stdout"/>
</root>
</loggers>
</configuration>
```
.. warning:: Be careful with logging sensitive information.
.. note:: More information about customizing the logging can be found `here <https://logging.apache.org/log4j/2.x>`_.
.. note:: The default logger is pre-configured to log `INFO` to `STDOUT` (see the configuration above)
.. note:: Log4j 2 supports various logging formats, including xml, yaml, json, properties, etc.
Currently, only the xml format is supported.
.. note:: Contact your Hansken administrator for more information on where to find logs for your Hansken environment.
## [EXPERIMENTAL FEATURE] Adding previews to a trace
.. warning:: This is an experimental feature, which might change or get removed in future releases.
Example:
```java
public class ExamplePlugin extends ExtractionPlugin {
@Override
public PluginInfo pluginInfo();
@Override
public void process(final Trace trace, final DataContext context) {
final byte[] previewData;
// set the preview data for the image/png MIME-type
trace.set("preview.image/png", previewData);
trace.set("preview.image/png", previewData);
}
}
```
+156
View File
@@ -0,0 +1,156 @@
# Using the Test Framework in Java
.. _java testing:
This section assumes you use the same setup as is used in the
[Extraction Plugin Examples](https://git.eminjenv.nl/hanskaton/hansken-extraction-plugin-sdk/examples).
## Prerequisites
Java Plugins can use the `plugin-super-pom` as maven parent, which makes sure the
FLITS [Test Framework](../concepts/test_framework.md) is included in the build.
```xml
<parent>
<groupId>org.hansken.plugin.extraction</groupId>
<artifactId>plugin-super-pom</artifactId>
<version>0.4.3</version>
</parent>
```
## Embedded Testing versus Remote Testing
There are ways of integration testing a plugin with the Test Framework:
* **Embedded testing**: Here the plugin is run directly from a JUnit test without using the gRPC layer.
* **Remote testing**: Here the test will start an ExtractionPluginServer that will serve the plugin. All communication
is between server and plugin is done using gRPC.
See below for an example of each way of testing.
The [Extraction Plugin Examples](https://git.eminjenv.nl/hanskaton/hansken-extraction-plugin-sdk/examples) contains many
more examples.
### Embedded Testing example
Embedded tests can be run as a unit test.
```java
import static nl.minvenj.nfi.flits.util.FlitsUtil.srcPath;
import java.nio.file.Path;
import org.hansken.plugin.extraction.api.ExtractionPlugin;
import org.hansken.plugin.extraction.test.EmbeddedExtractionPluginFlits;
/**
* An integration test for MyPlugin.
*/
class MyPluginIT extends EmbeddedExtractionPluginFlits {
@Override
protected ExtractionPlugin pluginToTest() {
// MyPlugin is a class implementing the ExtractionPlugin interface,
// with pluginInfo() and process() methods.
return new MyPlugin();
}
@Override
public Path testPath() {
// Provide the folder containing input files. For examples, see
// https://git.eminjenv.nl/hanskaton/hansken-extraction-plugin-sdk/examples.
return srcPath("integration/inputs");
}
@Override
public Path resultPath() {
// Provide the folder containing result files. For examples, see
// https://git.eminjenv.nl/hanskaton/hansken-extraction-plugin-sdk/examples.
return srcPath("integration/results");
}
@Override
public boolean regenerate() {
// Returning false means the test will fail if the result files don't
// match the outcome of the=++ test. Returning true means the test create
// new result files .
return false;
}
}
```
### Remote Testing example
Note that the following example serves the plugin by using `ExtractionServer`.
```java
import static nl.minvenj.nfi.flits.util.FlitsUtil.srcPath;
import java.nio.file.Path;
import org.hansken.plugin.extraction.runtime.grpc.client.ExtractionPluginClient;
import org.hansken.plugin.extraction.runtime.grpc.server.ExtractionPluginServer;
import org.hansken.plugin.extraction.test.plugins.DataTransformationsPlugin;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
public class RemoteTransformationPluginFlitsIT extends RemoteExtractionPluginFlits {
private static ExtractionPluginServer _server;
private static ExtractionPluginClient _client;
@BeforeAll
public static void init() throws Exception {
final int port = 8999;
// Serve MyPlugin.
// MyPlugin is a class implementing the ExtractionPlugin interface, with PluginInfo and Process methods.
_server = ExtractionPluginServer.serve(port, MyPlugin::new);
// Create an ExtractionPluginClient
_client = new ExtractionPluginClient("localhost", _server.getListeningPort());
}
@AfterAll
public static void destruct() {
// At the end of the test, make sure the server and client are closed.
if (_server != null) {
_server.close();
}
if (_client != null) {
_client.close();
}
}
@Override
public Path testPath() {
// Provide the folder containing input files. For examples, see https://git.eminjenv.nl/hanskaton/hansken-extraction-plugin-sdk/examples.
return srcPath("integration/inputs");
}
@Override
public Path resultPath() {
// Provide the folder containing result files. For examples, see https://git.eminjenv.nl/hanskaton/hansken-extraction-plugin-sdk/examples.
return srcPath("integration/results");
}
@Override
protected ExtractionPluginClient pluginToTest() {
// For Remote testing, the test won't talk directly to the plugin, but to the client.
// The client will use gRPC to communicate with the served plugin.
return _client;
}
@Override
public boolean regenerate() {
// Returning false means the test will fail if the result files don't match the outcome of the test.
// Returning true means the test create new result files.
return false;
}
}
```
.. note:: Note that with a `RemoteTransformationPluginFlitsIT` it is possible to start a docker image of a plugin and
run remote tests against it using your own testdata. To do this, simply remove all `_server` code and manually start
your plugin in a docker container. Then run the test against the docker container by setting the correct url and
port, presumably `new ExtractionPluginClient("localhost", 8999)`.