diff --git a/core/edr-cache-core/src/main/java/org/eclipse/tractusx/edc/edr/core/defaults/InMemoryEndpointDataReferenceCache.java b/core/edr-cache-core/src/main/java/org/eclipse/tractusx/edc/edr/core/defaults/InMemoryEndpointDataReferenceCache.java index cc6e24081..0149902bf 100644 --- a/core/edr-cache-core/src/main/java/org/eclipse/tractusx/edc/edr/core/defaults/InMemoryEndpointDataReferenceCache.java +++ b/core/edr-cache-core/src/main/java/org/eclipse/tractusx/edc/edr/core/defaults/InMemoryEndpointDataReferenceCache.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Predicate; import java.util.stream.Stream; @@ -45,7 +46,7 @@ public class InMemoryEndpointDataReferenceCache implements EndpointDataReference private final LockManager lockManager; private final EdrCacheEntryPredicateConverter predicateConverter = new EdrCacheEntryPredicateConverter(); - + private final Map> entriesByAssetId; private final Map entriesByEdrId; @@ -54,7 +55,7 @@ public class InMemoryEndpointDataReferenceCache implements EndpointDataReference public InMemoryEndpointDataReferenceCache() { lockManager = new LockManager(new ReentrantReadWriteLock()); entriesByAssetId = new HashMap<>(); - entriesByEdrId = new HashMap<>(); + entriesByEdrId = new ConcurrentHashMap<>(); edrsByTransferProcessId = new HashMap<>(); } diff --git a/edc-dataplane/edc-dataplane-base/build.gradle.kts b/edc-dataplane/edc-dataplane-base/build.gradle.kts index 09d88a015..4b2999a02 100644 --- a/edc-dataplane/edc-dataplane-base/build.gradle.kts +++ b/edc-dataplane/edc-dataplane-base/build.gradle.kts @@ -23,7 +23,11 @@ plugins { } dependencies { + runtimeOnly(project(":core:edr-cache-core")) runtimeOnly(project(":edc-extensions:observability-api-customization")) + runtimeOnly(project(":edc-dataplane:edc-dataplane-proxy-consumer-api")) + runtimeOnly(project(":edc-dataplane:edc-dataplane-proxy-provider-api")) + runtimeOnly(project(":edc-dataplane:edc-dataplane-proxy-provider-core")) runtimeOnly(libs.edc.config.filesystem) runtimeOnly(libs.edc.dpf.awss3) diff --git a/edc-dataplane/edc-dataplane-hashicorp-vault/build.gradle.kts b/edc-dataplane/edc-dataplane-hashicorp-vault/build.gradle.kts index 42bbd4d57..682c9b214 100644 --- a/edc-dataplane/edc-dataplane-hashicorp-vault/build.gradle.kts +++ b/edc-dataplane/edc-dataplane-hashicorp-vault/build.gradle.kts @@ -26,6 +26,7 @@ plugins { dependencies { implementation(project(":edc-dataplane:edc-dataplane-base")) implementation(project(":edc-extensions:hashicorp-vault")) + runtimeOnly(project(":edc-extensions:edr-cache-sql")) } tasks.withType { diff --git a/edc-dataplane/edc-dataplane-proxy-consumer-api/build.gradle.kts b/edc-dataplane/edc-dataplane-proxy-consumer-api/build.gradle.kts index 6af73c993..ee5edb153 100644 --- a/edc-dataplane/edc-dataplane-proxy-consumer-api/build.gradle.kts +++ b/edc-dataplane/edc-dataplane-proxy-consumer-api/build.gradle.kts @@ -24,7 +24,6 @@ dependencies { implementation(libs.edc.spi.http) implementation(libs.edc.util) implementation(libs.edc.dpf.framework) - implementation(libs.edc.api.observability) implementation(libs.edc.dpf.util) implementation(libs.edc.ext.http) diff --git a/edc-dataplane/edc-dataplane-proxy-provider-api/build.gradle.kts b/edc-dataplane/edc-dataplane-proxy-provider-api/build.gradle.kts index 37aabac01..9a9158299 100644 --- a/edc-dataplane/edc-dataplane-proxy-provider-api/build.gradle.kts +++ b/edc-dataplane/edc-dataplane-proxy-provider-api/build.gradle.kts @@ -22,7 +22,6 @@ dependencies { implementation(libs.edc.spi.http) implementation(libs.edc.util) implementation(libs.edc.dpf.framework) - implementation(libs.edc.api.observability) implementation(libs.edc.dpf.util) implementation(libs.edc.ext.http) implementation(libs.edc.spi.jwt) diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/build.gradle.kts b/edc-dataplane/edc-dataplane-proxy-provider-core/build.gradle.kts index fae93ad79..338cab554 100644 --- a/edc-dataplane/edc-dataplane-proxy-provider-core/build.gradle.kts +++ b/edc-dataplane/edc-dataplane-proxy-provider-core/build.gradle.kts @@ -20,7 +20,6 @@ dependencies { implementation(libs.edc.util) implementation(libs.edc.dpf.framework) - implementation(libs.edc.api.observability) implementation(libs.edc.dpf.util) implementation(libs.edc.jwt.core) implementation(libs.edc.ext.http) diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/EdrNegotiationHelperFunctions.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/EdrNegotiationHelperFunctions.java index f85f0dc46..bc4bb22a7 100644 --- a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/EdrNegotiationHelperFunctions.java +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/EdrNegotiationHelperFunctions.java @@ -20,6 +20,7 @@ import jakarta.json.JsonObject; import org.eclipse.edc.jsonld.TitaniumJsonLd; import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.spi.event.Event; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.tractusx.edc.api.cp.adapter.dto.NegotiateEdrRequestDto; @@ -62,4 +63,7 @@ public static JsonObject createCallback(String url, boolean transactional, Set ReceivedEvent createEvent(Class klass) { + return ReceivedEvent.Builder.newInstance().type(klass.getSimpleName()).build(); + } } diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/ReceivedEvent.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/ReceivedEvent.java new file mode 100644 index 000000000..55d012cc2 --- /dev/null +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/ReceivedEvent.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.tractusx.edc.helpers; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + + +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReceivedEvent { + private String type; + + public String getType() { + return type; + } + + @Override + public String toString() { + return "ReceivedEvent{" + + "type='" + type + '\'' + + '}'; + } + + public static class Builder { + private final ReceivedEvent event; + + private Builder(ReceivedEvent event) { + this.event = event; + } + + public static Builder newInstance() { + return new Builder(new ReceivedEvent()); + } + + public Builder type(String type) { + this.event.type = type; + return this; + } + + public ReceivedEvent build() { + return event; + } + } +} + diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/Participant.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/Participant.java index ea6e3054b..7f77f1726 100644 --- a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/Participant.java +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/Participant.java @@ -15,6 +15,7 @@ package org.eclipse.tractusx.edc.lifecycle; import com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.response.Response; import io.restassured.specification.RequestSpecification; import jakarta.json.Json; import jakarta.json.JsonArray; @@ -53,9 +54,14 @@ public class Participant { + private static final String PROXY_SUBPATH = "proxy/aas/request"; + private final String managementUrl; private final String apiKey; private final String dspEndpoint; + + private final String gatewayEndpoint; + private final String runtimeName; private final String bpn; private final String backend; @@ -63,18 +69,20 @@ public class Participant { private final Duration timeout = Duration.ofSeconds(30); private final ObjectMapper objectMapper = JacksonJsonLd.createObjectMapper(); + private final String proxyUrl; public Participant(String runtimeName, String bpn, Map properties) { this.managementUrl = URI.create(format("http://localhost:%s%s", properties.get("web.http.management.port"), properties.get("web.http.management.path"))).toString(); this.dspEndpoint = URI.create(format("http://localhost:%s%s", properties.get("web.http.protocol.port"), properties.get("web.http.protocol.path"))).toString(); this.apiKey = properties.get("edc.api.auth.key"); + this.gatewayEndpoint = URI.create(format("http://localhost:%s/api/gateway", properties.get("web.http.port"))).toString(); + this.proxyUrl = URI.create(format("http://localhost:%s", properties.get("tx.dpf.consumer.proxy.port"))).toString(); this.bpn = bpn; this.runtimeName = runtimeName; this.backend = properties.get("edc.receiver.http.dynamic.endpoint"); jsonLd = new TitaniumJsonLd(mock(Monitor.class)); } - /** * Creates an asset with the given ID and props using the participant's Data Management API */ @@ -150,7 +158,7 @@ public String negotiateContract(Participant other, String assetId) { return response.extract().jsonPath().getString(ID); } - public void negotiateEdr(Participant other, String assetId, JsonArray callbacks) { + public String negotiateEdr(Participant other, String assetId, JsonArray callbacks) { var dataset = getDatasetForAsset(other, assetId); assertThat(dataset).withFailMessage("Catalog received from " + other.runtimeName + " was empty!").isNotEmpty(); @@ -169,6 +177,7 @@ public void negotiateEdr(Participant other, String assetId, JsonArray callbacks) var body = response.extract().body().asString(); assertThat(response.extract().statusCode()).withFailMessage(body).isBetween(200, 299); + return response.extract().jsonPath().getString(ID); } public String getNegotiationState(String negotiationId) { @@ -180,7 +189,6 @@ public String getNegotiationState(String negotiationId) { .extract().body().jsonPath().getString("'edc:state'"); } - public String getContractAgreementId(String negotiationId) { return getContractNegotiationField(negotiationId, "contractAgreementId"); } @@ -206,7 +214,7 @@ public JsonObject getEdr(String transferProcessId) { .as(JsonObject.class); } - public JsonArray getEdrEntries(String assetId) { + public JsonArray getEdrEntriesByAssetId(String assetId) { return baseRequest() .when() .get("/adapter/edrs?assetId={assetId}", assetId) @@ -217,6 +225,17 @@ public JsonArray getEdrEntries(String assetId) { .as(JsonArray.class); } + public JsonArray getEdrEntriesByAgreementId(String agreementId) { + return baseRequest() + .when() + .get("/adapter/edrs?agreementId={agreementId}", agreementId) + .then() + .statusCode(200) + .extract() + .body() + .as(JsonArray.class); + } + /** * Returns this participant's BusinessPartnerNumber (=BPN). This is constructed of the runtime name plus "-BPN" @@ -309,6 +328,38 @@ public JsonArray getCatalogDatasets(Participant provider, JsonObject querySpec) return datasetReference.get(); } + public String pullProxyDataByAssetId(Participant provider, String assetId) { + var body = Map.of("assetId", assetId, "endpointUrl", format("%s/aas/test", provider.gatewayEndpoint)); + return getProxyData(body); + } + + public Response pullProxyDataResponseByAssetId(Participant provider, String assetId) { + var body = Map.of("assetId", assetId, "endpointUrl", format("%s/aas/test", provider.gatewayEndpoint)); + return proxyRequest(body); + } + + public String pullProxyDataByTransferProcessId(Participant provider, String transferProcessId) { + var body = Map.of("transferProcessId", transferProcessId, + "endpointUrl", format("%s/aas/test", provider.gatewayEndpoint)); + return getProxyData(body); + + } + + private String getProxyData(Map body) { + return proxyRequest(body) + .then() + .assertThat().statusCode(200) + .extract().body().asString(); + } + + private Response proxyRequest(Map body) { + return given() + .baseUri(proxyUrl) + .contentType("application/json") + .body(body) + .post(PROXY_SUBPATH); + } + public JsonObject getDatasetForAsset(Participant provider, String assetId) { var datasets = getCatalogDatasets(provider); return datasets.stream() @@ -318,7 +369,6 @@ public JsonObject getDatasetForAsset(Participant provider, String assetId) { .orElseThrow(() -> new EdcException(format("No dataset for asset %s in the catalog", assetId))); } - private RequestSpecification baseRequest() { return given() .baseUri(managementUrl) diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/TestRuntimeConfiguration.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/TestRuntimeConfiguration.java index 0e83f6ce7..5309f68b9 100644 --- a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/TestRuntimeConfiguration.java +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/TestRuntimeConfiguration.java @@ -30,6 +30,7 @@ public class TestRuntimeConfiguration { public static final String SOKRATES_BPN = SOKRATES_NAME + BPN_SUFFIX; public static final String PLATO_NAME = "PLATO"; public static final String PLATO_BPN = PLATO_NAME + BPN_SUFFIX; + public static final Integer PLATO_PROXIED_AAS_BACKEND_PORT = getFreePort(); static final String DSP_PATH = "/api/v1/dsp"; static final int PLATO_CONNECTOR_PORT = getFreePort(); static final int PLATO_MANAGEMENT_PORT = getFreePort(); @@ -46,8 +47,12 @@ public class TestRuntimeConfiguration { static final String SOKRATES_PUBLIC_API_PORT = String.valueOf(getFreePort()); static final String PLATO_PUBLIC_API_PORT = String.valueOf(getFreePort()); static final String PLATO_DATAPLANE_CONTROL_PORT = String.valueOf(getFreePort()); + static final String PLATO_DATAPLANE_PROXY_PORT = String.valueOf(getFreePort()); static final String SOKRATES_DATAPLANE_CONTROL_PORT = String.valueOf(getFreePort()); + static final String SOKRATES_DATAPLANE_PROXY_PORT = String.valueOf(getFreePort()); + + public static Map sokratesPostgresqlConfiguration() { var baseConfiguration = sokratesConfiguration(); var postgresConfiguration = postgresqlConfiguration(SOKRATES_NAME.toLowerCase()); @@ -64,7 +69,7 @@ public static Map platoPostgresqlConfiguration() { public static Map postgresqlConfiguration(String name) { var jdbcUrl = jdbcUrl(name); - return new HashMap() { + return new HashMap<>() { { put("edc.datasource.asset.name", "asset"); put("edc.datasource.asset.url", jdbcUrl); @@ -113,6 +118,7 @@ public static Map sokratesConfiguration() { // embedded dataplane config put("web.http.control.path", "/api/dataplane/control"); put("web.http.control.port", SOKRATES_DATAPLANE_CONTROL_PORT); + put("tx.dpf.consumer.proxy.port", SOKRATES_DATAPLANE_PROXY_PORT); put("edc.dataplane.token.validation.endpoint", "http://localhost:" + SOKRATES_DATAPLANE_CONTROL_PORT + "/api/dataplane/control/token"); put("edc.dataplane.selector.httpplane.url", "http://localhost:" + SOKRATES_DATAPLANE_CONTROL_PORT + "/api/dataplane/control"); put("edc.dataplane.selector.httpplane.sourcetypes", "HttpData"); @@ -124,7 +130,7 @@ public static Map sokratesConfiguration() { } }; } - + public static Map platoConfiguration() { return new HashMap<>() { { @@ -143,6 +149,7 @@ public static Map platoConfiguration() { // embedded dataplane config put("web.http.control.path", "/api/dataplane/control"); put("web.http.control.port", PLATO_DATAPLANE_CONTROL_PORT); + put("tx.dpf.consumer.proxy.port", PLATO_DATAPLANE_PROXY_PORT); put("edc.dataplane.token.validation.endpoint", "http://localhost:" + PLATO_DATAPLANE_CONTROL_PORT + "/api/dataplane/control/token"); put("edc.dataplane.selector.httpplane.url", "http://localhost:" + PLATO_DATAPLANE_CONTROL_PORT + "/api/dataplane/control"); put("edc.dataplane.selector.httpplane.sourcetypes", "HttpData"); @@ -150,6 +157,8 @@ public static Map platoConfiguration() { put("edc.dataplane.selector.httpplane.properties", "{\"publicApiUrl\":\"http://localhost:" + PLATO_PUBLIC_API_PORT + "/api/public\"}"); put("tractusx.businesspartnervalidation.log.agreement.validation", "true"); put("edc.agent.identity.key", "BusinessPartnerNumber"); + put("tx.dpf.proxy.gateway.aas.proxied.path", "http://localhost:" + PLATO_PROXIED_AAS_BACKEND_PORT); + put("tx.dpf.proxy.gateway.aas.authorization.type", "none"); } }; } diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/edr/AbstractNegotiateEdrTest.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/edr/AbstractNegotiateEdrTest.java index 65542bb9e..30ebb4bee 100644 --- a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/edr/AbstractNegotiateEdrTest.java +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/edr/AbstractNegotiateEdrTest.java @@ -14,7 +14,6 @@ package org.eclipse.tractusx.edc.tests.edr; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.json.Json; import okhttp3.mockwebserver.MockResponse; @@ -29,7 +28,7 @@ import org.eclipse.edc.connector.transfer.spi.event.TransferProcessProvisioned; import org.eclipse.edc.connector.transfer.spi.event.TransferProcessRequested; import org.eclipse.edc.connector.transfer.spi.event.TransferProcessStarted; -import org.eclipse.edc.spi.event.Event; +import org.eclipse.tractusx.edc.helpers.ReceivedEvent; import org.eclipse.tractusx.edc.lifecycle.Participant; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -44,6 +43,7 @@ import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; import static org.eclipse.edc.spi.types.domain.edr.EndpointDataReference.EDR_SIMPLE_TYPE; import static org.eclipse.tractusx.edc.helpers.EdrNegotiationHelperFunctions.createCallback; +import static org.eclipse.tractusx.edc.helpers.EdrNegotiationHelperFunctions.createEvent; import static org.eclipse.tractusx.edc.helpers.PolicyHelperFunctions.businessPartnerNumberPolicy; import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.PLATO_BPN; import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.PLATO_NAME; @@ -111,8 +111,7 @@ void negotiateEdr_shouldInvokeCallbacks() throws IOException { assertThat(expectedEvents).usingRecursiveFieldByFieldElementComparator().containsAll(events); - - var edrCaches = SOKRATES.getEdrEntries(assetId); + var edrCaches = SOKRATES.getEdrEntriesByAssetId(assetId); assertThat(edrCaches).hasSize(1); @@ -128,9 +127,6 @@ void negotiateEdr_shouldInvokeCallbacks() throws IOException { } - ReceivedEvent createEvent(Class klass) { - return ReceivedEvent.Builder.newInstance().type(klass.getSimpleName()).build(); - } ReceivedEvent waitForEvent(ReceivedEvent event) { try { @@ -145,42 +141,5 @@ ReceivedEvent waitForEvent(ReceivedEvent event) { } } - @JsonIgnoreProperties(ignoreUnknown = true) - private static class ReceivedEvent { - private String type; - - public String getType() { - return type; - } - - @Override - public String toString() { - return "ReceivedEvent{" + - "type='" + type + '\'' + - '}'; - } - - public static class Builder { - private final AbstractNegotiateEdrTest.ReceivedEvent event; - - private Builder(AbstractNegotiateEdrTest.ReceivedEvent event) { - this.event = event; - } - - public static Builder newInstance() { - return new Builder(new AbstractNegotiateEdrTest.ReceivedEvent()); - } - public Builder type(String type) { - this.event.type = type; - return this; - } - - public AbstractNegotiateEdrTest.ReceivedEvent build() { - return event; - } - } - - - } } diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/AbstractDataPlaneProxyTest.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/AbstractDataPlaneProxyTest.java new file mode 100644 index 000000000..176662720 --- /dev/null +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/AbstractDataPlaneProxyTest.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.tractusx.edc.tests.proxy; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.json.Json; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.eclipse.edc.connector.transfer.spi.event.TransferProcessCompleted; +import org.eclipse.edc.spi.event.EventEnvelope; +import org.eclipse.tractusx.edc.lifecycle.Participant; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; +import static org.eclipse.tractusx.edc.helpers.EdrNegotiationHelperFunctions.createCallback; +import static org.eclipse.tractusx.edc.helpers.PolicyHelperFunctions.businessPartnerNumberPolicy; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.PLATO_BPN; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.PLATO_NAME; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.PLATO_PROXIED_AAS_BACKEND_PORT; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.SOKRATES_BPN; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.SOKRATES_NAME; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.platoConfiguration; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.sokratesConfiguration; + +public abstract class AbstractDataPlaneProxyTest { + + protected static final Participant SOKRATES = new Participant(SOKRATES_NAME, SOKRATES_BPN, sokratesConfiguration()); + protected static final Participant PLATO = new Participant(PLATO_NAME, PLATO_BPN, platoConfiguration()); + + MockWebServer server = new MockWebServer(); + + ObjectMapper mapper = new ObjectMapper(); + + @Test + @DisplayName("Verify E2E flow with Data Plane proxies and EDR") + void httpPullDataTransfer_withEdrAndProxy() throws IOException { + + var eventsUrl = server.url("/events"); + + var assetId = "api-asset-1"; + var authCodeHeaderName = "test-authkey"; + var authCode = "test-authcode"; + PLATO.createAsset(assetId, Json.createObjectBuilder().build(), Json.createObjectBuilder() + .add(EDC_NAMESPACE + "type", "HttpData") + .add(EDC_NAMESPACE + "contentType", "application/json") + .add(EDC_NAMESPACE + "baseUrl", eventsUrl.toString()) + .add(EDC_NAMESPACE + "authKey", authCodeHeaderName) + .add(EDC_NAMESPACE + "authCode", authCode) + .build()); + + PLATO.createPolicy(businessPartnerNumberPolicy("policy-1", SOKRATES.getBpn())); + PLATO.createPolicy(businessPartnerNumberPolicy("policy-2", SOKRATES.getBpn())); + PLATO.createContractDefinition(assetId, "def-1", "policy-1", "policy-2"); + + var callbacks = Json.createArrayBuilder() + .add(createCallback(eventsUrl.toString(), true, Set.of("transfer.process.completed"))) + .build(); + + // response to callback + server.enqueue(new MockResponse()); + + SOKRATES.negotiateEdr(PLATO, assetId, callbacks); + + var transferEvent = waitForTransferCompletion(); + + var body = "{\"response\": \"ok\"}"; + + server.enqueue(new MockResponse().setBody(body)); + var data = SOKRATES.pullProxyDataByAssetId(PLATO, assetId); + assertThat(data).isEqualTo(body); + + server.enqueue(new MockResponse().setBody(body)); + data = SOKRATES.pullProxyDataByTransferProcessId(PLATO, transferEvent.getPayload().getTransferProcessId()); + assertThat(data).isEqualTo(body); + } + + @Test + @DisplayName("Verify E2E flow with Data Plane proxies fails when EDR is not found") + void httpPullDataTransfer_withoutEdr() throws IOException { + + var eventsUrl = server.url("/events"); + + var assetId = "api-asset-1"; + var authCodeHeaderName = "test-authkey"; + var authCode = "test-authcode"; + PLATO.createAsset(assetId, Json.createObjectBuilder().build(), Json.createObjectBuilder() + .add(EDC_NAMESPACE + "type", "HttpData") + .add(EDC_NAMESPACE + "contentType", "application/json") + .add(EDC_NAMESPACE + "baseUrl", eventsUrl.toString()) + .add(EDC_NAMESPACE + "authKey", authCodeHeaderName) + .add(EDC_NAMESPACE + "authCode", authCode) + .build()); + + PLATO.createPolicy(businessPartnerNumberPolicy("policy-1", SOKRATES.getBpn())); + PLATO.createPolicy(businessPartnerNumberPolicy("policy-2", SOKRATES.getBpn())); + PLATO.createContractDefinition(assetId, "def-1", "policy-1", "policy-2"); + + + SOKRATES.pullProxyDataResponseByAssetId(PLATO, assetId) + .then() + .assertThat().statusCode(400); + + } + + @Test + @DisplayName("Verify E2E flow with Data Plane proxies and Two EDR") + void httpPullDataTransfer_shouldFailForAsset_withTwoEdrAndProxy() throws IOException { + + var eventsUrl = server.url("/events"); + + var assetId = "api-asset-1"; + var authCodeHeaderName = "test-authkey"; + var authCode = "test-authcode"; + PLATO.createAsset(assetId, Json.createObjectBuilder().build(), Json.createObjectBuilder() + .add(EDC_NAMESPACE + "type", "HttpData") + .add(EDC_NAMESPACE + "contentType", "application/json") + .add(EDC_NAMESPACE + "baseUrl", eventsUrl.toString()) + .add(EDC_NAMESPACE + "authKey", authCodeHeaderName) + .add(EDC_NAMESPACE + "authCode", authCode) + .build()); + + PLATO.createPolicy(businessPartnerNumberPolicy("policy-1", SOKRATES.getBpn())); + PLATO.createPolicy(businessPartnerNumberPolicy("policy-2", SOKRATES.getBpn())); + PLATO.createContractDefinition(assetId, "def-1", "policy-1", "policy-2"); + + var callbacks = Json.createArrayBuilder() + .add(createCallback(eventsUrl.toString(), true, Set.of("transfer.process.completed"))) + .build(); + + // response to callback + server.enqueue(new MockResponse()); + server.enqueue(new MockResponse()); + + SOKRATES.negotiateEdr(PLATO, assetId, callbacks); + SOKRATES.negotiateEdr(PLATO, assetId, callbacks); + + var transferEvent1 = waitForTransferCompletion(); + var transferEvent2 = waitForTransferCompletion(); + + var body = "{\"response\": \"ok\"}"; + + server.enqueue(new MockResponse().setBody(body)); + SOKRATES.pullProxyDataResponseByAssetId(PLATO, assetId).then() + .assertThat().statusCode(428); + + server.enqueue(new MockResponse().setBody(body)); + var data = SOKRATES.pullProxyDataByTransferProcessId(PLATO, transferEvent1.getPayload().getTransferProcessId()); + assertThat(data).isEqualTo(body); + + server.enqueue(new MockResponse().setBody(body)); + data = SOKRATES.pullProxyDataByTransferProcessId(PLATO, transferEvent2.getPayload().getTransferProcessId()); + assertThat(data).isEqualTo(body); + } + + @BeforeEach + void setup() throws IOException { + server.start(PLATO_PROXIED_AAS_BACKEND_PORT); + } + + @AfterEach + void teardown() throws IOException { + server.shutdown(); + } + + EventEnvelope waitForTransferCompletion() { + try { + var request = server.takeRequest(20, TimeUnit.SECONDS); + if (request != null) { + return mapper.readValue(request.getBody().inputStream(), new TypeReference<>() { + }); + } else { + throw new RuntimeException("Timeout exceeded waiting for events"); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/DataPlaneProxyInMemoryTest.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/DataPlaneProxyInMemoryTest.java new file mode 100644 index 000000000..828383b19 --- /dev/null +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/DataPlaneProxyInMemoryTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.tractusx.edc.tests.proxy; + +import org.eclipse.edc.junit.annotations.EndToEndTest; +import org.eclipse.tractusx.edc.lifecycle.ParticipantRuntime; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.PLATO_BPN; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.PLATO_NAME; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.SOKRATES_BPN; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.SOKRATES_NAME; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.platoConfiguration; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.sokratesConfiguration; + +@EndToEndTest +public class DataPlaneProxyInMemoryTest extends AbstractDataPlaneProxyTest { + + @RegisterExtension + protected static final ParticipantRuntime SOKRATES_RUNTIME = new ParticipantRuntime( + ":edc-tests:runtime:runtime-memory", + SOKRATES_NAME, + SOKRATES_BPN, + sokratesConfiguration() + ); + + @RegisterExtension + protected static final ParticipantRuntime PLATO_RUNTIME = new ParticipantRuntime( + ":edc-tests:runtime:runtime-memory", + PLATO_NAME, + PLATO_BPN, + platoConfiguration() + ); +} diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/DataPlaneProxyPostgresqlTest.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/DataPlaneProxyPostgresqlTest.java new file mode 100644 index 000000000..f2da5eba8 --- /dev/null +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/DataPlaneProxyPostgresqlTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.tractusx.edc.tests.proxy; + +import org.eclipse.edc.junit.annotations.PostgresqlDbIntegrationTest; +import org.eclipse.tractusx.edc.lifecycle.PgParticipantRuntime; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.PLATO_BPN; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.PLATO_NAME; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.SOKRATES_BPN; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.SOKRATES_NAME; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.platoPostgresqlConfiguration; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.sokratesPostgresqlConfiguration; + +@PostgresqlDbIntegrationTest +public class DataPlaneProxyPostgresqlTest extends AbstractDataPlaneProxyTest { + + @RegisterExtension + protected static final PgParticipantRuntime SOKRATES_RUNTIME = new PgParticipantRuntime( + ":edc-tests:runtime:runtime-postgresql", + SOKRATES_NAME, + SOKRATES_BPN, + sokratesPostgresqlConfiguration() + ); + @RegisterExtension + protected static final PgParticipantRuntime PLATO_RUNTIME = new PgParticipantRuntime( + ":edc-tests:runtime:runtime-postgresql", + PLATO_NAME, + PLATO_BPN, + platoPostgresqlConfiguration() + ); +} diff --git a/edc-tests/runtime/runtime-memory/build.gradle.kts b/edc-tests/runtime/runtime-memory/build.gradle.kts index c4f3054ea..f339202e2 100644 --- a/edc-tests/runtime/runtime-memory/build.gradle.kts +++ b/edc-tests/runtime/runtime-memory/build.gradle.kts @@ -28,13 +28,13 @@ dependencies { } implementation(project(":edc-tests:runtime:extensions")) - + // use basic (all in-mem) data plane runtimeOnly(project(":edc-dataplane:edc-dataplane-base")) { exclude("org.eclipse.edc", "api-observability") } - + implementation(libs.edc.core.controlplane) // for the controller implementation(libs.jakarta.rsApi)