This is an automated email from the ASF dual-hosted git repository.

dominikriemer pushed a commit to branch remove-lightcouch-dependency
in repository https://gitbox.apache.org/repos/asf/streampipes.git

commit abdd45196797ddb2fb27ad48bea88552994965ec
Author: Dominik Riemer <[email protected]>
AuthorDate: Tue Nov 3 09:07:41 2026 +0100

    refactor: Eliminate lightcouch dependency
---
 pom.xml                                            |   6 --
 .../src/main/resources/logback.xml                 |   1 -
 streampipes-storage-couchdb/pom.xml                |  12 +--
 .../streampipes/storage/couchdb/utils/Utils.java   |  98 ------------------
 .../couchdb/compat/CodecCompatibilityTest.java     |   4 +-
 .../storage/couchdb/compat/LegacyCouchDbHttp.java  | 114 +++++++++++++++++++++
 .../storage/couchdb/compat/LegacyCouchDbPath.java  |   7 +-
 .../compat/LiveCouchDbCompatibilityTest.java       |  39 +++----
 ... StoredFormatCompatibilityIntegrationTest.java} |  69 ++++---------
 9 files changed, 159 insertions(+), 191 deletions(-)

diff --git a/pom.xml b/pom.xml
index 60148aa3cb..cad644642e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,7 +67,6 @@
         
<hadoop-mapreduce-client-core.version>3.4.1</hadoop-mapreduce-client-core.version>
         <jgrapht.version>1.5.1</jgrapht.version>
         <jjwt.version>0.11.2</jjwt.version>
-        <lightcouch.version>0.2.0</lightcouch.version>
         <eclipse.milo.version>1.1.1</eclipse.milo.version>
         <fogsy-qudt.version>1.0</fogsy-qudt.version>
         <httpclient.version>4.5.13</httpclient.version>
