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) {
