feat(plugin): adapter plugin -- influxdb

This commit is contained in:
qianmoQ 2024-11-27 23:19:14 +08:00
parent e14fc43ac2
commit d2db649f14
32 changed files with 372 additions and 281 deletions

View File

@ -1,5 +1,6 @@
datacap-plugin-mysql=plugin/datacap-plugin-mysql/pom.xml
datacap-plugin-clickhouse=plugin/datacap-plugin-clickhouse/pom.xml
datacap-plugin-influxdb=plugin/datacap-plugin-influxdb/pom.xml
datacap-convert-txt=convert/datacap-convert-txt/pom.xml
datacap-convert-json=convert/datacap-convert-json/pom.xml
datacap-convert-xml=convert/datacap-convert-xml/pom.xml

View File

@ -35,6 +35,21 @@
],
"url": "https://cdn.north.devlive.org/applications/datacap/plugins/2024.4.0-SNAPSHOT/plugin/datacap-plugin-clickhouse-bin.tar.gz"
},
{
"key": "datacap-plugin-influxdb",
"label": "InfluxDB",
"description": "InfluxDB is a time series database that stores and retrieves data points. It is a distributed database with a focus on performance, scalability, and ease of use.",
"i18nFormat": true,
"type": "Connector",
"version": "2024.4.0-SNAPSHOT",
"author": "datacap-community",
"logo": "https://cdn.north.devlive.org/applications/datacap/resources/logo/plugin/influxdb.svg",
"released": "2024-11-21 23:11:15",
"supportVersion": [
"ALL"
],
"url": "https://cdn.north.devlive.org/applications/datacap/plugins/2024.4.0-SNAPSHOT/plugin/datacap-plugin-influxdb-bin.tar.gz"
},
{
"key": "datacap-convert-csv",
"label": "CsvConvert",

View File

@ -421,12 +421,6 @@
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>io.edurt.datacap</groupId>-->
<!-- <artifactId>datacap-plugin-influxdb</artifactId>-->
<!-- <version>${project.version}</version>-->
<!-- <scope>provided</scope>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>io.edurt.datacap</groupId>-->
<!-- <artifactId>datacap-captcha</artifactId>-->
<!-- <version>${project.version}</version>-->
<!-- </dependency>-->

View File

@ -6,14 +6,17 @@ import io.edurt.datacap.spi.adapter.HttpAdapter;
import io.edurt.datacap.spi.adapter.JdbcAdapter;
import io.edurt.datacap.spi.adapter.NativeAdapter;
import io.edurt.datacap.spi.connection.Connection;
import io.edurt.datacap.spi.connection.JdbcConfigure;
import io.edurt.datacap.spi.connection.JdbcConnection;
import io.edurt.datacap.spi.model.Configure;
import io.edurt.datacap.spi.model.Response;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
public interface PluginService
extends Service
{
@ -54,23 +57,64 @@ public interface PluginService
{
Response response = new Response();
try {
JdbcConfigure jdbcConfigure = new JdbcConfigure();
if (jdbcConfigure.getJdbcDriver() == null) {
jdbcConfigure.setJdbcDriver(this.driver());
}
if (jdbcConfigure.getJdbcType() == null) {
jdbcConfigure.setJdbcType(this.connectType());
}
BeanUtils.copyProperties(jdbcConfigure, configure);
local.set(new JdbcConnection(jdbcConfigure, response));
configure.setDriver(this.driver());
configure.setType(this.connectType());
configure.setUrl(Optional.of(url(configure)));
local.set(new JdbcConnection(configure, response));
}
catch (Exception ex) {
response.setIsConnected(Boolean.FALSE);
response.setMessage(ex.getMessage());
log.error("Error connecting : {}", ex);
log.error("Error connecting :", ex);
}
}
/**
* 构建驱动路径
* Build the driver path
*
* @param configure 配置信息 | Configuration information
* @return 驱动路径 | Driver path
*/
default String url(Configure configure)
{
if (configure.getUrl().isPresent()) {
return configure.getUrl().get();
}
StringBuilder buffer = new StringBuilder();
buffer.append("jdbc:");
buffer.append(configure.getType());
buffer.append("://");
buffer.append(configure.getHost());
buffer.append(":");
buffer.append(configure.getPort());
if (configure.getDatabase().isPresent()) {
buffer.append("/");
buffer.append(configure.getDatabase().get());
}
if (configure.getSsl().isPresent()) {
buffer.append(String.format("?ssl=%s", configure.getSsl().get()));
}
if (configure.getEnv().isPresent()) {
Map<String, Object> env = configure.getEnv().get();
List<String> flatEnv = env.entrySet()
.stream()
.map(value -> String.format("%s=%s", value.getKey(), value.getValue()))
.collect(Collectors.toList());
if (configure.getSsl().isEmpty()) {
buffer.append("?");
}
else {
if (configure.getIsAppendChar()) {
buffer.append("&");
}
}
buffer.append(String.join("&", flatEnv));
}
return buffer.toString();
}
@Deprecated
default Response execute(String content)
{

View File

@ -3,8 +3,8 @@ package io.edurt.datacap.spi.adapter;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.edurt.datacap.spi.column.Column;
import io.edurt.datacap.spi.column.JdbcColumn;
import io.edurt.datacap.spi.connection.JdbcConfigure;
import io.edurt.datacap.spi.connection.JdbcConnection;
import io.edurt.datacap.spi.model.Configure;
import io.edurt.datacap.spi.model.Response;
import io.edurt.datacap.spi.model.Time;
import lombok.extern.slf4j.Slf4j;
@ -39,7 +39,7 @@ public class JdbcAdapter
processorTime.setStart(new Date().getTime());
Response response = jdbcConnection.getResponse();
Connection connection = (Connection) jdbcConnection.getConnection();
JdbcConfigure configure = (JdbcConfigure) jdbcConnection.getConfigure();
Configure configure = jdbcConnection.getConfigure();
if (response.getIsConnected()) {
try (Statement statement = connection.createStatement()) {
List<String> headers = new ArrayList<>();

View File

@ -25,8 +25,6 @@ public abstract class Connection
this.response.setConnection(connectionTime);
}
protected abstract String formatJdbcUrl();
protected abstract java.sql.Connection openConnection();
public Object getConnection()

View File

@ -1,20 +0,0 @@
package io.edurt.datacap.spi.connection;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.edurt.datacap.spi.model.Configure;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Data
@ToString
@EqualsAndHashCode
@SuppressFBWarnings(value = {"EQ_OVERRIDING_EQUALS_NOT_SYMMETRIC"},
justification = "I prefer to suppress these FindBugs warnings")
public class JdbcConfigure
extends Configure
{
private String jdbcDriver;
private String jdbcType;
private Boolean isAppendChar = Boolean.TRUE;
}

View File

@ -2,6 +2,7 @@ package io.edurt.datacap.spi.connection;
import io.edurt.datacap.plugin.PluginContextManager;
import io.edurt.datacap.plugin.loader.PluginClassLoader;
import io.edurt.datacap.spi.model.Configure;
import io.edurt.datacap.spi.model.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
@ -11,11 +12,8 @@ import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@Slf4j
public class JdbcConnection
@ -23,88 +21,41 @@ public class JdbcConnection
{
private java.sql.Connection jdbcConnection;
public JdbcConnection(JdbcConfigure configure, Response response)
public JdbcConnection(Configure configure, Response response)
{
super(configure, response);
}
protected String formatJdbcUrl()
{
JdbcConfigure jdbcConfigure = getJdbcConfigure();
StringBuilder buffer = new StringBuilder();
buffer.append("jdbc:");
buffer.append(jdbcConfigure.getJdbcType());
if (jdbcConfigure.getJdbcType().equals("influxdb")) {
buffer.append(":");
}
else {
buffer.append("://");
}
buffer.append(jdbcConfigure.getHost());
buffer.append(":");
buffer.append(jdbcConfigure.getPort());
if (jdbcConfigure.getDatabase().isPresent()) {
if (jdbcConfigure.getJdbcType().equals("solr")) {
buffer.append("/?collection=");
}
else {
buffer.append("/");
}
buffer.append(jdbcConfigure.getDatabase().get());
}
if (jdbcConfigure.getSsl().isPresent()) {
buffer.append(String.format("?ssl=%s", jdbcConfigure.getSsl().get()));
}
if (jdbcConfigure.getEnv().isPresent()) {
Map<String, Object> env = jdbcConfigure.getEnv().get();
List<String> flatEnv = env.entrySet()
.stream()
.map(value -> String.format("%s=%s", value.getKey(), value.getValue()))
.collect(Collectors.toList());
if (jdbcConfigure.getSsl().isEmpty()) {
buffer.append("?");
}
else {
if (jdbcConfigure.getIsAppendChar()) {
buffer.append("&");
}
}
buffer.append(String.join("&", flatEnv));
}
return buffer.toString();
}
protected JdbcConfigure getJdbcConfigure()
{
return (JdbcConfigure) this.configure;
}
protected java.sql.Connection openConnection()
{
JdbcConfigure jdbcConfigure = getJdbcConfigure();
try {
PluginClassLoader pluginClassLoader = jdbcConfigure.getPlugin().getPluginClassLoader();
PluginClassLoader pluginClassLoader = configure.getPlugin().getPluginClassLoader();
PluginContextManager.runWithClassLoader(pluginClassLoader, () -> {
Class<?> driverClass = Class.forName(jdbcConfigure.getJdbcDriver(), true, pluginClassLoader);
Class<?> driverClass = Class.forName(configure.getDriver(), true, pluginClassLoader);
Driver driver = (Driver) driverClass.getDeclaredConstructor().newInstance();
DriverManager.registerDriver(new DriverShim(driver));
String url = formatJdbcUrl();
log.info("Connection driver {}", jdbcConfigure.getJdbcDriver());
if (configure.getUrl().isEmpty()) {
throw new RuntimeException("Connection url not present");
}
String url = configure.getUrl().get();
log.info("Connection driver {}", configure.getType());
log.info("Connection url {}", url);
if (jdbcConfigure.getUsername().isPresent() && jdbcConfigure.getPassword().isPresent()) {
if (configure.getUsername().isPresent() && configure.getPassword().isPresent()) {
log.info("Connection username with {} password with {}",
jdbcConfigure.getUsername().get(), "***");
this.jdbcConnection = DriverManager.getConnection(url,
jdbcConfigure.getUsername().get(),
jdbcConfigure.getPassword().get());
configure.getUsername().get(), "***");
this.jdbcConnection = DriverManager.getConnection(
url,
configure.getUsername().get(),
configure.getPassword().get()
);
}
else {
log.info("Connection username and password not present");
Properties properties = new Properties();
if (jdbcConfigure.getUsername().isPresent()) {
properties.put("user", jdbcConfigure.getUsername().get());
if (configure.getUsername().isPresent()) {
properties.put("user", configure.getUsername().get());
}
this.jdbcConnection = DriverManager.getConnection(url, properties);
}

View File

@ -27,12 +27,26 @@ public class Configure
private PluginManager pluginManager;
private String host;
private Integer port;
@Builder.Default
private Optional<String> username = Optional.empty();
@Builder.Default
private Optional<String> password = Optional.empty();
@Builder.Default
private Optional<String> database = Optional.empty();
@Builder.Default
private Optional<String> version = Optional.empty();
@Builder.Default
private Optional<Map<String, Object>> env = Optional.empty();
@Builder.Default
private Optional<Boolean> ssl = Optional.empty();
@Builder.Default
private String format = "JsonConvert";
// if `to`: skip
private Optional<String> query = Optional.empty();
@ -40,4 +54,15 @@ public class Configure
private String home;
private boolean usedConfig;
private String id;
// 自定义 url
// Custom url
@Builder.Default
private Optional<String> url = Optional.empty();
private String driver;
private String type;
@Builder.Default
private Boolean isAppendChar = Boolean.TRUE;
}

View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -15,7 +15,7 @@
:key="plugin.name"
:value="plugin.name">
<ShadcnTooltip :content="plugin.name" class="p-1">
<img class="h-16 w-16 object-contain" :src="'/static/images/plugin/' + plugin.name + '.png'" :alt="plugin.name">
<img class="h-16 w-16 object-contain" :src="'/static/images/plugin/' + plugin.name.toLowerCase() + '.png'" :alt="plugin.name">
</ShadcnTooltip>
</ShadcnToggle>
</ShadcnToggleGroup>

View File

@ -1,11 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
<!-- 背景圆 -->
<!-- Background circle -->
<circle cx="100" cy="100" r="90" fill="#f0f8ff" />
<circle cx="100" cy="100" r="100" fill="#f0f8ff" />
<!-- 外部圆环 -->
<!-- Outer ring -->
<circle cx="100" cy="100" r="80" fill="none" stroke="#1E90FF" stroke-width="8" />
<circle cx="100" cy="100" r="96" fill="none" stroke="#1E90FF" stroke-width="8" />
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg version="1.1"

Before

Width:  |  Height:  |  Size: 290 KiB

After

Width:  |  Height:  |  Size: 290 KiB

4
logo/plugin/influxdb.svg Normal file
View File

@ -0,0 +1,4 @@
<svg enable-background="new -173 -143 900 900" height="900" viewBox="-173 -143 900 900" width="900" xmlns="http://www.w3.org/2000/svg">
<path d="m-173-143h900v900h-900z" fill="none" />
<path d="m694.1 394.9-81-352.7c-4.6-19.3-22.1-38.6-41.4-44.2l-370.2-114.2c-4.6-1.8-10.1-1.8-15.7-1.8-15.7 0-32.2 6.4-43.3 15.7l-265.2 246.8c-14.7 12.9-22.1 38.7-17.5 57.1l86.6 377.6c4.6 19.3 22.1 38.7 41.4 44.2l346.2 106.8c4.6 1.8 10.1 1.8 15.7 1.8 15.7 0 32.2-6.4 43.3-15.7l283.6-263.3c14.8-13.8 22.1-38.7 17.5-58.1zm-453.9-427.3 254.1 78.3c10.1 2.8 10.1 7.4 0 10.1l-133.5 30.4c-10.1 2.8-23.9-1.8-31.3-9.2l-93-100.4c-8.3-8.2-6.5-11.9 3.7-9.2zm158.3 455.9c2.8 10.1-3.7 15.7-13.8 12.9l-274.4-84.7c-10.1-2.8-12-11.1-4.6-18.4l210-195.3c7.4-7.4 15.7-4.6 18.4 5.5zm-452.1-248.7 222.9-207.2c7.4-7.4 19.3-6.4 26.7.9l111.4 120.7c7.4 7.4 6.4 19.3-.9 26.7l-222.9 207.2c-7.4 7.4-19.3 6.4-26.7-.9l-111.4-120.6c-7.4-8.3-6.4-20.3.9-26.8zm54.4 328.8-58.9-258.8c-2.8-10.1 1.8-12 8.3-4.6l93 100.4c7.4 7.4 10.1 22.1 7.4 32.2l-40.6 130.8c-2.8 10.1-7.4 10.1-9.2 0zm325.9 151-291-89.3c-10.1-2.8-15.7-13.8-12.9-23.9l48.8-156.6c2.8-10.1 13.8-15.7 23.9-12.9l291 89.3c10.1 2.8 15.7 13.8 12.9 23.9l-48.8 156.6c-3.6 10.2-13.7 15.7-23.9 12.9zm257.8-211.8-194.2 180.5c-7.4 7.4-11 4.6-8.3-5.5l40.5-130.8c2.8-10.1 13.8-20.3 23.9-22.1l133.5-30.4c10.2-2.7 12 1.9 4.6 8.3zm21.2-38.6-160.2 36.8c-10.1 2.8-20.3-3.7-23-13.8l-68.1-296.5c-2.8-10.1 3.7-20.3 13.8-23l160.2-36.8c10.1-2.8 20.3 3.7 23 13.8l68.1 296.5c2.8 11-3.6 21.1-13.8 23z" fill="#22adf6" />
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -11,11 +11,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>datacap-plugin-influxdb</artifactId>
<description>DataCap - InfluxDB</description>
<properties>
<plugin.name>datacap-influxdb</plugin.name>
</properties>
<description>DataCap - Plugin - InfluxDB</description>
<dependencies>
<dependency>
@ -32,11 +28,6 @@
<artifactId>kotlin-reflect</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.suteren.jdbc.influxdb</groupId>
<artifactId>influxdb-jdbc</artifactId>
@ -70,7 +61,24 @@
<groupId>org.jetbrains.dokka</groupId>
<artifactId>dokka-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dependencies</outputDirectory>
<excludeScope>provided</excludeScope>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,21 +0,0 @@
package io.edurt.datacap.plugin.influxdb
import com.google.inject.multibindings.Multibinder
import io.edurt.datacap.spi.AbstractPluginModule
import io.edurt.datacap.spi.PluginService
import io.edurt.datacap.spi.PluginModule
class InfluxDBModule : AbstractPluginModule(), PluginModule
{
override fun get(): AbstractPluginModule
{
return this
}
override fun configure()
{
Multibinder.newSetBinder(binder(), _root_ide_package_.io.edurt.datacap.spi.PluginService::class.java)
.addBinding()
.to(InfluxDBPlugin::class.java)
}
}

View File

@ -1,21 +0,0 @@
package io.edurt.datacap.plugin.influxdb
import io.edurt.datacap.spi.PluginService
class InfluxDBPlugin : _root_ide_package_.io.edurt.datacap.spi.PluginService
{
override fun validator(): String
{
return "SELECT 1"
}
override fun driver(): String
{
return "net.suteren.jdbc.influxdb.InfluxDbDriver"
}
override fun connectType(): String
{
return "influxdb"
}
}

View File

@ -0,0 +1,5 @@
package io.edurt.datacap.plugin.influxdb
import io.edurt.datacap.plugin.Plugin
class InfluxdbPlugin : Plugin()

View File

@ -0,0 +1,79 @@
package io.edurt.datacap.plugin.influxdb
import io.edurt.datacap.spi.PluginService
import io.edurt.datacap.spi.model.Configure
class InfluxdbService : PluginService
{
override fun validator(): String
{
return "SELECT 1"
}
override fun driver(): String
{
return "net.suteren.jdbc.influxdb.InfluxDbDriver"
}
override fun connectType(): String
{
return "influxdb"
}
override fun url(configure: Configure): String
{
// 如果已经有自定义 URL直接使用
// If there is a custom URL, use it
if (configure.url.isPresent)
{
return configure.url.get()
}
val builder = StringBuilder("jdbc:${configure.type}:")
// 添加主机和端口
// Add host and port
builder.append(configure.host)
if (configure.port != null)
{
builder.append(":").append(configure.port)
}
builder.append("/")
// 添加参数
// Add parameters
val params = mutableListOf<String>()
// 添加数据库
// Add database
configure.database.ifPresent { db ->
params.add("db=$db")
}
// 添加用户名和密码
// Add username and password
configure.username.ifPresent { username ->
params.add("u=$username")
}
configure.password.ifPresent { password ->
params.add("p=$password")
}
// 添加其他环境参数
// Add other environment parameters
configure.env.ifPresent { envMap ->
envMap.forEach { (key, value) ->
params.add("$key=$value")
}
}
// 将所有参数添加到 URL
// Add all parameters to the URL
if (params.isNotEmpty())
{
builder.append("?").append(params.joinToString("&"))
}
return builder.toString()
}
}

View File

@ -0,0 +1 @@
io.edurt.datacap.plugin.influxdb.InfluxdbPlugin

View File

@ -0,0 +1 @@
io.edurt.datacap.plugin.influxdb.InfluxdbService

View File

@ -1 +0,0 @@
io.edurt.datacap.plugin.influxdb.InfluxDBModule

View File

@ -1,32 +0,0 @@
package io.edurt.datacap.plugin.influxdb
import com.google.inject.Guice.createInjector
import com.google.inject.Injector
import com.google.inject.Key
import com.google.inject.TypeLiteral
import io.edurt.datacap.spi.Plugin
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
class InfluxDBModuleTest
{
private val name = "InfluxDB"
private var injector: Injector? = null
@Before
fun before()
{
injector = createInjector(InfluxDBModule())
}
@Test
fun test()
{
injector !!.getInstance(Key.get(object : TypeLiteral<Set<Plugin>>()
{}))
.stream()
.findFirst()
.ifPresent { assertEquals(name, it.name()) }
}
}

View File

@ -1,80 +0,0 @@
package io.edurt.datacap.plugin.influxdb
import com.google.common.collect.Lists
import com.google.inject.Guice.createInjector
import com.google.inject.Injector
import com.google.inject.Key
import com.google.inject.TypeLiteral
import io.edurt.datacap.file.FileManager
import io.edurt.datacap.spi.Plugin
import io.edurt.datacap.spi.model.Configure
import io.edurt.datacap.spi.model.Response
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.slf4j.LoggerFactory.getLogger
import org.testcontainers.containers.Network
import org.testcontainers.lifecycle.Startables
import org.testcontainers.shaded.org.awaitility.Awaitility.given
import java.util.*
import java.util.concurrent.TimeUnit
class InfluxDBPluginTest
{
private val log = getLogger(this.javaClass)
private val host = "TestInfluxDBContainer"
private var container: InfluxDBContainer? = null
private var injector: Injector? = null
private var configure: Configure? = null
@Before
fun before()
{
val network = Network.newNetwork()
container = InfluxDBContainer()
.withNetwork(network)
.withNetworkAliases(host)
container?.portBindings = Lists.newArrayList(String.format("%s:%s", InfluxDBContainer.PORT, InfluxDBContainer.DOCKER_PORT))
Startables.deepStart(java.util.stream.Stream.of(container))
.join()
log.info("InfluxDB container started")
given().ignoreExceptions()
.await()
.atMost(1, TimeUnit.MINUTES)
injector = createInjector(
InfluxDBModule(),
FileManager()
)
configure = Configure()
configure !!.injector = injector
configure !!.host = container?.host
configure !!.port = InfluxDBContainer.PORT
configure !!.username = Optional.of(InfluxDBContainer.USERNAME)
configure !!.password = Optional.of(InfluxDBContainer.PASSWORD)
configure !!.env = Optional.of(mapOf("useEncryption" to false, "useHTTP2" to false, "db" to "test"))
}
@Test
fun test()
{
injector !!.getInstance(Key.get(object : TypeLiteral<Set<Plugin>>()
{}))
.stream()
.findFirst()
.ifPresent {
it.connect(configure)
val response: Response = it.execute(it.validator())
log.info("================ Plugin executed information =================")
if (! response.isSuccessful)
{
log.error("Message: {}", response.message)
}
else
{
response.columns.forEach { column -> log.info(column.toString()) }
}
assertTrue(response.isSuccessful)
}
}
}

View File

@ -75,7 +75,7 @@
<!-- <module>plugin/datacap-plugin-paradedb</module>-->
<!-- <module>plugin/datacap-plugin-timescale</module>-->
<!-- <module>plugin/datacap-plugin-solr</module>-->
<!-- <module>plugin/datacap-plugin-influxdb</module>-->
<module>plugin/datacap-plugin-influxdb</module>
<module>executor/datacap-executor-spi</module>
<module>executor/datacap-executor-local</module>
<module>executor/datacap-executor-seatunnel</module>

View File

@ -19,5 +19,26 @@
<artifactId>datacap-plugin</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-spi</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-convert-spi</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-plugin-influxdb</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -4,7 +4,7 @@ import org.testcontainers.containers.GenericContainer
import org.testcontainers.utility.DockerImageName
import org.testcontainers.utility.DockerImageName.parse
class InfluxDBContainer : GenericContainer<InfluxDBContainer>
class InfluxdbContainer : GenericContainer<InfluxdbContainer>
{
constructor() : super(parse(DEFAULT_IMAGE_NAME))
{

View File

@ -0,0 +1,29 @@
package io.edurt.datacap.plugin.influxdb
import io.edurt.datacap.plugin.PluginConfigure
import io.edurt.datacap.plugin.PluginManager
import io.edurt.datacap.plugin.utils.PluginPathUtils
import org.junit.Assert.assertNotNull
import org.junit.Test
class InfluxdbPluginTest
{
private val pluginManager: PluginManager
private val pluginName = "Influxdb"
init
{
val projectRoot = PluginPathUtils.findProjectRoot()
val config = PluginConfigure.builder()
.pluginsDir(projectRoot.resolve("plugin/datacap-plugin-influxdb"))
.build()
pluginManager = PluginManager(config).apply { start() }
}
@Test
fun test()
{
assertNotNull(pluginManager.getPlugin(pluginName).get())
}
}

View File

@ -0,0 +1,88 @@
package io.edurt.datacap.plugin.influxdb
import io.edurt.datacap.plugin.PluginConfigure
import io.edurt.datacap.plugin.PluginManager
import io.edurt.datacap.plugin.utils.PluginPathUtils
import io.edurt.datacap.spi.PluginService
import io.edurt.datacap.spi.model.Configure
import org.junit.Assert.assertNotNull
import org.junit.Test
import org.slf4j.LoggerFactory.getLogger
import org.testcontainers.containers.Network
import org.testcontainers.lifecycle.Startables
import org.testcontainers.shaded.org.awaitility.Awaitility.given
import java.nio.file.Path
import java.util.*
import java.util.concurrent.TimeUnit
class InfluxdbServiceTest
{
private val log = getLogger(this.javaClass)
private val pluginManager: PluginManager
private var container: InfluxdbContainer
private val pluginName = "Influxdb"
init
{
val network = Network.newNetwork()
container = InfluxdbContainer()
.withNetwork(network)
.withNetworkAliases(this.javaClass.simpleName)
container.portBindings = listOf(String.format("%s:%s", InfluxdbContainer.PORT, InfluxdbContainer.DOCKER_PORT))
Startables.deepStart(java.util.stream.Stream.of(container))
.join()
given().ignoreExceptions()
.await()
.atMost(1, TimeUnit.MINUTES)
log.info("Influxdb container started")
val configFile = this::class
.java
.classLoader
.getResource("influxdb-config.properties")
assertNotNull(configFile)
log.info("Specified config file: {}", configFile)
val projectRoot = PluginPathUtils.findProjectRoot()
val config = PluginConfigure.builder()
.pluginsDir(projectRoot.resolve(Path.of(configFile.path)))
.build()
log.info("Initializing plugin manager")
pluginManager = PluginManager(config).apply { start() }
}
@Test
fun test()
{
val plugin = pluginManager.getPlugin(pluginName).get()
assertNotNull(plugin)
val configure: Configure = Configure.builder()
.host(container.host)
.port(InfluxdbContainer.PORT)
.username(Optional.of(InfluxdbContainer.USERNAME))
.password(Optional.of(InfluxdbContainer.PASSWORD))
.database(Optional.of(InfluxdbContainer.BUCKET))
.plugin(plugin)
.pluginManager(pluginManager)
.env(
Optional.of(
mapOf(
"useEncryption" to false,
"useHTTP2" to false,
"org" to "TestOrg"
)
)
)
.build()
val pluginService = plugin.getService(PluginService::class.java)
val response = pluginService.execute(configure, pluginService.validator())
assertNotNull(response)
}
}

View File

@ -0,0 +1,2 @@
datacap-plugin-influxdb=plugin/datacap-plugin-influxdb/pom.xml
datacap-convert-json=convert/datacap-convert-json/pom.xml