@@ -790,11 +789,6 @@
                 <artifactId>jgrapht-core</artifactId>
                 <version>${jgrapht.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.lightcouch</groupId>
-                <artifactId>lightcouch</artifactId>
-                <version>${lightcouch.version}</version>
-            </dependency>
             <dependency>
                 <groupId>org.locationtech.jts</groupId>
                 <artifactId>jts-core</artifactId>
diff --git a/streampipes-service-base/src/main/resources/logback.xml 
b/streampipes-service-base/src/main/resources/logback.xml
index 1331d020df..062b095218 100644
--- a/streampipes-service-base/src/main/resources/logback.xml
+++ b/streampipes-service-base/src/main/resources/logback.xml
@@ -28,7 +28,6 @@
         </encoder>
     </appender>
 
-    <logger name="org.lightcouch" level="ERROR"/>
     <logger name="org.apache.kafka" level="ERROR"/>
 
 
diff --git a/streampipes-storage-couchdb/pom.xml 
b/streampipes-storage-couchdb/pom.xml
index 6c081db049..05e6292c60 100644
--- a/streampipes-storage-couchdb/pom.xml
+++ b/streampipes-storage-couchdb/pom.xml
@@ -73,10 +73,6 @@
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.lightcouch</groupId>
-            <artifactId>lightcouch</artifactId>
-        </dependency>
 
         <!-- Test dependencies -->
         <dependency>
@@ -90,18 +86,12 @@
             <artifactId>junit-jupiter-api</artifactId>
             <scope>test</scope>
         </dependency>
-        <!-- Serialization compatibility tests against LightCouch (package 
storage.couchdb.compat) -->
+        <!-- Stored format compatibility tests against CouchDB (package 
storage.couchdb.compat) -->
         <dependency>
             <groupId>org.testcontainers</groupId>
             <artifactId>testcontainers</artifactId>
             <scope>test</scope>
         </dependency>
-        <!-- LightCouch's HttpClient 4 logs through commons-logging, which the 
services get from Spring -->
-        <dependency>
-            <groupId>commons-logging</groupId>
-            <artifactId>commons-logging</artifactId>
-            <scope>test</scope>
-        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git 
a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
 
b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
index d42646e008..6aa26eacf1 100644
--- 
a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
+++ 
b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
@@ -21,15 +21,12 @@ package org.apache.streampipes.storage.couchdb.utils;
 import org.apache.streampipes.commons.environment.Environment;
 import org.apache.streampipes.commons.environment.Environments;
 import org.apache.streampipes.storage.couchdb.CouchDbStores;
-import org.apache.streampipes.storage.couchdb.serializer.GsonSerializer;
 
 import com.google.common.net.UrlEscapers;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.http.HttpHeaders;
 import org.apache.http.client.fluent.Request;
 import org.apache.http.entity.ContentType;
-import org.lightcouch.CouchDbClient;
-import org.lightcouch.CouchDbProperties;
 
 public class Utils {
 
@@ -37,105 +34,10 @@ public class Utils {
   public static final String LEGACY_DATA_LAKE_DB_NAME = "data-lake";
   public static final String DATA_LAKE_DB_NAME = 
CouchDbStores.DATA_LAKE_DB_NAME;
 
-  public static CouchDbClient getCouchDbDataProcessorDescriptionClient() {
-    return getCouchDbGsonClient("data-processor");
-  }
-
   public static String escapePathSegment(String urlSegment) {
     return UrlEscapers.urlPathSegmentEscaper().escape(urlSegment);
   }
 
-  public static CouchDbClient getCouchDbDataStreamDescriptionClient() {
-    return getCouchDbGsonClient("data-stream");
-  }
-
-  public static CouchDbClient getCouchDbDataSinkDescriptionClient() {
-    return getCouchDbGsonClient("data-sink");
-  }
-
-  public static CouchDbClient getCouchDbImageClient() {
-    return getCouchDbGsonClient("images");
-  }
-
-  public static CouchDbClient getCouchDbPipelineElementTemplateClient() {
-    return getCouchDbGsonClient("pipelineelementtemplate-v2");
-  }
-
-  public static CouchDbClient getCouchDbPipelineCanvasMetadataClient() {
-    return getCouchDbGsonClient("pipelinecanvasmetadata");
-  }
-
-  public static CouchDbClient getCouchDbGeneralConfigStorage() {
-    return getCouchDbGsonClient("general-configuration");
-  }
-
-  public static CouchDbClient getCouchDbFileMetadataClient() {
-    return getCouchDbGsonClient("filemetadata");
-  }
-
-  public static CouchDbClient getCouchDbAdapterInstanceClient() {
-    return getCouchDbAdapterClient("adapterinstance");
-  }
-
-  public static CouchDbClient getCouchDbAdapterInstanceBackupClient() {
-    return new CouchDbClient(props("adapterinstance_backup"));
-  }
-
-  public static CouchDbClient getCouchDbAdapterDescriptionClient() {
-    return getCouchDbAdapterClient("adapterdescription");
-  }
-
-  public static CouchDbClient getCouchDbPipelineClient() {
-    return getCouchDbGsonClient("pipeline");
-  }
-
-  public static CouchDbClient getCouchDbUserClient() {
-    return getCouchDbPrincipalClient(USER_DB_NAME);
-  }
-
-  public static CouchDbClient getCouchDbGsonClient(String dbname) {
-    CouchDbClient dbClient = new CouchDbClient(props(dbname));
-    dbClient.setGsonBuilder(GsonSerializer.getGsonBuilder());
-    return dbClient;
-  }
-
-  private static CouchDbClient getCouchDbPrincipalClient(String dbname) {
-    CouchDbClient dbClient = new CouchDbClient(props(dbname));
-    dbClient.setGsonBuilder(GsonSerializer.getPrincipalGsonBuilder());
-    return dbClient;
-  }
-
-  private static CouchDbClient getCouchDbAdapterClient(String dbname) {
-    CouchDbClient dbClient = new CouchDbClient(props(dbname));
-    dbClient.setGsonBuilder(GsonSerializer.getAdapterGsonBuilder());
-    return dbClient;
-  }
-
-  private static CouchDbClient getCouchDbStandardSerializerClient(String 
dbname) {
-    return new CouchDbClient(props(dbname));
-  }
-
-  public static CouchDbClient getCouchDbClient(String database, boolean 
createIfNotExists) {
-    return new CouchDbClient(props(database, createIfNotExists));
-  }
-
-  private static CouchDbProperties props(String dbname,
-                                         boolean createDbIfNotExists) {
-    var env = getEnvironment();
-    return new CouchDbProperties(
-        dbname,
-        createDbIfNotExists,
-        env.getCouchDbProtocol().getValueOrDefault(),
-        env.getCouchDbHost().getValueOrDefault(),
-        env.getCouchDbPort().getValueOrDefault(),
-        env.getCouchDbUsername().getValueOrDefault(),
-        env.getCouchDbPassword().getValueOrDefault());
-  }
-
-  private static CouchDbProperties props(String dbname) {
-    return props(dbname, true);
-  }
-
   public static String getDatabaseRoute(String databaseName) {
     return toUrl() + "/" + databaseName;
   }
diff --git 
a/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/CodecCompatibilityTest.java
 
b/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/CodecCompatibilityTest.java
index f20a9c57b0..d0ed787ee1 100644
--- 
a/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/CodecCompatibilityTest.java
+++ 
b/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/CodecCompatibilityTest.java
@@ -44,8 +44,8 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 /**
  * Checks that the new client with {@link GsonCodec} writes and reads every 
stored model exactly as LightCouch
- * does: same JSON on write, same objects (compared by their JSON) on read 
through {@code find}, {@code _all_docs}
- * and views. Gate for every phase that moves a storage off LightCouch 
(docs/couchdb-client-concept.md, 6.4).
+ * did: same JSON on write, same objects (compared by their JSON) on read 
through {@code find}, {@code _all_docs}
+ * and views. Guards documents already stored and rollback to a previous 
version (docs/couchdb-client-concept.md, 6.4).
  */
 public class CodecCompatibilityTest {
 
diff --git 
a/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LegacyCouchDbHttp.java
 
b/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LegacyCouchDbHttp.java
new file mode 100644
index 0000000000..366b517982
--- /dev/null
+++ 
b/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LegacyCouchDbHttp.java
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ *
+ */
+
+package org.apache.streampipes.storage.couchdb.compat;
+
+import com.google.gson.Gson;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.List;
+
+/**
+ * Sends the requests LightCouch sent, with the bodies from {@link 
LegacyCouchDbPath}, independently of the new client.
+ */
+final class LegacyCouchDbHttp implements AutoCloseable {
+
+  private final HttpClient http = HttpClient.newHttpClient();
+  private final String baseUrl;
+  private final String authorization;
+  private final Gson gson;
+
+  LegacyCouchDbHttp(String baseUrl, String user, String password, Gson gson) {
+    this.baseUrl = baseUrl;
+    this.authorization = "Basic "
+        + Base64.getEncoder().encodeToString((user + ":" + 
password).getBytes(StandardCharsets.UTF_8));
+    this.gson = gson;
+  }
+
+  /**
+   * {@code CouchDbClient.save} for a document with an id.
+   */
+  void save(String database, String id, Object document) throws IOException, 
InterruptedException {
+    put(database, id, LegacyCouchDbPath.encode(gson, document));
+  }
+
+  /**
+   * {@code CouchDbClient.find(Class, String)}.
+   */
+  <T> T find(String database, String id, Class<T> type) throws IOException, 
InterruptedException {
+    return LegacyCouchDbPath.find(gson, get(database + "/" + encode(id)), 
type);
+  }
+
+  /**
+   * {@code CouchDbClient.view("_all_docs").includeDocs(true).query(Class)}.
+   */
+  <T> List<T> allDocs(String database, Class<T> type) throws IOException, 
InterruptedException {
+    return LegacyCouchDbPath.view(gson, get(database + 
"/_all_docs?include_docs=true"), type);
+  }
+
+  /**
+   * {@code CouchDbClient.view("design/view").includeDocs(true).query(Class)}.
+   */
+  <T> List<T> view(String database, String design, String view, Class<T> type)
+      throws IOException, InterruptedException {
+    return LegacyCouchDbPath.view(gson,
+        get(database + "/_design/" + encode(design) + "/_view/" + encode(view) 
+ "?include_docs=true"),
+        type);
+  }
+
+  /**
+   * Stores the body unchanged.
+   */
+  void put(String database, String id, String body) throws IOException, 
InterruptedException {
+    var response = http.send(request(database + "/" + encode(id))
+        .header("Content-Type", "application/json")
+        .PUT(HttpRequest.BodyPublishers.ofString(body))
+        .build(), HttpResponse.BodyHandlers.ofString());
+    if (response.statusCode() != 201) {
+      throw new IOException("PUT " + database + "/" + id + ": " + 
response.statusCode() + " " + response.body());
+    }
+  }
+
+  @Override
+  public void close() {
+    http.close();
+  }
+
+  private byte[] get(String path) throws IOException, InterruptedException {
+    var response = http.send(request(path).GET().build(), 
HttpResponse.BodyHandlers.ofByteArray());
+    if (response.statusCode() != 200) {
+      throw new IOException("GET " + path + ": " + response.statusCode());
+    }
+    return response.body();
+  }
+
+  private HttpRequest.Builder request(String path) {
+    return HttpRequest.newBuilder(URI.create(baseUrl + "/" + 
path)).header("Authorization", authorization);
+  }
+
+  private static String encode(String segment) {
+    return URLEncoder.encode(segment, StandardCharsets.UTF_8).replace("+", 
"%20");
+  }
+}
diff --git 
a/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LegacyCouchDbPath.java
 
b/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LegacyCouchDbPath.java
index 05b809e456..6586e98c0f 100644
--- 
a/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LegacyCouchDbPath.java
+++ 
b/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LegacyCouchDbPath.java
@@ -33,9 +33,10 @@ import java.util.ArrayList;
 import java.util.List;
 
 /**
- * The serialization steps of LightCouch 0.2.0, reproduced without its HTTP 
client, which cannot be constructed
- * without a server. Each method names the LightCouch code it mirrors; the 
integration test checks the same
- * fixtures against the real {@code CouchDbClient}.
+ * The serialization steps of LightCouch 0.2.0, kept as the reference for the 
stored format now that LightCouch is
+ * gone: existing documents were written this way, and a previous version 
reads documents this way. Each method names
+ * the LightCouch code it mirrors. These steps matched the real {@code 
CouchDbClient} against CouchDB 3.3.1 for every
+ * fixture until the dependency was removed.
  */
 final class LegacyCouchDbPath {
 
diff --git 
a/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LiveCouchDbCompatibilityTest.java
 
b/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LiveCouchDbCompatibilityTest.java
index 2a3c58b79f..92824c5169 100644
--- 
a/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LiveCouchDbCompatibilityTest.java
+++ 
b/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LiveCouchDbCompatibilityTest.java
@@ -30,10 +30,7 @@ import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.DynamicTest;
 import org.junit.jupiter.api.TestFactory;
 import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
-import org.lightcouch.CouchDbClient;
-import org.lightcouch.CouchDbProperties;
 
-import java.net.URI;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -44,8 +41,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.fail;
 
 /**
- * Reads the documents of an existing StreamPipes installation with LightCouch 
and with the new client and compares
- * the results. Read-only: databases are opened without creating them and 
nothing is written.
+ * Reads the documents of an existing StreamPipes installation the way 
LightCouch did ({@link LegacyCouchDbHttp}) and
+ * with the new client and compares the results. Read-only: only {@code GET} 
and {@code HEAD}, nothing is created or
+ * written.
  *
  * <p>Run against a local stack with
  * {@code -Dstreampipes.couchdb.compat.url=http://localhost:5984 
-Dstreampipes.couchdb.compat.user=...
@@ -56,17 +54,17 @@ public class LiveCouchDbCompatibilityTest {
 
   private static final int MAX_FIND_COMPARISONS = 50;
 
-  private static URI url;
+  private static String url;
   private static String user;
   private static String password;
   private static CouchServer server;
 
   @BeforeAll
   public static void connect() {
-    url = URI.create(System.getProperty("streampipes.couchdb.compat.url"));
+    url = System.getProperty("streampipes.couchdb.compat.url");
     user = System.getProperty("streampipes.couchdb.compat.user", "admin");
     password = System.getProperty("streampipes.couchdb.compat.password", 
"admin");
-    server = CouchServer.builder().url(url.toString()).credentials(user, 
password).build();
+    server = CouchServer.builder().url(url).credentials(user, 
password).build();
   }
 
   @AfterAll
@@ -81,18 +79,15 @@ public class LiveCouchDbCompatibilityTest {
     return StoredModels.ALL.stream().map(model -> 
DynamicTest.dynamicTest(model.name(), () -> check(model)));
   }
 
-  private static void check(StoredModel model) {
+  private static void check(StoredModel model) throws Exception {
     Assumptions.assumeTrue(server.database(model.database()).exists(), "no 
database " + model.database());
     Gson legacyGson = LegacyCouchDbPath.gson(model.gsonBuilder().get());
     GsonCodec codec = model.newCodec();
     TypedCollection<Object> collection = 
server.database(model.database()).typed(rawClass(model.readType()), codec);
-    var legacy = new CouchDbClient(new CouchDbProperties(model.database(), 
false, url.getScheme(), url.getHost(),
-        url.getPort(), user, password));
-    legacy.setGsonBuilder(model.gsonBuilder().get());
-    try {
-      List<?> legacyDocs = legacy.view(model.view() == null ? "_all_docs" : 
model.view())
-          .includeDocs(true)
-          .query(model.readType());
+    try (var legacy = new LegacyCouchDbHttp(url, user, password, legacyGson)) {
+      List<?> legacyDocs = model.view() == null
+          ? legacy.allDocs(model.database(), model.readType())
+          : legacy.view(model.database(), model.designDocument(), 
model.viewName(), model.readType());
       List<Object> newDocs = model.view() == null
           ? collection.findAll()
           : collection.view(model.designDocument(), model.viewName()).docs();
@@ -107,16 +102,16 @@ public class LiveCouchDbCompatibilityTest {
         collect(failures, model + " encode", 
JsonTrees.parse(LegacyCouchDbPath.encode(legacyGson, document)),
             JsonTrees.parse(codec.encode(document)));
       }
-      expected.keySet().stream().filter(id -> 
!id.startsWith("#")).limit(MAX_FIND_COMPARISONS).forEach(id ->
-          collect(failures, model + " " + id + " find",
-              reencode(legacyGson, legacy.find(model.readType(), id)),
-              reencode(legacyGson, collection.get(id))));
+      for (String id : expected.keySet().stream().filter(id -> 
!id.startsWith("#")).limit(MAX_FIND_COMPARISONS)
+          .toList()) {
+        collect(failures, model + " " + id + " find",
+            reencode(legacyGson, legacy.find(model.database(), id, 
model.readType())),
+            reencode(legacyGson, collection.get(id)));
+      }
       if (!failures.isEmpty()) {
         fail(String.join("\n", failures));
       }
       System.out.printf("%s: %d documents compared%n", model, expected.size());
-    } finally {
-      legacy.shutdown();
     }
   }
 
diff --git 
a/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LightCouchCompatibilityIntegrationTest.java
 
b/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/StoredFormatCompatibilityIntegrationTest.java
similarity index 76%
rename from 
streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LightCouchCompatibilityIntegrationTest.java
rename to 
streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/StoredFormatCompatibilityIntegrationTest.java
index 0d82341305..d8f53ec76d 100644
--- 
a/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/LightCouchCompatibilityIntegrationTest.java
+++ 
b/streampipes-storage-couchdb/src/test/java/org/apache/streampipes/storage/couchdb/compat/StoredFormatCompatibilityIntegrationTest.java
@@ -28,41 +28,33 @@ import 
org.apache.streampipes.storage.couchdb.compat.ModelFixtures.Variant;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.DynamicTest;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestFactory;
 import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
-import org.lightcouch.CouchDbClient;
-import org.lightcouch.CouchDbProperties;
 import org.testcontainers.containers.GenericContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
 
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
-import java.nio.charset.StandardCharsets;
 import java.time.Duration;
-import java.util.Base64;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.fail;
 
 /**
- * Writes every stored model with the real LightCouch client and with the new 
client into CouchDB 3.3.1, then
- * compares what CouchDB stored and reads each document back with both 
clients. Unlike
+ * Writes every stored model the way LightCouch did ({@link 
LegacyCouchDbHttp}) and with the new client into CouchDB
+ * 3.3.1, then compares what CouchDB stored and reads each document back both 
ways. Unlike
  * {@link CodecCompatibilityTest} this covers CouchDB's own re-serialization 
of documents. Enable with
  * {@code -Dstreampipes.couchdb.integration=true}.
  */
 @EnabledIfSystemProperty(named = "streampipes.couchdb.integration", matches = 
"true")
-public class LightCouchCompatibilityIntegrationTest {
+public class StoredFormatCompatibilityIntegrationTest {
 
   private static final String USER = "admin";
   private static final String PASSWORD = "admin";
@@ -114,7 +106,9 @@ public class LightCouchCompatibilityIntegrationTest {
     var db = server.database("compat-generic");
     db.create();
 
-    putVerbatim("compat-generic", "verbatim", payload);
+    try (var legacy = legacy(new Gson())) {
+      legacy.put("compat-generic", "verbatim", payload);
+    }
     Map<String, Object> parsed = 
JacksonSerializer.getObjectMapper().readValue(payload, new TypeReference<>() {
     });
     parsed.put("_id", "via-map");
@@ -130,7 +124,7 @@ public class LightCouchCompatibilityIntegrationTest {
    * {@link GsonCodec}.
    */
   @Test
-  public void eventMapStoredLikeLightCouch() {
+  public void eventMapStoredLikeLightCouch() throws Exception {
     var event = new LinkedHashMap<String, Object>();
     event.put("_id", "event");
     event.put("text", "Ünï <&> \u2028 😀");
@@ -143,12 +137,9 @@ public class LightCouchCompatibilityIntegrationTest {
     event.put("none", null);
     event.put("nested", Map.of("list", List.of(1, "a", Map.of("k", 
List.of()))));
 
-    var legacy = new CouchDbClient(new CouchDbProperties("compat-sink-legacy", 
true, "http", couchDb.getHost(),
-        couchDb.getMappedPort(5984), USER, PASSWORD));
-    try {
-      legacy.save(event);
-    } finally {
-      legacy.shutdown();
+    server.database("compat-sink-legacy").create();
+    try (var legacy = legacy(LegacyCouchDbPath.gson(new GsonBuilder()))) {
+      legacy.save("compat-sink-legacy", "event", event);
     }
     var db = server.database("compat-sink-new");
     db.create();
@@ -159,14 +150,14 @@ public class LightCouchCompatibilityIntegrationTest {
         JsonTrees.without(db.typed(JsonNode.class, EXACT).get("event"), 
"_rev"));
   }
 
-  private static void check(StoredModel model, String databasePrefix) {
+  private static void check(StoredModel model, String databasePrefix) throws 
Exception {
     String legacyDb = databasePrefix + "-legacy";
     String newDb = databasePrefix + "-new";
+    server.database(legacyDb).create();
+    server.database(newDb).create();
     Gson legacyGson = LegacyCouchDbPath.gson(model.gsonBuilder().get());
     GsonCodec codec = model.newCodec();
-    CouchDbClient legacyOnLegacy = lightCouch(legacyDb, model);
-    CouchDbClient legacyOnNew = lightCouch(newDb, model);
-    try {
+    try (var legacy = legacy(legacyGson)) {
       TypedCollection<Object> newOnLegacy = 
server.database(legacyDb).typed(rawClass(model.readType()), codec);
       TypedCollection<Object> newOnNew = 
server.database(newDb).typed(rawClass(model.readType()), codec);
       for (Variant variant : Variant.values()) {
@@ -174,45 +165,27 @@ public class LightCouchCompatibilityIntegrationTest {
         Object fixture = ModelFixtures.create(model.fixtureType(), variant, 
id, codec.gson());
         String step = model + " " + variant;
 
-        legacyOnLegacy.save(fixture);
+        legacy.save(legacyDb, id, fixture);
         newOnNew.create(fixture);
         assertSame(step + ", stored document",
             JsonTrees.without(server.database(legacyDb).typed(JsonNode.class, 
EXACT).get(id), "_rev"),
             JsonTrees.without(server.database(newDb).typed(JsonNode.class, 
EXACT).get(id), "_rev"));
 
-        JsonNode expected = reencode(legacyGson, 
legacyOnLegacy.find(model.readType(), id));
+        JsonNode expected = reencode(legacyGson, legacy.find(legacyDb, id, 
model.readType()));
         assertSame(step + ", LightCouch reads new client's document", expected,
-            reencode(legacyGson, legacyOnNew.find(model.readType(), id)));
+            reencode(legacyGson, legacy.find(newDb, id, model.readType())));
         assertSame(step + ", new client reads LightCouch's document", expected,
             reencode(legacyGson, newOnLegacy.get(id)));
         assertSame(step + ", new client reads its own document", expected, 
reencode(legacyGson, newOnNew.get(id)));
         assertSame(step + ", LightCouch _all_docs", expected,
-            byId(legacyGson, 
legacyOnNew.view("_all_docs").includeDocs(true).query(model.readType()), id));
+            byId(legacyGson, legacy.allDocs(newDb, model.readType()), id));
         assertSame(step + ", new client findAll", expected, byId(legacyGson, 
newOnLegacy.findAll(), id));
       }
-    } finally {
-      legacyOnLegacy.shutdown();
-      legacyOnNew.shutdown();
     }
   }
 
-  private static CouchDbClient lightCouch(String database, StoredModel model) {
-    var client = new CouchDbClient(new CouchDbProperties(database, true, 
"http", couchDb.getHost(),
-        couchDb.getMappedPort(5984), USER, PASSWORD));
-    client.setGsonBuilder(model.gsonBuilder().get());
-    return client;
-  }
-
-  private static void putVerbatim(String database, String id, String payload) 
throws Exception {
-    String auth = Base64.getEncoder().encodeToString((USER + ":" + 
PASSWORD).getBytes(StandardCharsets.UTF_8));
-    try (var http = HttpClient.newHttpClient()) {
-      var response = 
http.send(HttpRequest.newBuilder(URI.create(server.config().baseUrl() + "/" + 
database + "/" + id))
-          .header("Authorization", "Basic " + auth)
-          .header("Content-Type", "application/json")
-          .PUT(HttpRequest.BodyPublishers.ofString(payload))
-          .build(), HttpResponse.BodyHandlers.ofString());
-      assertEquals(201, response.statusCode(), response.body());
-    }
+  private static LegacyCouchDbHttp legacy(Gson gson) {
+    return new LegacyCouchDbHttp(server.config().baseUrl(), USER, PASSWORD, 
gson);
   }
 
   private static JsonNode byId(Gson legacyGson, List<?> documents, String id) {

Reply via email to