diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md index 66e703df3..abd5b9ef6 100644 --- a/.github/ISSUE_TEMPLATE/release.md +++ b/.github/ISSUE_TEMPLATE/release.md @@ -50,7 +50,7 @@ Feel free to edit this release checklist in-progress depending on what tasks nee - [ ] Set the UI release version for `EDC_UI_IMAGE` of the [docker-compose's .env file](https://github.com/sovity/edc-ce/blob/main/.env). - [ ] If the Eclipse EDC version changed, update - the [eclipse-edc-management-api.yaml file](https://github.com/sovity/edc-ce/blob/main/docs/api/eclipse-edc-management-api.yaml). + the [eclipse-edc-management-api.yaml file](https://github.com/sovity/edc-ce/blob/main/docs/api/eclipse-edc-management-api.yaml) with [the official one](https://app.swaggerhub.com/apis/eclipse-edc-bot/management-api/). - [ ] Run all tests locally as long as the [GH flaky tests](https://github.com/sovity/edc-ce/issues/870) are a problem. - [ ] Merge the `release-prep` PR. - [ ] Wait for the main branch to be green. You can check the status in GH [actions](https://github.com/sovity/edc-ce/actions). diff --git a/.github/markdown-link-checker-config.jq b/.github/markdown-link-checker-config.jq index e73dc13c3..b045bf216 100755 --- a/.github/markdown-link-checker-config.jq +++ b/.github/markdown-link-checker-config.jq @@ -7,7 +7,9 @@ {"pattern": "^https://www\\.linkedin\\.com"}, {"pattern": "https://(.*?)\\.azure\\.sovity\\.io"}, {"pattern": "http://edc2?:"}, - {"pattern": "^https?://connector:"} + {"pattern": "^https?://connector:"}, + {"pattern": "^https://app.swaggerhub.com/apis/eclipse-edc-bot/management-api/.*?"}, + {"pattern": "^http://www.w3.org/ns/dcat.*"} ], "replacementPatterns": [ { diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3520f132c..5e0b8a9a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,8 +39,7 @@ jobs: - name: "Gradle: Overwrite Artifact Version (Release Only)" if: ${{ startsWith(github.ref, 'refs/tags/v') }} run: | - GRADLE_ARGS="-PsovityEdcExtensionsVersion=${GITHUB_REF#refs/tags/v}" - echo "GRADLE_ARGS=$GRADLE_ARGS" >> $GITHUB_ENV + sed -i "s/sovityCeVersion = \"[^\"]*\"/sovityCeVersion = \"${GITHUB_REF#refs/tags/v}\"/" gradle/libs.versions.toml - name: "Gradle: Build" uses: gradle/gradle-build-action@v2.10.0 with: diff --git a/UPDATES.md b/UPDATES.md index 62e413204..55c5530a9 100644 --- a/UPDATES.md +++ b/UPDATES.md @@ -8,7 +8,7 @@ These are not easily testable and require a manual check. After each EDC version update -- [ ] Check if `org.eclipse.edc.spi.types.domain.asset.Asset.toBuilder` added a new +- [ ] Check if `org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.toBuilder` added a new field and adjust the builder in `de.sovity.edc.ext.wrapper.api.ui.pages.asset.AssetBuilder.fromEditMetadataRequest` accordingly ## Context @@ -28,5 +28,5 @@ will remove that hypothetical new field. #### Workaround -On the EDC version update, check that `org.eclipse.edc.spi.types.domain.asset.Asset.toBuilder` doesn't set more +On the EDC version update, check that `org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset.toBuilder` doesn't set more fields than what we set. If a new field was added, add it to this function too. diff --git a/build.gradle.kts b/build.gradle.kts index 4172f9034..7628b7547 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,43 +12,10 @@ dependencies { testRuntimeOnly(libs.junit.engine) } -val downloadArtifact: Configuration by configurations.creating { - isTransitive = false -} - - -val identityHubVersion: String by project -val registrationServiceVersion: String by project - -// task that downloads the RegSrv CLI and IH CLI -val getJars by tasks.registering(Copy::class) { - outputs.upToDateWhen { false } //always download - - from(downloadArtifact) - // strip away the version string - .rename { s -> - s.replace("-${identityHubVersion}", "") - .replace("-${registrationServiceVersion}", "") - .replace("-all", "") - } - into(layout.projectDirectory.dir("libs/cli-tools")) -} - -// run the download jars task after the "jar" task -tasks { - jar { - finalizedBy(getJars) - } -} - allprojects { apply(plugin = "java") apply(plugin = "checkstyle") - configurations.all { - resolutionStrategy.force("org.eclipse.edc:runtime-metamodel:0.2.1") - } - tasks.withType { options.encoding = "UTF-8" sourceCompatibility = JavaVersion.VERSION_17.toString() @@ -60,7 +27,7 @@ allprojects { useJUnitPlatform { if (runningOnGithub) { - excludeTags = setOf("not-on-github") + excludeTags = setOf("exclude-on-github") } } @@ -70,6 +37,7 @@ allprojects { showExceptions = true showCauses = true } + failFast = true } @@ -88,17 +56,11 @@ allprojects { } maven { url = uri("https://maven.pkg.github.com/truzzt/mds-ap3") - credentials { - username = project.findProperty("gpr.user") as String? ?: System.getenv("USERNAME") - password = project.findProperty("gpr.key") as String? ?: System.getenv("TOKEN") - } + withGitHubCredentials() } maven { url = uri("https://maven.pkg.github.com/ids-basecamp/ids-infomodel-java") - credentials { - username = project.findProperty("gpr.user") as String? ?: System.getenv("USERNAME") - password = project.findProperty("gpr.key") as String? ?: System.getenv("TOKEN") - } + withGitHubCredentials() } maven { url = @@ -109,27 +71,25 @@ allprojects { } subprojects { + val libs = rootProject.libs + apply(plugin = "maven-publish") - val sovityEdcExtensionsVersion: String by project - version = sovityEdcExtensionsVersion + version = libs.versions.sovityCeVersion.get() publishing { repositories { maven { name = "GitHubPackages" url = uri("https://maven.pkg.github.com/sovity/edc-ce") - credentials { - username = project.findProperty("gpr.user") as String? ?: System.getenv("USERNAME") - password = project.findProperty("gpr.key") as String? ?: System.getenv("TOKEN") - } + withGitHubCredentials() } } } tasks.register("printClasspath") { - group = libs.versions.edcGroup.get() - description = "The EdcRuntimeExtension JUnit Extension requires the gradle task 'printClasspath'" + group = libs.versions.sovityEdcGroup.get() + description = "Prints the classpath so EDC Integration tests can load a runtime of a full EDC including modules in tests" println(sourceSets.main.get().runtimeClasspath.asPath) } @@ -137,3 +97,19 @@ subprojects { withSourcesJar() } } + +fun MavenArtifactRepository.withGitHubCredentials() { + val gitHubUser = System.getenv("USERNAME") + ?: project.findProperty("gpr.user") as String? + val gitHubToken = System.getenv("TOKEN") + ?: project.findProperty("gpr.key") as String? + + if (gitHubUser.isNullOrBlank() || gitHubToken.isNullOrBlank()) { + error("Need Gradle Properties 'gpr.user' and 'gpr.key' or environment variables 'USERNAME' and 'TOKEN' with a GitHub PAT to access the GitHub Maven Repository.") + } + + credentials { + username = gitHubUser + password = gitHubToken + } +} diff --git a/config/src/main/java/de/sovity/edc/utils/config/ConfigProps.java b/config/src/main/java/de/sovity/edc/utils/config/CeConfigProps.java similarity index 73% rename from config/src/main/java/de/sovity/edc/utils/config/ConfigProps.java rename to config/src/main/java/de/sovity/edc/utils/config/CeConfigProps.java index 55e0a6174..a2944bb15 100644 --- a/config/src/main/java/de/sovity/edc/utils/config/ConfigProps.java +++ b/config/src/main/java/de/sovity/edc/utils/config/CeConfigProps.java @@ -16,16 +16,12 @@ import de.sovity.edc.utils.config.model.ConfigProp; import de.sovity.edc.utils.config.utils.UrlPathUtils; -import lombok.RequiredArgsConstructor; -import lombok.Setter; -import lombok.experimental.Accessors; import lombok.experimental.UtilityClass; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Consumer; -import java.util.function.Supplier; /** * Configuration Properties for the EDC:
@@ -35,16 +31,16 @@ */ @SuppressWarnings("unused") @UtilityClass -public class ConfigProps { +public class CeConfigProps { public static final List ALL_CE_PROPS = new ArrayList<>(); public static final ConfigProp MY_EDC_NETWORK_TYPE = addCeProp(builder -> builder .category(Category.ADVANCED) .property("my.edc.network.type") .description("Configuring EDCs for different environments. Available values are: %s".formatted( - String.join(", ", NetworkType.ALL_NETWORK_TYPES))) + String.join(", ", CeEnvironment.ALL_CE_ENVIRONMENTS))) .warnIfOverridden(true) - .defaultValue(NetworkType.PRODUCTION) + .defaultValue(CeEnvironment.PRODUCTION) ); /* Basic Configuration */ @@ -102,8 +98,9 @@ public class ConfigProps { .category(Category.BASIC) .property("my.edc.fqdn") .description("Fully Qualified Domain Name of where the Connector is hosted, e.g. my-connector.myorg.com") - .requiredIf(props -> NetworkType.isProduction(props) || NetworkType.isLocalDemoDockerCompose(props)) - .defaultValueFn(props -> new NetworkTypeMatcher(props).unitTest(() -> "localhost").orElseThrow()) + .requiredIf(props -> !CeEnvironment.isUnitTest(props)) + // Only in network type "unit test" will the default be applied + .defaultValue("localhost") ); public static final ConfigProp MY_EDC_JDBC_URL = addCeProp(builder -> builder @@ -127,9 +124,20 @@ public class ConfigProps { .required(true) ); - /* Auth */ + public static final ConfigProp MY_EDC_VAULT_INIT_ENABLED = addCeProp(builder -> builder + .category(Category.BASIC) + .property("my.edc.vault.init.enabled") + .description("Enable Vault Initialization. Enabled by default if in-memory vault is active.") + .defaultValue("true") + ); - // EDC_API_AUTH_KEY: ApiKeyDefaultValue + public static final ConfigProp MY_EDC_VAULT_INIT_ENTRIES_WILDCARD = addCeProp(builder -> builder + .category(Category.BASIC) + .property("my.edc.vault.init.entries.*") + .description("Puts given value into the vault on startup. Replace '*' with the key you want to put into the vault.") + ); + + /* Auth */ public static final ConfigProp EDC_API_AUTH_KEY = addCeProp(builder -> builder .category(Category.BASIC) .property("edc.api.auth.key") @@ -152,7 +160,7 @@ public class ConfigProps { .category(Category.C2C_IAM) .property("edc.oauth.token.url") .description("OAuth2 / DAPS: Token URL") - .relevantIf(props -> MY_EDC_C2C_IAM_TYPE.getRaw(props).startsWith("daps")) + .onlyValidateAndDefaultIf(CeC2cIamType::isDaps) .required(true) ); @@ -160,7 +168,7 @@ public class ConfigProps { .category(Category.C2C_IAM) .property("edc.oauth.provider.jwks.url") .description("OAuth2 / DAPS: JWKS URL") - .relevantIf(props -> MY_EDC_C2C_IAM_TYPE.getRaw(props).startsWith("daps")) + .onlyValidateAndDefaultIf(CeC2cIamType::isDaps) .required(true) ); @@ -168,7 +176,7 @@ public class ConfigProps { .category(Category.C2C_IAM) .property("edc.oauth.client.id") .description("OAuth2 / DAPS: Client ID. Defaults to Participant ID") - .relevantIf(props -> MY_EDC_C2C_IAM_TYPE.getRaw(props).startsWith("daps")) + .onlyValidateAndDefaultIf(CeC2cIamType::isDaps) .defaultValueFn(MY_EDC_PARTICIPANT_ID::getRaw) ); @@ -176,7 +184,7 @@ public class ConfigProps { .category(Category.C2C_IAM) .property("edc.keystore") .description("File-Based Vault: Keystore file (.jks)") - .relevantIf(props -> MY_EDC_C2C_IAM_TYPE.getRaw(props).startsWith("daps")) + .onlyValidateAndDefaultIf(CeC2cIamType::isDaps) .required(true) ); @@ -184,7 +192,7 @@ public class ConfigProps { .category(Category.C2C_IAM) .property("edc.keystore.password") .description("File-Based Vault: Keystore password") - .relevantIf(props -> MY_EDC_C2C_IAM_TYPE.getRaw(props).startsWith("daps")) + .onlyValidateAndDefaultIf(CeC2cIamType::isDaps) .required(true) ); @@ -192,7 +200,7 @@ public class ConfigProps { .category(Category.C2C_IAM) .property("edc.oauth.certificate.alias") .description("OAuth2 / DAPS: Certificate Vault Entry for the Public Key. Default: '1'") - .relevantIf(props -> MY_EDC_C2C_IAM_TYPE.getRaw(props).startsWith("daps")) + .onlyValidateAndDefaultIf(CeC2cIamType::isDaps) .defaultValue("1") ); @@ -200,7 +208,7 @@ public class ConfigProps { .category(Category.C2C_IAM) .property("edc.oauth.private.key.alias") .description("OAuth2 / DAPS: Certificate Vault Entry for the Private Key. Default: '1'") - .relevantIf(props -> MY_EDC_C2C_IAM_TYPE.getRaw(props).startsWith("daps")) + .onlyValidateAndDefaultIf(CeC2cIamType::isDaps) .defaultValue("1") ); @@ -208,10 +216,10 @@ public class ConfigProps { .category(Category.C2C_IAM) .property("edc.oauth.provider.audience") .description("OAuth2 / DAPS: Provider Audience") - .relevantIf(props -> MY_EDC_C2C_IAM_TYPE.getRaw(props).startsWith("daps")) + .onlyValidateAndDefaultIf(CeC2cIamType::isDaps) .warnIfOverridden(true) .defaultValueFn(props -> { - if ("daps-omejdn".equals(MY_EDC_C2C_IAM_TYPE.getRaw(props))) { + if (CeC2cIamType.isDapsOmejdn(props)) { return "idsc:IDS_CONNECTORS_ALL"; } @@ -224,7 +232,7 @@ public class ConfigProps { .category(Category.C2C_IAM) .property("edc.oauth.endpoint.audience") .description("OAuth2 / DAPS: Endpoint Audience") - .relevantIf(props -> MY_EDC_C2C_IAM_TYPE.getRaw(props).startsWith("daps")) + .onlyValidateAndDefaultIf(CeC2cIamType::isDaps) .warnIfOverridden(true) .defaultValue("idsc:IDS_CONNECTORS_ALL") ); @@ -233,10 +241,10 @@ public class ConfigProps { .category(Category.C2C_IAM) .property("edc.agent.identity.key") .description("OAuth2 / DAPS: Agent Identity Key") - .relevantIf(props -> MY_EDC_C2C_IAM_TYPE.getRaw(props).startsWith("daps")) + .onlyValidateAndDefaultIf(CeC2cIamType::isDaps) .warnIfOverridden(true) .defaultValueFn(props -> { - if ("daps-omejdn".equals(MY_EDC_C2C_IAM_TYPE.getRaw(props))) { + if (CeC2cIamType.isDapsOmejdn(props)) { return "client_id"; } @@ -290,7 +298,7 @@ public class ConfigProps { .category(Category.ADVANCED) .property("edc.flyway.clean.enable") .description( - "Allows the deletion of the database. Goes in pair with edc.flyway.clean.enable. Both options must be enabled for a clean to happen.") + "Allows the deletion of the database. Goes in pair with edc.flyway.clean. Both options must be enabled for a clean to happen.") .defaultValue("false") .warnIfOverridden(true) ); @@ -299,7 +307,7 @@ public class ConfigProps { .category(Category.ADVANCED) .property("edc.flyway.clean") .description( - "Request the deletion of the database. Goes in pair with edc.flyway.clean. Both options must be enabled for a clean to happen.") + "Request the deletion of the database. Goes in pair with edc.flyway.clean.enable. Both options must be enabled for a clean to happen.") .defaultValue("false") .warnIfOverridden(true) ); @@ -309,7 +317,7 @@ public class ConfigProps { .property("edc.web.rest.cors.enabled") .description("Enable CORS") .warnIfOverridden(true) - .relevantIf(props -> !NetworkType.isProduction(props)) + .onlyValidateAndDefaultIf(props -> !CeEnvironment.isProduction(props)) .defaultValue("true") ); @@ -318,7 +326,7 @@ public class ConfigProps { .property("edc.web.rest.cors.headers") .description("CORS: Allowed Headers") .warnIfOverridden(true) - .relevantIf(props -> !NetworkType.isProduction(props)) + .onlyValidateAndDefaultIf(props -> !CeEnvironment.isProduction(props)) .defaultValue("origin,content-type,accept,authorization,X-Api-Key") ); @@ -327,7 +335,7 @@ public class ConfigProps { .property("edc.web.rest.cors.origins") .description("CORS: Allowed Origins") .warnIfOverridden(true) - .relevantIf(props -> !NetworkType.isProduction(props)) + .onlyValidateAndDefaultIf(props -> !CeEnvironment.isProduction(props)) .defaultValue("*") ); @@ -345,23 +353,89 @@ public class ConfigProps { .defaultValue("Unknown Version") ); - public static final ConfigProp MY_EDC_DOCKER_COMPOSE_SERVICE_NAME = addCeProp(builder -> builder + public static final ConfigProp EDC_TRANSFER_SEND_RETRY_LIMIT = addCeProp(builder -> builder .category(Category.ADVANCED) - .property("edc.web.rest.cors.origins") - .description("CORS: Allowed Origins") - .warnIfOverridden(true) - .relevantIf(props -> !NetworkType.isProduction(props)) - .defaultValue("*") + .property("edc.transfer.send.retry.limit") + .description("Transfer Process Retry Limit") + .defaultValue("1") + ); + + public static final ConfigProp EDC_TRANSFER_SEND_RETRY_BASE_DELAY_MS = addCeProp(builder -> builder + .category(Category.ADVANCED) + .property("edc.transfer.send.retry.base-delay.ms") + .description("Transfer Process Retry Base Delay in Milliseconds") + .defaultValue("100") + ); + + public static final ConfigProp EDC_NEGOTIATION_CONSUMER_SEND_RETRY_LIMIT = addCeProp(builder -> builder + .category(Category.ADVANCED) + .property("edc.negotiation.consumer.send.retry.limit") + .description("Contract Negotiation Retry Limit (Consuming Side)") + .defaultValue("1") + ); + + public static final ConfigProp EDC_NEGOTIATION_PROVIDER_SEND_RETRY_LIMIT = addCeProp(builder -> builder + .category(Category.ADVANCED) + .property("edc.negotiation.provider.send.retry.limit") + .description("Contract Negotiation Retry Limit (Providing Side)") + .defaultValue("1") + ); + + public static final ConfigProp EDC_NEGOTIATION_CONSUMER_SEND_RETRY_BASE_DELAY_MS = addCeProp(builder -> builder + .category(Category.ADVANCED) + .property("edc.negotiation.consumer.send.retry.base-delay.ms") + .description("Contract Negotiation Retry Base Delay in Milliseconds (Consuming Side)") + .defaultValue("100") ); + public static final ConfigProp EDC_NEGOTIATION_PROVIDER_SEND_RETRY_BASE_DELAY_MS = addCeProp(builder -> builder + .category(Category.ADVANCED) + .property("edc.negotiation.provider.send.retry.base-delay.ms") + .description("Contract Negotiation Retry Base Delay in Milliseconds (Providing Side)") + .defaultValue("100") + ); + + /* Defaults of EDC Configuration */ + public static final ConfigProp EDC_DATASOURCE_DEFAULT_NAME = addCeProp(builder -> builder + .category(Category.RAW_EDC_CONFIG_DEFAULTS) + .property("edc.datasource.default.name") + .description("Ensures the EDC initializes the DataSource 'default' because it initializes all edc.datasource.* data sources.") + .warnIfOverridden(true) + .defaultValue("default") + ); + + public static final ConfigProp MY_EDC_VAULT_INIT_ENTRY_DEFAULT_DATASOURCE_JDBC_URL = addCeProp(builder -> builder + .category(Category.RAW_EDC_CONFIG_DEFAULTS) + .property("my.edc.vault.init.entries.edc.datasource.default.url") + .description("Initializes Vault Value: edc.datasource.default.url") + .warnIfOverridden(true) + .defaultValueFn(MY_EDC_JDBC_URL::getRaw) + ); + + public static final ConfigProp MY_EDC_VAULT_INIT_ENTRY_DEFAULT_DATASOURCE_JDBC_USER = addCeProp(builder -> builder + .category(Category.RAW_EDC_CONFIG_DEFAULTS) + .property("my.edc.vault.init.entries.edc.datasource.default.user") + .description("Initializes Vault Value: edc.datasource.default.user") + .warnIfOverridden(true) + .defaultValueFn(MY_EDC_JDBC_USER::getRaw) + ); + + public static final ConfigProp MY_EDC_VAULT_INIT_ENTRY_DEFAULT_DATASOURCE_JDBC_PASSWORD = addCeProp(builder -> builder + .category(Category.RAW_EDC_CONFIG_DEFAULTS) + .property("my.edc.vault.init.entries.edc.datasource.default.password") + .description("Initializes Vault Value: edc.datasource.default.password") + .warnIfOverridden(true) + .defaultValueFn(MY_EDC_JDBC_PASSWORD::getRaw) + ); + public static final ConfigProp MY_EDC_PROTOCOL = addCeProp(builder -> builder .category(Category.RAW_EDC_CONFIG_DEFAULTS) .property("my.edc.protocol") .description("HTTP Protocol for when the EDC exposes its own URL for callbacks") .warnIfOverridden(true) - .defaultValueFn(props -> NetworkType.isProduction(props) ? "https://" : "http://") + .defaultValueFn(props -> CeEnvironment.isProduction(props) ? "https://" : "http://") ); public static final ConfigProp MY_EDC_BASE_PATH = addCeProp(builder -> builder @@ -520,34 +594,22 @@ public class ConfigProps { .defaultValueFn(EDC_DSP_CALLBACK_ADDRESS::getRaw) ); - public static final ConfigProp EDC_DATASOURCE_DEFAULT_URL = addCeProp(builder -> builder + public static final ConfigProp EDC_DATAPLANE_API_PUBLIC_BASEURL = addCeProp(builder -> builder .category(Category.RAW_EDC_CONFIG_DEFAULTS) - .property("edc.datasource.default.url") - .description("Default Datasource: JDBC URL. Prefer setting %s".formatted(MY_EDC_JDBC_URL.getProperty())) + .property("edc.dataplane.api.public.baseurl") + .description("Base URL for the public data plane API") .warnIfOverridden(true) - .defaultValueFn(MY_EDC_JDBC_URL::getRaw) - ); - - public static final ConfigProp EDC_DATASOURCE_DEFAULT_USER = addCeProp(builder -> builder - .category(Category.RAW_EDC_CONFIG_DEFAULTS) - .property("edc.datasource.default.user") - .description("Default Datasource: Username. Prefer setting %s".formatted(MY_EDC_JDBC_USER.getProperty())) - .warnIfOverridden(true) - .defaultValueFn(MY_EDC_JDBC_USER::getRaw) - ); - - public static final ConfigProp EDC_DATASOURCE_DEFAULT_PASSWORD = addCeProp(builder -> builder - .category(Category.RAW_EDC_CONFIG_DEFAULTS) - .property("edc.datasource.default.password") - .description("Default Datasource: Password. Prefer setting %s".formatted(MY_EDC_JDBC_PASSWORD.getProperty())) - .warnIfOverridden(true) - .defaultValueFn(MY_EDC_JDBC_PASSWORD::getRaw) + .defaultValueFn(props -> UrlPathUtils.urlPathJoin( + ConfigUtils.getPublicApiUrl(props), + // See org.eclipse.edc.test.e2e.TransferEndToEndParticipant#dataPlaneConfiguration + "/v2" + )) ); public static final ConfigProp EDC_DATASOURCE_LOGGINGHOUSE_URL = addCeProp(builder -> builder .category(Category.RAW_EDC_CONFIG_DEFAULTS) .property("edc.datasource.logginghouse.url") - .relevantIf(NetworkType::isProduction) + .onlyValidateAndDefaultIf(CeEnvironment::isProduction) .description("MDS Prod Variants Only: Logging House URL") .defaultValueFn(MY_EDC_JDBC_URL::getRaw) ); @@ -555,7 +617,7 @@ public class ConfigProps { public static final ConfigProp EDC_DATASOURCE_LOGGINGHOUSE_USER = addCeProp(builder -> builder .category(Category.RAW_EDC_CONFIG_DEFAULTS) .property("edc.datasource.logginghouse.user") - .relevantIf(NetworkType::isProduction) + .onlyValidateAndDefaultIf(CeEnvironment::isProduction) .description("MDS Prod Variants Only: Logging House User") .defaultValueFn(MY_EDC_JDBC_USER::getRaw) ); @@ -563,7 +625,7 @@ public class ConfigProps { public static final ConfigProp EDC_DATASOURCE_LOGGINGHOUSE_PASSWORD = addCeProp(builder -> builder .category(Category.RAW_EDC_CONFIG_DEFAULTS) .property("edc.datasource.logginghouse.password") - .relevantIf(NetworkType::isProduction) + .onlyValidateAndDefaultIf(CeEnvironment::isProduction) .description("MDS Prod Variants Only: Logging House Password") .defaultValueFn(MY_EDC_JDBC_PASSWORD::getRaw) ); @@ -574,7 +636,40 @@ public class ConfigProps { .description("This file could contain an entry replacing the EDC_KEYSTORE ENV var, " + "but for some reason it is required, and EDC won't start up if it isn't configured." + "It is created in the Dockerfile") - .relevantIf(NetworkType::isProduction) + .onlyValidateAndDefaultIf(CeEnvironment::isProduction) + ); + + public static final ConfigProp EDC_DATAPLANE_TRANSFERTYPES = addCeProp(builder -> builder + .category(Category.RAW_EDC_CONFIG_DEFAULTS) + .property("edc.dataplane.transfertypes") + .description("Data Plane Transfer Types, not to be confused with the Data Plane Source and Dest Types") + .warnIfOverridden(true) + .defaultValue("HttpData-PUSH,HttpData-PULL,AmazonS3-PUSH") + ); + + // MY_EDC_TRANSFER_TYPES=HttpData,HttpProxy,HttpPush,AzureStorage,AmazonS3 + public static final ConfigProp MY_EDC_TRANSFER_TYPES = addCeProp(builder -> builder + .category(Category.RAW_EDC_CONFIG_DEFAULTS) + .property("my.edc.transfer.types") + .description("Data Plane Source and Dest Types") + .warnIfOverridden(true) + .defaultValue("HttpData,HttpProxy,HttpPush") + ); + + public static final ConfigProp EDC_DATAPLANE_DESTTYPES = addCeProp(builder -> builder + .category(Category.RAW_EDC_CONFIG_DEFAULTS) + .property("edc.dataplane.desttypes") + .description("Data Plane Destination Types") + .warnIfOverridden(true) + .defaultValueFn(MY_EDC_TRANSFER_TYPES::getRaw) + ); + + public static final ConfigProp EDC_DATAPLANE_SOURCETYPES = addCeProp(builder -> builder + .category(Category.RAW_EDC_CONFIG_DEFAULTS) + .property("edc.dataplane.sourcetypes") + .description("Data Plane Source Types") + .warnIfOverridden(true) + .defaultValueFn(MY_EDC_TRANSFER_TYPES::getRaw) ); private static ConfigProp addCeProp(Consumer builderFn) { @@ -604,58 +699,46 @@ private static String plus(Map props, ConfigProp prop, int add) } @UtilityClass - public static class NetworkType { + public static class CeEnvironment { public static final String PRODUCTION = "production"; public static final String LOCAL_DEMO_DOCKER_COMPOSE = "local-demo-docker-compose"; public static final String UNIT_TEST = "unit-test"; - public static final List ALL_NETWORK_TYPES = List.of(PRODUCTION, LOCAL_DEMO_DOCKER_COMPOSE, UNIT_TEST); + public static final List ALL_CE_ENVIRONMENTS = List.of(PRODUCTION, LOCAL_DEMO_DOCKER_COMPOSE, UNIT_TEST); public static boolean isProduction(Map props) { - return NetworkType.PRODUCTION.equals(MY_EDC_NETWORK_TYPE.getRaw(props)); + return CeEnvironment.PRODUCTION.equals(MY_EDC_NETWORK_TYPE.getRaw(props)); } public static boolean isLocalDemoDockerCompose(Map props) { - return NetworkType.LOCAL_DEMO_DOCKER_COMPOSE.equals(MY_EDC_NETWORK_TYPE.getRaw(props)); + return CeEnvironment.LOCAL_DEMO_DOCKER_COMPOSE.equals(MY_EDC_NETWORK_TYPE.getRaw(props)); } public static boolean isUnitTest(Map props) { - return NetworkType.UNIT_TEST.equals(MY_EDC_NETWORK_TYPE.getRaw(props)); + return CeEnvironment.UNIT_TEST.equals(MY_EDC_NETWORK_TYPE.getRaw(props)); } } - @Setter - @Accessors(fluent = true, chain = true) - @RequiredArgsConstructor - public static class NetworkTypeMatcher { - private final Map props; - private Supplier production; - private Supplier localDemoDockerCompose; - private Supplier unitTest; - - public T orElse(Supplier elseFn) { - if (production != null && NetworkType.isProduction(props)) { - return production.get(); - } - - if (localDemoDockerCompose != null && NetworkType.isLocalDemoDockerCompose(props)) { - return localDemoDockerCompose.get(); - } + @UtilityClass + public static class CeC2cIamType { + public static final String DAPS_SOVITY = "daps-sovity"; + public static final String DAPS_OMEJDN = "daps-omejdn"; + public static final String MOCK_IAM = "mock-iam"; + public static final List ALL_NETWORK_TYPES = List.of(DAPS_SOVITY, DAPS_OMEJDN, MOCK_IAM); + + public static boolean isDaps(Map props) { + return isDapsSovity(props) || isDapsOmejdn(props); + } - if (unitTest != null && NetworkType.isUnitTest(props)) { - return unitTest.get(); - } + public static boolean isDapsSovity(Map props) { + return DAPS_SOVITY.equals(MY_EDC_C2C_IAM_TYPE.getRaw(props)); + } - return elseFn.get(); + public static boolean isDapsOmejdn(Map props) { + return DAPS_OMEJDN.equals(MY_EDC_C2C_IAM_TYPE.getRaw(props)); } - public T orElseThrow() { - return orElse(() -> { - var msg = "Unhandled %s: %s".formatted( - MY_EDC_NETWORK_TYPE.getProperty(), - MY_EDC_NETWORK_TYPE.getRaw(props) - ); - throw new IllegalArgumentException(msg); - }); + public static boolean isMockIam(Map props) { + return MOCK_IAM.equals(MY_EDC_C2C_IAM_TYPE.getRaw(props)); } } diff --git a/launchers/common/base/src/main/java/de/sovity/edc/Main.java b/config/src/main/java/de/sovity/edc/utils/config/CeMain.java similarity index 58% rename from launchers/common/base/src/main/java/de/sovity/edc/Main.java rename to config/src/main/java/de/sovity/edc/utils/config/CeMain.java index 9ad0eaf8c..11995c6b8 100644 --- a/launchers/common/base/src/main/java/de/sovity/edc/Main.java +++ b/config/src/main/java/de/sovity/edc/utils/config/CeMain.java @@ -12,13 +12,10 @@ * */ -package de.sovity.edc; +package de.sovity.edc.utils.config; -import de.sovity.edc.utils.config.ConfigProps; -import de.sovity.edc.utils.config.SovityEdcRuntime; - -public class Main { - public static void main(String[] args) { - SovityEdcRuntime.boot(ConfigProps.ALL_CE_PROPS); +public class CeMain { + public static void main(String[] argv) { + SovityEdcRuntime.boot(argv, CeConfigProps.ALL_CE_PROPS); } } diff --git a/config/src/main/java/de/sovity/edc/utils/config/ConfigService.java b/config/src/main/java/de/sovity/edc/utils/config/ConfigService.java index c85eda45b..94b6f0804 100644 --- a/config/src/main/java/de/sovity/edc/utils/config/ConfigService.java +++ b/config/src/main/java/de/sovity/edc/utils/config/ConfigService.java @@ -48,7 +48,7 @@ public Map applyDefaults(Map properties) { } private void applyDefault(Map properties, ConfigProp prop) { - if (prop.getRelevantIf() != null && !prop.getRelevantIf().predicate(properties)) { + if (prop.getOnlyValidateAndDefaultIf() != null && !prop.getOnlyValidateAndDefaultIf().predicate(properties)) { return; } String value = prop.getRaw(properties); diff --git a/config/src/main/java/de/sovity/edc/utils/config/ConfigUtils.java b/config/src/main/java/de/sovity/edc/utils/config/ConfigUtils.java index fa643bb41..57454d3e8 100644 --- a/config/src/main/java/de/sovity/edc/utils/config/ConfigUtils.java +++ b/config/src/main/java/de/sovity/edc/utils/config/ConfigUtils.java @@ -17,54 +17,101 @@ import de.sovity.edc.utils.config.model.ConfigProp; import de.sovity.edc.utils.config.utils.UrlPathUtils; import lombok.experimental.UtilityClass; +import org.eclipse.edc.spi.system.configuration.Config; import org.jetbrains.annotations.Nullable; import java.util.Map; @UtilityClass public class ConfigUtils { + public static String getParticipantId(Map props) { + return CeConfigProps.EDC_PARTICIPANT_ID.getRaw(props); + } + + public static String getParticipantId(Config config) { + return getParticipantId(config.getEntries()); + } public static String getProtocolApiUrl(Map props) { return UrlPathUtils.urlPathJoin( - ConfigProps.MY_EDC_PROTOCOL.getRaw(props), - getHost(props, ConfigProps.WEB_HTTP_PROTOCOL_PORT), - ConfigProps.WEB_HTTP_PROTOCOL_PATH.getRaw(props) + CeConfigProps.MY_EDC_PROTOCOL.getRaw(props), + getHost(props, CeConfigProps.WEB_HTTP_PROTOCOL_PORT), + CeConfigProps.WEB_HTTP_PROTOCOL_PATH.getRaw(props) ); } + public static String getProtocolApiUrl(Config config) { + return getProtocolApiUrl(config.getEntries()); + } + public static String getManagementApiUrl(Map props) { return UrlPathUtils.urlPathJoin( - ConfigProps.MY_EDC_PROTOCOL.getRaw(props), - getHost(props, ConfigProps.WEB_HTTP_MANAGEMENT_PORT), - ConfigProps.WEB_HTTP_MANAGEMENT_PATH.getRaw(props) + CeConfigProps.MY_EDC_PROTOCOL.getRaw(props), + getHost(props, CeConfigProps.WEB_HTTP_MANAGEMENT_PORT), + CeConfigProps.WEB_HTTP_MANAGEMENT_PATH.getRaw(props) ); } + public static String getManagementApiUrl(Config config) { + return getManagementApiUrl(config.getEntries()); + } + public static String getManagementApiKey(Map props) { - return ConfigProps.EDC_API_AUTH_KEY.getRaw(props); + return CeConfigProps.EDC_API_AUTH_KEY.getRaw(props); + } + + public static String getManagementApiKey(Config config) { + return getManagementApiKey(config.getEntries()); } public static String getDefaultApiUrl(Map props) { return UrlPathUtils.urlPathJoin( - ConfigProps.MY_EDC_PROTOCOL.getRaw(props), - getHost(props, ConfigProps.WEB_HTTP_PORT), - ConfigProps.WEB_HTTP_PATH.getRaw(props) + CeConfigProps.MY_EDC_PROTOCOL.getRaw(props), + getHost(props, CeConfigProps.WEB_HTTP_PORT), + CeConfigProps.WEB_HTTP_PATH.getRaw(props) ); } + public static String getDefaultApiUrl(Config config) { + return getDefaultApiUrl(config.getEntries()); + } + public static String getPublicApiUrl(Map props) { return UrlPathUtils.urlPathJoin( - ConfigProps.MY_EDC_PROTOCOL.getRaw(props), - getHost(props, ConfigProps.WEB_HTTP_PUBLIC_PORT), - ConfigProps.WEB_HTTP_PUBLIC_PATH.getRaw(props) + CeConfigProps.MY_EDC_PROTOCOL.getRaw(props), + getHost(props, CeConfigProps.WEB_HTTP_PUBLIC_PORT), + CeConfigProps.WEB_HTTP_PUBLIC_PATH.getRaw(props) + ); + } + + public static String getPublicApiUrl(Config config) { + return getPublicApiUrl(config.getEntries()); + } + + public static String getControlApiUrl(Map props) { + return UrlPathUtils.urlPathJoin( + CeConfigProps.MY_EDC_PROTOCOL.getRaw(props), + getHost(props, CeConfigProps.WEB_HTTP_CONTROL_PORT), + CeConfigProps.WEB_HTTP_CONTROL_PATH.getRaw(props) + ); + } + + public static String getControlApiUrl(Config config) { + return getControlApiUrl(config.getEntries()); + } + + public static String getIntegratedDataPlaneUrl(Config config) { + return UrlPathUtils.urlPathJoin( + getControlApiUrl(config), + "v1/dataflows" ); } @Nullable - private static String getHost(Map props, ConfigProp portIfNoReverseProxy) { - var hasReverseProxy = ConfigProps.NetworkType.isProduction(props); + public static String getHost(Map props, ConfigProp portIfNoReverseProxy) { + var hasReverseProxy = CeConfigProps.CeEnvironment.isProduction(props); - var host = ConfigProps.MY_EDC_FQDN.getRaw(props); + var host = CeConfigProps.MY_EDC_FQDN.getRaw(props); if (!hasReverseProxy) { host = "%s:%s".formatted(host, portIfNoReverseProxy.getRaw(props)); } diff --git a/config/src/main/java/de/sovity/edc/utils/config/SovityConfigurationLoader.java b/config/src/main/java/de/sovity/edc/utils/config/SovityConfigurationLoader.java new file mode 100644 index 000000000..3f276d72c --- /dev/null +++ b/config/src/main/java/de/sovity/edc/utils/config/SovityConfigurationLoader.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - init + * + */ + +package de.sovity.edc.utils.config; + +import de.sovity.edc.utils.config.model.ConfigProp; +import org.eclipse.edc.boot.config.ConfigurationLoader; +import org.eclipse.edc.boot.config.EnvironmentVariables; +import org.eclipse.edc.boot.config.SystemProperties; +import org.eclipse.edc.boot.system.ServiceLocator; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.configuration.Config; +import org.eclipse.edc.spi.system.configuration.ConfigFactory; + +import java.util.List; + +/** + * Custom {@link ServiceExtensionContext} for applying config defaults on EDC startup + */ +public class SovityConfigurationLoader extends ConfigurationLoader { + private final List configProps; + + public SovityConfigurationLoader( + ServiceLocator serviceLocator, + EnvironmentVariables environmentVariables, + SystemProperties systemProperties, + List configProps + ) { + super(serviceLocator, environmentVariables, systemProperties); + this.configProps = configProps; + } + + @Override + public Config loadConfiguration(Monitor monitor) { + var config = super.loadConfiguration(monitor); + return applyDefaults(monitor, config, configProps); + } + + public static Config applyDefaults(Monitor monitor, Config rawConfig, List configProps) { + var configService = new ConfigService(monitor, configProps); + return ConfigFactory.fromMap(configService.applyDefaults(rawConfig.getEntries())); + } +} diff --git a/config/src/main/java/de/sovity/edc/utils/config/SovityEdcRuntime.java b/config/src/main/java/de/sovity/edc/utils/config/SovityEdcRuntime.java index 64034e12c..c8d1dfaca 100644 --- a/config/src/main/java/de/sovity/edc/utils/config/SovityEdcRuntime.java +++ b/config/src/main/java/de/sovity/edc/utils/config/SovityEdcRuntime.java @@ -15,11 +15,14 @@ package de.sovity.edc.utils.config; import de.sovity.edc.utils.config.model.ConfigProp; +import de.sovity.edc.utils.config.utils.ReflectionUtils; import lombok.RequiredArgsConstructor; +import org.eclipse.edc.boot.config.EnvironmentVariables; +import org.eclipse.edc.boot.config.SystemProperties; +import org.eclipse.edc.boot.system.ExtensionLoader; +import org.eclipse.edc.boot.system.ServiceLocator; +import org.eclipse.edc.boot.system.ServiceLocatorImpl; import org.eclipse.edc.boot.system.runtime.BaseRuntime; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.system.ServiceExtensionContext; -import org.jetbrains.annotations.NotNull; import java.util.List; @@ -28,20 +31,27 @@ */ @RequiredArgsConstructor public class SovityEdcRuntime extends BaseRuntime { - /** - * Will be evaluated in sequence to apply default config values and validate the configuration. - */ - private final List configProps; - - @Override - protected @NotNull ServiceExtensionContext createContext(Monitor monitor) { - return new SovityServiceExtensionContext(monitor, configProps, this.loadConfigurationExtensions()); + + public SovityEdcRuntime(List configProps) { + this(new ServiceLocatorImpl(), configProps); } - public static void boot(List configProps) { - var runtime = new SovityEdcRuntime(configProps); + public SovityEdcRuntime(ServiceLocator serviceLocator, List configProps) { + // overwrite private final "extensionLoader" + var extensionLoader = new ExtensionLoader(serviceLocator); + ReflectionUtils.setFieldValue(BaseRuntime.class, this, "extensionLoader", extensionLoader); + + // overwrite private final "configLoader" + var configurationLoader = new SovityConfigurationLoader(serviceLocator, EnvironmentVariables.ofDefault(), + SystemProperties.ofDefault(), configProps); + ReflectionUtils.setFieldValue(BaseRuntime.class, this, "configurationLoader", configurationLoader); + } + + public static void boot(String[] args, List configProps) { + // overwrite private static final "programArgs" + ReflectionUtils.setFieldValue(BaseRuntime.class, null, "programArgs", args); - // This method is protected, so we need to have the static method here - runtime.boot(); + var runtime = new SovityEdcRuntime(configProps); + runtime.boot(true); } } diff --git a/config/src/main/java/de/sovity/edc/utils/config/SovityServiceExtensionContext.java b/config/src/main/java/de/sovity/edc/utils/config/SovityServiceExtensionContext.java deleted file mode 100644 index 1a4d05f11..000000000 --- a/config/src/main/java/de/sovity/edc/utils/config/SovityServiceExtensionContext.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - init - * - */ - -package de.sovity.edc.utils.config; - -import de.sovity.edc.utils.config.model.ConfigProp; -import org.eclipse.edc.boot.system.DefaultServiceExtensionContext; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.system.ConfigurationExtension; -import org.eclipse.edc.spi.system.ServiceExtensionContext; -import org.eclipse.edc.spi.system.configuration.Config; -import org.eclipse.edc.spi.system.configuration.ConfigFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * Custom {@link ServiceExtensionContext} for applying config defaults on EDC startup - */ -public class SovityServiceExtensionContext extends DefaultServiceExtensionContext { - /** - * Will be evaluated in sequence to apply default config values and validate the configuration. - */ - private final List configProps; - private final List configurationExtensions; - private final Config config; - - public SovityServiceExtensionContext(Monitor monitor, List configProps, List configurationExtensions) { - super(monitor, configurationExtensions); - this.configProps = configProps; - this.configurationExtensions = configurationExtensions; - this.config = loadValidatedConfigWithDefaults(); - } - - @Override - public Config getConfig(String path) { - return this.config.getConfig(path); - } - - private Config loadValidatedConfigWithDefaults() { - var configs = new ArrayList(); - - this.configurationExtensions.stream() - .map(ConfigurationExtension::getConfig) - .filter(Objects::nonNull) - .forEach(configs::add); - - configs.add(ConfigFactory.fromEnvironment(System.getenv())); - configs.add(ConfigFactory.fromProperties(System.getProperties())); - - var rawConfig = configs.stream().reduce(Config::merge) - .orElseGet(ConfigFactory::empty); - - var configService = new ConfigService(getMonitor(), configProps); - return ConfigFactory.fromMap(configService.applyDefaults(rawConfig.getEntries())); - } -} diff --git a/config/src/main/java/de/sovity/edc/utils/config/model/ConfigProp.java b/config/src/main/java/de/sovity/edc/utils/config/model/ConfigProp.java index efc312fce..499b1b8dc 100644 --- a/config/src/main/java/de/sovity/edc/utils/config/model/ConfigProp.java +++ b/config/src/main/java/de/sovity/edc/utils/config/model/ConfigProp.java @@ -23,8 +23,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; import java.util.Map; import java.util.function.Consumer; +import java.util.stream.Stream; @Setter @Getter @@ -43,7 +45,7 @@ public class ConfigProp { /** * Turns off all required / defaulting logic, if false */ - private ConfigPropRequiredIfFn relevantIf; + private ConfigPropRequiredIfFn onlyValidateAndDefaultIf; private boolean required; private ConfigPropRequiredIfFn requiredIf; @@ -85,4 +87,30 @@ public Integer getInt(Config config) { // Default should already be handled by ConfigProp return config.getInteger(property); } + + public Config getWildcardSubconfig(Config config) throws IllegalArgumentException { + if (!property.endsWith(".*")) { + throw new IllegalArgumentException("Property does not contain wildcard: %s".formatted(property)); + } + + var key = property.substring(0, property.length() - 2); + return config.getConfig(key); + } + + public List getListOrEmpty(Config config) { + var string = config.getString(property, ""); + return Stream.of(string.split(",")) + .map(String::trim) + .filter(it -> !it.isEmpty()) + .toList(); + } + + public List getListOrThrow(Config config) { + var list = getListOrEmpty(config); + + if (list.isEmpty()) { + throw new IllegalArgumentException("Required list property is empty: %s".formatted(property)); + } + return list; + } } diff --git a/config/src/main/java/de/sovity/edc/utils/config/utils/ReflectionUtils.java b/config/src/main/java/de/sovity/edc/utils/config/utils/ReflectionUtils.java new file mode 100644 index 000000000..ac1f03dda --- /dev/null +++ b/config/src/main/java/de/sovity/edc/utils/config/utils/ReflectionUtils.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + * + */ + +package de.sovity.edc.utils.config.utils; + +import lombok.SneakyThrows; +import lombok.experimental.UtilityClass; + +import java.lang.reflect.Field; + +/** + * We want to extend {@link org.eclipse.edc.boot.system.runtime.BaseRuntime}, but unfortunately some vital fields are private. + *

+ * Instead of maintaining a little bit more code, we do this. Where there's a will, there's a way. + */ +@UtilityClass +public class ReflectionUtils { + + @SuppressWarnings("unchecked") + @SneakyThrows + public static R getFieldValue(Class clazz, T obj, String fieldName) { + var field = getField(clazz, fieldName); + return (R) field.get(obj); + } + + @SneakyThrows + public static void setFieldValue(Class clazz, T obj, String fieldName, Object value) { + var field = getField(clazz, fieldName); + field.set(obj, value); + } + + @SneakyThrows + private static Field getField(Class clazz, String fieldName) { + var field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } +} diff --git a/config/src/test/java/UrlPathUtilsTest.java b/config/src/test/java/de/sovity/edc/utils/config/utils/UrlPathUtilsTest.java similarity index 96% rename from config/src/test/java/UrlPathUtilsTest.java rename to config/src/test/java/de/sovity/edc/utils/config/utils/UrlPathUtilsTest.java index dfbdf6bc7..8c9533fa6 100644 --- a/config/src/test/java/UrlPathUtilsTest.java +++ b/config/src/test/java/de/sovity/edc/utils/config/utils/UrlPathUtilsTest.java @@ -8,10 +8,12 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - initial API and implementation * */ +package de.sovity.edc.utils.config.utils; + import org.junit.jupiter.api.Test; import static de.sovity.edc.utils.config.utils.UrlPathUtils.urlPathJoin; diff --git a/docs/api/eclipse-edc-management-api.yaml b/docs/api/eclipse-edc-management-api.yaml index 181094d05..26731d8d9 100644 --- a/docs/api/eclipse-edc-management-api.yaml +++ b/docs/api/eclipse-edc-management-api.yaml @@ -1,266 +1,181 @@ openapi: 3.0.1 info: title: management-api - description: REST API documentation for the Eclipse EDC management-api. This does not include endpoints of the sovity EDC API Wrapper. - version: 0.2.1 + description: REST API documentation for the management-api + version: 0.7.0 servers: - - url: https://[MY_EDC_FQDN]/api/management +- url: / paths: /callback/{processId}/deprovision: post: tags: - - HTTP Provisioner Webhook + - HTTP Provisioner Webhook operationId: callDeprovisionWebhook parameters: - - name: processId - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: processId + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null requestBody: content: application/json: schema: - $ref: '#/components/schemas/DeprovisionedResource' + $ref: "#/components/schemas/DeprovisionedResource" responses: default: description: default response content: - application/json: { } + application/json: {} /callback/{processId}/provision: post: tags: - - HTTP Provisioner Webhook + - HTTP Provisioner Webhook operationId: callProvisionWebhook parameters: - - name: processId - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: processId + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null requestBody: content: application/json: schema: - $ref: '#/components/schemas/ProvisionerWebhookRequest' + $ref: "#/components/schemas/ProvisionerWebhookRequest" responses: default: description: default response content: - application/json: { } - /check/health: - get: - tags: - - Application Observability - description: Performs a liveness probe to determine whether the runtime is working - properly. - operationId: checkHealth - responses: - "200": - description: The runtime is working properly. - content: - application/json: - schema: - $ref: '#/components/schemas/HealthStatus' - /check/liveness: - get: - tags: - - Application Observability - description: Performs a liveness probe to determine whether the runtime is working - properly. - operationId: getLiveness - responses: - "200": - description: The runtime is working properly. - content: - application/json: - schema: - $ref: '#/components/schemas/HealthStatus' - /check/readiness: - get: - tags: - - Application Observability - description: Performs a readiness probe to determine whether the runtime is - able to accept requests. - operationId: getReadiness - responses: - "200": - description: The runtime is able to accept requests. - content: - application/json: - schema: - $ref: '#/components/schemas/HealthStatus' - /check/startup: - get: - tags: - - Application Observability - description: Performs a startup probe to determine whether the runtime has completed - startup. - operationId: getStartup - responses: - "200": - description: The runtime has completed startup. - content: - application/json: - schema: - $ref: '#/components/schemas/HealthStatus' - /select: + application/json: {} + /v1/edrs/request: post: tags: - - Dataplane Selector - description: Finds the best fitting data plane instance for a particular query - operationId: find + - EDR Cache + description: Request all Edr entries according to a particular query + operationId: requestEdrEntries requestBody: content: - '*/*': + application/json: schema: - $ref: '#/components/schemas/SelectionRequestSchema' + $ref: "#/components/schemas/QuerySpec" responses: "200": - description: The DataPlane instance that fits best for the given selection - request - content: - '*/*': - schema: - $ref: '#/components/schemas/DataPlaneInstanceSchema' - "204": - description: No suitable DataPlane instance was found - "400": - description: Request body was malformed + description: The edr entries matching the query content: - '*/*': + application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' - /v2/assets: - put: - tags: - - Asset - description: "Updates an asset with the given ID if it exists. If the asset\ - \ is not found, no further action is taken. DANGER ZONE: Note that updating\ - \ assets can have unexpected results, especially for contract offers that\ - \ have been sent out or are ongoing in contract negotiations." - operationId: updateAsset - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/Asset' - responses: - "200": - description: Asset was updated successfully + $ref: "#/components/schemas/EndpointDataReferenceEntry" "400": - description: "Request was malformed, e.g. id was null" + description: Request body was malformed content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' - "404": - description: "Asset could not be updated, because it does not exist." - deprecated: true - post: + $ref: "#/components/schemas/ApiErrorDetail" + /v1/edrs/{transferProcessId}: + delete: tags: - - Asset - description: Creates a new asset together with a data address - operationId: createAsset - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/AssetEntryNewDto' + - EDR Cache + description: Removes an EDR entry given the transfer process ID + operationId: removeEdrEntry + parameters: + - name: transferProcessId + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: - "200": - description: Asset was created successfully. Returns the asset Id and created - timestamp - content: - application/json: - schema: - $ref: '#/components/schemas/IdResponse' + "204": + description: EDR entry was deleted successfully "400": - description: Request body was malformed + description: "Request was malformed, e.g. id was null" content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' - "409": - description: "Could not create asset, because an asset with that ID already\ - \ exists" + $ref: "#/components/schemas/ApiErrorDetail" + "404": + description: An EDR entry with the given ID does not exist content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true - /v2/assets/request: - post: + $ref: "#/components/schemas/ApiErrorDetail" + /v1/edrs/{transferProcessId}/dataaddress: + get: tags: - - Asset - description: ' all assets according to a particular query' - operationId: requestAssets - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/QuerySpec' + - EDR Cache + description: Gets the EDR data address with the given transfer process ID + operationId: getEdrEntryDataAddress + parameters: + - name: transferProcessId + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": - description: The assets matching the query + description: The data address + content: + application/json: + schema: + $ref: "#/components/schemas/DataAddress" + "400": + description: "Request was malformed, e.g. id was null" content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/Asset' - "400": - description: Request body was malformed + $ref: "#/components/schemas/ApiErrorDetail" + "404": + description: An EDR data address with the given transfer process ID does + not exist content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true - /v2/assets/{assetId}/dataaddress: + $ref: "#/components/schemas/ApiErrorDetail" + /v1/secrets: put: tags: - - Asset - description: Updates a DataAddress for an asset with the given ID. - operationId: updateDataAddress - parameters: - - name: assetId - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - Secret + description: "Updates a secret with the given ID if it exists. If the secret\ + \ is not found, no further action is taken. " + operationId: updateSecret requestBody: content: application/json: schema: - $ref: '#/components/schemas/Asset' + $ref: "#/components/schemas/SecretInput" responses: - "200": - description: Asset was updated successfully + "204": + description: Secret was updated successfully "400": description: "Request was malformed, e.g. id was null" content: @@ -269,130 +184,103 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": - description: An asset with the given ID does not exist - content: - application/json: - schema: - type: array - example: null - items: - $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true - /v2/assets/{id}: - get: + description: "Secret could not be updated, because it does not exist." + post: tags: - - Asset - description: Gets an asset with the given ID - operationId: getAsset - parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - Secret + description: Creates a new secret. + operationId: createSecret + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/SecretInput" responses: "200": - description: The asset + description: Secret was created successfully. Returns the secret Id and + created timestamp content: application/json: schema: - $ref: '#/components/schemas/Asset' + $ref: "#/components/schemas/IdResponse" "400": - description: "Request was malformed, e.g. id was null" + description: Request body was malformed content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' - "404": - description: An asset with the given ID does not exist + $ref: "#/components/schemas/ApiErrorDetail" + "409": + description: "Could not create secret, because a secret with that ID already\ + \ exists" content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true - delete: + $ref: "#/components/schemas/ApiErrorDetail" + /v1/secrets/{id}: + get: tags: - - Asset - description: "Removes an asset with the given ID if possible. Deleting an asset\ - \ is only possible if that asset is not yet referenced by a contract agreement,\ - \ in which case an error is returned. DANGER ZONE: Note that deleting assets\ - \ can have unexpected results, especially for contract offers that have been\ - \ sent out or ongoing or contract negotiations." - operationId: removeAsset + - Secret + description: Gets a secret with the given ID + operationId: getSecret parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": - description: Asset was deleted successfully - "400": - description: "Request was malformed, e.g. id was null" + description: The secret content: application/json: schema: - type: array - example: null - items: - $ref: '#/components/schemas/ApiErrorDetail' - "404": - description: An asset with the given ID does not exist + $ref: "#/components/schemas/SecretOutput" + "400": + description: "Request was malformed, e.g. id was null" content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' - "409": - description: "The asset cannot be deleted, because it is referenced by a\ - \ contract agreement" + $ref: "#/components/schemas/ApiErrorDetail" + "404": + description: A secret with the given ID does not exist content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true - /v2/assets/{id}/dataaddress: - get: + $ref: "#/components/schemas/ApiErrorDetail" + delete: tags: - - Asset - description: Gets a data address of an asset with the given ID - operationId: getAssetDataAddress + - Secret + description: Removes a secret with the given ID if possible. + operationId: removeSecret parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: - "200": - description: The data address - content: - application/json: - schema: - $ref: '#/components/schemas/DataAddress' + "204": + description: Secret was deleted successfully "400": description: "Request was malformed, e.g. id was null" content: @@ -401,62 +289,61 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": - description: An asset with the given ID does not exist + description: A secret with the given ID does not exist content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true + $ref: "#/components/schemas/ApiErrorDetail" /v2/catalog/dataset/request: post: tags: - - Catalog + - Catalog operationId: getDataset requestBody: content: application/json: schema: - $ref: '#/components/schemas/DatasetRequest' + $ref: "#/components/schemas/DatasetRequest" responses: default: description: Gets single dataset from a connector content: application/json: schema: - $ref: '#/components/schemas/Dataset' + $ref: "#/components/schemas/Dataset" /v2/catalog/request: post: tags: - - Catalog + - Catalog operationId: requestCatalog requestBody: content: application/json: schema: - $ref: '#/components/schemas/CatalogRequest' + $ref: "#/components/schemas/CatalogRequest" responses: default: description: Gets contract offers (=catalog) of a single connector content: application/json: schema: - $ref: '#/components/schemas/Catalog' + $ref: "#/components/schemas/Catalog" /v2/contractagreements/request: post: tags: - - Contract Agreement + - Contract Agreement description: Gets all contract agreements according to a particular query - operationId: queryAllAgreements + operationId: queryAgreements requestBody: content: - '*/*': + application/json: schema: - $ref: '#/components/schemas/QuerySpec' + $ref: "#/components/schemas/QuerySpec" responses: "200": description: The contract agreements matching the query @@ -466,7 +353,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ContractAgreement' + $ref: "#/components/schemas/ContractAgreement" "400": description: Request body was malformed content: @@ -475,29 +362,29 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/contractagreements/{id}: get: tags: - - Contract Agreement + - Contract Agreement description: Gets an contract agreement with the given ID operationId: getAgreementById parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The contract agreement content: application/json: schema: - $ref: '#/components/schemas/ContractAgreement' + $ref: "#/components/schemas/ContractAgreement" "400": description: "Request was malformed, e.g. id was null" content: @@ -506,7 +393,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: An contract agreement with the given ID does not exist content: @@ -515,29 +402,29 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/contractagreements/{id}/negotiation: get: tags: - - Contract Agreement + - Contract Agreement description: Gets a contract negotiation with the given contract agreement ID operationId: getNegotiationByAgreementId parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The contract negotiation content: application/json: schema: - $ref: '#/components/schemas/ContractNegotiation' + $ref: "#/components/schemas/ContractNegotiation" "400": description: "Request was malformed, e.g. id was null" content: @@ -546,7 +433,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: An contract agreement with the given ID does not exist content: @@ -555,19 +442,19 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/contractdefinitions: put: tags: - - Contract Definition + - Contract Definition description: Updated a contract definition with the given ID. The supplied JSON structure must be a valid JSON-LD object operationId: updateContractDefinition requestBody: content: - '*/*': + application/json: schema: - $ref: '#/components/schemas/ContractDefinitionInput' + $ref: "#/components/schemas/ContractDefinitionInput" responses: "204": description: Contract definition was updated successfully @@ -579,7 +466,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: A contract definition with the given ID does not exist content: @@ -588,17 +475,17 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" post: tags: - - Contract Definition + - Contract Definition description: Creates a new contract definition operationId: createContractDefinition requestBody: content: - '*/*': + application/json: schema: - $ref: '#/components/schemas/ContractDefinitionInput' + $ref: "#/components/schemas/ContractDefinitionInput" responses: "200": description: contract definition was created successfully. Returns the Contract @@ -606,7 +493,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/IdResponse' + $ref: "#/components/schemas/IdResponse" "400": description: Request body was malformed content: @@ -615,7 +502,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "409": description: "Could not create contract definition, because a contract definition\ \ with that ID already exists" @@ -625,18 +512,18 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/contractdefinitions/request: post: tags: - - Contract Definition + - Contract Definition description: Returns all contract definitions according to a query - operationId: queryAllContractDefinitions + operationId: queryContractDefinitions requestBody: content: - '*/*': + application/json: schema: - $ref: '#/components/schemas/QuerySpec' + $ref: "#/components/schemas/QuerySpec" responses: "200": description: The contract definitions matching the query @@ -646,7 +533,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ContractDefinitionOutput' + $ref: "#/components/schemas/ContractDefinitionOutput" "400": description: Request was malformed content: @@ -655,29 +542,29 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/contractdefinitions/{id}: get: tags: - - Contract Definition + - Contract Definition description: Gets an contract definition with the given ID operationId: getContractDefinition parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The contract definition content: application/json: schema: - $ref: '#/components/schemas/ContractDefinitionOutput' + $ref: "#/components/schemas/ContractDefinitionOutput" "400": description: "Request was malformed, e.g. id was null" content: @@ -686,7 +573,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: An contract agreement with the given ID does not exist content: @@ -695,26 +582,26 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" delete: tags: - - Contract Definition + - Contract Definition description: "Removes a contract definition with the given ID if possible. DANGER\ \ ZONE: Note that deleting contract definitions can have unexpected results,\ \ especially for contract offers that have been sent out or ongoing or contract\ \ negotiations." operationId: deleteContractDefinition parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: - "200": + "204": description: Contract definition was deleted successfully "400": description: "Request was malformed, e.g. id was null" @@ -724,7 +611,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: A contract definition with the given ID does not exist content: @@ -733,11 +620,11 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/contractnegotiations: post: tags: - - Contract Negotiation + - Contract Negotiation description: "Initiates a contract negotiation for a given offer and with the\ \ given counter part. Please note that successfully invoking this endpoint\ \ only means that the negotiation was initiated. Clients must poll the /{id}/state\ @@ -747,7 +634,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ContractRequest' + $ref: "#/components/schemas/ContractRequest" responses: "200": description: The negotiation was successfully initiated. Returns the contract @@ -755,7 +642,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/IdResponse' + $ref: "#/components/schemas/IdResponse" links: poll-state: operationId: getNegotiationState @@ -769,18 +656,18 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/contractnegotiations/request: post: tags: - - Contract Negotiation + - Contract Negotiation description: Returns all contract negotiations according to a query operationId: queryNegotiations requestBody: content: application/json: schema: - $ref: '#/components/schemas/QuerySpec' + $ref: "#/components/schemas/QuerySpec" responses: "200": description: The contract negotiations that match the query @@ -790,7 +677,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ContractNegotiation' + $ref: "#/components/schemas/ContractNegotiation" "400": description: Request was malformed content: @@ -799,29 +686,29 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/contractnegotiations/{id}: get: tags: - - Contract Negotiation + - Contract Negotiation description: Gets a contract negotiation with the given ID operationId: getNegotiation parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The contract negotiation content: application/json: schema: - $ref: '#/components/schemas/ContractNegotiation' + $ref: "#/components/schemas/ContractNegotiation" "400": description: "Request was malformed, e.g. id was null" content: @@ -830,7 +717,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: An contract negotiation with the given ID does not exist content: @@ -839,23 +726,23 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/contractnegotiations/{id}/agreement: get: tags: - - Contract Negotiation + - Contract Negotiation description: Gets a contract agreement for a contract negotiation with the given ID operationId: getAgreementForNegotiation parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: "The contract agreement that is attached to the negotiation,\ @@ -863,7 +750,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ContractAgreement' + $ref: "#/components/schemas/ContractAgreement" "400": description: "Request was malformed, e.g. id was null" content: @@ -872,7 +759,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: An contract negotiation with the given ID does not exist content: @@ -881,117 +768,29 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' - /v2/contractnegotiations/{id}/cancel: - post: - tags: - - Contract Negotiation - description: "Requests aborting the contract negotiation. Due to the asynchronous\ - \ nature of contract negotiations, a successful response only indicates that\ - \ the request was successfully received. Clients must poll the /{id}/state\ - \ endpoint to track the state." - operationId: cancelNegotiation - parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null - responses: - "200": - description: Request to cancel the Contract negotiation was successfully - received - links: - poll-state: - operationId: getNegotiationState - "400": - description: "Request was malformed, e.g. id was null" - content: - application/json: - schema: - type: array - example: null - items: - $ref: '#/components/schemas/ApiErrorDetail' - "404": - description: A contract negotiation with the given ID does not exist - content: - application/json: - schema: - type: array - example: null - items: - $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true - /v2/contractnegotiations/{id}/decline: - post: - tags: - - Contract Negotiation - description: "Requests cancelling the contract negotiation. Due to the asynchronous\ - \ nature of contract negotiations, a successful response only indicates that\ - \ the request was successfully received. Clients must poll the /{id}/state\ - \ endpoint to track the state." - operationId: declineNegotiation - parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null - responses: - "200": - description: Request to decline the Contract negotiation was successfully - received - links: - poll-state: - operationId: getNegotiationState - "400": - description: "Request was malformed, e.g. id was null" - content: - application/json: - schema: - type: array - example: null - items: - $ref: '#/components/schemas/ApiErrorDetail' - "404": - description: A contract negotiation with the given ID does not exist - content: - application/json: - schema: - type: array - example: null - items: - $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true + $ref: "#/components/schemas/ApiErrorDetail" /v2/contractnegotiations/{id}/state: get: tags: - - Contract Negotiation + - Contract Negotiation description: Gets the state of a contract negotiation with the given ID operationId: getNegotiationState parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The contract negotiation's state content: application/json: schema: - $ref: '#/components/schemas/NegotiationState' + $ref: "#/components/schemas/NegotiationState" "400": description: "Request was malformed, e.g. id was null" content: @@ -1000,7 +799,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: An contract negotiation with the given ID does not exist content: @@ -1009,27 +808,27 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/contractnegotiations/{id}/terminate: post: tags: - - Contract Negotiation + - Contract Negotiation description: Terminates the contract negotiation. operationId: terminateNegotiation parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null requestBody: content: application/json: schema: - $ref: '#/components/schemas/TerminateNegotiationSchema' + $ref: "#/components/schemas/TerminateNegotiationSchema" responses: "200": description: ContractNegotiation is terminating @@ -1044,7 +843,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: A contract negotiation with the given ID does not exist content: @@ -1053,39 +852,42 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/dataplanes: get: tags: - - Dataplane Selector + - Dataplane Selector description: Returns a list of all currently registered data plane instances - operationId: getAll + operationId: getAllDataPlaneInstances responses: - "204": + "200": description: A (potentially empty) list of currently registered data plane instances - "400": - description: Request body was malformed content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/DataPlaneInstanceSchema" post: tags: - - Dataplane Selector - description: Adds one datatplane instance to the internal database of the selector - operationId: addEntry + - Dataplane Selector + description: "Adds one dataplane instance to the internal database of the selector.\ + \ DEPRECATED: dataplanes should register themselves through control-api" + operationId: addDataPlaneInstance requestBody: content: application/json: schema: - $ref: '#/components/schemas/DataPlaneInstanceSchema' + $ref: "#/components/schemas/DataPlaneInstanceSchema" responses: "200": description: Entry was added successfully to the database + content: + application/json: + schema: + $ref: "#/components/schemas/IdResponse" "400": description: Request body was malformed content: @@ -1094,18 +896,19 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" + deprecated: true /v2/dataplanes/select: post: tags: - - Dataplane Selector + - Dataplane Selector description: Finds the best fitting data plane instance for a particular query - operationId: find_1 + operationId: selectDataPlaneInstance requestBody: content: application/json: schema: - $ref: '#/components/schemas/SelectionRequestSchema' + $ref: "#/components/schemas/SelectionRequestSchema" responses: "200": description: The DataPlane instance that fits best for the given selection @@ -1113,7 +916,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/DataPlaneInstanceSchema' + $ref: "#/components/schemas/DataPlaneInstanceSchema" "204": description: No suitable DataPlane instance was found "400": @@ -1124,18 +927,19 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" + deprecated: true /v2/policydefinitions: post: tags: - - Policy Definition + - Policy Definition description: Creates a new policy definition operationId: createPolicyDefinition requestBody: content: application/json: schema: - $ref: '#/components/schemas/PolicyDefinitionInput' + $ref: "#/components/schemas/PolicyDefinitionInput" responses: "200": description: policy definition was created successfully. Returns the Policy @@ -1143,7 +947,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/IdResponse' + $ref: "#/components/schemas/IdResponse" "400": description: Request body was malformed content: @@ -1152,7 +956,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "409": description: "Could not create policy definition, because a contract definition\ \ with that ID already exists" @@ -1162,18 +966,18 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/policydefinitions/request: post: tags: - - Policy Definition + - Policy Definition description: Returns all policy definitions according to a query operationId: queryPolicyDefinitions requestBody: content: application/json: schema: - $ref: '#/components/schemas/QuerySpec' + $ref: "#/components/schemas/QuerySpec" responses: "200": description: The policy definitions matching the query @@ -1183,7 +987,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/PolicyDefinitionOutput' + $ref: "#/components/schemas/PolicyDefinitionOutput" "400": description: Request was malformed content: @@ -1192,29 +996,29 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/policydefinitions/{id}: get: tags: - - Policy Definition + - Policy Definition description: Gets a policy definition with the given ID operationId: getPolicyDefinition parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The policy definition content: application/json: schema: - $ref: '#/components/schemas/PolicyDefinitionOutput' + $ref: "#/components/schemas/PolicyDefinitionOutput" "400": description: "Request was malformed, e.g. id was null" content: @@ -1223,7 +1027,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: An policy definition with the given ID does not exist content: @@ -1232,31 +1036,30 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" put: tags: - - Policy Definition + - Policy Definition description: "Updates an existing Policy, If the Policy is not found, an error\ \ is reported" operationId: updatePolicyDefinition parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null requestBody: content: application/json: schema: - $ref: '#/components/schemas/PolicyDefinitionInput' + $ref: "#/components/schemas/PolicyDefinitionInput" responses: - "200": - description: policy definition was updated successfully. Returns the Policy - Definition Id and updated timestamp + "204": + description: policy definition was updated successfully. "400": description: Request body was malformed content: @@ -1265,17 +1068,17 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: "policy definition could not be updated, because it does not\ \ exists" content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" delete: tags: - - Policy Definition + - Policy Definition description: "Removes a policy definition with the given ID if possible. Deleting\ \ a policy definition is only possible if that policy definition is not yet\ \ referenced by a contract definition, in which case an error is returned.\ @@ -1283,16 +1086,16 @@ paths: \ do this at your own risk!" operationId: deletePolicyDefinition parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: - "200": + "204": description: Policy definition was deleted successfully "400": description: "Request was malformed, e.g. id was null" @@ -1302,7 +1105,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: An policy definition with the given ID does not exist content: @@ -1311,7 +1114,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "409": description: "The policy definition cannot be deleted, because it is referenced\ \ by a contract definition" @@ -1321,20 +1124,21 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/transferprocesses: post: tags: - - Transfer Process - description: "Initiates a data transfer with the given parameters. Please note\ - \ that successfully invoking this endpoint only means that the transfer was\ - \ initiated. Clients must poll the /{id}/state endpoint to track the state" + - Transfer Process + description: "Initiates a data transfer with the given parameters. Due to the\ + \ asynchronous nature of transfers, a successful response only indicates that\ + \ the request was successfully received. This may take a long time, so clients\ + \ must poll the /{id}/state endpoint to track the state." operationId: initiateTransferProcess requestBody: content: application/json: schema: - $ref: '#/components/schemas/TransferRequest' + $ref: "#/components/schemas/TransferRequest" responses: "200": description: The transfer was successfully initiated. Returns the transfer @@ -1342,7 +1146,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/IdResponse' + $ref: "#/components/schemas/IdResponse" links: poll-state: operationId: getTransferProcessState @@ -1356,18 +1160,18 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/transferprocesses/request: post: tags: - - Transfer Process + - Transfer Process description: Returns all transfer process according to a query operationId: queryTransferProcesses requestBody: content: application/json: schema: - $ref: '#/components/schemas/QuerySpec' + $ref: "#/components/schemas/QuerySpec" responses: "200": description: The transfer processes matching the query @@ -1377,7 +1181,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/TransferProcess' + $ref: "#/components/schemas/TransferProcess" "400": description: Request was malformed content: @@ -1386,29 +1190,29 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/transferprocesses/{id}: get: tags: - - Transfer Process + - Transfer Process description: Gets an transfer process with the given ID operationId: getTransferProcess parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The transfer process content: application/json: schema: - $ref: '#/components/schemas/TransferProcess' + $ref: "#/components/schemas/TransferProcess" "400": description: "Request was malformed, e.g. id was null" content: @@ -1417,7 +1221,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: A transfer process with the given ID does not exist content: @@ -1426,11 +1230,11 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v2/transferprocesses/{id}/deprovision: post: tags: - - Transfer Process + - Transfer Process description: "Requests the deprovisioning of resources associated with a transfer\ \ process. Due to the asynchronous nature of transfers, a successful response\ \ only indicates that the request was successfully received. This may take\ @@ -1438,21 +1242,21 @@ paths: \ state." operationId: deprovisionTransferProcess parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: - "200": + "204": description: Request to deprovision the transfer process was successfully received links: poll-state: - operationId: getTransferProcessState + operationId: deprovisionTransferProcess "400": description: "Request was malformed, e.g. id was null" content: @@ -1461,38 +1265,80 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": - description: A contract negotiation with the given ID does not exist + description: A transfer process with the given ID does not exist + content: + application/json: + schema: + type: array + example: null + items: + $ref: "#/components/schemas/ApiErrorDetail" + /v2/transferprocesses/{id}/resume: + post: + tags: + - Transfer Process + description: "Requests the resumption of a suspended transfer process. Due to\ + \ the asynchronous nature of transfers, a successful response only indicates\ + \ that the request was successfully received. This may take a long time, so\ + \ clients must poll the /{id}/state endpoint to track the state." + operationId: resumeTransferProcess + parameters: + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null + responses: + "204": + description: Request to resume the transfer process was successfully received + links: + poll-state: + operationId: resumeTransferProcess + "400": + description: "Request was malformed, e.g. id was null" content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" + "404": + description: A transfer process with the given ID does not exist + content: + application/json: + schema: + type: array + example: null + items: + $ref: "#/components/schemas/ApiErrorDetail" /v2/transferprocesses/{id}/state: get: tags: - - Transfer Process + - Transfer Process description: Gets the state of a transfer process with the given ID operationId: getTransferProcessState parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The transfer process's state content: application/json: schema: - $ref: '#/components/schemas/TransferState' + $ref: "#/components/schemas/TransferState" "400": description: "Request was malformed, e.g. id was null" content: @@ -1501,7 +1347,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: An transfer process with the given ID does not exist content: @@ -1510,36 +1356,94 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" + /v2/transferprocesses/{id}/suspend: + post: + tags: + - Transfer Process + description: "Requests the suspension of a transfer process. Due to the asynchronous\ + \ nature of transfers, a successful response only indicates that the request\ + \ was successfully received. This may take a long time, so clients must poll\ + \ the /{id}/state endpoint to track the state." + operationId: suspendTransferProcess + parameters: + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/SuspendTransfer" + responses: + "204": + description: Request to suspend the transfer process was successfully received + links: + poll-state: + operationId: suspendTransferProcess + "400": + description: "Request was malformed, e.g. id was null" + content: + application/json: + schema: + type: array + example: null + items: + $ref: "#/components/schemas/ApiErrorDetail" + "404": + description: A transfer process with the given ID does not exist + content: + application/json: + schema: + type: array + example: null + items: + $ref: "#/components/schemas/ApiErrorDetail" + "409": + description: "Could not suspend the transfer process, because it is already\ + \ completed or terminated." + content: + application/json: + schema: + type: array + example: null + items: + $ref: "#/components/schemas/ApiErrorDetail" /v2/transferprocesses/{id}/terminate: post: tags: - - Transfer Process + - Transfer Process description: "Requests the termination of a transfer process. Due to the asynchronous\ \ nature of transfers, a successful response only indicates that the request\ - \ was successfully received. Clients must poll the /{id}/state endpoint to\ - \ track the state." + \ was successfully received. This may take a long time, so clients must poll\ + \ the /{id}/state endpoint to track the state." operationId: terminateTransferProcess parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null requestBody: content: application/json: schema: - $ref: '#/components/schemas/TerminateTransfer' + $ref: "#/components/schemas/TerminateTransfer" responses: - "200": - description: Request to cancel the transfer process was successfully received + "204": + description: Request to terminate the transfer process was successfully + received links: poll-state: - operationId: getTransferProcessState + operationId: terminateTransferProcess "400": description: "Request was malformed, e.g. id was null" content: @@ -1548,16 +1452,16 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": - description: A contract negotiation with the given ID does not exist + description: A transfer process with the given ID does not exist content: application/json: schema: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "409": description: "Could not terminate transfer process, because it is already\ \ completed or terminated." @@ -1567,23 +1471,23 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v3/assets: put: tags: - - Asset + - Asset description: "Updates an asset with the given ID if it exists. If the asset\ \ is not found, no further action is taken. DANGER ZONE: Note that updating\ \ assets can have unexpected results, especially for contract offers that\ \ have been sent out or are ongoing in contract negotiations." - operationId: updateAsset_1 + operationId: updateAsset requestBody: content: application/json: schema: - $ref: '#/components/schemas/AssetInput' + $ref: "#/components/schemas/AssetInput" responses: - "200": + "204": description: Asset was updated successfully "400": description: "Request was malformed, e.g. id was null" @@ -1593,19 +1497,19 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: "Asset could not be updated, because it does not exist." post: tags: - - Asset + - Asset description: Creates a new asset together with a data address - operationId: createAsset_1 + operationId: createAsset requestBody: content: application/json: schema: - $ref: '#/components/schemas/AssetInput' + $ref: "#/components/schemas/AssetInput" responses: "200": description: Asset was created successfully. Returns the asset Id and created @@ -1613,7 +1517,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/IdResponse' + $ref: "#/components/schemas/IdResponse" "400": description: Request body was malformed content: @@ -1622,7 +1526,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "409": description: "Could not create asset, because an asset with that ID already\ \ exists" @@ -1632,18 +1536,18 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v3/assets/request: post: tags: - - Asset - description: ' all assets according to a particular query' - operationId: requestAssets_1 + - Asset + description: Request all assets according to a particular query + operationId: requestAssets requestBody: content: application/json: schema: - $ref: '#/components/schemas/QuerySpec' + $ref: "#/components/schemas/QuerySpec" responses: "200": description: The assets matching the query @@ -1653,7 +1557,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/AssetOutput' + $ref: "#/components/schemas/AssetOutput" "400": description: Request body was malformed content: @@ -1662,29 +1566,29 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" /v3/assets/{id}: get: tags: - - Asset + - Asset description: Gets an asset with the given ID - operationId: getAsset_1 + operationId: getAsset parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The asset content: application/json: schema: - $ref: '#/components/schemas/AssetOutput' + $ref: "#/components/schemas/AssetOutput" "400": description: "Request was malformed, e.g. id was null" content: @@ -1693,7 +1597,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: An asset with the given ID does not exist content: @@ -1702,27 +1606,27 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" delete: tags: - - Asset + - Asset description: "Removes an asset with the given ID if possible. Deleting an asset\ \ is only possible if that asset is not yet referenced by a contract agreement,\ \ in which case an error is returned. DANGER ZONE: Note that deleting assets\ \ can have unexpected results, especially for contract offers that have been\ \ sent out or ongoing or contract negotiations." - operationId: removeAsset_1 + operationId: removeAsset parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - example: null + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: - "200": + "204": description: Asset was deleted successfully "400": description: "Request was malformed, e.g. id was null" @@ -1732,7 +1636,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "404": description: An asset with the given ID does not exist content: @@ -1741,7 +1645,7 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" "409": description: "The asset cannot be deleted, because it is referenced by a\ \ contract agreement" @@ -1751,14 +1655,14 @@ paths: type: array example: null items: - $ref: '#/components/schemas/ApiErrorDetail' + $ref: "#/components/schemas/ApiErrorDetail" components: schemas: ApiErrorDetail: type: object properties: invalidValue: - type: object + type: string example: null message: type: string @@ -1769,43 +1673,21 @@ components: type: type: string example: null - example: null - Asset: + example: + message: error message + type: ErrorType + path: object.error.path + invalidValue: this value is not valid + AssetInput: + required: + - '@context' + - dataAddress + - properties type: object properties: - createdAt: - type: integer - format: int64 - example: null - dataAddress: - $ref: '#/components/schemas/DataAddress' - id: - type: string - example: null - privateProperties: - type: object - additionalProperties: - type: object - example: null - example: null - properties: + '@context': type: object - additionalProperties: - type: object - example: null example: null - example: null - AssetEntryNewDto: - type: object - properties: - asset: - $ref: '#/components/schemas/Asset' - dataAddress: - $ref: '#/components/schemas/DataAddress' - example: null - AssetInput: - type: object - properties: '@id': type: string example: null @@ -1813,22 +1695,14 @@ components: type: string example: https://w3id.org/edc/v0.0.1/ns/Asset dataAddress: - $ref: '#/components/schemas/DataAddress' + $ref: "#/components/schemas/DataAddress" privateProperties: - type: object - additionalProperties: - type: object - example: null - example: null + $ref: "#/components/schemas/Properties" properties: - type: object - additionalProperties: - type: object - example: null - example: null + $ref: "#/components/schemas/Properties" example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@id': asset-id properties: key: value @@ -1836,6 +1710,7 @@ components: privateKey: privateValue dataAddress: type: HttpData + baseUrl: https://jsonplaceholder.typicode.com/todos AssetOutput: type: object properties: @@ -1850,30 +1725,23 @@ components: format: int64 example: null dataAddress: - $ref: '#/components/schemas/DataAddress' + $ref: "#/components/schemas/DataAddress" privateProperties: - type: object - additionalProperties: - type: object - example: null - example: null + $ref: "#/components/schemas/Properties" properties: - type: object - additionalProperties: - type: object - example: null - example: null + $ref: "#/components/schemas/Properties" example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@id': asset-id - edc:properties: - edc:key: value - edc:privateProperties: - edc:privateKey: privateValue - edc:dataAddress: - edc:type: HttpData - edc:createdAt: 1688465655 + properties: + key: value + privateProperties: + privateKey: privateValue + dataAddress: + type: HttpData + baseUrl: https://jsonplaceholder.typicode.com/todos + createdAt: 1688465655 CallbackAddress: type: object properties: @@ -1918,67 +1786,73 @@ components: odrl:type: http://www.w3.org/ns/odrl/2/use odrl:constraint: odrl:and: - - odrl:leftOperand: https://w3id.org/edc/v0.0.1/ns/inForceDate - odrl:operator: - '@id': odrl:gteq - odrl:rightOperand: 2023-07-07T07:19:58.585601395Z - - odrl:leftOperand: https://w3id.org/edc/v0.0.1/ns/inForceDate - odrl:operator: - '@id': odrl:lteq - odrl:rightOperand: 2023-07-12T07:19:58.585601395Z - odrl:prohibition: [ ] - odrl:obligation: [ ] - odrl:target: bcca61be-e82e-4da6-bfec-9716a56cef35 + - odrl:leftOperand: https://w3id.org/edc/v0.0.1/ns/inForceDate + odrl:operator: + '@id': odrl:gteq + odrl:rightOperand: 2023-07-07T07:19:58.585601395Z + - odrl:leftOperand: https://w3id.org/edc/v0.0.1/ns/inForceDate + odrl:operator: + '@id': odrl:lteq + odrl:rightOperand: 2023-07-12T07:19:58.585601395Z + odrl:prohibition: [] + odrl:obligation: [] dcat:distribution: - - '@type': dcat:Distribution - dct:format: - '@id': HttpData - dcat:accessService: 5e839777-d93e-4785-8972-1005f51cf367 - edc:description: description - edc:id: bcca61be-e82e-4da6-bfec-9716a56cef35 + - '@type': dcat:Distribution + dct:format: + '@id': HttpData + dcat:accessService: 5e839777-d93e-4785-8972-1005f51cf367 + description: description + id: bcca61be-e82e-4da6-bfec-9716a56cef35 dcat:service: '@id': 5e839777-d93e-4785-8972-1005f51cf367 '@type': dcat:DataService dct:terms: connector dct:endpointUrl: http://localhost:16806/protocol - edc:participantId: urn:connector:provider + dspace:participantId: urn:connector:provider '@context': - dct: https://purl.org/dc/terms/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ + dct: http://purl.org/dc/terms/ edc: https://w3id.org/edc/v0.0.1/ns/ - dcat: https://www.w3.org/ns/dcat/ + dcat: http://www.w3.org/ns/dcat# odrl: http://www.w3.org/ns/odrl/2/ dspace: https://w3id.org/dspace/v0.8/ CatalogRequest: + required: + - '@context' + - counterPartyAddress + - protocol type: object properties: + '@context': + type: object + example: null '@type': type: string example: https://w3id.org/edc/v0.0.1/ns/CatalogRequest counterPartyAddress: type: string example: null - protocol: + counterPartyId: type: string example: null - providerUrl: + protocol: type: string - description: please use counterPartyAddress instead example: null - deprecated: true querySpec: - $ref: '#/components/schemas/QuerySpec' + $ref: "#/components/schemas/QuerySpec" example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@type': CatalogRequest counterPartyAddress: http://provider-address + counterPartyId: providerId protocol: dataspace-protocol-http querySpec: offset: 0 limit: 50 sortOrder: DESC sortField: fieldName - filterExpression: [ ] + filterExpression: [] ContractAgreement: type: object properties: @@ -1999,13 +1873,13 @@ components: format: int64 example: null policy: - $ref: '#/components/schemas/Policy' + $ref: "#/components/schemas/Policy" providerId: type: string example: null example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@type': https://w3id.org/edc/v0.0.1/ns/ContractAgreement '@id': negotiation-id providerId: provider-id @@ -2017,11 +1891,19 @@ components: '@type': Set '@id': offer-id permission: - - target: asset-id - action: display + - target: asset-id + action: display ContractDefinitionInput: + required: + - '@context' + - accessPolicyId + - assetsSelector + - contractPolicyId type: object properties: + '@context': + type: object + example: null '@id': type: string example: null @@ -2035,17 +1917,17 @@ components: type: array example: null items: - $ref: '#/components/schemas/Criterion' + $ref: "#/components/schemas/Criterion" contractPolicyId: type: string example: null example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@id': definition-id accessPolicyId: asset-policy-id contractPolicyId: contract-policy-id - assetsSelector: [ ] + assetsSelector: [] ContractDefinitionOutput: type: object properties: @@ -2062,7 +1944,7 @@ components: type: array example: null items: - $ref: '#/components/schemas/Criterion' + $ref: "#/components/schemas/Criterion" contractPolicyId: type: string example: null @@ -2072,12 +1954,12 @@ components: example: null example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@id': definition-id - edc:accessPolicyId: asset-policy-id - edc:contractPolicyId: contract-policy-id - edc:assetsSelector: [ ] - edc:createdAt: 1688465655 + accessPolicyId: asset-policy-id + contractPolicyId: contract-policy-id + assetsSelector: [] + createdAt: 1688465655 ContractNegotiation: type: object properties: @@ -2091,7 +1973,7 @@ components: type: array example: null items: - $ref: '#/components/schemas/CallbackAddress' + $ref: "#/components/schemas/CallbackAddress" contractAgreementId: type: string example: null @@ -2114,11 +1996,11 @@ components: type: string example: null enum: - - CONSUMER - - PROVIDER + - CONSUMER + - PROVIDER example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@type': https://w3id.org/edc/v0.0.1/ns/ContractNegotiation '@id': negotiation-id type: PROVIDER @@ -2130,13 +2012,13 @@ components: errorDetail: eventual-error-detail createdAt: 1688465655 callbackAddresses: - - transactional: false - uri: http://callback/url - events: - - contract.negotiation - - transfer.process - authKey: auth-key - authCodeId: auth-code-id + - transactional: false + uri: http://callback/url + events: + - contract.negotiation + - transfer.process + authKey: auth-key + authCodeId: auth-code-id ContractOfferDescription: type: object properties: @@ -2150,11 +2032,21 @@ components: type: string example: null policy: - $ref: '#/components/schemas/Policy' + $ref: "#/components/schemas/Policy" + description: please use policy instead of offer example: null + deprecated: true ContractRequest: + required: + - '@context' + - counterPartyAddress + - policy + - protocol type: object properties: + '@context': + type: object + example: null '@type': type: string example: https://w3id.org/edc/v0.0.1/ns/ContractRequest @@ -2162,54 +2054,55 @@ components: type: array example: null items: - $ref: '#/components/schemas/CallbackAddress' + $ref: "#/components/schemas/CallbackAddress" connectorAddress: type: string - example: null - connectorId: - type: string - description: please use providerId instead + description: please use counterPartyAddress instead example: null deprecated: true - consumerId: + counterPartyAddress: type: string - description: this field is not used anymore example: null - deprecated: true offer: - $ref: '#/components/schemas/ContractOfferDescription' + $ref: "#/components/schemas/ContractOfferDescription" + policy: + $ref: "#/components/schemas/Offer" protocol: type: string example: null providerId: type: string + description: please use policy.assigner instead example: null + deprecated: true example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@type': https://w3id.org/edc/v0.0.1/ns/ContractRequest - connectorAddress: http://provider-address + counterPartyAddress: http://provider-address protocol: dataspace-protocol-http - providerId: provider-id - offer: - offerId: offer-id - assetId: asset-id - policy: - '@context': http://www.w3.org/ns/odrl.jsonld - '@type': Set - '@id': offer-id - permission: - - target: asset-id - action: display + policy: + '@context': http://www.w3.org/ns/odrl.jsonld + '@type': odrl:Offer + '@id': offer-id + assigner: providerId + permission: [] + prohibition: [] + obligation: [] + target: assetId callbackAddresses: - - transactional: false - uri: http://callback/url - events: - - contract.negotiation - - transfer.process - authKey: auth-key - authCodeId: auth-code-id + - transactional: false + uri: http://callback/url + events: + - contract.negotiation + - transfer.process + authKey: auth-key + authCodeId: auth-code-id Criterion: + required: + - operandLeft + - operandRight + - operator type: object properties: '@type': @@ -2226,7 +2119,7 @@ components: example: null example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@type': Criterion operandLeft: fieldName operator: = @@ -2242,8 +2135,16 @@ components: example: null example: null DataPlaneInstanceSchema: + required: + - '@context' + - allowedDestTypes + - allowedSourceTypes + - url type: object properties: + '@context': + type: object + example: null '@id': type: string example: null @@ -2277,13 +2178,17 @@ components: format: url example: null example: + '@context': + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@id': your-dataplane-id url: http://somewhere.com:1234/api/v1 allowedSourceTypes: - - source-type1 - - source-type2 + - source-type1 + - source-type2 allowedDestTypes: - - your-dest-type + - your-dest-type + allowedTransferTypes: + - transfer-type Dataset: type: object description: DCAT dataset @@ -2299,28 +2204,29 @@ components: odrl:type: http://www.w3.org/ns/odrl/2/use odrl:constraint: odrl:and: - - odrl:leftOperand: https://w3id.org/edc/v0.0.1/ns/inForceDate - odrl:operator: - '@id': odrl:gteq - odrl:rightOperand: 2023-07-07T07:19:58.585601395Z - - odrl:leftOperand: https://w3id.org/edc/v0.0.1/ns/inForceDate - odrl:operator: - '@id': odrl:lteq - odrl:rightOperand: 2023-07-12T07:19:58.585601395Z - odrl:prohibition: [ ] - odrl:obligation: [ ] + - odrl:leftOperand: https://w3id.org/edc/v0.0.1/ns/inForceDate + odrl:operator: + '@id': odrl:gteq + odrl:rightOperand: 2023-07-07T07:19:58.585601395Z + - odrl:leftOperand: https://w3id.org/edc/v0.0.1/ns/inForceDate + odrl:operator: + '@id': odrl:lteq + odrl:rightOperand: 2023-07-12T07:19:58.585601395Z + odrl:prohibition: [] + odrl:obligation: [] odrl:target: bcca61be-e82e-4da6-bfec-9716a56cef35 dcat:distribution: - - '@type': dcat:Distribution - dct:format: - '@id': HttpData - dcat:accessService: 5e839777-d93e-4785-8972-1005f51cf367 - edc:description: description - edc:id: bcca61be-e82e-4da6-bfec-9716a56cef35 + - '@type': dcat:Distribution + dct:format: + '@id': HttpData + dcat:accessService: 5e839777-d93e-4785-8972-1005f51cf367 + description: description + id: bcca61be-e82e-4da6-bfec-9716a56cef35 '@context': - dct: https://purl.org/dc/terms/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ + dct: http://purl.org/dc/terms/ edc: https://w3id.org/edc/v0.0.1/ns/ - dcat: https://www.w3.org/ns/dcat/ + dcat: http://www.w3.org/ns/dcat# odrl: http://www.w3.org/ns/odrl/2/ dspace: https://w3id.org/dspace/v0.8/ DatasetRequest: @@ -2332,17 +2238,21 @@ components: counterPartyAddress: type: string example: null + counterPartyId: + type: string + example: null protocol: type: string example: null querySpec: - $ref: '#/components/schemas/QuerySpec' + $ref: "#/components/schemas/QuerySpec" example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@type': DatasetRequest '@id': dataset-id counterPartyAddress: http://counter-party-address + counterPartyId: counter-party-id protocol: dataspace-protocol-http DeprovisionedResource: type: object @@ -2360,43 +2270,25 @@ components: type: string example: null example: null - Failure: + EndpointDataReferenceEntry: type: object properties: - failureDetail: + '@id': type: string example: null - messages: - type: array - example: null - items: - type: string - example: null - example: null - HealthCheckResult: - type: object - properties: - component: + '@type': type: string - example: null - failure: - $ref: '#/components/schemas/Failure' - isHealthy: - type: boolean - example: null - example: null - HealthStatus: - type: object - properties: - componentResults: - type: array - example: null - items: - $ref: '#/components/schemas/HealthCheckResult' - isSystemHealthy: - type: boolean - example: null - example: null + example: https://w3id.org/edc/v0.0.1/ns/EndpointDataReferenceEntry + example: + '@context': + '@vocab': https://w3id.org/edc/v0.0.1/ns/ + '@id': transfer-process-id + transferProcessId: transfer-process-id + agreementId: agreement-id + contractNegotiationId: contract-negotiation-id + assetId: asset-id + providerId: provider-id + createdAt: 1688465655 IdResponse: type: object properties: @@ -2409,7 +2301,7 @@ components: example: null example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@id': id-value createdAt: 1688465655 JsonArray: @@ -2422,16 +2314,16 @@ components: type: string example: null enum: - - ARRAY - - OBJECT - - STRING - - NUMBER - - "TRUE" - - "FALSE" - - "NULL" + - ARRAY + - OBJECT + - STRING + - NUMBER + - "TRUE" + - "FALSE" + - "NULL" example: null items: - $ref: '#/components/schemas/JsonValue' + $ref: "#/components/schemas/JsonValue" JsonObject: type: object properties: @@ -2442,15 +2334,15 @@ components: type: string example: null enum: - - ARRAY - - OBJECT - - STRING - - NUMBER - - "TRUE" - - "FALSE" - - "NULL" + - ARRAY + - OBJECT + - STRING + - NUMBER + - "TRUE" + - "FALSE" + - "NULL" additionalProperties: - $ref: '#/components/schemas/JsonValue' + $ref: "#/components/schemas/JsonValue" example: null JsonValue: type: object @@ -2459,13 +2351,13 @@ components: type: string example: null enum: - - ARRAY - - OBJECT - - STRING - - NUMBER - - "TRUE" - - "FALSE" - - "NULL" + - ARRAY + - OBJECT + - STRING + - NUMBER + - "TRUE" + - "FALSE" + - "NULL" example: null NegotiationState: type: object @@ -2474,6 +2366,35 @@ components: type: string example: null example: null + Offer: + required: + - '@id' + - assigner + - target + type: object + properties: + '@id': + type: string + example: null + '@type': + type: string + example: http://www.w3.org/ns/odrl/2/Offer + assigner: + type: string + example: null + target: + type: string + example: null + description: ODRL offer + example: + '@context': http://www.w3.org/ns/odrl.jsonld + '@type': odrl:Offer + '@id': offer-id + assigner: providerId + target: assetId + permission: [] + prohibition: [] + obligation: [] Policy: type: object description: ODRL policy @@ -2489,11 +2410,17 @@ components: leftOperand: https://w3id.org/edc/v0.0.1/ns/left operator: eq rightOperand: value - prohibition: [ ] - obligation: [ ] + prohibition: [] + obligation: [] PolicyDefinitionInput: + required: + - '@context' + - policy type: object properties: + '@context': + type: object + example: null '@id': type: string example: null @@ -2501,23 +2428,23 @@ components: type: string example: https://w3id.org/edc/v0.0.1/ns/PolicyDefinition policy: - $ref: '#/components/schemas/Policy' + $ref: "#/components/schemas/Policy" example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@id': definition-id policy: '@context': http://www.w3.org/ns/odrl.jsonld '@type': Set uid: http://example.com/policy:1010 permission: - - target: http://example.com/asset:9898.movie - action: display - constraint: - - leftOperand: spatial - operator: eq - rightOperand: https://www.wikidata.org/wiki/Q183 - comment: i.e Germany + - target: http://example.com/asset:9898.movie + action: display + constraint: + - leftOperand: spatial + operator: eq + rightOperand: https://www.wikidata.org/wiki/Q183 + comment: i.e Germany PolicyDefinitionOutput: type: object properties: @@ -2528,24 +2455,27 @@ components: type: string example: https://w3id.org/edc/v0.0.1/ns/PolicyDefinition policy: - $ref: '#/components/schemas/Policy' + $ref: "#/components/schemas/Policy" example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@id': definition-id policy: '@context': http://www.w3.org/ns/odrl.jsonld '@type': Set uid: http://example.com/policy:1010 permission: - - target: http://example.com/asset:9898.movie - action: display - constraint: - - leftOperand: spatial - operator: eq - rightOperand: https://www.wikidata.org/wiki/Q183 - comment: i.e Germany + - target: http://example.com/asset:9898.movie + action: display + constraint: + - leftOperand: spatial + operator: eq + rightOperand: https://www.wikidata.org/wiki/Q183 + comment: i.e Germany createdAt: 1688465655 + Properties: + type: object + example: null ProvisionerWebhookRequest: type: object properties: @@ -2556,7 +2486,7 @@ components: type: string example: null contentDataAddress: - $ref: '#/components/schemas/DataAddress' + $ref: "#/components/schemas/DataAddress" hasToken: type: boolean example: null @@ -2577,7 +2507,7 @@ components: type: array example: null items: - $ref: '#/components/schemas/Criterion' + $ref: "#/components/schemas/Criterion" limit: type: integer format: int32 @@ -2593,17 +2523,60 @@ components: type: string example: null enum: - - ASC - - DESC + - ASC + - DESC example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@type': QuerySpec offset: 5 limit: 10 sortOrder: DESC sortField: fieldName - filterExpression: [ ] + filterExpression: [] + SecretInput: + required: + - '@context' + - https://w3id.org/edc/v0.0.1/ns/value + type: object + properties: + '@context': + type: object + example: null + '@id': + type: string + example: null + '@type': + type: string + example: https://w3id.org/edc/v0.0.1/ns/Secret + https://w3id.org/edc/v0.0.1/ns/value: + type: string + example: null + example: + '@context': + '@vocab': https://w3id.org/edc/v0.0.1/ns/ + '@id': secret-id + value: secret-value + SecretOutput: + required: + - https://w3id.org/edc/v0.0.1/ns/value + type: object + properties: + '@id': + type: string + example: null + '@type': + type: string + example: https://w3id.org/edc/v0.0.1/ns/Secret + https://w3id.org/edc/v0.0.1/ns/value: + type: string + example: null + example: + '@context': + '@vocab': https://w3id.org/edc/v0.0.1/ns/ + '@id': secret-id + '@type': https://w3id.org/edc/v0.0.1/ns/Secret + value: secret-value SelectionRequestSchema: type: object properties: @@ -2611,13 +2584,18 @@ components: type: string example: https://w3id.org/edc/v0.0.1/ns/SelectionRequest destination: - $ref: '#/components/schemas/DataAddress' + $ref: "#/components/schemas/DataAddress" source: - $ref: '#/components/schemas/DataAddress' + $ref: "#/components/schemas/DataAddress" strategy: type: string example: null + transferType: + type: string + example: null example: + '@context': + '@vocab': https://w3id.org/edc/v0.0.1/ns/ source: '@type': https://w3id.org/edc/v0.0.1/ns/DataAddress type: test-src1 @@ -2625,6 +2603,21 @@ components: '@type': https://w3id.org/edc/v0.0.1/ns/DataAddress type: test-dst2 strategy: you_custom_strategy + transferType: you_custom_transfer_type + SuspendTransfer: + type: object + properties: + '@type': + type: string + example: https://w3id.org/edc/v0.0.1/ns/SuspendTransfer + state: + type: string + example: null + example: + '@context': + '@vocab': https://w3id.org/edc/v0.0.1/ns/ + '@type': https://w3id.org/edc/v0.0.1/ns/SuspendTransfer + reason: a reason to suspend TerminateNegotiationSchema: type: object properties: @@ -2639,7 +2632,7 @@ components: example: null example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@type': https://w3id.org/edc/v0.0.1/ns/TerminateNegotiation '@id': negotiation-id reason: a reason to terminate @@ -2648,13 +2641,13 @@ components: properties: '@type': type: string - example: https://w3id.org/edc/v0.0.1/ns/TransferState + example: https://w3id.org/edc/v0.0.1/ns/TerminateTransfer state: type: string example: null example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@type': https://w3id.org/edc/v0.0.1/ns/TerminateTransfer reason: a reason to terminate TransferProcess: @@ -2670,7 +2663,7 @@ components: type: array example: null items: - $ref: '#/components/schemas/CallbackAddress' + $ref: "#/components/schemas/CallbackAddress" contractAgreementId: type: string example: null @@ -2680,23 +2673,13 @@ components: counterPartyId: type: string example: null + dataDestination: + $ref: "#/components/schemas/DataAddress" errorDetail: type: string example: null privateProperties: - type: object - additionalProperties: - type: object - example: null - example: null - properties: - type: object - additionalProperties: - type: string - example: null - deprecated: true - example: null - deprecated: true + $ref: "#/components/schemas/Properties" protocol: type: string example: null @@ -2707,11 +2690,11 @@ components: type: string example: null enum: - - CONSUMER - - PROVIDER + - CONSUMER + - PROVIDER example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@type': https://w3id.org/edc/v0.0.1/ns/TransferProcess '@id': process-id correlationId: correlation-id @@ -2719,7 +2702,6 @@ components: state: STARTED stateTimestamp: 1688465655 assetId: asset-id - connectorId: connectorId contractId: contractId dataDestination: type: data-destination-type @@ -2728,16 +2710,26 @@ components: errorDetail: eventual-error-detail createdAt: 1688465655 callbackAddresses: - - transactional: false - uri: http://callback/url - events: - - contract.negotiation - - transfer.process - authKey: auth-key - authCodeId: auth-code-id + - transactional: false + uri: http://callback/url + events: + - contract.negotiation + - transfer.process + authKey: auth-key + authCodeId: auth-code-id TransferRequest: + required: + - '@context' + - assetId + - contractId + - counterPartyAddress + - protocol + - transferType type: object properties: + '@context': + type: object + example: null '@type': type: string example: https://w3id.org/edc/v0.0.1/ns/TransferRequest @@ -2748,60 +2740,54 @@ components: type: array example: null items: - $ref: '#/components/schemas/CallbackAddress' + $ref: "#/components/schemas/CallbackAddress" connectorAddress: type: string + description: please use counterPartyAddress instead example: null + deprecated: true connectorId: type: string + description: Provider connector id is stored in the contract agreement example: null + deprecated: true contractId: type: string example: null + counterPartyAddress: + type: string + example: null dataDestination: - $ref: '#/components/schemas/DataAddress' + $ref: "#/components/schemas/DataAddress" privateProperties: - type: object - additionalProperties: - type: string - example: null - example: null - properties: - type: object - additionalProperties: - type: string - description: "Deprecated as this field is not used anymore, please use\ - \ privateProperties instead" - example: null - deprecated: true - description: "Deprecated as this field is not used anymore, please use privateProperties\ - \ instead" - example: null - deprecated: true + $ref: "#/components/schemas/Properties" protocol: type: string example: null + transferType: + type: string + example: null example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@type': https://w3id.org/edc/v0.0.1/ns/TransferRequest protocol: dataspace-protocol-http - connectorAddress: http://provider-address - connectorId: provider-id + counterPartyAddress: http://provider-address contractId: contract-id assetId: asset-id + transferType: transferType dataDestination: type: data-destination-type privateProperties: private-key: private-value callbackAddresses: - - transactional: false - uri: http://callback/url - events: - - contract.negotiation - - transfer.process - authKey: auth-key - authCodeId: auth-code-id + - transactional: false + uri: http://callback/url + events: + - contract.negotiation + - transfer.process + authKey: auth-key + authCodeId: auth-code-id TransferState: type: object properties: @@ -2813,6 +2799,6 @@ components: example: null example: '@context': - edc: https://w3id.org/edc/v0.0.1/ns/ + '@vocab': https://w3id.org/edc/v0.0.1/ns/ '@type': https://w3id.org/edc/v0.0.1/ns/TransferState - state: STARTED + state: STARTED \ No newline at end of file diff --git a/docs/api/sovity-edc-api-wrapper.yaml b/docs/api/sovity-edc-api-wrapper.yaml index a6400de63..ec8b5fc62 100644 --- a/docs/api/sovity-edc-api-wrapper.yaml +++ b/docs/api/sovity-edc-api-wrapper.yaml @@ -39,7 +39,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ConnectorLimits' + $ref: "#/components/schemas/ConnectorLimits" /wrapper/ee/file-upload/blobs/{blobId}/asset: post: tags: @@ -59,7 +59,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/UiAssetCreateRequest' + $ref: "#/components/schemas/UiAssetCreateRequest" required: true responses: default: @@ -91,14 +91,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/UiAssetCreateRequest' + $ref: "#/components/schemas/UiAssetCreateRequest" responses: default: description: default response content: application/json: schema: - $ref: '#/components/schemas/IdResponseDto' + $ref: "#/components/schemas/IdResponseDto" /wrapper/ui/pages/contract-definition-page/contract-definitions: post: tags: @@ -109,14 +109,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ContractDefinitionRequest' + $ref: "#/components/schemas/ContractDefinitionRequest" responses: default: description: default response content: application/json: schema: - $ref: '#/components/schemas/IdResponseDto' + $ref: "#/components/schemas/IdResponseDto" /wrapper/ui/pages/create-data-offer: post: tags: @@ -129,14 +129,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/DataOfferCreationRequest' + $ref: "#/components/schemas/DataOfferCreationRequest" responses: default: description: default response content: application/json: schema: - $ref: '#/components/schemas/IdResponseDto' + $ref: "#/components/schemas/IdResponseDto" /wrapper/ui/pages/policy-page/policy-definitions: post: tags: @@ -148,14 +148,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PolicyDefinitionCreateRequest' + $ref: "#/components/schemas/PolicyDefinitionCreateRequest" responses: default: description: default response content: application/json: schema: - $ref: '#/components/schemas/IdResponseDto' + $ref: "#/components/schemas/IdResponseDto" deprecated: true /wrapper/ui/v2/pages/policy-page/policy-definitions: post: @@ -167,14 +167,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PolicyDefinitionCreateDto' + $ref: "#/components/schemas/PolicyDefinitionCreateDto" responses: default: description: default response content: application/json: schema: - $ref: '#/components/schemas/IdResponseDto' + $ref: "#/components/schemas/IdResponseDto" /wrapper/ui/pages/asset-page/assets/{assetId}: put: tags: @@ -191,14 +191,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/UiAssetEditRequest' + $ref: "#/components/schemas/UiAssetEditRequest" responses: default: description: default response content: application/json: schema: - $ref: '#/components/schemas/IdResponseDto' + $ref: "#/components/schemas/IdResponseDto" delete: tags: - UI @@ -216,7 +216,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/IdResponseDto' + $ref: "#/components/schemas/IdResponseDto" /wrapper/ui/pages/contract-definition-page/contract-definitions/{contractDefinitionId}: delete: tags: @@ -235,7 +235,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/IdResponseDto' + $ref: "#/components/schemas/IdResponseDto" /wrapper/ui/pages/policy-page/policy-definitions/{policyId}: delete: tags: @@ -254,7 +254,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/IdResponseDto' + $ref: "#/components/schemas/IdResponseDto" /wrapper/ui/pages/asset-page: get: tags: @@ -267,7 +267,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/AssetPage' + $ref: "#/components/schemas/AssetPage" /wrapper/ui/pages/catalog-page/data-offers: get: tags: @@ -275,6 +275,10 @@ paths: description: Fetch a connector's data offers operationId: getCatalogPageDataOffers parameters: + - name: participantId + in: query + schema: + type: string - name: connectorEndpoint in: query schema: @@ -287,7 +291,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/UiDataOffer' + $ref: "#/components/schemas/UiDataOffer" /wrapper/ui/pages/contract-agreement-page/{contractAgreementId}: get: tags: @@ -306,7 +310,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ContractAgreementCard' + $ref: "#/components/schemas/ContractAgreementCard" /wrapper/ui/pages/contract-agreement-page: post: tags: @@ -318,14 +322,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ContractAgreementPageQuery' + $ref: "#/components/schemas/ContractAgreementPageQuery" responses: default: description: default response content: application/json: schema: - $ref: '#/components/schemas/ContractAgreementPage' + $ref: "#/components/schemas/ContractAgreementPage" /wrapper/ui/pages/contract-definition-page: get: tags: @@ -338,7 +342,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ContractDefinitionPage' + $ref: "#/components/schemas/ContractDefinitionPage" /wrapper/ui/pages/catalog-page/contract-negotiations/{contractNegotiationId}: get: tags: @@ -357,7 +361,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/UiContractNegotiation' + $ref: "#/components/schemas/UiContractNegotiation" /wrapper/ui/pages/dashboard-page: get: tags: @@ -370,7 +374,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/DashboardPage' + $ref: "#/components/schemas/DashboardPage" /wrapper/ui/pages/policy-page: get: tags: @@ -383,7 +387,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PolicyDefinitionPage' + $ref: "#/components/schemas/PolicyDefinitionPage" /wrapper/ui/pages/transfer-history-page: get: tags: @@ -396,7 +400,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/TransferHistoryPage' + $ref: "#/components/schemas/TransferHistoryPage" /wrapper/ui/pages/transfer-history-page/transfer-processes/{transferProcessId}/asset: get: tags: @@ -415,7 +419,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/UiAsset' + $ref: "#/components/schemas/UiAsset" /wrapper/ui/pages/catalog-page/contract-negotiations: post: tags: @@ -426,14 +430,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ContractNegotiationRequest' + $ref: "#/components/schemas/ContractNegotiationRequest" responses: default: description: default response content: application/json: schema: - $ref: '#/components/schemas/UiContractNegotiation' + $ref: "#/components/schemas/UiContractNegotiation" /wrapper/ui/pages/contract-agreement-page/transfers/custom: post: tags: @@ -446,14 +450,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/InitiateCustomTransferRequest' + $ref: "#/components/schemas/InitiateCustomTransferRequest" responses: default: description: default response content: application/json: schema: - $ref: '#/components/schemas/IdResponseDto' + $ref: "#/components/schemas/IdResponseDto" /wrapper/ui/pages/contract-agreement-page/transfers: post: tags: @@ -464,14 +468,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/InitiateTransferRequest' + $ref: "#/components/schemas/InitiateTransferRequest" responses: default: description: default response content: application/json: schema: - $ref: '#/components/schemas/IdResponseDto' + $ref: "#/components/schemas/IdResponseDto" /wrapper/ui/pages/data-offer-page/validate-asset-id/{assetId}: get: tags: @@ -490,7 +494,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/IdAvailabilityResponse' + $ref: "#/components/schemas/IdAvailabilityResponse" /wrapper/ui/pages/data-offer-page/validate-contract-definition-id/{contractDefinitionId}: get: tags: @@ -509,7 +513,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/IdAvailabilityResponse' + $ref: "#/components/schemas/IdAvailabilityResponse" /wrapper/ui/pages/data-offer-page/validate-policy-id/{policyId}: get: tags: @@ -528,7 +532,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/IdAvailabilityResponse' + $ref: "#/components/schemas/IdAvailabilityResponse" /wrapper/ui/pages/content-agreement-page/{contractAgreementId}/terminate: post: tags: @@ -546,14 +550,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ContractTerminationRequest' + $ref: "#/components/schemas/ContractTerminationRequest" responses: default: description: default response content: application/json: schema: - $ref: '#/components/schemas/IdResponseDto' + $ref: "#/components/schemas/IdResponseDto" /wrapper/use-case-api/kpis: get: tags: @@ -566,7 +570,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/KpiResult' + $ref: "#/components/schemas/KpiResult" /wrapper/use-case-api/supported-policy-functions: get: tags: @@ -592,7 +596,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/CatalogQuery' + $ref: "#/components/schemas/CatalogQuery" required: true responses: default: @@ -602,7 +606,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/UiDataOffer' + $ref: "#/components/schemas/UiDataOffer" components: schemas: ConnectorLimits: @@ -623,11 +627,11 @@ components: DataSourceType: type: string description: Supported Data Source Types by UiDataSource + default: CUSTOM enum: - HTTP_DATA - ON_REQUEST - CUSTOM - default: CUSTOM SecretValue: type: object properties: @@ -649,7 +653,7 @@ components: type: object properties: dataSource: - $ref: '#/components/schemas/UiDataSource' + $ref: "#/components/schemas/UiDataSource" id: type: string description: Asset Id @@ -768,11 +772,11 @@ components: type: object properties: type: - $ref: '#/components/schemas/DataSourceType' + $ref: "#/components/schemas/DataSourceType" httpData: - $ref: '#/components/schemas/UiDataSourceHttpData' + $ref: "#/components/schemas/UiDataSourceHttpData" onRequest: - $ref: '#/components/schemas/UiDataSourceOnRequest' + $ref: "#/components/schemas/UiDataSourceOnRequest" customProperties: type: object additionalProperties: @@ -787,7 +791,7 @@ components: type: object properties: method: - $ref: '#/components/schemas/UiDataSourceHttpDataMethod' + $ref: "#/components/schemas/UiDataSourceHttpDataMethod" baseUrl: type: string description: "HTTP Request URL. If parameterized, additional pathParams\ @@ -803,7 +807,7 @@ components: EDC as its value can be read from a vault. example: Authorization authHeaderValue: - $ref: '#/components/schemas/SecretValue' + $ref: "#/components/schemas/SecretValue" headers: type: object additionalProperties: @@ -835,6 +839,7 @@ components: UiDataSourceHttpDataMethod: type: string description: Supported HTTP Methods by UiDataSource + default: GET enum: - GET - POST @@ -842,7 +847,6 @@ components: - PATCH - DELETE - OPTIONS - default: GET UiDataSourceOnRequest: required: - contactEmail @@ -893,7 +897,7 @@ components: type: array description: List of Criteria for the contract items: - $ref: '#/components/schemas/UiCriterion' + $ref: "#/components/schemas/UiCriterion" description: Data for creating a Contract Definition UiCriterion: required: @@ -906,15 +910,15 @@ components: type: string description: Left Operand operator: - $ref: '#/components/schemas/UiCriterionOperator' + $ref: "#/components/schemas/UiCriterionOperator" operandRight: - $ref: '#/components/schemas/UiCriterionLiteral' + $ref: "#/components/schemas/UiCriterionLiteral" description: Contract Definition Criterion as supported by the UI UiCriterionLiteral: type: object properties: type: - $ref: '#/components/schemas/UiCriterionLiteralType' + $ref: "#/components/schemas/UiCriterionLiteralType" value: type: string description: Only for type VALUE. The single value representation. @@ -945,7 +949,7 @@ components: type: object properties: uiAssetCreateRequest: - $ref: '#/components/schemas/UiAssetCreateRequest' + $ref: "#/components/schemas/UiAssetCreateRequest" policy: type: string description: Which policy to apply to this asset creation. @@ -954,7 +958,7 @@ components: - PUBLISH_UNRESTRICTED - PUBLISH_RESTRICTED uiPolicyExpression: - $ref: '#/components/schemas/UiPolicyExpression' + $ref: "#/components/schemas/UiPolicyExpression" description: Request to create a data offer OperatorDto: type: string @@ -984,9 +988,9 @@ components: type: string description: Left side of the expression. operator: - $ref: '#/components/schemas/OperatorDto' + $ref: "#/components/schemas/OperatorDto" right: - $ref: '#/components/schemas/UiPolicyLiteral' + $ref: "#/components/schemas/UiPolicyLiteral" description: "ODRL AtomicConstraint as supported by the sovity product landscape.\ \ For example 'a EQ b', 'c IN [d, e, f]'" UiPolicyExpression: @@ -995,15 +999,15 @@ components: type: object properties: type: - $ref: '#/components/schemas/UiPolicyExpressionType' + $ref: "#/components/schemas/UiPolicyExpressionType" expressions: type: array description: "Only for types AND, OR, XONE. List of sub-expressions to be\ \ evaluated according to the expressionType." items: - $ref: '#/components/schemas/UiPolicyExpression' + $ref: "#/components/schemas/UiPolicyExpression" constraint: - $ref: '#/components/schemas/UiPolicyConstraint' + $ref: "#/components/schemas/UiPolicyConstraint" description: ODRL constraint as supported by the sovity product landscape UiPolicyExpressionType: type: string @@ -1025,7 +1029,7 @@ components: type: object properties: type: - $ref: '#/components/schemas/UiPolicyLiteralType' + $ref: "#/components/schemas/UiPolicyLiteralType" value: type: string description: Only for types STRING and JSON @@ -1053,7 +1057,7 @@ components: type: string description: Policy Definition ID policy: - $ref: '#/components/schemas/UiPolicyCreateRequest' + $ref: "#/components/schemas/UiPolicyCreateRequest" description: "[Deprecated] Create a Policy Definition. Use PolicyDefinitionCreateDto" deprecated: true UiPolicyCreateRequest: @@ -1064,7 +1068,7 @@ components: description: Conjunction of required constraints deprecated: true items: - $ref: '#/components/schemas/UiPolicyConstraint' + $ref: "#/components/schemas/UiPolicyConstraint" description: "[Deprecated] Conjunction of constraints (simplified UiPolicyExpression)" deprecated: true PolicyDefinitionCreateDto: @@ -1077,13 +1081,13 @@ components: type: string description: Policy Definition ID expression: - $ref: '#/components/schemas/UiPolicyExpression' + $ref: "#/components/schemas/UiPolicyExpression" description: Create a Policy Definition UiAssetEditRequest: type: object properties: dataSourceOverrideOrNull: - $ref: '#/components/schemas/UiDataSource' + $ref: "#/components/schemas/UiDataSource" title: type: string description: Asset Title @@ -1202,7 +1206,7 @@ components: type: array description: Visible Assets items: - $ref: '#/components/schemas/UiAsset' + $ref: "#/components/schemas/UiAsset" description: All data for the Asset Page DataSourceAvailability: type: string @@ -1224,7 +1228,7 @@ components: type: object properties: dataSourceAvailability: - $ref: '#/components/schemas/DataSourceAvailability' + $ref: "#/components/schemas/DataSourceAvailability" assetId: type: string description: Asset Id @@ -1391,7 +1395,7 @@ components: type: string description: Contract Offer ID policy: - $ref: '#/components/schemas/UiPolicy' + $ref: "#/components/schemas/UiPolicy" description: Catalog Data Offer's Contract Offer as required by the UI UiDataOffer: required: @@ -1408,12 +1412,12 @@ components: type: string description: Participant ID. Required for initiating transfers. asset: - $ref: '#/components/schemas/UiAsset' + $ref: "#/components/schemas/UiAsset" contractOffers: type: array description: Available Contract Offers items: - $ref: '#/components/schemas/UiContractOffer' + $ref: "#/components/schemas/UiContractOffer" description: Catalog Data Offer as required by the UI UiPolicy: required: @@ -1426,7 +1430,7 @@ components: description: EDC Policy JSON-LD. This is required because the EDC requires the full policy when initiating contract negotiations. expression: - $ref: '#/components/schemas/UiPolicyExpression' + $ref: "#/components/schemas/UiPolicyExpression" errors: type: array description: "When trying to reduce the policy JSON-LD to our opinionated\ @@ -1462,7 +1466,7 @@ components: type: string description: Contract Negotiation ID direction: - $ref: '#/components/schemas/ContractAgreementDirection' + $ref: "#/components/schemas/ContractAgreementDirection" counterPartyAddress: type: string description: Other Connector's Endpoint @@ -1474,18 +1478,18 @@ components: description: Contract Agreements Signing Date format: date-time asset: - $ref: '#/components/schemas/UiAsset' + $ref: "#/components/schemas/UiAsset" contractPolicy: - $ref: '#/components/schemas/UiPolicy' + $ref: "#/components/schemas/UiPolicy" transferProcesses: type: array description: Contract Agreement's Transfer Processes items: - $ref: '#/components/schemas/ContractAgreementTransferProcess' + $ref: "#/components/schemas/ContractAgreementTransferProcess" terminationStatus: - $ref: '#/components/schemas/ContractTerminationStatus' + $ref: "#/components/schemas/ContractTerminationStatus" terminationInformation: - $ref: '#/components/schemas/ContractAgreementTerminationInfo' + $ref: "#/components/schemas/ContractAgreementTerminationInfo" description: Contract Agreement for Contract Agreement Page ContractAgreementDirection: type: string @@ -1514,7 +1518,7 @@ components: description: Detailed message from the terminating party about why the contract was terminated. terminatedBy: - $ref: '#/components/schemas/ContractTerminatedBy' + $ref: "#/components/schemas/ContractTerminatedBy" description: Contract's agreement metadata ContractAgreementTransferProcess: required: @@ -1531,7 +1535,7 @@ components: description: Last Change Date format: date-time state: - $ref: '#/components/schemas/TransferProcessState' + $ref: "#/components/schemas/TransferProcessState" errorMessage: type: string description: Error Message @@ -1572,7 +1576,7 @@ components: description: State code format: int32 simplifiedState: - $ref: '#/components/schemas/TransferProcessSimplifiedState' + $ref: "#/components/schemas/TransferProcessSimplifiedState" description: Transfer Process State interpreted ContractAgreementPage: required: @@ -1583,13 +1587,13 @@ components: type: array description: Contract Agreement Cards items: - $ref: '#/components/schemas/ContractAgreementCard' + $ref: "#/components/schemas/ContractAgreementCard" description: Data as required by the UI's Contract Agreement Page ContractAgreementPageQuery: type: object properties: terminationStatus: - $ref: '#/components/schemas/ContractTerminationStatus' + $ref: "#/components/schemas/ContractTerminationStatus" description: Filters for querying a Contract Contract Agreement Page ContractDefinitionEntry: required: @@ -1612,7 +1616,7 @@ components: type: array description: Criteria for the contract items: - $ref: '#/components/schemas/UiCriterion' + $ref: "#/components/schemas/UiCriterion" description: Contract Definition List Entry for Contract Definition Page ContractDefinitionPage: required: @@ -1623,7 +1627,7 @@ components: type: array description: Contract Definition Entries items: - $ref: '#/components/schemas/ContractDefinitionEntry' + $ref: "#/components/schemas/ContractDefinitionEntry" ContractNegotiationSimplifiedState: type: string description: Simplified Contract Negotiation State to be used in UI @@ -1647,7 +1651,7 @@ components: description: State code format: int32 simplifiedState: - $ref: '#/components/schemas/ContractNegotiationSimplifiedState' + $ref: "#/components/schemas/ContractNegotiationSimplifiedState" description: Contract Negotiation State interpreted UiContractNegotiation: required: @@ -1667,8 +1671,33 @@ components: type: string description: Contract Agreement Id state: - $ref: '#/components/schemas/ContractNegotiationState' + $ref: "#/components/schemas/ContractNegotiationState" description: Contract Negotiation Information + DashboardCxDidConfig: + required: + - bdrsUrl + - dimUrl + - myDid + - trustedVcIssuer + - walletTokenUrl + type: object + properties: + myDid: + type: string + description: My DID / edc.iam.issuer.id + walletTokenUrl: + type: string + description: Wallet Token Url / edc.iam.sts.oauth.token.url + trustedVcIssuer: + type: string + description: Trusted VC Issuer / edc.iam.trusted-issuer.cofinity.id + bdrsUrl: + type: string + description: BDRS Url / tx.iam.iatp.bdrs.server.url + dimUrl: + type: string + description: STS DIM Url / edc.iam.sts.dim.url + description: Managed Identity Wallet (MIW) Config DashboardDapsConfig: required: - jwksUrl @@ -1682,23 +1711,6 @@ components: type: string description: Your Connector's DAPS JWKS URL description: DAPS Config - DashboardMiwConfig: - required: - - authorityId - - tokenUrl - - url - type: object - properties: - url: - type: string - description: Your Connector's MIW's URL - tokenUrl: - type: string - description: Your Connector's MIW's Token URL - authorityId: - type: string - description: Your Connector's MIW's Authority ID - description: Managed Identity Wallet (MIW) Config DashboardPage: required: - connectorCuratorName @@ -1739,9 +1751,9 @@ components: description: Number of providing Contract Agreements format: int64 transferProcessesConsuming: - $ref: '#/components/schemas/DashboardTransferAmounts' + $ref: "#/components/schemas/DashboardTransferAmounts" transferProcessesProviding: - $ref: '#/components/schemas/DashboardTransferAmounts' + $ref: "#/components/schemas/DashboardTransferAmounts" connectorEndpoint: type: string description: Your Connector's Connector Endpoint @@ -1767,9 +1779,9 @@ components: type: string description: Your Connector's Maintainer's Organization Name connectorDapsConfig: - $ref: '#/components/schemas/DashboardDapsConfig' - connectorMiwConfig: - $ref: '#/components/schemas/DashboardMiwConfig' + $ref: "#/components/schemas/DashboardDapsConfig" + connectorCxDidConfig: + $ref: "#/components/schemas/DashboardCxDidConfig" description: Data as required by the UI's Dashboard Page DashboardTransferAmounts: required: @@ -1806,7 +1818,7 @@ components: type: string description: Policy Definition ID policy: - $ref: '#/components/schemas/UiPolicy' + $ref: "#/components/schemas/UiPolicy" description: Policy Definition as required for the Policy Definition Page PolicyDefinitionPage: required: @@ -1817,7 +1829,7 @@ components: type: array description: Policy Definition Entries items: - $ref: '#/components/schemas/PolicyDefinitionDto' + $ref: "#/components/schemas/PolicyDefinitionDto" description: All data for the policy definition page as required by the UI TransferHistoryEntry: required: @@ -1845,12 +1857,12 @@ components: description: Last Change Date format: date-time state: - $ref: '#/components/schemas/TransferProcessState' + $ref: "#/components/schemas/TransferProcessState" contractAgreementId: type: string description: Contract Agreement ID direction: - $ref: '#/components/schemas/ContractAgreementDirection' + $ref: "#/components/schemas/ContractAgreementDirection" counterPartyConnectorEndpoint: type: string description: Other Connector's Endpoint @@ -1876,23 +1888,23 @@ components: type: array description: Transfer History Page Entries items: - $ref: '#/components/schemas/TransferHistoryEntry' + $ref: "#/components/schemas/TransferHistoryEntry" description: Data as required by the UI's Transfer History Page ContractNegotiationRequest: required: - assetId - contractOfferId - counterPartyAddress - - counterPartyParticipantId + - counterPartyId - policyJsonLd type: object properties: + counterPartyId: + type: string + description: Counter Party Id counterPartyAddress: type: string description: Counter Party Address - counterPartyParticipantId: - type: string - description: Counter Party Participant ID contractOfferId: type: string description: 'Contract Offer Dto ' @@ -1923,11 +1935,17 @@ components: - contractAgreementId - dataSinkProperties - transferProcessProperties + - transferType type: object properties: contractAgreementId: type: string description: Contract Agreement ID + transferType: + type: string + description: "Transfer Type. Used to select a compatible DataPlane. Examples\ + \ are 'HttpData-PUSH', 'HttpData-PULL'. Not to be confused with the 'type'\ + \ of the data source, or the 'type' of the data sink found in the 'properties'" dataSinkProperties: type: object additionalProperties: @@ -2000,7 +2018,7 @@ components: description: Counts of contract agreements format: int32 transferProcessDto: - $ref: '#/components/schemas/TransferProcessStatesDto' + $ref: "#/components/schemas/TransferProcessStatesDto" description: EDC-status-defining KPIs TransferProcessStatesDto: required: @@ -2035,15 +2053,15 @@ components: description: Asset property name example: https://w3id.org/edc/v0.0.1/ns/assetId operator: - $ref: '#/components/schemas/CatalogFilterExpressionOperator' + $ref: "#/components/schemas/CatalogFilterExpressionOperator" operandRight: - $ref: '#/components/schemas/CatalogFilterExpressionLiteral' + $ref: "#/components/schemas/CatalogFilterExpressionLiteral" description: Generic expression for filtering the data offers in the catalog CatalogFilterExpressionLiteral: type: object properties: type: - $ref: '#/components/schemas/CatalogFilterExpressionLiteralType' + $ref: "#/components/schemas/CatalogFilterExpressionLiteralType" value: type: string description: Only for type VALUE. The single value representation. @@ -2074,7 +2092,12 @@ components: properties: connectorEndpoint: type: string - description: Target EDC DSP endpoint URL + description: "Target EDC DSP endpoint URL. Can contain a queryParam 'participantId',\ + \ which is provided by default in the Connector Endpoint in the EDC UI." + participantId: + type: string + description: Target EDC Participant ID. It is required if the connector + endpoint does not contain the queryParam 'participantId'. limit: type: integer description: Limit the number of results @@ -2087,5 +2110,5 @@ components: type: array description: Filter expressions for catalog filtering items: - $ref: '#/components/schemas/CatalogFilterExpression' + $ref: "#/components/schemas/CatalogFilterExpression" description: Catalog query parameters diff --git a/extensions/contract-termination/build.gradle.kts b/extensions/contract-termination/build.gradle.kts index 8e0ae126a..24254a428 100644 --- a/extensions/contract-termination/build.gradle.kts +++ b/extensions/contract-termination/build.gradle.kts @@ -22,34 +22,7 @@ dependencies { testAnnotationProcessor(libs.lombok) testCompileOnly(libs.lombok) - testImplementation(project(":extensions:postgres-flyway")) - testImplementation(project(":utils:test-utils")) - testImplementation(project(":utils:versions")) - - testImplementation(libs.edc.monitorJdkLogger) - testImplementation(libs.edc.http) { - exclude(group = "org.eclipse.jetty", module = "jetty-client") - exclude(group = "org.eclipse.jetty", module = "jetty-http") - exclude(group = "org.eclipse.jetty", module = "jetty-io") - exclude(group = "org.eclipse.jetty", module = "jetty-server") - exclude(group = "org.eclipse.jetty", module = "jetty-util") - exclude(group = "org.eclipse.jetty", module = "jetty-webapp") - } - - // Updated jetty versions for e.g. CVE-2023-26048 - testImplementation(libs.bundles.jetty.cve2023) - - testImplementation(libs.assertj.core) - testImplementation(libs.flyway.core) - testImplementation(libs.junit.api) - testImplementation(libs.hibernate.validation) - testImplementation(libs.jakarta.el) - testImplementation(libs.mockito.core) - testImplementation(libs.restAssured.restAssured) - testImplementation(libs.testcontainers.testcontainers) - testImplementation(libs.testcontainers.postgresql) - - testRuntimeOnly(libs.junit.engine) + testImplementation(project(":launchers:utils:vanilla-control-plane")) } group = libs.versions.sovityEdcExtensionGroup.get() diff --git a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractAgreementTerminationDetails.java b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractAgreementTerminationDetails.java index a16096979..152bb94e1 100644 --- a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractAgreementTerminationDetails.java +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractAgreementTerminationDetails.java @@ -16,7 +16,7 @@ import de.sovity.edc.ext.db.jooq.enums.ContractTerminatedBy; import lombok.Builder; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; import java.time.OffsetDateTime; diff --git a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractAgreementTerminationService.java b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractAgreementTerminationService.java index a8c8f7bf7..537ac6e7e 100644 --- a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractAgreementTerminationService.java +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractAgreementTerminationService.java @@ -71,7 +71,7 @@ public OffsetDateTime terminateAgreementOrThrow(DSLContext dsl, ContractTerminat val endEvent = ContractTerminationEvent.from(termination, terminatedAt, thisParticipantId); notifyObservers(it -> it.contractTerminationCompletedOnThisInstance(endEvent)); - notifyTerminationToProvider(details.counterpartyAddress(), termination); + notifyTerminationToProvider(details.counterpartyAddress(), details.counterpartyId(), termination); return terminatedAt; } @@ -114,7 +114,11 @@ public OffsetDateTime terminateAgreementAsCounterparty( return result; } - public void notifyTerminationToProvider(String counterPartyAddress, ContractTerminationParam termination) { + public void notifyTerminationToProvider( + String counterPartyAddress, + String counterPartyId, + ContractTerminationParam termination + ) { val notificationEvent = ContractTerminationEvent.from(termination, OffsetDateTime.now(), null); notifyObservers(it -> it.contractTerminationOnCounterpartyStarted(notificationEvent)); @@ -122,6 +126,7 @@ public void notifyTerminationToProvider(String counterPartyAddress, ContractTerm sovityMessenger.send( SovityMessage.class, counterPartyAddress, + counterPartyId, new ContractTerminationMessage( termination.contractAgreementId(), termination.detail(), diff --git a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractTerminationExtension.java b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractTerminationExtension.java index bd51bc29c..78642973e 100644 --- a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractTerminationExtension.java +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractTerminationExtension.java @@ -20,9 +20,9 @@ import de.sovity.edc.extension.db.directaccess.DslContextFactory; import de.sovity.edc.extension.messenger.SovityMessenger; import de.sovity.edc.extension.messenger.SovityMessengerRegistry; -import de.sovity.edc.utils.config.ConfigProps; +import de.sovity.edc.utils.config.CeConfigProps; import lombok.val; -import org.eclipse.edc.connector.transfer.spi.observe.TransferProcessObservable; +import org.eclipse.edc.connector.controlplane.transfer.spi.observe.TransferProcessObservable; import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.runtime.metamodel.annotation.Provides; import org.eclipse.edc.spi.agent.ParticipantAgentService; @@ -54,7 +54,6 @@ public class ContractTerminationExtension implements ServiceExtension { @Override public void initialize(ServiceExtensionContext context) { - val terminationService = setupTerminationService(context); setupMessenger(terminationService); setupTransferPrevention(); @@ -71,7 +70,7 @@ private ContractAgreementTerminationService setupTerminationService(ServiceExten contractAgreementTerminationDetailsQuery, terminateContractQuery, monitor, - ConfigProps.EDC_PARTICIPANT_ID.getStringOrEmpty(config) + CeConfigProps.EDC_PARTICIPANT_ID.getStringOrEmpty(config) ); context.registerService(ContractAgreementTerminationService.class, terminationService); diff --git a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/TransferProcessBlocker.java b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/TransferProcessBlocker.java index 256b8f179..2e7858d7f 100644 --- a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/TransferProcessBlocker.java +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/TransferProcessBlocker.java @@ -18,8 +18,8 @@ import de.sovity.edc.extension.db.directaccess.DslContextFactory; import lombok.RequiredArgsConstructor; import lombok.val; -import org.eclipse.edc.connector.transfer.spi.observe.TransferProcessListener; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; +import org.eclipse.edc.connector.controlplane.transfer.spi.observe.TransferProcessListener; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; @RequiredArgsConstructor public class TransferProcessBlocker implements TransferProcessListener { @@ -27,8 +27,7 @@ public class TransferProcessBlocker implements TransferProcessListener { private final DslContextFactory dslContextFactory; private final ContractAgreementIsTerminatedQuery contractAgreementIsTerminated; - @Override - public void preRequesting(TransferProcess process) { + private void stopIt(TransferProcess process) { val terminated = dslContextFactory.transactionResult(dsl -> contractAgreementIsTerminated.isTerminated(dsl, process.getContractId())); @@ -37,4 +36,9 @@ public void preRequesting(TransferProcess process) { throw new IllegalStateException(message); } } + + @Override + public void preCreated(TransferProcess process) { + stopIt(process); + } } diff --git a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementTerminationDetailsQuery.java b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementTerminationDetailsQuery.java index 46454d025..6ac0ec0f0 100644 --- a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementTerminationDetailsQuery.java +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementTerminationDetailsQuery.java @@ -17,7 +17,7 @@ import de.sovity.edc.extension.contacttermination.ContractAgreementTerminationDetails; import lombok.RequiredArgsConstructor; import lombok.val; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; import org.jooq.DSLContext; import static de.sovity.edc.ext.db.jooq.Tables.EDC_CONTRACT_AGREEMENT; diff --git a/extensions/contract-termination/src/test/java/de/sovity/edc/extension/contacttermination/query/TerminateContractQueryTest.java b/extensions/contract-termination/src/test/java/de/sovity/edc/extension/contacttermination/query/TerminateContractQueryTest.java index ce40e4670..5b68d3da0 100644 --- a/extensions/contract-termination/src/test/java/de/sovity/edc/extension/contacttermination/query/TerminateContractQueryTest.java +++ b/extensions/contract-termination/src/test/java/de/sovity/edc/extension/contacttermination/query/TerminateContractQueryTest.java @@ -16,14 +16,15 @@ import de.sovity.edc.extension.contacttermination.ContractTerminationParam; import de.sovity.edc.extension.db.directaccess.DslContextFactory; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.extension.Consumer; -import de.sovity.edc.extension.e2e.extension.E2eScenario; -import de.sovity.edc.extension.e2e.extension.E2eTestExtension; -import de.sovity.edc.extension.e2e.extension.Provider; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenario; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; import de.sovity.edc.extension.utils.junit.DisabledOnGithub; +import de.sovity.edc.utils.config.ConfigUtils; import lombok.val; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.spi.system.configuration.Config; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -31,21 +32,22 @@ import java.time.temporal.ChronoUnit; import static de.sovity.edc.ext.db.jooq.enums.ContractTerminatedBy.COUNTERPARTY; -import static de.sovity.edc.extension.e2e.extension.Helpers.defaultE2eTestExtension; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.within; class TerminateContractQueryTest { @RegisterExtension - private static E2eTestExtension e2eTestExtension = defaultE2eTestExtension(); + private static CeE2eTestExtension e2eTestExtension = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); @DisabledOnGithub @Test void terminateConsumerAgreementOrThrow_shouldInsertRowInTerminationTable( - E2eScenario scenario, + E2eTestScenario scenario, @Consumer DslContextFactory dslContextFactory, - @Provider ConnectorConfig providerConfig + @Provider Config providerConfig ) { val assetId = scenario.createAsset(); scenario.createContractDefinition(assetId); @@ -76,7 +78,7 @@ void terminateConsumerAgreementOrThrow_shouldInsertRowInTerminationTable( assertThat(detailsAfterTermination.contractAgreementId()).isEqualTo(agreementId); assertThat(detailsAfterTermination.counterpartyId()).isEqualTo("provider"); assertThat(detailsAfterTermination.counterpartyAddress()) - .isEqualTo(providerConfig.getProtocolApiUrl()); + .isEqualTo(ConfigUtils.getProtocolApiUrl(providerConfig)); assertThat(detailsAfterTermination.type()).isEqualTo(ContractNegotiation.Type.CONSUMER); assertThat(detailsAfterTermination.providerAgentId()).isEqualTo("provider"); assertThat(detailsAfterTermination.consumerAgentId()).isEqualTo("consumer"); diff --git a/extensions/database-direct-access/src/main/java/de/sovity/edc/extension/db/directaccess/DatabaseDirectAccessExtension.java b/extensions/database-direct-access/src/main/java/de/sovity/edc/extension/db/directaccess/DatabaseDirectAccessExtension.java index 12aac42b2..644b2114e 100644 --- a/extensions/database-direct-access/src/main/java/de/sovity/edc/extension/db/directaccess/DatabaseDirectAccessExtension.java +++ b/extensions/database-direct-access/src/main/java/de/sovity/edc/extension/db/directaccess/DatabaseDirectAccessExtension.java @@ -16,7 +16,7 @@ import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; -import de.sovity.edc.utils.config.ConfigProps; +import de.sovity.edc.utils.config.CeConfigProps; import lombok.val; import org.eclipse.edc.runtime.metamodel.annotation.Provides; import org.eclipse.edc.spi.system.ServiceExtension; @@ -40,15 +40,15 @@ private void initializeDirectDatabaseAccess(ServiceExtensionContext context) { val hikariConfig = new HikariConfig(); val config = context.getConfig(); - hikariConfig.setJdbcUrl(ConfigProps.EDC_DATASOURCE_DEFAULT_URL.getStringOrThrow(config)); - hikariConfig.setUsername(ConfigProps.EDC_DATASOURCE_DEFAULT_USER.getStringOrThrow(config)); - hikariConfig.setPassword(ConfigProps.EDC_DATASOURCE_DEFAULT_PASSWORD.getStringOrThrow(config)); + hikariConfig.setJdbcUrl(CeConfigProps.MY_EDC_JDBC_URL.getStringOrThrow(config)); + hikariConfig.setUsername(CeConfigProps.MY_EDC_JDBC_USER.getStringOrThrow(config)); + hikariConfig.setPassword(CeConfigProps.MY_EDC_JDBC_PASSWORD.getStringOrThrow(config)); hikariConfig.setMinimumIdle(1); - hikariConfig.setMaximumPoolSize(ConfigProps.EDC_SERVER_DB_CONNECTION_POOL_SIZE.getInt(config)); + hikariConfig.setMaximumPoolSize(CeConfigProps.EDC_SERVER_DB_CONNECTION_POOL_SIZE.getInt(config)); hikariConfig.setIdleTimeout(30000); hikariConfig.setPoolName("direct-database-access"); hikariConfig.setMaxLifetime(50000); - hikariConfig.setConnectionTimeout(ConfigProps.EDC_SERVER_DB_CONNECTION_TIMEOUT_IN_MS.getInt(config)); + hikariConfig.setConnectionTimeout(CeConfigProps.EDC_SERVER_DB_CONNECTION_TIMEOUT_IN_MS.getInt(config)); val dslContextFactory = new DslContextFactory(new HikariDataSource(hikariConfig)); context.registerService(DslContextFactory.class, dslContextFactory); diff --git a/extensions/dataset-bugfix/build.gradle.kts b/extensions/dataset-bugfix/build.gradle.kts deleted file mode 100644 index 8f4a914f5..000000000 --- a/extensions/dataset-bugfix/build.gradle.kts +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2024 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * 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. - * - * 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. - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -plugins { - `java-library` -} - -dependencies { - api(libs.edc.coreSpi) - api(libs.edc.jsonLdSpi) - api(libs.edc.webSpi) - api(libs.edc.dspApiConfiguration) -} diff --git a/extensions/dataset-bugfix/src/main/java/org/eclipse/tractusx/edc/dataset/fix/DatasetFixExtension.java b/extensions/dataset-bugfix/src/main/java/org/eclipse/tractusx/edc/dataset/fix/DatasetFixExtension.java deleted file mode 100644 index 2f3263c98..000000000 --- a/extensions/dataset-bugfix/src/main/java/org/eclipse/tractusx/edc/dataset/fix/DatasetFixExtension.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2024 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * 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. - * - * 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.eclipse.tractusx.edc.dataset.fix; - -import jakarta.json.JsonObject; -import jakarta.ws.rs.NotFoundException; -import jakarta.ws.rs.container.ContainerRequestContext; -import jakarta.ws.rs.container.ContainerResponseContext; -import jakarta.ws.rs.container.ContainerResponseFilter; -import org.eclipse.edc.protocol.dsp.api.configuration.DspApiConfiguration; -import org.eclipse.edc.runtime.metamodel.annotation.Inject; -import org.eclipse.edc.spi.system.ServiceExtension; -import org.eclipse.edc.spi.system.ServiceExtensionContext; -import org.eclipse.edc.web.spi.WebService; - -import static jakarta.ws.rs.HttpMethod.GET; -import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; -import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_DATASET_TYPE; -import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_POLICY_ATTRIBUTE; - -public class DatasetFixExtension implements ServiceExtension { - - - @Inject - private DspApiConfiguration apiConfiguration; - - @Inject - private WebService webService; - - @Override - public void initialize(ServiceExtensionContext context) { - webService.registerResource(apiConfiguration.getContextAlias(), new DatasetFilter()); - } - - private static class DatasetFilter implements ContainerResponseFilter { - - private static final String GET_DATASETS_PATH = "catalog/datasets/"; - - @Override - public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) { - if (requestContext.getUriInfo().getPath().contains(GET_DATASETS_PATH) && requestContext.getMethod().equals(GET)) { - if (responseContext.getEntity() instanceof JsonObject jsonObject) { - if (jsonObject.getString(TYPE).equals(DCAT_DATASET_TYPE) && - jsonObject.containsKey(ODRL_POLICY_ATTRIBUTE) && - jsonObject.getJsonArray(ODRL_POLICY_ATTRIBUTE).isEmpty() - ) { - throw new NotFoundException(); - } - } - } - } - } -} diff --git a/extensions/dataset-bugfix/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/dataset-bugfix/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension deleted file mode 100644 index b26160fa7..000000000 --- a/extensions/dataset-bugfix/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension +++ /dev/null @@ -1,20 +0,0 @@ -################################################################################# -# Copyright (c) 2024 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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. -# -# 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. -# -# SPDX-License-Identifier: Apache-2.0 -################################################################################# - -org.eclipse.tractusx.edc.dataset.fix.DatasetFixExtension diff --git a/extensions/edc-ui-config/build.gradle.kts b/extensions/edc-ui-config/build.gradle.kts index db5a00804..2e39b4d07 100644 --- a/extensions/edc-ui-config/build.gradle.kts +++ b/extensions/edc-ui-config/build.gradle.kts @@ -13,25 +13,7 @@ dependencies { implementation(libs.jakarta.rsApi) implementation(libs.jakarta.validationApi) - testImplementation(project(":utils:test-utils")) - testImplementation(libs.edc.controlPlaneCore) - testImplementation(libs.edc.junit) - testImplementation(libs.edc.http) { - exclude(group = "org.eclipse.jetty", module = "jetty-client") - exclude(group = "org.eclipse.jetty", module = "jetty-http") - exclude(group = "org.eclipse.jetty", module = "jetty-io") - exclude(group = "org.eclipse.jetty", module = "jetty-server") - exclude(group = "org.eclipse.jetty", module = "jetty-util") - exclude(group = "org.eclipse.jetty", module = "jetty-webapp") - } - - // Updated jetty versions for e.g. CVE-2023-26048 - testImplementation(libs.bundles.jetty.cve2023) - - testImplementation(libs.restAssured.restAssured) - testImplementation(libs.edc.dataPlaneSelectorCore) - testImplementation(libs.mockito.core) - testImplementation(libs.junit.api) + testImplementation(project(":launchers:utils:vanilla-control-plane")) testRuntimeOnly(libs.junit.engine) } diff --git a/extensions/edc-ui-config/src/main/java/de/sovity/edc/extension/EdcUiConfigExtension.java b/extensions/edc-ui-config/src/main/java/de/sovity/edc/extension/EdcUiConfigExtension.java index fd8461366..bd231bed7 100644 --- a/extensions/edc-ui-config/src/main/java/de/sovity/edc/extension/EdcUiConfigExtension.java +++ b/extensions/edc-ui-config/src/main/java/de/sovity/edc/extension/EdcUiConfigExtension.java @@ -14,19 +14,16 @@ package de.sovity.edc.extension; -import org.eclipse.edc.connector.api.management.configuration.ManagementApiConfiguration; import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; import org.eclipse.edc.web.spi.WebService; +import org.eclipse.edc.web.spi.configuration.ApiContext; public class EdcUiConfigExtension implements ServiceExtension { public static final String EXTENSION_NAME = "EdcUiConfigExtension"; - @Inject - private ManagementApiConfiguration config; - @Inject private WebService webService; @@ -39,6 +36,6 @@ public String name() { public void initialize(ServiceExtensionContext context) { var edcUiConfigService = new EdcUiConfigService(context.getConfig()); var controller = new EdcUiConfigController(edcUiConfigService); - webService.registerResource(config.getContextAlias(), controller); + webService.registerResource(ApiContext.MANAGEMENT, controller); } } diff --git a/extensions/edc-ui-config/src/test/java/de/sovity/edc/extension/version/controller/EdcUiConfigTest.java b/extensions/edc-ui-config/src/test/java/de/sovity/edc/extension/version/controller/EdcUiConfigTest.java index cb757f459..8b8735663 100644 --- a/extensions/edc-ui-config/src/test/java/de/sovity/edc/extension/version/controller/EdcUiConfigTest.java +++ b/extensions/edc-ui-config/src/test/java/de/sovity/edc/extension/version/controller/EdcUiConfigTest.java @@ -14,52 +14,48 @@ package de.sovity.edc.extension.version.controller; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory; -import de.sovity.edc.extension.e2e.db.JdbcCredentials; -import de.sovity.edc.extension.e2e.db.TestDatabase; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; +import de.sovity.edc.extension.e2e.junit.edc.EmbeddedRuntimeFixed; +import de.sovity.edc.utils.config.ConfigUtils; import io.restassured.http.ContentType; +import org.eclipse.edc.connector.dataplane.selector.spi.client.DataPlaneClientFactory; import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore; import org.eclipse.edc.jsonld.spi.JsonLd; -import org.eclipse.edc.junit.annotations.ApiTest; -import org.eclipse.edc.junit.extensions.EdcExtension; import org.eclipse.edc.spi.protocol.ProtocolWebhook; +import org.eclipse.edc.spi.system.configuration.Config; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; import static io.restassured.RestAssured.given; import static org.hamcrest.Matchers.equalTo; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -@ApiTest -@ExtendWith(EdcExtension.class) class EdcUiConfigTest { private static final String SOME_EXAMPLE_PROP = "this should also be passed through"; - private ConnectorConfig config; + @RegisterExtension + static CeIntegrationTestExtension extension = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:utils:vanilla-control-plane") + .configOverrides(config -> config.property("edc.ui.some.example.prop", SOME_EXAMPLE_PROP)) + .skipDb(true) + .beforeEdcStartup(runtime -> { + runtime.registerServiceMock(DataPlaneClientFactory.class, mock(DataPlaneClientFactory.class)); + }) + .build(); @BeforeEach - void setUp(EdcExtension extension) { - extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); - extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); - extension.registerServiceMock(DataPlaneInstanceStore.class, mock(DataPlaneInstanceStore.class)); - - var testDatabase = mock(TestDatabase.class); - when(testDatabase.getJdbcCredentials()).thenReturn(new JdbcCredentials("unused", "unused", "unused")); - - config = ConnectorConfigFactory.forTestDatabase("provider", testDatabase); - config.setProperty("edc.ui.some.example.prop", SOME_EXAMPLE_PROP); - - extension.setConfiguration(config.getProperties()); + void setUp(EmbeddedRuntimeFixed runtime) { + runtime.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + runtime.registerServiceMock(JsonLd.class, mock(JsonLd.class)); + runtime.registerServiceMock(DataPlaneInstanceStore.class, mock(DataPlaneInstanceStore.class)); } @Test - void testEdcUiConfigWithEverythingSet() { + void testEdcUiConfigWithEverythingSet(Config config) { var request = given() - .baseUri(config.getManagementApiUrl()) - .header("X-Api-Key", config.getManagementApiKey()) + .baseUri(ConfigUtils.getManagementApiUrl(config)) + .header("X-Api-Key", ConfigUtils.getManagementApiKey(config)) .when() .contentType(ContentType.JSON) .get("/edc-ui-config") diff --git a/extensions/integrated-data-plane-initializer/README.md b/extensions/integrated-data-plane-initializer/README.md new file mode 100644 index 000000000..9d2022078 --- /dev/null +++ b/extensions/integrated-data-plane-initializer/README.md @@ -0,0 +1,33 @@ + +
+

+ + Logo + + +

EDC-Connector Extension:
Data Plane Instance Initializer

+ +

+ Report Bug + · + Request Feature +

+
+ +## About this Extension + +This extension populates the data plane instance store from config properties on startup. + +This is useful when using an "integrated" control plane and data plane. + +## Why does this extension exist? + +The list of data plane instances is not populated automatically, thus this extennsion is needed. + +## License + +Apache License 2.0 - see [LICENSE](../../LICENSE) + +## Contact + +sovity GmbH - contact@sovity.de diff --git a/extensions/integrated-data-plane-initializer/build.gradle.kts b/extensions/integrated-data-plane-initializer/build.gradle.kts new file mode 100644 index 000000000..ab5f6012b --- /dev/null +++ b/extensions/integrated-data-plane-initializer/build.gradle.kts @@ -0,0 +1,37 @@ + +plugins { + `java-library` + `maven-publish` +} + +dependencies { + annotationProcessor(libs.lombok) + compileOnly(libs.lombok) + + api(libs.edc.coreSpi) + api(libs.edc.controlPlaneSpi) + api(libs.edc.dataPlaneSelectorCore) + + implementation(project(":config")) + implementation(libs.apache.commonsLang) + + testAnnotationProcessor(libs.lombok) + testCompileOnly(libs.lombok) + + testImplementation(libs.edc.controlPlaneCore) + testImplementation(libs.edc.junit) + testImplementation(libs.edc.dataPlaneSelectorCore) + testImplementation(libs.mockito.core) + testImplementation(libs.junit.api) + testRuntimeOnly(libs.junit.engine) +} + +group = libs.versions.sovityEdcExtensionGroup.get() + +publishing { + publications { + create(project.name) { + from(components["java"]) + } + } +} diff --git a/extensions/integrated-data-plane-initializer/src/main/java/de/sovity/edc/extension/dataplaneinstancestoreinit/DataPlaneInitializerService.java b/extensions/integrated-data-plane-initializer/src/main/java/de/sovity/edc/extension/dataplaneinstancestoreinit/DataPlaneInitializerService.java new file mode 100644 index 000000000..b577481eb --- /dev/null +++ b/extensions/integrated-data-plane-initializer/src/main/java/de/sovity/edc/extension/dataplaneinstancestoreinit/DataPlaneInitializerService.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2022 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.dataplaneinstancestoreinit; + +import de.sovity.edc.utils.config.CeConfigProps; +import de.sovity.edc.utils.config.ConfigUtils; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.eclipse.edc.connector.dataplane.selector.spi.DataPlaneSelectorService; +import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.system.configuration.Config; + +import java.util.HashSet; +import java.util.Set; + +@RequiredArgsConstructor +public class DataPlaneInitializerService { + private static final String INTEGRATED = "integrated"; + private final Monitor monitor; + private final Config config; + private final DataPlaneSelectorService dataPlaneSelectorService; + + @SneakyThrows + public void addIntegratedDataPlane() { + var dataPlaneUrl = ConfigUtils.getIntegratedDataPlaneUrl(config); + var transferTypes = new HashSet<>(CeConfigProps.EDC_DATAPLANE_TRANSFERTYPES.getListOrThrow(config)); + var destTypes = new HashSet<>(CeConfigProps.EDC_DATAPLANE_DESTTYPES.getListOrThrow(config)); + var sourceTypes = new HashSet<>(CeConfigProps.EDC_DATAPLANE_SOURCETYPES.getListOrThrow(config)); + var publicApiUrl = ConfigUtils.getPublicApiUrl(config); + + addDataPlane( + INTEGRATED, + dataPlaneUrl, + transferTypes, + sourceTypes, + destTypes, + publicApiUrl + ); + } + + @SneakyThrows + public void addDataPlane( + String id, + String dataPlaneUrl, + Set transferTypes, + Set sourceTypes, + Set destTypes, + String publicUrl + ) { + if (hasCorrectlyConfiguredInstance(id, dataPlaneUrl, transferTypes)) { + return; + } + + var instance = DataPlaneInstance.Builder.newInstance() + .id(id) + .url(dataPlaneUrl) + .allowedTransferType(transferTypes) + .allowedSourceTypes(sourceTypes) + .allowedDestTypes(destTypes) + .property("publicApiUrl", publicUrl) + .build(); + + dataPlaneSelectorService.addInstance(instance) + .orElseThrow(f -> new EdcException("Data Plane '%s' registration failed: ".formatted(id) + f.getFailureDetail())); + + var message = "Data Plane Instance created: '%s' '%s' '%s'".formatted( + id, + String.join(", ", transferTypes), + dataPlaneUrl + ); + + monitor.info(message); + } + + private boolean hasCorrectlyConfiguredInstance( + String id, + String dataPlaneUrl, + Set transferTypes + ) { + var instance = dataPlaneSelectorService.findById(id).orElse(unused -> null); + if (instance == null) { + return false; + } + + var isCorrectlyConfigured = transferTypes.equals(instance.getAllowedTransferTypes()) && + dataPlaneUrl.equals(instance.getUrl().toString()); + if (isCorrectlyConfigured) { + monitor.info("Data Plane Instance '%s' is already correctly registered.".formatted(id)); + return true; + } + + monitor.warning( + "Data Plane instance '%s' is out of date. Since the DataPlaneInstance lacks an update method, the Data Plane Instance will be deleted for a moment. This can cause running transfers to fail.".formatted(id) + ); + dataPlaneSelectorService.unregister(id) + .orElseThrow(f -> new EdcException("Data Plane '%s' deregistration failed: ".formatted(id) + f.getFailureDetail())); + return false; + } +} diff --git a/extensions/integrated-data-plane-initializer/src/main/java/de/sovity/edc/extension/dataplaneinstancestoreinit/DataPlaneInstanceInitializerExtension.java b/extensions/integrated-data-plane-initializer/src/main/java/de/sovity/edc/extension/dataplaneinstancestoreinit/DataPlaneInstanceInitializerExtension.java new file mode 100644 index 000000000..f389e26c4 --- /dev/null +++ b/extensions/integrated-data-plane-initializer/src/main/java/de/sovity/edc/extension/dataplaneinstancestoreinit/DataPlaneInstanceInitializerExtension.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.dataplaneinstancestoreinit; + +import org.eclipse.edc.connector.dataplane.selector.spi.DataPlaneSelectorService; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; + +public class DataPlaneInstanceInitializerExtension implements ServiceExtension { + public static final String EXTENSION_NAME = "VaultInitializer"; + + @Inject + private DataPlaneSelectorService dataPlaneSelectorService; + private DataPlaneInitializerService dataPlaneInitializerService; + + @Override + public String name() { + return EXTENSION_NAME; + } + + @Override + public void initialize(ServiceExtensionContext context) { + dataPlaneInitializerService = new DataPlaneInitializerService( + context.getMonitor(), + context.getConfig(), + dataPlaneSelectorService + ); + } + + @Override + public void start() { + dataPlaneInitializerService.addIntegratedDataPlane(); + } +} diff --git a/extensions/integrated-data-plane-initializer/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/integrated-data-plane-initializer/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 000000000..8cee557d6 --- /dev/null +++ b/extensions/integrated-data-plane-initializer/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1 @@ +de.sovity.edc.extension.dataplaneinstancestoreinit.DataPlaneInstanceInitializerExtension diff --git a/extensions/last-commit-info/build.gradle.kts b/extensions/last-commit-info/build.gradle.kts index 73d7bf916..46efc7a05 100644 --- a/extensions/last-commit-info/build.gradle.kts +++ b/extensions/last-commit-info/build.gradle.kts @@ -22,25 +22,7 @@ dependencies { testAnnotationProcessor(libs.lombok) testCompileOnly(libs.lombok) - testImplementation(project(":utils:test-utils")) - testImplementation(libs.edc.controlPlaneCore) - testImplementation(libs.edc.junit) - testImplementation(libs.edc.http) { - exclude(group = "org.eclipse.jetty", module = "jetty-client") - exclude(group = "org.eclipse.jetty", module = "jetty-http") - exclude(group = "org.eclipse.jetty", module = "jetty-io") - exclude(group = "org.eclipse.jetty", module = "jetty-server") - exclude(group = "org.eclipse.jetty", module = "jetty-util") - exclude(group = "org.eclipse.jetty", module = "jetty-webapp") - } - - // Updated jetty versions for e.g. CVE-2023-26048 - testImplementation(libs.bundles.jetty.cve2023) - - testImplementation(libs.restAssured.restAssured) - testImplementation(libs.edc.dataPlaneSelectorCore) - testImplementation(libs.mockito.core) - testImplementation(libs.junit.api) + testImplementation(project(":launchers:utils:vanilla-control-plane")) testRuntimeOnly(libs.junit.engine) } diff --git a/extensions/last-commit-info/src/main/java/de/sovity/edc/extension/LastCommitInfoExtension.java b/extensions/last-commit-info/src/main/java/de/sovity/edc/extension/LastCommitInfoExtension.java index d98515afe..d2471830b 100644 --- a/extensions/last-commit-info/src/main/java/de/sovity/edc/extension/LastCommitInfoExtension.java +++ b/extensions/last-commit-info/src/main/java/de/sovity/edc/extension/LastCommitInfoExtension.java @@ -14,18 +14,16 @@ package de.sovity.edc.extension; -import org.eclipse.edc.connector.api.management.configuration.ManagementApiConfiguration; import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; import org.eclipse.edc.web.spi.WebService; +import org.eclipse.edc.web.spi.configuration.ApiContext; public class LastCommitInfoExtension implements ServiceExtension { public static final String EXTENSION_NAME = "LastCommitInfoExtension"; @Inject - private ManagementApiConfiguration config; - @Inject private WebService webService; @@ -38,6 +36,6 @@ public String name() { public void initialize(ServiceExtensionContext context) { var lastCommitInfoService = new LastCommitInfoService(context.getConfig()); var controller = new LastCommitInfoController(lastCommitInfoService); - webService.registerResource(config.getContextAlias(), controller); + webService.registerResource(ApiContext.MANAGEMENT, controller); } } diff --git a/extensions/last-commit-info/src/main/java/de/sovity/edc/extension/LastCommitInfoService.java b/extensions/last-commit-info/src/main/java/de/sovity/edc/extension/LastCommitInfoService.java index a341a88dd..d5857927e 100644 --- a/extensions/last-commit-info/src/main/java/de/sovity/edc/extension/LastCommitInfoService.java +++ b/extensions/last-commit-info/src/main/java/de/sovity/edc/extension/LastCommitInfoService.java @@ -14,7 +14,7 @@ package de.sovity.edc.extension; -import de.sovity.edc.utils.config.ConfigProps; +import de.sovity.edc.utils.config.CeConfigProps; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import org.apache.commons.io.IOUtils; @@ -43,7 +43,7 @@ private String getJarLastCommitInfo() { } private String getEnvLastCommitInfo() { - return ConfigProps.EDC_LAST_COMMIT_INFO.getStringOrThrow(config); + return CeConfigProps.EDC_LAST_COMMIT_INFO.getStringOrThrow(config); } private String getJarBuildDate() { @@ -51,7 +51,7 @@ private String getJarBuildDate() { } private String getEnvBuildDate() { - return ConfigProps.EDC_BUILD_DATE.getStringOrThrow(config); + return CeConfigProps.EDC_BUILD_DATE.getStringOrThrow(config); } @SneakyThrows diff --git a/extensions/last-commit-info/src/test/java/de/sovity/edc/extension/version/controller/LastCommitInfoTest.java b/extensions/last-commit-info/src/test/java/de/sovity/edc/extension/version/controller/LastCommitInfoTest.java index c26b4b015..0ec68f642 100644 --- a/extensions/last-commit-info/src/test/java/de/sovity/edc/extension/version/controller/LastCommitInfoTest.java +++ b/extensions/last-commit-info/src/test/java/de/sovity/edc/extension/version/controller/LastCommitInfoTest.java @@ -14,54 +14,40 @@ package de.sovity.edc.extension.version.controller; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory; -import de.sovity.edc.extension.e2e.db.JdbcCredentials; -import de.sovity.edc.extension.e2e.db.TestDatabase; -import de.sovity.edc.utils.config.ConfigProps; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; +import de.sovity.edc.utils.config.CeConfigProps; +import de.sovity.edc.utils.config.ConfigUtils; import io.restassured.http.ContentType; -import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore; -import org.eclipse.edc.jsonld.spi.JsonLd; -import org.eclipse.edc.junit.annotations.ApiTest; -import org.eclipse.edc.junit.extensions.EdcExtension; -import org.eclipse.edc.spi.protocol.ProtocolWebhook; -import org.junit.jupiter.api.BeforeEach; +import org.eclipse.edc.connector.dataplane.selector.spi.client.DataPlaneClientFactory; +import org.eclipse.edc.spi.system.configuration.Config; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; import static io.restassured.RestAssured.given; import static org.hamcrest.Matchers.equalTo; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -@ApiTest -@ExtendWith(EdcExtension.class) class LastCommitInfoTest { - private ConnectorConfig config; - - @BeforeEach - void setUp(EdcExtension extension) { - - extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); - extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); - extension.registerServiceMock(DataPlaneInstanceStore.class, mock(DataPlaneInstanceStore.class)); - - var testDatabase = mock(TestDatabase.class); - when(testDatabase.getJdbcCredentials()).thenReturn(new JdbcCredentials("unused", "unused", "unused")); - - config = ConnectorConfigFactory.forTestDatabase("provider", testDatabase); - config.setProperty(ConfigProps.EDC_LAST_COMMIT_INFO, "test env commit message"); - config.setProperty(ConfigProps.EDC_BUILD_DATE, "2023-05-08T15:15:00Z"); - - extension.setConfiguration(config.getProperties()); - } + @RegisterExtension + static CeIntegrationTestExtension extension = CeIntegrationTestExtension.builder() + .additionalModule(":extensions:last-commit-info") + .additionalModule(":launchers:utils:vanilla-control-plane") + .skipDb(true) + .configOverrides(config -> config + .property(CeConfigProps.EDC_LAST_COMMIT_INFO, "test env commit message") + .property(CeConfigProps.EDC_BUILD_DATE, "2023-05-08T15:15:00Z") + ) + .beforeEdcStartup(runtime -> { + runtime.registerServiceMock(DataPlaneClientFactory.class, mock(DataPlaneClientFactory.class)); + }) + .build(); @Test - void testEnvAndJar() { + void testEnvAndJar(Config config) { var request = given() - .baseUri(config.getManagementApiUrl()) - .header("X-Api-Key", config.getManagementApiKey()) + .baseUri(ConfigUtils.getManagementApiUrl(config)) + .header("X-Api-Key", ConfigUtils.getManagementApiKey(config)) .when() .contentType(ContentType.JSON) .get("/last-commit-info") diff --git a/extensions/mds-logginghouse-binder/README.md b/extensions/mds-logginghouse-binder/README.md deleted file mode 100644 index 6330791e8..000000000 --- a/extensions/mds-logginghouse-binder/README.md +++ /dev/null @@ -1,44 +0,0 @@ - -
-
- - Logo - - -

EDC-Connector Extension:
MDS Contract Termination - LoggingHouse binder

- -

- Report Bug - · - Request Feature -

-
- - -## About this Extension - -It links the Contract Termination events with the LoggingHouse. - -## Why does this extension exist? - -MDS needs to log the events generated when terminating a contract with their Logging House extension. -The Logging House is an external dependency and the linkage must only happen for the MDS variant. - -This extension implements this specific task. - -## Architecture - -```mermaid -flowchart TD - Binder(MDS LoggingHouse Binder) --> LoggingHouse(Logging House Extension) - Binder(MDS LoggingHouse Binder) --> ContractTermination(Contract Termination Extension) - MDS(MDS CE) --> Binder -``` - -## License - -Apache License 2.0 - see [LICENSE](../../LICENSE) - -## Contact - -sovity GmbH - contact@sovity.de diff --git a/extensions/mds-logginghouse-binder/build.gradle.kts b/extensions/mds-logginghouse-binder/build.gradle.kts deleted file mode 100644 index bd378ea58..000000000 --- a/extensions/mds-logginghouse-binder/build.gradle.kts +++ /dev/null @@ -1,62 +0,0 @@ - -plugins { - `java-library` - `maven-publish` -} - -dependencies { - annotationProcessor(libs.lombok) - compileOnly(libs.lombok) - - implementation(project(":extensions:contract-termination")) - - implementation(libs.edc.coreSpi) - implementation(libs.edc.dspNegotiationTransform) - implementation(libs.edc.transferSpi) - - implementation(libs.loggingHouse.client) - implementation(libs.jakarta.rsApi) - - - testAnnotationProcessor(libs.lombok) - testCompileOnly(libs.lombok) - - testImplementation(project(":extensions:postgres-flyway")) - testImplementation(project(":utils:test-utils")) - testImplementation(project(":utils:versions")) - - testImplementation(libs.edc.monitorJdkLogger) - testImplementation(libs.edc.http) { - exclude(group = "org.eclipse.jetty", module = "jetty-client") - exclude(group = "org.eclipse.jetty", module = "jetty-http") - exclude(group = "org.eclipse.jetty", module = "jetty-io") - exclude(group = "org.eclipse.jetty", module = "jetty-server") - exclude(group = "org.eclipse.jetty", module = "jetty-util") - exclude(group = "org.eclipse.jetty", module = "jetty-webapp") - } - - // Updated jetty versions for e.g. CVE-2023-26048 - testImplementation(libs.bundles.jetty.cve2023) - - testImplementation(libs.assertj.core) - testImplementation(libs.flyway.core) - testImplementation(libs.junit.api) - testImplementation(libs.hibernate.validation) - testImplementation(libs.jakarta.el) - testImplementation(libs.mockito.core) - testImplementation(libs.restAssured.restAssured) - testImplementation(libs.testcontainers.testcontainers) - testImplementation(libs.testcontainers.postgresql) - - testRuntimeOnly(libs.junit.engine) -} - -group = libs.versions.sovityEdcExtensionGroup.get() - -publishing { - publications { - create(project.name) { - from(components["java"]) - } - } -} diff --git a/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/LogEntry.java b/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/LogEntry.java deleted file mode 100644 index 0ec722beb..000000000 --- a/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/LogEntry.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.extension.mdslogginhousebinder; - -import com.fasterxml.jackson.annotation.JsonProperty; -import de.sovity.edc.extension.contacttermination.ContractTerminationEvent; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.time.OffsetDateTime; - -@AllArgsConstructor -@Builder -@Data -@NoArgsConstructor -public class LogEntry { - - @JsonProperty("contractAgreementId") - private String contractAgreementId; - - @JsonProperty("event") - private String event; - - @JsonProperty("detail") - private String detail; - - @JsonProperty("reason") - private String reason; - - @JsonProperty("timestamp") - private OffsetDateTime timestamp; - - public static LogEntry from(String event, ContractTerminationEvent contractTerminationEvent) { - return LogEntry.builder() - .event(event) - .contractAgreementId(contractTerminationEvent.contractAgreementId()) - .detail(contractTerminationEvent.detail()) - .reason(contractTerminationEvent.reason()) - .timestamp(contractTerminationEvent.timestamp()) - .build(); - } -} diff --git a/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/MdsContractTerminationEvent.java b/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/MdsContractTerminationEvent.java deleted file mode 100644 index 0237f5fa2..000000000 --- a/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/MdsContractTerminationEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.extension.mdslogginhousebinder; - -import com.truzzt.extension.logginghouse.client.events.CustomLoggingHouseEvent; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Getter -public class MdsContractTerminationEvent extends CustomLoggingHouseEvent { - private final String eventId; - private final String processId; - private final String messageBody; -} diff --git a/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/MdsContractTerminationObserver.java b/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/MdsContractTerminationObserver.java deleted file mode 100644 index 3ba115efb..000000000 --- a/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/MdsContractTerminationObserver.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.extension.mdslogginhousebinder; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import de.sovity.edc.extension.contacttermination.ContractTerminationEvent; -import de.sovity.edc.extension.contacttermination.ContractTerminationObserver; -import lombok.RequiredArgsConstructor; -import lombok.val; -import org.eclipse.edc.spi.event.EventEnvelope; -import org.eclipse.edc.spi.event.EventRouter; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.uuid.UuidGenerator; -import org.jetbrains.annotations.NotNull; - -@RequiredArgsConstructor -public class MdsContractTerminationObserver implements ContractTerminationObserver { - - private final EventRouter eventRouter; - - private final Monitor monitor; - - private final ObjectMapper objectMapper; - - @Override - public void contractTerminationCompletedOnThisInstance(ContractTerminationEvent contractTerminationEvent) { - sendMessage("contractTerminatedByThisInstance", contractTerminationEvent); - } - - @Override - public void contractTerminatedByCounterparty(ContractTerminationEvent contractTerminationEvent) { - sendMessage("contractTerminatedByCounterparty", contractTerminationEvent); - } - - private void sendMessage(String logEvent, ContractTerminationEvent contractTerminationEvent) { - val logEntry = LogEntry.from(logEvent, contractTerminationEvent); - try { - val event = buildLogEvent(contractTerminationEvent.contractAgreementId(), logEntry); - publishEvent(event); - monitor.debug("Published event for " + logEntry); - } catch (JsonProcessingException e) { - val message = "Failed to serialize the event for the LoggingHouse " + logEntry; - throw new LoggingHouseException(message, e); - } - } - - private @NotNull MdsContractTerminationEvent buildLogEvent(String contractAgreementId, LogEntry logEntry) - throws JsonProcessingException { - val message = objectMapper.writeValueAsString(logEntry); - return new MdsContractTerminationEvent( - UuidGenerator.INSTANCE.generate().toString(), - contractAgreementId, - message - ); - } - - private void publishEvent(MdsContractTerminationEvent event) { - @SuppressWarnings("unchecked") - EventEnvelope.Builder builder = EventEnvelope.Builder.newInstance(); - - val eventEnvelope = builder - .at(System.currentTimeMillis()) - .payload(event) - .build(); - - eventRouter.publish(eventEnvelope); - } -} diff --git a/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/MdsLoggingHouseBinder.java b/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/MdsLoggingHouseBinder.java deleted file mode 100644 index 8fd10a763..000000000 --- a/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/MdsLoggingHouseBinder.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.extension.mdslogginhousebinder; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import de.sovity.edc.extension.contacttermination.ContractAgreementTerminationService; -import lombok.val; -import org.eclipse.edc.runtime.metamodel.annotation.Inject; -import org.eclipse.edc.spi.event.EventRouter; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.system.ServiceExtension; -import org.eclipse.edc.spi.system.ServiceExtensionContext; - -public class MdsLoggingHouseBinder implements ServiceExtension { - - @Inject - private EventRouter eventRouter; - - @Inject - private Monitor monitor; - - @Inject - private ContractAgreementTerminationService contractAgreementTerminationService; - - @Override - public void initialize(ServiceExtensionContext context) { - setupLoggingHouseTerminationEventsLogging(); - } - - private void setupLoggingHouseTerminationEventsLogging() { - val objectMapper = new ObjectMapper(); - objectMapper.registerModule(new JavaTimeModule()); - - contractAgreementTerminationService.getContractTerminationObservable() - .registerListener(new MdsContractTerminationObserver(eventRouter, monitor, objectMapper)); - } -} diff --git a/extensions/mds-logginghouse-binder/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/mds-logginghouse-binder/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension deleted file mode 100644 index 6ac768693..000000000 --- a/extensions/mds-logginghouse-binder/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension +++ /dev/null @@ -1 +0,0 @@ -de.sovity.edc.extension.mdslogginhousebinder.MdsLoggingHouseBinder diff --git a/extensions/policy-always-true/build.gradle.kts b/extensions/policy-always-true/build.gradle.kts index dd96f4f1a..d9acf8ccb 100644 --- a/extensions/policy-always-true/build.gradle.kts +++ b/extensions/policy-always-true/build.gradle.kts @@ -10,11 +10,8 @@ dependencies { api(libs.edc.controlPlaneSpi) implementation(libs.edc.apiCore) - testImplementation(libs.edc.controlPlaneCore) - testImplementation(libs.edc.junit) - testImplementation(libs.edc.dataPlaneSelectorCore) - testImplementation(libs.mockito.core) - testImplementation(libs.junit.api) + testImplementation(project(":launchers:utils:vanilla-control-plane")) + testImplementation(project(":utils:test-utils")) testRuntimeOnly(libs.junit.engine) } diff --git a/extensions/policy-always-true/src/main/java/de/sovity/edc/extension/policy/AlwaysTruePolicyExtension.java b/extensions/policy-always-true/src/main/java/de/sovity/edc/extension/policy/AlwaysTruePolicyExtension.java index a653d90e9..9d6d7bc79 100644 --- a/extensions/policy-always-true/src/main/java/de/sovity/edc/extension/policy/AlwaysTruePolicyExtension.java +++ b/extensions/policy-always-true/src/main/java/de/sovity/edc/extension/policy/AlwaysTruePolicyExtension.java @@ -16,7 +16,7 @@ import de.sovity.edc.extension.policy.services.AlwaysTruePolicyDefinitionService; import de.sovity.edc.extension.policy.services.AlwaysTruePolicyService; -import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService; +import org.eclipse.edc.connector.controlplane.services.spi.policydefinition.PolicyDefinitionService; import org.eclipse.edc.policy.engine.spi.PolicyEngine; import org.eclipse.edc.policy.engine.spi.RuleBindingRegistry; import org.eclipse.edc.runtime.metamodel.annotation.Inject; diff --git a/extensions/policy-always-true/src/main/java/de/sovity/edc/extension/policy/services/AlwaysTruePolicyDefinitionService.java b/extensions/policy-always-true/src/main/java/de/sovity/edc/extension/policy/services/AlwaysTruePolicyDefinitionService.java index be0b26f0c..224c8d070 100644 --- a/extensions/policy-always-true/src/main/java/de/sovity/edc/extension/policy/services/AlwaysTruePolicyDefinitionService.java +++ b/extensions/policy-always-true/src/main/java/de/sovity/edc/extension/policy/services/AlwaysTruePolicyDefinitionService.java @@ -14,8 +14,8 @@ package de.sovity.edc.extension.policy.services; -import org.eclipse.edc.connector.policy.spi.PolicyDefinition; -import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService; +import org.eclipse.edc.connector.controlplane.policy.spi.PolicyDefinition; +import org.eclipse.edc.connector.controlplane.services.spi.policydefinition.PolicyDefinitionService; import org.eclipse.edc.policy.model.Action; import org.eclipse.edc.policy.model.Permission; import org.eclipse.edc.policy.model.Policy; diff --git a/extensions/policy-always-true/src/test/java/de/sovity/edc/extension/policy/AlwaysTruePolicyExtensionTest.java b/extensions/policy-always-true/src/test/java/de/sovity/edc/extension/policy/AlwaysTruePolicyExtensionTest.java index 0919d269e..b6e590895 100644 --- a/extensions/policy-always-true/src/test/java/de/sovity/edc/extension/policy/AlwaysTruePolicyExtensionTest.java +++ b/extensions/policy-always-true/src/test/java/de/sovity/edc/extension/policy/AlwaysTruePolicyExtensionTest.java @@ -14,48 +14,55 @@ package de.sovity.edc.extension.policy; -import org.eclipse.edc.connector.contract.spi.offer.ContractDefinitionResolver; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; +import de.sovity.edc.extension.e2e.junit.edc.EmbeddedRuntimeFixed; +import org.eclipse.edc.connector.controlplane.contract.spi.offer.ContractDefinitionResolver; +import org.eclipse.edc.connector.controlplane.policy.spi.PolicyDefinition; +import org.eclipse.edc.connector.controlplane.services.spi.policydefinition.PolicyDefinitionService; +import org.eclipse.edc.connector.dataplane.selector.spi.client.DataPlaneClientFactory; import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore; -import org.eclipse.edc.connector.policy.spi.PolicyDefinition; -import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService; -import org.eclipse.edc.junit.annotations.ApiTest; -import org.eclipse.edc.junit.extensions.EdcExtension; import org.eclipse.edc.policy.engine.spi.PolicyContext; import org.eclipse.edc.policy.engine.spi.PolicyEngine; import org.eclipse.edc.spi.protocol.ProtocolWebhook; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; import static de.sovity.edc.extension.policy.AlwaysTruePolicyConstants.POLICY_DEFINITION_ID; import static java.util.Objects.requireNonNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; -@ApiTest -@ExtendWith(EdcExtension.class) class AlwaysTruePolicyExtensionTest { + @RegisterExtension + static CeIntegrationTestExtension extension = CeIntegrationTestExtension.builder() + .additionalModule(":extensions:edc-ui-config") + .additionalModule(":launchers:utils:vanilla-control-plane") + .skipDb(true) + .beforeEdcStartup(runtime -> runtime.registerServiceMock(DataPlaneClientFactory.class, mock())) + .build(); + @BeforeEach - void setUp(EdcExtension extension) { - extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); - extension.registerServiceMock( - DataPlaneInstanceStore.class, - mock(DataPlaneInstanceStore.class)); + void setUp(EmbeddedRuntimeFixed runtime) { + runtime.registerServiceMock(ProtocolWebhook.class, mock()); + runtime.registerServiceMock(DataPlaneInstanceStore.class, mock()); } @Test - void alwaysTruePolicyDef(PolicyEngine policyEngine, - PolicyDefinitionService policyDefinitionService) { + void alwaysTruePolicyDef( + PolicyEngine policyEngine, + PolicyDefinitionService policyDefinitionService + ) { // arrange var alwaysTrue = alwaysTruePolicy(policyDefinitionService); // act var result = policyEngine.evaluate( - ContractDefinitionResolver.CATALOGING_SCOPE, - alwaysTrue.getPolicy(), - mock(PolicyContext.class) + ContractDefinitionResolver.CATALOGING_SCOPE, + alwaysTrue.getPolicy(), + mock(PolicyContext.class) ); // assert diff --git a/extensions/policy-referring-connector/src/main/java/de/sovity/edc/extension/policy/ReferringConnectorValidationExtension.java b/extensions/policy-referring-connector/src/main/java/de/sovity/edc/extension/policy/ReferringConnectorValidationExtension.java index 61033b8c2..826f9b255 100644 --- a/extensions/policy-referring-connector/src/main/java/de/sovity/edc/extension/policy/ReferringConnectorValidationExtension.java +++ b/extensions/policy-referring-connector/src/main/java/de/sovity/edc/extension/policy/ReferringConnectorValidationExtension.java @@ -27,8 +27,8 @@ import de.sovity.edc.extension.policy.functions.ReferringConnectorDutyFunction; import de.sovity.edc.extension.policy.functions.ReferringConnectorPermissionFunction; import de.sovity.edc.extension.policy.functions.ReferringConnectorProhibitionFunction; -import org.eclipse.edc.connector.contract.spi.offer.ContractDefinitionResolver; -import org.eclipse.edc.connector.contract.spi.validation.ContractValidationService; +import org.eclipse.edc.connector.controlplane.contract.spi.offer.ContractDefinitionResolver; +import org.eclipse.edc.connector.controlplane.contract.spi.validation.ContractValidationService; import org.eclipse.edc.policy.engine.spi.AtomicConstraintFunction; import org.eclipse.edc.policy.engine.spi.PolicyEngine; import org.eclipse.edc.policy.engine.spi.RuleBindingRegistry; diff --git a/extensions/postgres-flyway/build.gradle.kts b/extensions/postgres-flyway/build.gradle.kts index bf3e52c75..1a866afbe 100644 --- a/extensions/postgres-flyway/build.gradle.kts +++ b/extensions/postgres-flyway/build.gradle.kts @@ -4,30 +4,31 @@ plugins { `maven-publish` } +var edcVersion = libs.versions.edc.get() + dependencies { annotationProcessor(libs.lombok) compileOnly(libs.lombok) implementation(project(":config")) - implementation(libs.edc.coreSpi) implementation(libs.edc.sqlCore) + implementation(libs.edc.httpSpi) // Adds Database-Related EDC-Extensions (EDC-SQL-Stores, JDBC-Driver, Pool and Transactions) implementation(libs.edc.controlPlaneSql) implementation(libs.edc.transactionLocal) - implementation(libs.tractus.sqlPool) - implementation(libs.apache.commonsLang) - implementation(libs.flyway.core) - implementation(libs.postgres) - implementation(libs.hikari) - testImplementation(libs.edc.junit) + // TODO check which ones are required in the EDC CE + implementation(libs.edc.sqlPoolApacheCommons) + implementation(libs.edc.dataPlaneInstanceStoreSql) + implementation(libs.edc.edrIndexSql) + implementation(libs.edc.policyMonitorStoreSql) } group = libs.versions.sovityEdcExtensionGroup.get() diff --git a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/FlywayFactory.java b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/FlywayFactory.java index 636983e70..71777d444 100644 --- a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/FlywayFactory.java +++ b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/FlywayFactory.java @@ -41,21 +41,7 @@ public Flyway setupFlywayForUnifiedHistory(DataSource dataSource) { .cleanDisabled(!config.flywayCleanEnabled()) .baselineVersion("0") .baselineOnMigrate(true) - .table("flyway_schema_history") - .locations(locations.toArray(new String[0])) - .load(); - } - - public Flyway setupFlywayForUnifiedHistoryFromLegacyDatabase(DataSource dataSource) { - val locations = new ArrayList(); - locations.add("classpath:db/migration"); - locations.addAll(getAdditionalFlywayMigrationLocations()); - - return Flyway.configure() - .dataSource(dataSource) - .baselineVersion("8") - .cleanDisabled(!config.flywayCleanEnabled()) - .table("flyway_schema_history") + .table(TableNames.SOVITY_MIGRATION_TABLE) .locations(locations.toArray(new String[0])) .load(); } diff --git a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/FlywayMigrator.java b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/FlywayMigrator.java index 1679f6ccd..e1c3c6200 100644 --- a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/FlywayMigrator.java +++ b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/FlywayMigrator.java @@ -1,75 +1,31 @@ package de.sovity.edc.extension.postgresql; import com.zaxxer.hikari.HikariDataSource; -import de.sovity.edc.extension.postgresql.legacy.migration.DatabaseMigrationManager; -import de.sovity.edc.extension.postgresql.legacy.migration.FlywayService; -import de.sovity.edc.extension.postgresql.utils.DatabaseUtils; -import de.sovity.edc.utils.config.ConfigProps; +import de.sovity.edc.utils.config.CeConfigProps; import lombok.val; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.persistence.EdcPersistenceException; -import org.eclipse.edc.spi.system.configuration.Config; import org.flywaydb.core.api.FlywayException; -import java.sql.SQLException; - public class FlywayMigrator { private final PostgresFlywayConfig config; - private final Config legacyConfig; private final HikariDataSource dataSource; private final Monitor monitor; private final FlywayFactory flywayFactory; - private final DatabaseUtils databaseUtils; - public FlywayMigrator(PostgresFlywayConfig config, Config legacyConfig, HikariDataSource dataSource, Monitor monitor) { + public FlywayMigrator(PostgresFlywayConfig config, HikariDataSource dataSource, Monitor monitor) { this.config = config; - this.legacyConfig = legacyConfig; this.dataSource = dataSource; this.monitor = monitor; this.flywayFactory = new FlywayFactory(config); - this.databaseUtils = new DatabaseUtils(dataSource); } public void updateDatabaseWithLegacyHandling() { - migrateLegacyHistory(); cleanDatabase(); updateDatabase(); } - private void migrateLegacyHistory() { - if (config.flywayClean() && config.flywayCleanEnabled()) { - return; - } - try { - val isLegacyDatabase = databaseUtils.hasLegacyMigrations(); - if (!isLegacyDatabase) { - return; - } - } catch (SQLException e) { - throw migrationFailed(e); - } - - monitor.debug(() -> "Legacy-style flyway migration table detected. Upgrading to the latest legacy database history revision."); - val flywayService = new FlywayService( - monitor, - config.flywayRepair(), - config.flywayCleanEnabled(), - config.flywayClean() - ); - val migrationManager = new DatabaseMigrationManager(legacyConfig, flywayService); - migrationManager.migrateAllDataSources(); - - monitor.debug(() -> "Upgrading to the latest unified database history revision."); - val flyway = flywayFactory.setupFlywayForUnifiedHistoryFromLegacyDatabase(dataSource); - - try { - flyway.baseline(); - } catch (FlywayException e) { - throw migrationFailed(e); - } - } - private void cleanDatabase() { boolean shouldClean = config.flywayClean(); @@ -77,11 +33,11 @@ private void cleanDatabase() { if (shouldClean) { if (!canClean) { throw new IllegalStateException("In order to clean the history both %s and %s must be set to true.".formatted( - ConfigProps.EDC_FLYWAY_CLEAN.getProperty(), ConfigProps.EDC_FLYWAY_CLEAN_ENABLE.getProperty() + CeConfigProps.EDC_FLYWAY_CLEAN.getProperty(), CeConfigProps.EDC_FLYWAY_CLEAN_ENABLE.getProperty() )); } monitor.info(() -> "Cleaning database before migrations, since %s=true and %s=true.".formatted( - ConfigProps.EDC_FLYWAY_CLEAN.getProperty(), ConfigProps.EDC_FLYWAY_CLEAN_ENABLE.getProperty() + CeConfigProps.EDC_FLYWAY_CLEAN.getProperty(), CeConfigProps.EDC_FLYWAY_CLEAN_ENABLE.getProperty() )); val flyway = flywayFactory.setupFlywayForUnifiedHistory(dataSource); diff --git a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/PostgresFlywayConfig.java b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/PostgresFlywayConfig.java index 7ae9d8c3e..cb420ee61 100644 --- a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/PostgresFlywayConfig.java +++ b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/PostgresFlywayConfig.java @@ -15,7 +15,7 @@ package de.sovity.edc.extension.postgresql; import de.sovity.edc.extension.postgresql.utils.JdbcCredentials; -import de.sovity.edc.utils.config.ConfigProps; +import de.sovity.edc.utils.config.CeConfigProps; import org.eclipse.edc.spi.system.configuration.Config; public record PostgresFlywayConfig( @@ -31,16 +31,17 @@ public record PostgresFlywayConfig( public static PostgresFlywayConfig fromConfig(Config config) { return new PostgresFlywayConfig( new JdbcCredentials( - ConfigProps.EDC_DATASOURCE_DEFAULT_URL.getStringOrThrow(config), - ConfigProps.EDC_DATASOURCE_DEFAULT_USER.getStringOrThrow(config), - ConfigProps.EDC_DATASOURCE_DEFAULT_PASSWORD.getStringOrThrow(config) + // TODO: Switch to Vault for EE + CeConfigProps.MY_EDC_JDBC_URL.getStringOrThrow(config), + CeConfigProps.MY_EDC_JDBC_USER.getStringOrThrow(config), + CeConfigProps.MY_EDC_JDBC_PASSWORD.getStringOrThrow(config) ), - ConfigProps.EDC_FLYWAY_REPAIR.getBoolean(config), - ConfigProps.EDC_FLYWAY_CLEAN_ENABLE.getBoolean(config), - ConfigProps.EDC_FLYWAY_CLEAN.getBoolean(config), - ConfigProps.EDC_FLYWAY_ADDITIONAL_MIGRATION_LOCATIONS.getStringOrEmpty(config), - ConfigProps.EDC_SERVER_DB_CONNECTION_POOL_SIZE.getInt(config), - ConfigProps.EDC_SERVER_DB_CONNECTION_TIMEOUT_IN_MS.getInt(config) + CeConfigProps.EDC_FLYWAY_REPAIR.getBoolean(config), + CeConfigProps.EDC_FLYWAY_CLEAN_ENABLE.getBoolean(config), + CeConfigProps.EDC_FLYWAY_CLEAN.getBoolean(config), + CeConfigProps.EDC_FLYWAY_ADDITIONAL_MIGRATION_LOCATIONS.getStringOrEmpty(config), + CeConfigProps.EDC_SERVER_DB_CONNECTION_POOL_SIZE.getInt(config), + CeConfigProps.EDC_SERVER_DB_CONNECTION_TIMEOUT_IN_MS.getInt(config) ); } } diff --git a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/PostgresFlywayExtension.java b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/PostgresFlywayExtension.java index 4103f3b87..6a8ff1f3f 100644 --- a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/PostgresFlywayExtension.java +++ b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/PostgresFlywayExtension.java @@ -35,7 +35,7 @@ public void initialize(ServiceExtensionContext context) { val dataSourceFactory = new DataSourceFactory(extensionConfig); dataSource = dataSourceFactory.newDataSource(); - val migrator = new FlywayMigrator(extensionConfig, legacyConfig, dataSource, context.getMonitor()); + val migrator = new FlywayMigrator(extensionConfig, dataSource, context.getMonitor()); migrator.updateDatabaseWithLegacyHandling(); } diff --git a/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/LoggingHouseException.java b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/TableNames.java similarity index 62% rename from extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/LoggingHouseException.java rename to extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/TableNames.java index 6ca7c24a1..302663628 100644 --- a/extensions/mds-logginghouse-binder/src/main/java/de/sovity/edc/extension/mdslogginhousebinder/LoggingHouseException.java +++ b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/TableNames.java @@ -12,10 +12,8 @@ * */ -package de.sovity.edc.extension.mdslogginhousebinder; +package de.sovity.edc.extension.postgresql; -public class LoggingHouseException extends RuntimeException { - public LoggingHouseException(String message, Throwable cause) { - super(message, cause); - } +public class TableNames { + public static final String SOVITY_MIGRATION_TABLE = "flyway_schema_history_sovity"; } diff --git a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/legacy/connection/DriverManagerConnectionFactory.java b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/legacy/connection/DriverManagerConnectionFactory.java deleted file mode 100644 index 13d2946e7..000000000 --- a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/legacy/connection/DriverManagerConnectionFactory.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - initial implementation - * - */ - -package de.sovity.edc.extension.postgresql.legacy.connection; - -import org.eclipse.edc.spi.persistence.EdcPersistenceException; -import org.eclipse.edc.sql.ConnectionFactory; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.Properties; - -public class DriverManagerConnectionFactory implements ConnectionFactory { - - private static final String CONNECTION_PROPERTY_USER = "user"; - private static final String CONNECTION_PROPERTY_PASSWORD = "password"; - - private final JdbcConnectionProperties jdbcProperties; - - public DriverManagerConnectionFactory(JdbcConnectionProperties jdbcProperties) { - this.jdbcProperties = jdbcProperties; - } - - @Override - public Connection create() { - try { - var properties = new Properties(); - properties.setProperty(CONNECTION_PROPERTY_USER, jdbcProperties.getUser()); - properties.setProperty(CONNECTION_PROPERTY_PASSWORD, jdbcProperties.getPassword()); - return DriverManager.getConnection(jdbcProperties.getJdbcUrl(), properties); - } catch (SQLException e) { - throw new EdcPersistenceException(e); - } - } -} diff --git a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/legacy/connection/JdbcConnectionProperties.java b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/legacy/connection/JdbcConnectionProperties.java deleted file mode 100644 index 1ed3830c6..000000000 --- a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/legacy/connection/JdbcConnectionProperties.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - initial implementation - * - */ - -package de.sovity.edc.extension.postgresql.legacy.connection; - -import org.eclipse.edc.runtime.metamodel.annotation.Setting; -import org.eclipse.edc.spi.system.configuration.Config; - -public class JdbcConnectionProperties { - - @Setting(required = true) - private static final String DATASOURCE_SETTING_JDBC_URL = "edc.datasource.%s.url"; - @Setting(required = true) - private static final String DATASOURCE_SETTING_USER = "edc.datasource.%s.user"; - @Setting(required = true) - private static final String DATASOURCE_SETTING_PASSWORD = "edc.datasource.%s.password"; - - private final String jdbcUrl; - private final String user; - private final String password; - - public JdbcConnectionProperties(Config config, String entityName) { - jdbcUrl = config.getString(String.format(DATASOURCE_SETTING_JDBC_URL, entityName)); - user = config.getString(String.format(DATASOURCE_SETTING_USER, entityName)); - password = config.getString(String.format(DATASOURCE_SETTING_PASSWORD, entityName)); - } - - public String getJdbcUrl() { - return jdbcUrl; - } - - public String getUser() { - return user; - } - - public String getPassword() { - return password; - } -} diff --git a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/legacy/migration/DatabaseMigrationManager.java b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/legacy/migration/DatabaseMigrationManager.java deleted file mode 100644 index 1e7dd4539..000000000 --- a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/legacy/migration/DatabaseMigrationManager.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - initial implementation - * - */ - -package de.sovity.edc.extension.postgresql.legacy.migration; - -import de.sovity.edc.extension.postgresql.legacy.connection.JdbcConnectionProperties; -import de.sovity.edc.utils.config.ConfigProps; -import org.eclipse.edc.spi.system.configuration.Config; - -import java.util.Arrays; -import java.util.List; - -public class DatabaseMigrationManager { - private static final String DEFAULT_DATASOURCE = "default"; - - private final Config config; - private final FlywayService flywayService; - - private final List dataSourceNames = List.of( - // Pre EDC 0 legacy migrations - "asset", - "contractdefinition", - "policy", - "contractnegotiation", - "transferprocess", - "dataplaneinstance", - - // Actual DB migrations - "default" - ); - - public DatabaseMigrationManager(Config config, FlywayService flywayService) { - this.config = config; - this.flywayService = flywayService; - } - - public void migrateAllDataSources() { - flywayService.cleanDatabase(DEFAULT_DATASOURCE, new JdbcConnectionProperties(config, DEFAULT_DATASOURCE)); - for (String datasourceName : dataSourceNames) { - var jdbcConnectionProperties = new JdbcConnectionProperties(config, datasourceName); - List additionalMigrationLocations = getAdditionalFlywayMigrationLocations(datasourceName); - flywayService.migrateDatabase(datasourceName, jdbcConnectionProperties, additionalMigrationLocations); - } - } - - public List getAdditionalFlywayMigrationLocations(String datasourceName) { - // Only the default data has configurable additional migration scripts - if (!datasourceName.equals(DEFAULT_DATASOURCE)) { - return List.of(); - } - - String commaJoined = ConfigProps.EDC_FLYWAY_ADDITIONAL_MIGRATION_LOCATIONS.getStringOrEmpty(config); - return Arrays.stream(commaJoined.split(",")) - .map(String::trim) - .filter(it -> !it.isEmpty()) - .toList(); - } -} diff --git a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/legacy/migration/FlywayService.java b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/legacy/migration/FlywayService.java deleted file mode 100644 index 9fc9ec60c..000000000 --- a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/legacy/migration/FlywayService.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - initial implementation - * - */ - -package de.sovity.edc.extension.postgresql.legacy.migration; - -import de.sovity.edc.extension.postgresql.legacy.connection.DriverManagerConnectionFactory; -import de.sovity.edc.extension.postgresql.legacy.connection.JdbcConnectionProperties; -import lombok.RequiredArgsConstructor; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.persistence.EdcPersistenceException; -import org.eclipse.edc.sql.datasource.ConnectionFactoryDataSource; -import org.flywaydb.core.Flyway; -import org.flywaydb.core.api.FlywayException; -import org.flywaydb.core.api.MigrationVersion; -import org.flywaydb.core.api.output.MigrateResult; -import org.flywaydb.core.api.output.RepairResult; - -import java.util.ArrayList; -import java.util.List; -import javax.sql.DataSource; - -@RequiredArgsConstructor -public class FlywayService { - - private static final String MIGRATION_LOCATION_BASE = "classpath:db/legacy/migration"; - - private final Monitor monitor; - private final boolean tryRepairOnFailedMigration; - private final boolean cleanEnabled; - private final boolean clean; - - public void cleanDatabase(String datasourceName, JdbcConnectionProperties jdbcConnectionProperties) { - if (clean) { - monitor.info("Running flyway clean."); - var flyway = setupFlyway(datasourceName, jdbcConnectionProperties, List.of()); - flyway.clean(); - } - } - - public void migrateDatabase( - String datasourceName, - JdbcConnectionProperties jdbcConnectionProperties, - List additionalMigrationLocations - ) { - var flyway = setupFlyway(datasourceName, jdbcConnectionProperties, additionalMigrationLocations); - flyway.info().getInfoResult().migrations.stream() - .map(migration -> "Found migration: %s".formatted(migration.filepath)) - .forEach(monitor::info); - - try { - var migrateResult = flyway.migrate(); - handleFlywayMigrationResult(datasourceName, migrateResult); - } catch (FlywayException e) { - if (tryRepairOnFailedMigration) { - repairAndRetryMigration(datasourceName, flyway); - } else { - throw new EdcPersistenceException("Flyway migration failed for '%s'" - .formatted(datasourceName), e); - } - } - } - - private void repairAndRetryMigration(String datasourceName, Flyway flyway) { - try { - var repairResult = flyway.repair(); - handleFlywayRepairResult(datasourceName, repairResult); - var migrateResult = flyway.migrate(); - handleFlywayMigrationResult(datasourceName, migrateResult); - } catch (FlywayException e) { - throw new EdcPersistenceException("Flyway migration failed for '%s'" - .formatted(datasourceName), e); - } - } - - private void handleFlywayRepairResult(String datasourceName, RepairResult repairResult) { - if (!repairResult.repairActions.isEmpty()) { - var repairActions = String.join(", ", repairResult.repairActions); - monitor.info("Repair actions for datasource %s: %s" - .formatted(datasourceName, repairActions)); - } - - if (!repairResult.warnings.isEmpty()) { - var warnings = String.join(", ", repairResult.warnings); - throw new EdcPersistenceException("Repairing datasource %s failed: %s" - .formatted(datasourceName, warnings)); - } - } - - private Flyway setupFlyway( - String datasourceName, - JdbcConnectionProperties jdbcConnectionProperties, - List additionalMigrationLocations - ) { - var dataSource = getDataSource(jdbcConnectionProperties); - var migrationTableName = String.format("flyway_schema_history_%s", datasourceName); - var migrationLocations = new ArrayList(); - migrationLocations.add(String.join("/", MIGRATION_LOCATION_BASE, datasourceName)); - migrationLocations.addAll(additionalMigrationLocations); - monitor.info("Flyway migration locations for '%s': %s".formatted(datasourceName, migrationLocations)); - return Flyway.configure() - .baselineVersion(MigrationVersion.fromVersion("0.0.0")) - .baselineOnMigrate(true) - .failOnMissingLocations(true) - .dataSource(dataSource) - .table(migrationTableName) - .locations(migrationLocations.toArray(new String[0])) - .cleanDisabled(!cleanEnabled) - .load(); - } - - private DataSource getDataSource(JdbcConnectionProperties jdbcConnectionProperties) { - var connectionFactory = new DriverManagerConnectionFactory(jdbcConnectionProperties); - return new ConnectionFactoryDataSource(connectionFactory); - } - - private void handleFlywayMigrationResult(String datasourceName, MigrateResult migrateResult) { - if (migrateResult.migrationsExecuted > 0) { - monitor.info(String.format( - "Successfully migrated database for datasource %s " + - "from version %s to version %s", - datasourceName, - migrateResult.initialSchemaVersion, - migrateResult.targetSchemaVersion)); - } else { - monitor.info(String.format( - "No migration necessary for datasource %s. Current version is %s", - datasourceName, - migrateResult.initialSchemaVersion)); - } - } - -} diff --git a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/utils/DatabaseUtils.java b/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/utils/DatabaseUtils.java deleted file mode 100644 index 295555ae2..000000000 --- a/extensions/postgres-flyway/src/main/java/de/sovity/edc/extension/postgresql/utils/DatabaseUtils.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.extension.postgresql.utils; - -import lombok.RequiredArgsConstructor; -import lombok.val; - -import java.sql.SQLException; -import javax.sql.DataSource; - -@RequiredArgsConstructor -public class DatabaseUtils { - - public static class TableNames { - public static final String UNIFIED_MIGRATION_TABLE = "flyway_schema_history"; - public static final String DEFAULT_MIGRATION_TABLE = "flyway_schema_history_default"; - } - - private final DataSource dataSource; - - public boolean tableExists(String tableName) throws SQLException { - try ( - val connection = dataSource.getConnection(); - val stmt = connection.prepareStatement( - "select exists (select 1 from information_schema.tables where table_schema = 'public' and table_name = ?)")) { - stmt.setString(1, tableName); - val result = stmt.executeQuery(); - if (!result.next()) { - return false; - } - return result.getBoolean("exists"); - } - } - - public boolean hasBaseline(String tableName, String baseline) throws SQLException { - try ( - val connection = dataSource.getConnection(); - val stmt = connection.prepareStatement( - "select exists (select 1 from public." + tableName + " where type = 'BASELINE' and version = ?)")) { - stmt.setString(1, baseline); - val result = stmt.executeQuery(); - if (!result.next()) { - return false; - } - return result.getBoolean("exists"); - } - } - - public boolean hasUnifiedMigrations() throws SQLException { - return tableExists(TableNames.UNIFIED_MIGRATION_TABLE); - } - - public boolean hasDefaultMigrations() throws SQLException { - return tableExists(TableNames.DEFAULT_MIGRATION_TABLE); - } - - public boolean hasSplitHistory() throws SQLException { - return tableExists("flyway_schema_history_asset") || - tableExists("flyway_schema_history_contractdefinition") || - tableExists("flyway_schema_history_contractnegotiation") || - tableExists("flyway_schema_history_dataplaneinstance") || - tableExists("flyway_schema_history_policy") || - tableExists("flyway_schema_history_transferprocess"); - } - - public boolean hasLegacyMigrations() throws SQLException { - return hasSplitHistory() || hasDefaultMigrations(); - } - - public boolean hasUnifiedBaseline(String s) throws SQLException { - return hasBaseline(TableNames.UNIFIED_MIGRATION_TABLE, s); - } -} diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/asset/V0_0_1__Asset_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/asset/V0_0_1__Asset_Schema.sql deleted file mode 100644 index bd4b5da08..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/asset/V0_0_1__Asset_Schema.sql +++ /dev/null @@ -1,52 +0,0 @@ --- --- Copyright (c) 2022 Daimler TSS GmbH --- --- 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: --- Daimler TSS GmbH - Initial SQL Query --- - --- THIS SCHEMA HAS BEEN WRITTEN AND TESTED ONLY FOR POSTGRES - --- table: edc_asset -CREATE TABLE IF NOT EXISTS edc_asset -( - asset_id VARCHAR NOT NULL, - PRIMARY KEY (asset_id) -); - --- table: edc_asset_dataaddress -CREATE TABLE IF NOT EXISTS edc_asset_dataaddress -( - asset_id_fk VARCHAR NOT NULL, - properties JSON NOT NULL, - PRIMARY KEY (asset_id_fk), - FOREIGN KEY (asset_id_fk) REFERENCES edc_asset (asset_id) ON DELETE CASCADE -); -COMMENT ON COLUMN edc_asset_dataaddress.properties IS 'DataAddress properties serialized as JSON'; - --- table: edc_asset_property -CREATE TABLE IF NOT EXISTS edc_asset_property -( - asset_id_fk VARCHAR NOT NULL, - property_name VARCHAR NOT NULL, - property_value VARCHAR NOT NULL, - property_type VARCHAR NOT NULL, - PRIMARY KEY (asset_id_fk, property_name), - FOREIGN KEY (asset_id_fk) REFERENCES edc_asset (asset_id) ON DELETE CASCADE -); - -COMMENT ON COLUMN edc_asset_property.property_name IS - 'Asset property key'; -COMMENT ON COLUMN edc_asset_property.property_value IS - 'Asset property value'; -COMMENT ON COLUMN edc_asset_property.property_type IS - 'Asset property class name'; - -CREATE INDEX IF NOT EXISTS idx_edc_asset_property_value - ON edc_asset_property (property_name, property_value); \ No newline at end of file diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/asset/V0_0_2__Asset_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/asset/V0_0_2__Asset_Schema.sql deleted file mode 100644 index 410ef423a..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/asset/V0_0_2__Asset_Schema.sql +++ /dev/null @@ -1,21 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-7 EDC --- --- - -ALTER TABLE edc_asset - ADD created_at BIGINT; - -UPDATE edc_asset SET created_at=EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000; - -ALTER TABLE edc_asset - ALTER COLUMN created_at SET NOT NULL; \ No newline at end of file diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractdefinition/V0_0_1__ContractDefinition_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractdefinition/V0_0_1__ContractDefinition_Schema.sql deleted file mode 100644 index 80f09c506..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractdefinition/V0_0_1__ContractDefinition_Schema.sql +++ /dev/null @@ -1,24 +0,0 @@ --- --- Copyright (c) 2022 Daimler TSS GmbH --- --- 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: --- Daimler TSS GmbH - Initial SQL Query --- Microsoft Corporation - refactoring --- - --- table: edc_contract_definitions --- only intended for and tested with H2 and Postgres! -CREATE TABLE IF NOT EXISTS edc_contract_definitions -( - contract_definition_id VARCHAR NOT NULL, - access_policy_id VARCHAR NOT NULL, - contract_policy_id VARCHAR NOT NULL, - selector_expression JSON NOT NULL, - PRIMARY KEY (contract_definition_id) -); diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractdefinition/V0_0_2__ContractDefinition_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractdefinition/V0_0_2__ContractDefinition_Schema.sql deleted file mode 100644 index c1dd04041..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractdefinition/V0_0_2__ContractDefinition_Schema.sql +++ /dev/null @@ -1,20 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-7 EDC --- --- -ALTER TABLE edc_contract_definitions - ADD created_at BIGINT; - -UPDATE edc_contract_definitions SET created_at=EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000; - -ALTER TABLE edc_contract_definitions - ALTER COLUMN created_at SET NOT NULL; \ No newline at end of file diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractdefinition/V0_0_3__ContractDefinition_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractdefinition/V0_0_3__ContractDefinition_Schema.sql deleted file mode 100644 index a1446460b..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractdefinition/V0_0_3__ContractDefinition_Schema.sql +++ /dev/null @@ -1,14 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-8 EDC --- --- -ALTER TABLE edc_contract_definitions ADD validity BIGINT; \ No newline at end of file diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractdefinition/V0_0_4__Set_Default_Validity.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractdefinition/V0_0_4__Set_Default_Validity.sql deleted file mode 100644 index f166a9ce2..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractdefinition/V0_0_4__Set_Default_Validity.sql +++ /dev/null @@ -1,14 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-8 EDC --- --- -UPDATE edc_contract_definitions SET validity=60*60*24*365 WHERE validity IS NULL; diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractnegotiation/V0_0_1__ContractNegotiation_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractnegotiation/V0_0_1__ContractNegotiation_Schema.sql deleted file mode 100644 index 82049c460..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractnegotiation/V0_0_1__ContractNegotiation_Schema.sql +++ /dev/null @@ -1,78 +0,0 @@ --- Statements are designed for and tested with Postgres only! - -CREATE TABLE IF NOT EXISTS edc_lease -( - leased_by VARCHAR NOT NULL, - leased_at BIGINT, - lease_duration INTEGER DEFAULT 60000 NOT NULL, - lease_id VARCHAR NOT NULL - CONSTRAINT lease_pk - PRIMARY KEY -); - -COMMENT ON COLUMN edc_lease.leased_at IS 'posix timestamp of lease'; - -COMMENT ON COLUMN edc_lease.lease_duration IS 'duration of lease in milliseconds'; - - -CREATE UNIQUE INDEX IF NOT EXISTS lease_lease_id_uindex - ON edc_lease (lease_id); - - - -CREATE TABLE IF NOT EXISTS edc_contract_agreement -( - agr_id VARCHAR NOT NULL - CONSTRAINT contract_agreement_pk - PRIMARY KEY, - provider_agent_id VARCHAR, - consumer_agent_id VARCHAR, - signing_date BIGINT, - start_date BIGINT, - end_date INTEGER, - asset_id VARCHAR NOT NULL, - policy JSON -); - - -CREATE TABLE IF NOT EXISTS edc_contract_negotiation -( - id VARCHAR NOT NULL - CONSTRAINT contract_negotiation_pk - PRIMARY KEY, - correlation_id VARCHAR, - counterparty_id VARCHAR NOT NULL, - counterparty_address VARCHAR NOT NULL, - protocol VARCHAR DEFAULT 'ids-multipart'::CHARACTER VARYING NOT NULL, - type INTEGER DEFAULT 0 NOT NULL, - state INTEGER DEFAULT 0 NOT NULL, - state_count INTEGER DEFAULT 0, - state_timestamp BIGINT, - error_detail VARCHAR, - agreement_id VARCHAR - CONSTRAINT contract_negotiation_contract_agreement_id_fk - REFERENCES edc_contract_agreement, - contract_offers JSON, - trace_context JSON, - lease_id VARCHAR - CONSTRAINT contract_negotiation_lease_lease_id_fk - REFERENCES edc_lease - ON DELETE SET NULL, - CONSTRAINT provider_correlation_id CHECK (type = '0' OR correlation_id IS NOT NULL) -); - -COMMENT ON COLUMN edc_contract_negotiation.agreement_id IS 'ContractAgreement serialized as JSON'; - -COMMENT ON COLUMN edc_contract_negotiation.contract_offers IS 'List serialized as JSON'; - -COMMENT ON COLUMN edc_contract_negotiation.trace_context IS 'Map serialized as JSON'; - - -CREATE INDEX IF NOT EXISTS contract_negotiation_correlationid_index - ON edc_contract_negotiation (correlation_id); - -CREATE UNIQUE INDEX IF NOT EXISTS contract_negotiation_id_uindex - ON edc_contract_negotiation (id); - -CREATE UNIQUE INDEX IF NOT EXISTS contract_agreement_id_uindex - ON edc_contract_agreement (agr_id); \ No newline at end of file diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractnegotiation/V0_0_2__ContractNegotiation_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractnegotiation/V0_0_2__ContractNegotiation_Schema.sql deleted file mode 100644 index 91587e425..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractnegotiation/V0_0_2__ContractNegotiation_Schema.sql +++ /dev/null @@ -1,24 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-7 EDC --- --- -ALTER TABLE edc_contract_negotiation - ADD created_at BIGINT, - ADD updated_at BIGINT; - -UPDATE edc_contract_negotiation SET created_at=EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000; -UPDATE edc_contract_negotiation SET updated_at=created_at; - -ALTER TABLE edc_contract_negotiation - ALTER COLUMN created_at SET NOT NULL; -ALTER TABLE edc_contract_negotiation - ALTER COLUMN updated_at SET NOT NULL; diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractnegotiation/V0_0_3__Fix_Contract_Offer_JSON.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractnegotiation/V0_0_3__Fix_Contract_Offer_JSON.sql deleted file mode 100644 index 243fda6be..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/contractnegotiation/V0_0_3__Fix_Contract_Offer_JSON.sql +++ /dev/null @@ -1,37 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-7 EDC --- --- - -UPDATE edc_contract_negotiation -SET contract_offers = co.contract_offers_edited -FROM ( - SELECT - cn.id, - jsonb_agg( - jsonb_set( - jsonb_set( - elems, - '{contractStart}', - to_json(to_char(to_timestamp(created_at/1000) AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')::text)::jsonb - ), - '{contractEnd}', - to_json(to_char(to_timestamp((created_at/1000) + 60 * 60 * 24 * 365) AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')::text)::jsonb - ) - )::json as contract_offers_edited - FROM - edc_contract_negotiation cn, - jsonb_array_elements(cn.contract_offers::jsonb) elems - GROUP BY cn.id -) co -WHERE edc_contract_negotiation.id = co.id; - diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/dataplaneinstance/V0_0_1__DataplaneInstance_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/dataplaneinstance/V0_0_1__DataplaneInstance_Schema.sql deleted file mode 100644 index b8329e9bd..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/dataplaneinstance/V0_0_1__DataplaneInstance_Schema.sql +++ /dev/null @@ -1,19 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - initial API and implementation for DataplaneInstances --- --- -CREATE TABLE IF NOT EXISTS edc_data_plane_instance -( - id VARCHAR NOT NULL, - data JSON NOT NULL, - PRIMARY KEY (id) -); diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V1_0_0_Example_Migration.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V1_0_0_Example_Migration.sql deleted file mode 100644 index efe29c442..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V1_0_0_Example_Migration.sql +++ /dev/null @@ -1,5 +0,0 @@ --- Empty example migration --- This directory will contain all our Community Edition migrations in the future. --- Commercial Edition migrations will have to be compatible version-wise. --- This file is added to prevent flyway from crashing due no migrations. -SELECT 1; diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V2__Delete-Transfer-Processes-Trigger.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V2__Delete-Transfer-Processes-Trigger.sql deleted file mode 100644 index 5ca84691b..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V2__Delete-Transfer-Processes-Trigger.sql +++ /dev/null @@ -1,41 +0,0 @@ --- Required for reasonably fast ON DELETE CASCADE from edc_transfer_process -create index data_request_transfer_process_id_idx - on edc_data_request (transfer_process_id); --- Speed up sort + limit query --- Include transferprocess_id to enable index-only scan -create index transfer_process_created_at_idx - on edc_transfer_process (created_at) include (transferprocess_id); - --- Delete oldest row when table size exceeds 3000 rows --- The row count should mostly stabilize slightly above 3000, as the reltuples data in pg_class is only updated by VACUUM --- Unfortunately, I was not able to get conclusive results on the behavior under concurrent inserts --- One problem is that the table might still grow over time, if concurrent inserts can delete the same row --- To avoid this, we could delete two rows instead of just one --- Then the table would shrink until the next auto-vacuum detects that it is below 3000 rows again -create function transfer_process_delete_old_rows() returns trigger as $$ -begin - delete from edc_transfer_process o - using ( - select i2.transferprocess_id - from edc_transfer_process i2 - order by i2.created_at - limit 2 - ) i, - ( - -- Hack to avoid count(*), which takes several hundred milliseconds - -- Not perfectly accurate, but close enough - -- Idea taken from: https://www.cybertec-postgresql.com/en/postgresql-count-made-fast/ - select pgc.reltuples::bigint as count - from pg_catalog.pg_class pgc - where pgc.relname = 'edc_transfer_process' - ) c - where i.transferprocess_id = o.transferprocess_id and c.count > 3000; - - return null; -end; -$$ language plpgsql; - -create trigger delete_old_rows after insert - on edc_transfer_process - for each row -execute function transfer_process_delete_old_rows(); \ No newline at end of file diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V3__MS8-to-0.2.1.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V3__MS8-to-0.2.1.sql deleted file mode 100644 index e08d4659c..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V3__MS8-to-0.2.1.sql +++ /dev/null @@ -1,416 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables From MS8 to 0.1.0 EDC --- --- - --- Migrates an Asset ID -create - or replace function pg_temp.migrate_asset_id(asset_id text) returns text as -$$ -begin - return replace(replace(asset_id::text, 'urn:artifact:', ''), ':', '-'); -end; -$$ - language plpgsql; - --- Migrate a contract agreement ID to EDC 0 -create - or replace function pg_temp.migrate_contract_agreement_id(contract_agreement_id text, asset_id text) returns text as -$$ -begin - return pg_temp.base64encode(split_part(contract_agreement_id, ':', 1)) || ':' || - pg_temp.base64encode(asset_id) || ':' || - pg_temp.base64encode(split_part(contract_agreement_id, ':', 2)); -end; -$$ - language plpgsql; - --- Migrates a Connector Endpoint to EDC 0 -create - or replace function pg_temp.migrate_connector_endpoint(endpoint text) returns text as -$$ -begin - return pg_temp.replace_suffix(endpoint, '/api/v1/ids/data', '/api/dsp'); -end; -$$ - language plpgsql; - --- Migrates a Participant ID to EDC 0 -create - or replace function pg_temp.migrate_participant_id(asset_id text) returns text as -$$ -begin - return replace(replace(asset_id::text, 'urn:connector:', ''), ':', '-'); -end; -$$ - language plpgsql; - --- Migrates an Asset Property Name to EDC 0 (if possible) -create - or replace function pg_temp.migrate_asset_property_name(asset_property_key text) returns text as -$$ -begin - return case asset_property_key - -- This list only contains properties that are directly mappable - -- Properties that require a new nested JSON structure are not included - when 'asset:prop:id' then 'https://w3id.org/edc/v0.0.1/ns/id' - when 'asset:prop:name' then 'http://purl.org/dc/terms/title' - when 'asset:prop:language' then 'http://purl.org/dc/terms/language' - when 'asset:prop:description' then 'http://purl.org/dc/terms/description' - when 'asset:prop:standardLicense' then 'http://purl.org/dc/terms/license' - when 'asset:prop:version' then 'http://www.w3.org/ns/dcat#version' - when 'asset:prop:keywords' then 'http://www.w3.org/ns/dcat#keyword' - when 'asset:prop:contenttype' then 'http://www.w3.org/ns/dcat#mediaType' - when 'asset:prop:endpointDocumentation' then 'http://www.w3.org/ns/dcat#landingPage' - when 'http://w3id.org/mds#dataCategory' then asset_property_key - when 'http://w3id.org/mds#dataSubcategory' then asset_property_key - when 'http://w3id.org/mds#dataModel' then asset_property_key - when 'http://w3id.org/mds#geoReferenceMethod' then asset_property_key - when 'http://w3id.org/mds#transportMode' then asset_property_key - when 'asset:prop:datasource:http:hints:proxyMethod' - then 'https://semantic.sovity.io/dcat-ext#httpDatasourceHintsProxyMethod' - when 'asset:prop:datasource:http:hints:proxyPath' - then 'https://semantic.sovity.io/dcat-ext#httpDatasourceHintsProxyPath' - when 'asset:prop:datasource:http:hints:proxyQueryParams' - then 'https://semantic.sovity.io/dcat-ext#httpDatasourceHintsProxyQueryParams' - when 'asset:prop:datasource:http:hints:proxyBody' - then 'https://semantic.sovity.io/dcat-ext#httpDatasourceHintsProxyBody' - else pg_temp.migrate_unknown_asset_property_name(asset_property_key) - end; -end; -$$ - language plpgsql; - --- Migrates an unknown Asset Property Name to EDC 0 (if possible) -create - or replace function pg_temp.migrate_unknown_asset_property_name(asset_property_key text) returns text as -$$ -begin - asset_property_key := replace(asset_property_key, 'asset:prop:', ''); - if pg_temp.starts_with(asset_property_key, 'http://') or - pg_temp.starts_with(asset_property_key, 'https://') then - return asset_property_key; - end if; - - return 'http://unknown/' || replace(asset_property_key, ':', '-'); -end; -$$ - language plpgsql; - - --- Migrates the "keywords" property value to EDC 0 --- 'a, b'::text becomes '["a", "b"]'::text -create - or replace function pg_temp.migrate_asset_keywords(keywords_comma_joined text) returns text as -$$ -begin - return (select coalesce(json_agg(to_json(trim(keyword)))::text, '[]') - from unnest(regexp_split_to_array(keywords_comma_joined, ',')) as keyword - where trim(keyword) <> ''); -end; -$$ - language plpgsql; - --- Migrates an asset property to EDC 0 -create - or replace function pg_temp.migrate_asset_property(property_name text, property_value text, property_type text) returns jsonb as -$$ -declare - name_mapped text; - value_mapped text; - type_mapped text; -begin - if property_name = 'asset:prop:id' then - name_mapped = pg_temp.migrate_asset_property_name(property_name); - value_mapped = pg_temp.migrate_asset_id(property_value); - type_mapped = property_type; - elsif property_name = 'asset:prop:keywords' then - name_mapped = pg_temp.migrate_asset_property_name(property_name); - value_mapped = pg_temp.migrate_asset_keywords(property_value); - type_mapped = 'java.util.ArrayList'; - elsif property_name = 'asset:prop:publisher' then - name_mapped = 'http://purl.org/dc/terms/publisher'; - value_mapped = jsonb_build_object('http://xmlns.com/foaf/0.1/homepage', - pg_temp.jsonld_value(property_value))::text; - type_mapped = 'java.util.LinkedHashMap'; - elsif property_name = 'asset:prop:curatorOrganizationName' or - property_name = 'asset:prop:originatorOrganization' then - name_mapped = 'http://purl.org/dc/terms/creator'; - value_mapped = jsonb_build_object('http://xmlns.com/foaf/0.1/name', - pg_temp.jsonld_value(property_value))::text; - type_mapped = 'java.util.LinkedHashMap'; - else - name_mapped = pg_temp.migrate_asset_property_name(property_name); - value_mapped = property_value; - type_mapped = property_type; - end if; - - return jsonb_build_object( - 'name', name_mapped, - 'value', value_mapped, - 'type', type_mapped - ); -end; -$$ - language plpgsql; - --- Migrates a contract definition criterion operator -create - or replace function pg_temp.migrate_criterion_operator(op text) returns text as -$$ -begin - -- due to previous mixing of the criterion operator with ODRL operators, we need to ensure the data in the db - -- is correct - return case lower(op) - when 'eq' then '=' - when 'in' then 'in' - when 'like' then 'like' - else op - end; -end; -$$ - language plpgsql; - --- Migrates a contract definition criterion to EDC 0 -create - or replace function pg_temp.migrate_criterion(criterion jsonb) returns jsonb as -$$ -declare - operand_left_mapped text; - operator_mapped text; - operand_right_mapped jsonb; -begin - operand_left_mapped = pg_temp.migrate_asset_property_name(criterion ->> 'operandLeft'); - operator_mapped = pg_temp.migrate_criterion_operator(criterion ->> 'operator'); - - if criterion ->> 'operandLeft' = 'asset:prop:id' then - if jsonb_typeof(criterion -> 'operandRight') = 'array' then - operand_right_mapped = (select jsonb_agg(to_jsonb(pg_temp.migrate_asset_id(items.item))) - from (select jsonb_array_elements_text(criterion -> 'operandRight') item) items); - else - operand_right_mapped = to_jsonb(pg_temp.migrate_asset_id(criterion ->> 'operandRight')); - end if; - else - operand_right_mapped = criterion -> 'operandRight'; - end if; - - return jsonb_build_object( - 'operandLeft', operand_left_mapped, - 'operator', operator_mapped, - 'operandRight', operand_right_mapped - ); -end; -$$ - language plpgsql; - --- Migrates a contract offer JSON to EDC 0 -create - or replace function pg_temp.migrate_negotiation_contract_offer(contract_offer jsonb) returns jsonb as -$$ -begin - return (contract_offer - '{asset,provider,consumer,offerStart,offerEnd,contractStart,contractEnd}'::text[] - || jsonb_build_object('assetId', pg_temp.migrate_asset_id(contract_offer -> 'asset' ->> 'id'))); -end; -$$ - language plpgsql; - --- Migrates a JSON array of contract offers to EDC 0 -create - or replace function pg_temp.migrate_negotiation_contract_offers(contract_offers jsonb) returns jsonb as -$$ -begin - return (select jsonb_agg(pg_temp.migrate_negotiation_contract_offer(contract_offers.contract_offer)) - from (select jsonb_array_elements(contract_offers) contract_offer) contract_offers); -end; -$$ - language plpgsql; - --- Utility Function: Wraps a value in expanded JSON-LD --- 'a'::text becomes '[{"@value": "a"}]'::jsonb -create - or replace function pg_temp.jsonld_value(value text) returns jsonb as -$$ -begin - return jsonb_build_array(jsonb_build_object('@value', to_jsonb(value))); -end; -$$ - language plpgsql; - --- Utility Function: base64 encode -create - or replace function pg_temp.base64encode(str text) returns text as -$$ -begin - return encode(str::bytea, 'base64'); -end; -$$ - language plpgsql; - --- Utility Function: replaceSuffix -create - or replace function pg_temp.replace_suffix(str text, old_suffix text, new_suffix text) returns text as -$$ -begin - return case - when pg_temp.ends_with(str, old_suffix) then - left(str, length(str) - length(old_suffix)) || new_suffix - else - str - end; -end; -$$ - language plpgsql; - --- Utility Function: endsWith -create or replace function pg_temp.ends_with(str text, suffix text) - returns boolean as -$$ -begin - return right(str, length(suffix)) = suffix; -end; -$$ language plpgsql; - --- Utility Function: startsWith -create or replace function pg_temp.starts_with(str text, prefix text) - returns boolean as -$$ -begin - return left(str, length(prefix)) = prefix; -end; -$$ language plpgsql; - --- Asset IDs -alter table edc_asset_dataaddress - drop constraint edc_asset_dataaddress_asset_id_fk_fkey; -alter table edc_asset_property - drop constraint edc_asset_property_asset_id_fk_fkey; -update edc_asset -set asset_id = pg_temp.migrate_asset_id(asset_id); -update edc_asset_dataaddress -set asset_id_fk = pg_temp.migrate_asset_id(asset_id_fk); -update edc_asset_property -set asset_id_fk = pg_temp.migrate_asset_id(asset_id_fk); -update edc_contract_agreement -set asset_id = pg_temp.migrate_asset_id(asset_id); -update edc_data_request -set asset_id = pg_temp.migrate_asset_id(asset_id); -alter table edc_asset_dataaddress - add constraint edc_asset_dataaddress_asset_id_fk_fkey foreign key (asset_id_fk) references edc_asset (asset_id) on delete cascade; -alter table edc_asset_property - add constraint edc_asset_property_asset_id_fk_fkey foreign key (asset_id_fk) references edc_asset (asset_id) on delete cascade; - --- Contract Agreement IDs -alter table edc_contract_negotiation - drop constraint contract_negotiation_contract_agreement_id_fk; -update edc_contract_negotiation -set agreement_id = pg_temp.migrate_contract_agreement_id(agreement_id, - pg_temp.migrate_asset_id(contract_offers -> 0 -> 'asset' ->> 'id')); -update edc_contract_agreement -set agr_id = pg_temp.migrate_contract_agreement_id(agr_id, asset_id); -update edc_data_request -set contract_id = pg_temp.migrate_contract_agreement_id(contract_id, asset_id); -alter table edc_contract_negotiation - add constraint contract_negotiation_contract_agreement_id_fk foreign key (agreement_id) references edc_contract_agreement (agr_id); - --- Protocol -update edc_contract_negotiation -set protocol = 'dataspace-protocol-http'; - --- Connector Endpoints -update edc_contract_negotiation -set counterparty_address = pg_temp.migrate_connector_endpoint(counterparty_address); -update edc_data_request -set connector_address = pg_temp.migrate_connector_endpoint(connector_address); - - --- Participant IDs -update edc_data_request -set connector_id = pg_temp.migrate_participant_id(connector_id); -update edc_contract_agreement -set provider_agent_id = pg_temp.migrate_participant_id(provider_agent_id), - consumer_agent_id = pg_temp.migrate_participant_id(consumer_agent_id); - --- Asset Properties -alter table edc_asset_property - add column property_is_private boolean; -delete -from edc_asset_property legacy_prop -where legacy_prop.property_name = 'asset:prop:originator'; -delete -from edc_asset_property legacy_prop -where legacy_prop.property_name = 'asset:prop:originatorOrganization' - and exists(select 1 - from edc_asset_property newer_prop - where legacy_prop.asset_id_fk = newer_prop.asset_id_fk - and newer_prop.property_name = 'asset:prop:curatorOrganizationName'); -- prevents errors from merging the legacy properties -update edc_asset_property -set property_name = pg_temp.migrate_asset_property(property_name, property_value, property_type) ->> 'name', - property_value = pg_temp.migrate_asset_property(property_name, property_value, property_type) ->> 'value', - property_type = pg_temp.migrate_asset_property(property_name, property_value, property_type) ->> 'type'; - --- Contract Negotiation Type -alter table edc_contract_negotiation - drop constraint provider_correlation_id; -alter table edc_contract_negotiation - add column "type_new" text; -update edc_contract_negotiation -set "type_new" = case "type" when 1 then 'PROVIDER' else 'CONSUMER' end; -alter table edc_contract_negotiation - drop column "type"; -alter table edc_contract_negotiation - rename column "type_new" to "type"; -alter table edc_contract_negotiation - add constraint provider_correlation_id check (type = 'CONSUMER' OR correlation_id IS NOT NULL); - --- Contract Negotiation Contract Offers -update edc_contract_negotiation -set contract_offers = pg_temp.migrate_negotiation_contract_offers(contract_offers::jsonb)::json; - --- Contract Definitions Asset Selector -alter table edc_contract_definitions - rename column selector_expression to assets_selector; -with cd_updated as (select cd.contract_definition_id, - jsonb_agg(pg_temp.migrate_criterion(criterion))::json as asset_selector - from edc_contract_definitions cd, - jsonb_array_elements(cd.assets_selector::jsonb -> 'criteria') criterion - group by cd.contract_definition_id) -update edc_contract_definitions cd -set assets_selector = cd_updated.asset_selector -from cd_updated -where cd_updated.contract_definition_id = cd.contract_definition_id; - --- Fix transfer processes stuck in running state -update edc_transfer_process -set state = 800 -where state = 600; - --- Other DDL Changes -alter table edc_contract_negotiation - add column callback_addresses json; -alter table edc_contract_negotiation - add column pending boolean default false; -alter table edc_transfer_process - add column pending boolean default false; -alter table edc_transfer_process - add column callback_addresses json; - -alter table edc_transfer_process - rename column transferprocess_properties to private_properties; - -alter table edc_contract_definitions - drop column validity; -alter table edc_data_request - drop column if exists managed_resources; -alter table edc_data_request - drop column if exists properties; -alter table edc_data_request - drop column if exists transfer_type; diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V4__MS8-to-0.2.1_bugfixes.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V4__MS8-to-0.2.1_bugfixes.sql deleted file mode 100644 index ee64152ba..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V4__MS8-to-0.2.1_bugfixes.sql +++ /dev/null @@ -1,48 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables From MS8 to 0.1.0 EDC --- --- - --- Migrates a Participant ID to EDC 0 -create - or replace function pg_temp.migrate_participant_id(asset_id text) returns text as -$$ -begin - return replace(replace(asset_id::text, 'urn:connector:', ''), ':', '-'); -end; -$$ - language plpgsql; - --- Participant IDs -update edc_contract_negotiation -set counterparty_id = pg_temp.migrate_participant_id(counterparty_id); - -update edc_contract_agreement -set provider_agent_id = neg.counterparty_id -from edc_contract_negotiation neg -where neg.agreement_id = edc_contract_agreement.agr_id - and neg.type = 'CONSUMER'; - -update edc_contract_agreement -set consumer_agent_id = neg.counterparty_id -from edc_contract_negotiation neg -where neg.agreement_id = edc_contract_agreement.agr_id - and neg.type = 'PROVIDER'; - --- Optimizations for Transfer Processes -create index transfer_process_status - on edc_transfer_process (state); - --- Fix transfer processes stuck in running state -update edc_transfer_process -set state = 800 -where state = 600; diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V5__Mobility_DCAT_Mapping.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V5__Mobility_DCAT_Mapping.sql deleted file mode 100644 index 64a9ed66c..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V5__Mobility_DCAT_Mapping.sql +++ /dev/null @@ -1,76 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - SQL Script --- --- - - --- "http://www.w3.org/ns/dcat#distribution": { --- "http://www.w3.org/ns/dcat#mediaType": "previously http://www.w3.org/ns/dcat#mediaType", --- "https://w3id.org/mobilitydcat-ap/mobilityDataStandard": { --- "@id": "previously http://w3id.org/mds#dataModel" --- } --- }, -with data as ( - select asset_id, - (select property_value from edc_asset_property p where p.property_name = 'http://www.w3.org/ns/dcat#mediaType' and p.asset_id_fk = a.asset_id) as media_type, - (select property_value from edc_asset_property p where p.property_name = 'http://w3id.org/mds#dataModel' and p.asset_id_fk = a.asset_id) as data_model - from edc_asset a -) -insert into edc_asset_property (asset_id_fk, property_name, property_type, property_value) ( - select asset_id, - 'http://www.w3.org/ns/dcat#distribution', - 'java.util.LinkedHashMap', - jsonb_build_object( - 'http://www.w3.org/ns/dcat#mediaType', media_type, - 'https://w3id.org/mobilitydcat-ap/mobilityDataStandard', jsonb_build_object('@id', data_model) - )::text - from data - where media_type is not null or data_model is not null -); -delete from edc_asset_property where property_name = 'http://www.w3.org/ns/dcat#mediaType'; -delete from edc_asset_property where property_name = 'http://w3id.org/mds#dataModel'; - - --- "https://w3id.org/mobilitydcat-ap/mobilityTheme": { --- "https://w3id.org/mobilitydcat-ap/mobility-theme/data-content-category": "previously http://w3id.org/mds#dataCategory", --- "https://w3id.org/mobilitydcat-ap/mobility-theme/data-content-sub-category": "previously http://w3id.org/mds#dataSubcategory" --- }, -with data as ( - select asset_id, - (select property_value from edc_asset_property p where p.property_name = 'http://w3id.org/mds#dataCategory' and p.asset_id_fk = a.asset_id) as data_category, - (select property_value from edc_asset_property p where p.property_name = 'http://w3id.org/mds#dataSubcategory' and p.asset_id_fk = a.asset_id) as data_subcategory - from edc_asset a -) -insert into edc_asset_property (asset_id_fk, property_name, property_type, property_value) ( - select asset_id, - 'https://w3id.org/mobilitydcat-ap/mobilityTheme', - 'java.util.LinkedHashMap', - jsonb_build_object( - 'https://w3id.org/mobilitydcat-ap/mobility-theme/data-content-category', data_category, - 'https://w3id.org/mobilitydcat-ap/mobility-theme/data-content-sub-category', data_subcategory - )::text - from data - where data_category is not null or data_subcategory is not null -); -delete from edc_asset_property where property_name = 'http://w3id.org/mds#dataCategory'; -delete from edc_asset_property where property_name = 'http://w3id.org/mds#dataSubcategory'; - - --- "https://w3id.org/mobilitydcat-ap/georeferencingMethod": "previously http://w3id.org/mds#geoReferenceMethod", -update edc_asset_property -set property_name = 'https://w3id.org/mobilitydcat-ap/georeferencingMethod' -where property_name = 'http://w3id.org/mds#geoReferenceMethod'; - --- "https://w3id.org/mobilitydcat-ap/transportMode": "previously http://w3id.org/mds#transportMode" -update edc_asset_property -set property_name = 'https://w3id.org/mobilitydcat-ap/transportMode' -where property_name = 'http://w3id.org/mds#transportMode'; diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V6__Fix_DataModel_ID_Field.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V6__Fix_DataModel_ID_Field.sql deleted file mode 100644 index f8b0f7f98..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V6__Fix_DataModel_ID_Field.sql +++ /dev/null @@ -1,63 +0,0 @@ --- --- Copyright (c) 2024 sovity GmbH --- --- 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: --- sovity GmbH - SQL Script --- --- - -create - or replace function pg_temp.migrate_distribution(distribution jsonb) returns jsonb as -$$ -declare - data_standard jsonb; - data_standard_path text[]; -begin - data_standard_path := '{https://w3id.org/mobilitydcat-ap/mobilityDataStandard}'; - data_standard := distribution #> data_standard_path; - - if jsonb_typeof(data_standard) = 'object' then - data_standard := pg_temp.migrate_mobility_data_standard(data_standard); - elsif jsonb_typeof(data_standard) = 'array' then - data_standard := (select jsonb_agg(pg_temp.migrate_mobility_data_standard(it)) - from jsonb_array_elements(data_standard) as it); - end if; - - return jsonb_set(distribution, data_standard_path, data_standard, true); -end; -$$ language plpgsql; - - -create - or replace function pg_temp.migrate_mobility_data_standard(data_standard jsonb) returns jsonb as -$$ -begin - return pg_temp.remove_if_blank(data_standard, '{@id}'); -end; -$$ language plpgsql; - - -create - or replace function pg_temp.remove_if_blank(obj jsonb, path text[]) returns jsonb as -$$ -declare - value text; -begin - value := obj #>> path; - if value is null or trim(value) = '' then - obj := obj #- path; - end if; - return obj; -end; -$$ language plpgsql; - - -update edc_asset_property -set property_value = pg_temp.migrate_distribution(property_value::jsonb)::text -where property_name = 'http://www.w3.org/ns/dcat#distribution'; diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V7__last_legacy_migration_do_not_continue_here.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V7__last_legacy_migration_do_not_continue_here.sql deleted file mode 100644 index f86d034a1..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/default/V7__last_legacy_migration_do_not_continue_here.sql +++ /dev/null @@ -1,3 +0,0 @@ --- Do not add any more migration in this folder structure. --- These are legacy migrations and any new migration must be placed in the `db/migration` folder. --- See the README in `resources/db`. diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/policy/V0_0_1__Policy_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/policy/V0_0_1__Policy_Schema.sql deleted file mode 100644 index 87199a519..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/policy/V0_0_1__Policy_Schema.sql +++ /dev/null @@ -1,39 +0,0 @@ --- --- Copyright (c) 2022 ZF Friedrichshafen 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: --- ZF Friedrichshafen AG - Initial SQL Query --- - --- Statements are designed for and tested with Postgres only! - --- table: edc_policydefinitions -CREATE TABLE IF NOT EXISTS edc_policydefinitions -( - policy_id VARCHAR NOT NULL, - permissions JSON, - prohibitions JSON, - duties JSON, - extensible_properties JSON, - inherits_from VARCHAR, - assigner VARCHAR, - assignee VARCHAR, - target VARCHAR, - policy_type VARCHAR NOT NULL, - PRIMARY KEY (policy_id) -); - -COMMENT ON COLUMN edc_policydefinitions.permissions IS 'Java List serialized as JSON'; -COMMENT ON COLUMN edc_policydefinitions.prohibitions IS 'Java List serialized as JSON'; -COMMENT ON COLUMN edc_policydefinitions.duties IS 'Java List serialized as JSON'; -COMMENT ON COLUMN edc_policydefinitions.extensible_properties IS 'Java Map serialized as JSON'; -COMMENT ON COLUMN edc_policydefinitions.policy_type IS 'Java PolicyType serialized as JSON'; - -CREATE UNIQUE INDEX IF NOT EXISTS edc_policydefinitions_id_uindex - ON edc_policydefinitions (policy_id); diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/policy/V0_0_2__Policy_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/policy/V0_0_2__Policy_Schema.sql deleted file mode 100644 index e6dcb8266..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/policy/V0_0_2__Policy_Schema.sql +++ /dev/null @@ -1,20 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-7 EDC --- --- -ALTER TABLE edc_policydefinitions - ADD created_at BIGINT; - -UPDATE edc_policydefinitions SET created_at=EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000; - -ALTER TABLE edc_policydefinitions - ALTER COLUMN created_at SET NOT NULL; diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/transferprocess/V0_0_1__TransferProcess_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/transferprocess/V0_0_1__TransferProcess_Schema.sql deleted file mode 100644 index a5764deaf..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/transferprocess/V0_0_1__TransferProcess_Schema.sql +++ /dev/null @@ -1,86 +0,0 @@ --- Statements are designed for and tested with Postgres only! - -CREATE TABLE IF NOT EXISTS edc_lease -( - leased_by VARCHAR NOT NULL, - leased_at BIGINT, - lease_duration INTEGER NOT NULL, - lease_id VARCHAR NOT NULL - CONSTRAINT lease_pk - PRIMARY KEY -); - -COMMENT ON COLUMN edc_lease.leased_at IS 'posix timestamp of lease'; - -COMMENT ON COLUMN edc_lease.lease_duration IS 'duration of lease in milliseconds'; - -CREATE TABLE IF NOT EXISTS edc_transfer_process -( - transferprocess_id VARCHAR NOT NULL - CONSTRAINT transfer_process_pk - PRIMARY KEY, - type VARCHAR NOT NULL, - state INTEGER NOT NULL, - state_count INTEGER DEFAULT 0 NOT NULL, - state_time_stamp BIGINT, - created_time_stamp BIGINT, - trace_context JSON, - error_detail VARCHAR, - resource_manifest JSON, - provisioned_resource_set JSON, - content_data_address JSON, - deprovisioned_resources JSON, - lease_id VARCHAR - CONSTRAINT transfer_process_lease_lease_id_fk - REFERENCES edc_lease - ON DELETE SET NULL -); - -COMMENT ON COLUMN edc_transfer_process.trace_context IS 'Java Map serialized as JSON'; - -COMMENT ON COLUMN edc_transfer_process.resource_manifest IS 'java ResourceManifest serialized as JSON'; - -COMMENT ON COLUMN edc_transfer_process.provisioned_resource_set IS 'ProvisionedResourceSet serialized as JSON'; - -COMMENT ON COLUMN edc_transfer_process.content_data_address IS 'DataAddress serialized as JSON'; - -COMMENT ON COLUMN edc_transfer_process.deprovisioned_resources IS 'List of deprovisioned resources, serialized as JSON'; - - -CREATE UNIQUE INDEX IF NOT EXISTS transfer_process_id_uindex - ON edc_transfer_process (transferprocess_id); - -CREATE TABLE IF NOT EXISTS edc_data_request -( - datarequest_id VARCHAR NOT NULL - CONSTRAINT data_request_pk - PRIMARY KEY, - process_id VARCHAR NOT NULL, - connector_address VARCHAR NOT NULL, - protocol VARCHAR NOT NULL, - connector_id VARCHAR, - asset_id VARCHAR NOT NULL, - contract_id VARCHAR NOT NULL, - data_destination JSON NOT NULL, - managed_resources BOOLEAN DEFAULT TRUE, - properties JSON, - transfer_type JSON, - transfer_process_id VARCHAR NOT NULL - CONSTRAINT data_request_transfer_process_id_fk - REFERENCES edc_transfer_process - ON UPDATE RESTRICT ON DELETE CASCADE -); - -COMMENT ON COLUMN edc_data_request.data_destination IS 'DataAddress serialized as JSON'; - -COMMENT ON COLUMN edc_data_request.properties IS 'java Map serialized as JSON'; - -COMMENT ON COLUMN edc_data_request.transfer_type IS 'TransferType serialized as JSON'; - - -CREATE UNIQUE INDEX IF NOT EXISTS data_request_id_uindex - ON edc_data_request (datarequest_id); - -CREATE UNIQUE INDEX IF NOT EXISTS lease_lease_id_uindex - ON edc_lease (lease_id); - diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/transferprocess/V0_0_2__TransferProcess_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/transferprocess/V0_0_2__TransferProcess_Schema.sql deleted file mode 100644 index db875a04c..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/transferprocess/V0_0_2__TransferProcess_Schema.sql +++ /dev/null @@ -1,28 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-7 EDC --- --- - -ALTER TABLE edc_transfer_process - RENAME COLUMN created_time_stamp TO created_at; - -UPDATE edc_transfer_process - SET created_at = EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000 - WHERE created_at = NULL; - -ALTER TABLE edc_transfer_process - ADD updated_at BIGINT; - -UPDATE edc_transfer_process SET updated_at=created_at; - -ALTER TABLE edc_transfer_process ALTER COLUMN updated_at SET NOT NULL; -ALTER TABLE edc_transfer_process ALTER COLUMN created_at SET NOT NULL; diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/transferprocess/V0_0_3__TransferProcess_Schema.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/transferprocess/V0_0_3__TransferProcess_Schema.sql deleted file mode 100644 index cd2d45af7..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/transferprocess/V0_0_3__TransferProcess_Schema.sql +++ /dev/null @@ -1,14 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-8 EDC --- --- -ALTER TABLE edc_transfer_process ADD transferprocess_properties JSON; diff --git a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/transferprocess/V0_0_4__Set_Default_Properties.sql b/extensions/postgres-flyway/src/main/resources/db/legacy/migration/transferprocess/V0_0_4__Set_Default_Properties.sql deleted file mode 100644 index 41402c7f6..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/legacy/migration/transferprocess/V0_0_4__Set_Default_Properties.sql +++ /dev/null @@ -1,14 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-8 EDC --- --- -UPDATE edc_transfer_process SET transferprocess_properties = '{}'::json WHERE transferprocess_properties IS NULL; diff --git a/extensions/postgres-flyway/src/main/resources/db/migration/V10__add_contract_termination.sql b/extensions/postgres-flyway/src/main/resources/db/migration/V10__add_contract_termination.sql deleted file mode 100644 index 24c8c3d88..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/migration/V10__add_contract_termination.sql +++ /dev/null @@ -1,25 +0,0 @@ --- --- Copyright (c) 2024 sovity GmbH --- --- 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: --- sovity GmbH - initial API and implementation --- - -create type contract_terminated_by as enum ('SELF', 'COUNTERPARTY'); - -create table sovity_contract_termination -( - contract_agreement_id varchar primary key, - reason text not null, - detail text not null, - terminated_at timestamp with time zone not null, - terminated_by contract_terminated_by not null, - constraint agreement_fk foreign key (contract_agreement_id) - references edc_contract_agreement (agr_id) -); diff --git a/extensions/postgres-flyway/src/main/resources/db/migration/V11_0_0_0__baseline.sql b/extensions/postgres-flyway/src/main/resources/db/migration/V11_0_0_0__baseline.sql new file mode 100644 index 000000000..3ecfc62fb --- /dev/null +++ b/extensions/postgres-flyway/src/main/resources/db/migration/V11_0_0_0__baseline.sql @@ -0,0 +1,439 @@ +-- Aggregated baseline from the Eclipse Dataspace Connector V0.7.2 + +--- + +-- extensions/common/store/sql/edr-index-sql/docs/schema.sql +create table edc_edr_entry +( + transfer_process_id VARCHAR not null primary key, + agreement_id VARCHAR not null, + asset_id VARCHAR not null, + provider_id VARCHAR not null, + contract_negotiation_id VARCHAR, + created_at BIGINT not null +); + +--- + +-- extensions/control-plane/store/sql/contract-negotiation-store-sql/docs/schema.sql +-- Statements are designed for and tested with Postgres only! + +create table edc_lease +( + leased_by VARCHAR not null, + leased_at BIGINT, + lease_duration INTEGER not null, + lease_id VARCHAR not null + constraint lease_pk + primary key +); + +comment on column edc_lease.leased_at is 'posix timestamp of lease'; + +comment on column edc_lease.lease_duration is 'duration of lease in milliseconds'; + + + +create table edc_contract_agreement +( + agr_id VARCHAR not null + constraint contract_agreement_pk + primary key, + provider_agent_id VARCHAR, + consumer_agent_id VARCHAR, + signing_date BIGINT, + start_date BIGINT, + end_date INTEGER, + asset_id VARCHAR not null, + policy JSON +); + + +create table edc_contract_negotiation +( + id VARCHAR not null + constraint contract_negotiation_pk + primary key, + created_at BIGINT not null, + updated_at BIGINT not null, + correlation_id VARCHAR, + counterparty_id VARCHAR not null, + counterparty_address VARCHAR not null, + protocol VARCHAR not null, + type VARCHAR not null, + state INTEGER default 0 not null, + state_count INTEGER default 0, + state_timestamp BIGINT, + error_detail VARCHAR, + agreement_id VARCHAR + constraint contract_negotiation_contract_agreement_id_fk + references edc_contract_agreement, + contract_offers JSON, + callback_addresses JSON, + trace_context JSON, + pending BOOLEAN default false, + protocol_messages JSON, + lease_id VARCHAR + constraint contract_negotiation_lease_lease_id_fk + references edc_lease + on delete set null +); + +comment on column edc_contract_negotiation.agreement_id is 'ContractAgreement serialized as JSON'; + +comment on column edc_contract_negotiation.contract_offers is 'List serialized as JSON'; + +comment on column edc_contract_negotiation.trace_context is 'Map serialized as JSON'; + + +create index contract_negotiation_correlationid_index + on edc_contract_negotiation (correlation_id); + + +-- This will help to identify states that need to be transitioned without a table scan when the entries grow +create index contract_negotiation_state on edc_contract_negotiation (state, state_timestamp); + +--- + +-- extensions/control-plane/store/sql/transfer-process-store-sql/docs/schema.sql +-- Statements are designed for and tested with Postgres only! + +comment on column edc_lease.leased_at is 'posix timestamp of lease'; + +comment on column edc_lease.lease_duration is 'duration of lease in milliseconds'; + +create table edc_transfer_process +( + transferprocess_id VARCHAR not null + constraint transfer_process_pk + primary key, + type VARCHAR not null, + state INTEGER not null, + state_count INTEGER default 0 not null, + state_time_stamp BIGINT, + created_at BIGINT not null, + updated_at BIGINT not null, + trace_context JSON, + error_detail VARCHAR, + resource_manifest JSON, + provisioned_resource_set JSON, + content_data_address JSON, + deprovisioned_resources JSON, + private_properties JSON, + callback_addresses JSON, + pending BOOLEAN default false, + transfer_type VARCHAR, + protocol_messages JSON, + data_plane_id VARCHAR, + correlation_id VARCHAR, + counter_party_address VARCHAR, + protocol VARCHAR, + asset_id VARCHAR, + contract_id VARCHAR, + data_destination JSON, + lease_id VARCHAR + constraint transfer_process_lease_lease_id_fk + references edc_lease + on delete set null +); + +comment on column edc_transfer_process.trace_context is 'Java Map serialized as JSON'; + +comment on column edc_transfer_process.resource_manifest is 'java ResourceManifest serialized as JSON'; + +comment on column edc_transfer_process.provisioned_resource_set is 'ProvisionedResourceSet serialized as JSON'; + +comment on column edc_transfer_process.content_data_address is 'DataAddress serialized as JSON'; + +comment on column edc_transfer_process.deprovisioned_resources is 'List of deprovisioned resources, serialized as JSON'; + + +create unique index transfer_process_id_uindex + on edc_transfer_process (transferprocess_id); + + +-- This will help to identify states that need to be transitioned without a table scan when the entries grow +create index transfer_process_state on edc_transfer_process (state, state_time_stamp); + +--- + +-- extensions/data-plane-selector/store/sql/data-plane-instance-store-sql/docs/schema.sq + + +create table edc_data_plane_instance +( + id VARCHAR not null primary key, + data JSON, + lease_id VARCHAR + constraint data_plane_instance_lease_id_fk + references edc_lease + on delete set null +); + +--- + +-- extensions/data-plane/store/sql/accesstokendata-store-sql/docs/schema.sql +/* + * Copyright (c) 2024 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 + * + */ + +-- Statements are designed for and tested with Postgres only! + +create table edc_accesstokendata +( + id VARCHAR not null primary key, + claim_token JSON not null, + data_address JSON not null, + additional_properties JSON default '{}' +); + +comment on column edc_accesstokendata.claim_token is 'ClaimToken serialized as JSON map'; +comment on column edc_accesstokendata.data_address is 'DataAddress serialized as JSON map'; +comment on column edc_accesstokendata.additional_properties is 'Optional Additional properties serialized as JSON map'; + +--- + +-- extensions/data-plane/store/sql/data-plane-store-sql/docs/schema.sql +-- Statements are designed for and tested with Postgres only! + +comment on column edc_lease.leased_at is 'posix timestamp of lease'; +comment on column edc_lease.lease_duration is 'duration of lease in milliseconds'; + +create table edc_data_plane +( + process_id VARCHAR not null primary key, + state INTEGER not null, + created_at BIGINT not null, + updated_at BIGINT not null, + state_count INTEGER default 0 not null, + state_time_stamp BIGINT, + trace_context JSON, + error_detail VARCHAR, + callback_address VARCHAR, + lease_id VARCHAR + constraint data_plane_lease_lease_id_fk + references edc_lease + on delete set null, + source JSON, + destination JSON, + properties JSON, + flow_type VARCHAR +); + +comment on column edc_data_plane.trace_context is 'Java Map serialized as JSON'; +comment on column edc_data_plane.source is 'DataAddress serialized as JSON'; +comment on column edc_data_plane.destination is 'DataAddress serialized as JSON'; +comment on column edc_data_plane.properties is 'Java Map serialized as JSON'; + +-- This will help to identify states that need to be transitioned without a table scan when the entries grow +create index data_plane_state on edc_data_plane (state, state_time_stamp); + +--- + +-- extensions/policy-monitor/store/sql/policy-monitor-store-sql/docs/schema.sql +-- Statements are designed for and tested with Postgres only! + +comment on column edc_lease.leased_at is 'posix timestamp of lease'; +comment on column edc_lease.lease_duration is 'duration of lease in milliseconds'; + +create table edc_policy_monitor +( + entry_id VARCHAR not null primary key, + state INTEGER not null, + created_at BIGINT not null, + updated_at BIGINT not null, + state_count INTEGER default 0 not null, + state_time_stamp BIGINT, + trace_context JSON, + error_detail VARCHAR, + lease_id VARCHAR + constraint policy_monitor_lease_lease_id_fk + references edc_lease + on delete set null, + properties JSON, + contract_id VARCHAR +); + + +-- This will help to identify states that need to be transitioned without a table scan when the entries grow +create index policy_monitor_state on edc_policy_monitor (state, state_time_stamp); + +--- + +-- extensions/common/sql/sql-lease/src/test/resources/schema.sql +-- Statements are designed for and tested with Postgres only! + +comment on column edc_lease.leased_at is 'posix timestamp of lease'; + +comment on column edc_lease.lease_duration is 'duration of lease in milliseconds'; + + +-- test entity +create table edc_test_entity +( + id VARCHAR not null + constraint test_id_pk primary key, + lease_id VARCHAR + constraint test_entity_lease_id_fk + references edc_lease + on delete set null +); + +create unique index test_entity_id_uindex + on edc_test_entity (id); + +--- + +-- extensions/control-plane/store/sql/asset-index-sql/docs/schema.sql +-- +-- Copyright (c) 2022 - 2023 Daimler TSS GmbH +-- +-- 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: +-- Daimler TSS GmbH - Initial SQL Query +-- Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - improvements +-- + +-- THIS SCHEMA HAS BEEN WRITTEN AND TESTED ONLY FOR POSTGRES + +-- table: edc_asset +create table edc_asset +( + asset_id VARCHAR not null, + created_at BIGINT not null, + properties JSON default '{}', + private_properties JSON default '{}', + data_address JSON default '{}', + primary key (asset_id) +); + +comment on column edc_asset.properties is 'Asset properties serialized as JSON'; +comment on column edc_asset.private_properties is 'Asset private properties serialized as JSON'; +comment on column edc_asset.data_address is 'Asset DataAddress serialized as JSON'; + + +--- + +-- extensions/control-plane/store/sql/contract-definition-store-sql/docs/schema.sql +-- +-- Copyright (c) 2022 Daimler TSS GmbH +-- +-- 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: +-- Daimler TSS GmbH - Initial SQL Query +-- Microsoft Corporation - refactoring +-- SAP SE - add private properties to contract definition +-- + +-- table: edc_contract_definitions +-- only intended for and tested with H2 and Postgres! +create table edc_contract_definitions +( + created_at BIGINT not null, + contract_definition_id VARCHAR not null, + access_policy_id VARCHAR not null, + contract_policy_id VARCHAR not null, + assets_selector JSON not null, + private_properties JSON, + primary key (contract_definition_id) +); + +--- + +-- extensions/control-plane/store/sql/policy-definition-store-sql/docs/schema.sql +-- +-- Copyright (c) 2022 ZF Friedrichshafen 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: +-- ZF Friedrichshafen AG - Initial SQL Query +-- + +-- Statements are designed for and tested with Postgres only! + +-- table: edc_policydefinitions +create table if not exists edc_policydefinitions +( + policy_id VARCHAR not null, + created_at BIGINT not null, + permissions JSON, + prohibitions JSON, + duties JSON, + extensible_properties JSON, + inherits_from VARCHAR, + assigner VARCHAR, + assignee VARCHAR, + target VARCHAR, + policy_type VARCHAR not null, + private_properties JSON, + primary key (policy_id) +); + +comment on column edc_policydefinitions.permissions is 'Java List serialized as JSON'; +comment on column edc_policydefinitions.prohibitions is 'Java List serialized as JSON'; +comment on column edc_policydefinitions.duties is 'Java List serialized as JSON'; +comment on column edc_policydefinitions.extensible_properties is 'Java Map serialized as JSON'; +comment on column edc_policydefinitions.policy_type is 'Java PolicyType serialized as JSON'; + +create unique index if not exists edc_policydefinitions_id_uindex + on edc_policydefinitions (policy_id); + +--- + +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +-- sovity + +create type contract_terminated_by as enum ('SELF', 'COUNTERPARTY'); + +create table sovity_contract_termination +( + contract_agreement_id varchar primary key, + reason text not null, + detail text not null, + terminated_at timestamp with time zone not null, + terminated_by contract_terminated_by not null, + constraint agreement_fk foreign key (contract_agreement_id) + references edc_contract_agreement (agr_id) +); + +-- Drop the duplicate indexes if they exist for improved resource usage. +drop index if exists edc_policydefinitions_id_uindex; +drop index if exists transfer_process_id_uindex; diff --git a/extensions/postgres-flyway/src/main/resources/db/migration/V11__migrate_always_true_policy.sql b/extensions/postgres-flyway/src/main/resources/db/migration/V11__migrate_always_true_policy.sql deleted file mode 100644 index 1b24d14ea..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/migration/V11__migrate_always_true_policy.sql +++ /dev/null @@ -1,19 +0,0 @@ --- --- Copyright (c) 2024 sovity GmbH --- --- 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: --- sovity GmbH - initial API and implementation --- - -update edc_policydefinitions -set permissions = jsonb_set( - permissions::jsonb, - '{0,constraints}', - '[]'::jsonb)::json -where policy_id = 'always-true'; diff --git a/extensions/postgres-flyway/src/main/resources/db/migration/V12__DROP_duplicate_indices.sql b/extensions/postgres-flyway/src/main/resources/db/migration/V12__DROP_duplicate_indices.sql deleted file mode 100644 index e1a8f3d46..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/migration/V12__DROP_duplicate_indices.sql +++ /dev/null @@ -1,21 +0,0 @@ --- --- Copyright (c) 2024 sovity GmbH --- --- 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: --- sovity GmbH - Improve database performance by removing duplicate indices --- - --- Drop the duplicate indexes if they exist for improved resource usage. -DROP INDEX IF EXISTS contract_agreement_id_uindex; -DROP INDEX IF EXISTS contract_negotiation_id_uindex; -DROP INDEX IF EXISTS data_request_id_uindex; -DROP INDEX IF EXISTS lease_lease_id_uindex; -DROP INDEX IF EXISTS edc_policydefinitions_id_uindex; -DROP INDEX IF EXISTS transfer_process_id_uindex; - diff --git a/extensions/postgres-flyway/src/main/resources/db/migration/V1__MS8.sql b/extensions/postgres-flyway/src/main/resources/db/migration/V1__MS8.sql deleted file mode 100644 index e916c5e30..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/migration/V1__MS8.sql +++ /dev/null @@ -1,505 +0,0 @@ --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - initial API and implementation for DataplaneInstances --- --- -CREATE TABLE IF NOT EXISTS edc_data_plane_instance -( - id VARCHAR NOT NULL, - data JSON NOT NULL, - PRIMARY KEY (id) -); --- Statements are designed for and tested with Postgres only! - -CREATE TABLE IF NOT EXISTS edc_lease -( - leased_by VARCHAR NOT NULL, - leased_at BIGINT, - lease_duration INTEGER NOT NULL, - lease_id VARCHAR NOT NULL - CONSTRAINT lease_pk - PRIMARY KEY -); - -COMMENT ON COLUMN edc_lease.leased_at IS 'posix timestamp of lease'; - -COMMENT ON COLUMN edc_lease.lease_duration IS 'duration of lease in milliseconds'; - -CREATE TABLE IF NOT EXISTS edc_transfer_process -( - transferprocess_id VARCHAR NOT NULL - CONSTRAINT transfer_process_pk - PRIMARY KEY, - type VARCHAR NOT NULL, - state INTEGER NOT NULL, - state_count INTEGER DEFAULT 0 NOT NULL, - state_time_stamp BIGINT, - created_time_stamp BIGINT, - trace_context JSON, - error_detail VARCHAR, - resource_manifest JSON, - provisioned_resource_set JSON, - content_data_address JSON, - deprovisioned_resources JSON, - lease_id VARCHAR - CONSTRAINT transfer_process_lease_lease_id_fk - REFERENCES edc_lease - ON DELETE SET NULL -); - -COMMENT ON COLUMN edc_transfer_process.trace_context IS 'Java Map serialized as JSON'; - -COMMENT ON COLUMN edc_transfer_process.resource_manifest IS 'java ResourceManifest serialized as JSON'; - -COMMENT ON COLUMN edc_transfer_process.provisioned_resource_set IS 'ProvisionedResourceSet serialized as JSON'; - -COMMENT ON COLUMN edc_transfer_process.content_data_address IS 'DataAddress serialized as JSON'; - -COMMENT ON COLUMN edc_transfer_process.deprovisioned_resources IS 'List of deprovisioned resources, serialized as JSON'; - - -CREATE UNIQUE INDEX IF NOT EXISTS transfer_process_id_uindex - ON edc_transfer_process (transferprocess_id); - -CREATE TABLE IF NOT EXISTS edc_data_request -( - datarequest_id VARCHAR NOT NULL - CONSTRAINT data_request_pk - PRIMARY KEY, - process_id VARCHAR NOT NULL, - connector_address VARCHAR NOT NULL, - protocol VARCHAR NOT NULL, - connector_id VARCHAR, - asset_id VARCHAR NOT NULL, - contract_id VARCHAR NOT NULL, - data_destination JSON NOT NULL, - managed_resources BOOLEAN DEFAULT TRUE, - properties JSON, - transfer_type JSON, - transfer_process_id VARCHAR NOT NULL - CONSTRAINT data_request_transfer_process_id_fk - REFERENCES edc_transfer_process - ON UPDATE RESTRICT ON DELETE CASCADE -); - -COMMENT ON COLUMN edc_data_request.data_destination IS 'DataAddress serialized as JSON'; - -COMMENT ON COLUMN edc_data_request.properties IS 'java Map serialized as JSON'; - -COMMENT ON COLUMN edc_data_request.transfer_type IS 'TransferType serialized as JSON'; - - -CREATE UNIQUE INDEX IF NOT EXISTS data_request_id_uindex - ON edc_data_request (datarequest_id); - -CREATE UNIQUE INDEX IF NOT EXISTS lease_lease_id_uindex - ON edc_lease (lease_id); - --- Empty example migration --- This directory will contain all our Community Edition migrations in the future. --- Commercial Edition migrations will have to be compatible version-wise. --- This file is added to prevent flyway from crashing due no migrations. -SELECT 1; --- Statements are designed for and tested with Postgres only! - -CREATE TABLE IF NOT EXISTS edc_lease -( - leased_by VARCHAR NOT NULL, - leased_at BIGINT, - lease_duration INTEGER DEFAULT 60000 NOT NULL, - lease_id VARCHAR NOT NULL - CONSTRAINT lease_pk - PRIMARY KEY -); - -COMMENT ON COLUMN edc_lease.leased_at IS 'posix timestamp of lease'; - -COMMENT ON COLUMN edc_lease.lease_duration IS 'duration of lease in milliseconds'; - - -CREATE UNIQUE INDEX IF NOT EXISTS lease_lease_id_uindex - ON edc_lease (lease_id); - - - -CREATE TABLE IF NOT EXISTS edc_contract_agreement -( - agr_id VARCHAR NOT NULL - CONSTRAINT contract_agreement_pk - PRIMARY KEY, - provider_agent_id VARCHAR, - consumer_agent_id VARCHAR, - signing_date BIGINT, - start_date BIGINT, - end_date INTEGER, - asset_id VARCHAR NOT NULL, - policy JSON -); - - -CREATE TABLE IF NOT EXISTS edc_contract_negotiation -( - id VARCHAR NOT NULL - CONSTRAINT contract_negotiation_pk - PRIMARY KEY, - correlation_id VARCHAR, - counterparty_id VARCHAR NOT NULL, - counterparty_address VARCHAR NOT NULL, - protocol VARCHAR DEFAULT 'ids-multipart'::CHARACTER VARYING NOT NULL, - type INTEGER DEFAULT 0 NOT NULL, - state INTEGER DEFAULT 0 NOT NULL, - state_count INTEGER DEFAULT 0, - state_timestamp BIGINT, - error_detail VARCHAR, - agreement_id VARCHAR - CONSTRAINT contract_negotiation_contract_agreement_id_fk - REFERENCES edc_contract_agreement, - contract_offers JSON, - trace_context JSON, - lease_id VARCHAR - CONSTRAINT contract_negotiation_lease_lease_id_fk - REFERENCES edc_lease - ON DELETE SET NULL, - CONSTRAINT provider_correlation_id CHECK (type = '0' OR correlation_id IS NOT NULL) -); - -COMMENT ON COLUMN edc_contract_negotiation.agreement_id IS 'ContractAgreement serialized as JSON'; - -COMMENT ON COLUMN edc_contract_negotiation.contract_offers IS 'List serialized as JSON'; - -COMMENT ON COLUMN edc_contract_negotiation.trace_context IS 'Map serialized as JSON'; - - -CREATE INDEX IF NOT EXISTS contract_negotiation_correlationid_index - ON edc_contract_negotiation (correlation_id); - -CREATE UNIQUE INDEX IF NOT EXISTS contract_negotiation_id_uindex - ON edc_contract_negotiation (id); - -CREATE UNIQUE INDEX IF NOT EXISTS contract_agreement_id_uindex - ON edc_contract_agreement (agr_id);-- - --- --- Copyright (c) 2022 Daimler TSS GmbH --- --- 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: --- Daimler TSS GmbH - Initial SQL Query --- Microsoft Corporation - refactoring --- - --- table: edc_contract_definitions --- only intended for and tested with H2 and Postgres! -CREATE TABLE IF NOT EXISTS edc_contract_definitions -( - contract_definition_id VARCHAR NOT NULL, - access_policy_id VARCHAR NOT NULL, - contract_policy_id VARCHAR NOT NULL, - selector_expression JSON NOT NULL, - PRIMARY KEY (contract_definition_id) -); --- --- Copyright (c) 2022 ZF Friedrichshafen 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: --- ZF Friedrichshafen AG - Initial SQL Query --- - --- Statements are designed for and tested with Postgres only! - --- table: edc_policydefinitions -CREATE TABLE IF NOT EXISTS edc_policydefinitions -( - policy_id VARCHAR NOT NULL, - permissions JSON, - prohibitions JSON, - duties JSON, - extensible_properties JSON, - inherits_from VARCHAR, - assigner VARCHAR, - assignee VARCHAR, - target VARCHAR, - policy_type VARCHAR NOT NULL, - PRIMARY KEY (policy_id) -); - -COMMENT ON COLUMN edc_policydefinitions.permissions IS 'Java List serialized as JSON'; -COMMENT ON COLUMN edc_policydefinitions.prohibitions IS 'Java List serialized as JSON'; -COMMENT ON COLUMN edc_policydefinitions.duties IS 'Java List serialized as JSON'; -COMMENT ON COLUMN edc_policydefinitions.extensible_properties IS 'Java Map serialized as JSON'; -COMMENT ON COLUMN edc_policydefinitions.policy_type IS 'Java PolicyType serialized as JSON'; - -CREATE UNIQUE INDEX IF NOT EXISTS edc_policydefinitions_id_uindex - ON edc_policydefinitions (policy_id); --- --- Copyright (c) 2022 Daimler TSS GmbH --- --- 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: --- Daimler TSS GmbH - Initial SQL Query --- - --- THIS SCHEMA HAS BEEN WRITTEN AND TESTED ONLY FOR POSTGRES - --- table: edc_asset -CREATE TABLE IF NOT EXISTS edc_asset -( - asset_id VARCHAR NOT NULL, - PRIMARY KEY (asset_id) -); - --- table: edc_asset_dataaddress -CREATE TABLE IF NOT EXISTS edc_asset_dataaddress -( - asset_id_fk VARCHAR NOT NULL, - properties JSON NOT NULL, - PRIMARY KEY (asset_id_fk), - FOREIGN KEY (asset_id_fk) REFERENCES edc_asset (asset_id) ON DELETE CASCADE -); -COMMENT ON COLUMN edc_asset_dataaddress.properties IS 'DataAddress properties serialized as JSON'; - --- table: edc_asset_property -CREATE TABLE IF NOT EXISTS edc_asset_property -( - asset_id_fk VARCHAR NOT NULL, - property_name VARCHAR NOT NULL, - property_value VARCHAR NOT NULL, - property_type VARCHAR NOT NULL, - PRIMARY KEY (asset_id_fk, property_name), - FOREIGN KEY (asset_id_fk) REFERENCES edc_asset (asset_id) ON DELETE CASCADE -); - -COMMENT ON COLUMN edc_asset_property.property_name IS - 'Asset property key'; -COMMENT ON COLUMN edc_asset_property.property_value IS - 'Asset property value'; -COMMENT ON COLUMN edc_asset_property.property_type IS - 'Asset property class name'; - -CREATE INDEX IF NOT EXISTS idx_edc_asset_property_value - ON edc_asset_property (property_name, property_value);-- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-7 EDC --- --- -ALTER TABLE edc_contract_negotiation - ADD created_at BIGINT, - ADD updated_at BIGINT; - -UPDATE edc_contract_negotiation SET created_at=EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000; -UPDATE edc_contract_negotiation SET updated_at=created_at; - -ALTER TABLE edc_contract_negotiation - ALTER COLUMN created_at SET NOT NULL; -ALTER TABLE edc_contract_negotiation - ALTER COLUMN updated_at SET NOT NULL; --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-7 EDC --- --- - -ALTER TABLE edc_transfer_process - RENAME COLUMN created_time_stamp TO created_at; - -UPDATE edc_transfer_process - SET created_at = EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000 - WHERE created_at = NULL; - -ALTER TABLE edc_transfer_process - ADD updated_at BIGINT; - -UPDATE edc_transfer_process SET updated_at=created_at; - -ALTER TABLE edc_transfer_process ALTER COLUMN updated_at SET NOT NULL; -ALTER TABLE edc_transfer_process ALTER COLUMN created_at SET NOT NULL; --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-7 EDC --- --- -ALTER TABLE edc_contract_definitions - ADD created_at BIGINT; - -UPDATE edc_contract_definitions SET created_at=EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000; - -ALTER TABLE edc_contract_definitions - ALTER COLUMN created_at SET NOT NULL;-- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-7 EDC --- --- -ALTER TABLE edc_policydefinitions - ADD created_at BIGINT; - -UPDATE edc_policydefinitions SET created_at=EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000; - -ALTER TABLE edc_policydefinitions - ALTER COLUMN created_at SET NOT NULL; --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-7 EDC --- --- - -ALTER TABLE edc_asset - ADD created_at BIGINT; - -UPDATE edc_asset SET created_at=EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000; - -ALTER TABLE edc_asset - ALTER COLUMN created_at SET NOT NULL;-- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-7 EDC --- --- - -UPDATE edc_contract_negotiation -SET contract_offers = co.contract_offers_edited -FROM ( - SELECT - cn.id, - jsonb_agg( - jsonb_set( - jsonb_set( - elems, - '{contractStart}', - to_json(to_char(to_timestamp(created_at/1000) AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')::text)::jsonb - ), - '{contractEnd}', - to_json(to_char(to_timestamp((created_at/1000) + 60 * 60 * 24 * 365) AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')::text)::jsonb - ) - )::json as contract_offers_edited - FROM - edc_contract_negotiation cn, - jsonb_array_elements(cn.contract_offers::jsonb) elems - GROUP BY cn.id -) co -WHERE edc_contract_negotiation.id = co.id; - --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-8 EDC --- --- -ALTER TABLE edc_transfer_process ADD transferprocess_properties JSON; --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-8 EDC --- --- -ALTER TABLE edc_contract_definitions ADD validity BIGINT;-- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-8 EDC --- --- -UPDATE edc_transfer_process SET transferprocess_properties = '{}'::json WHERE transferprocess_properties IS NULL; --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables to Milestone-8 EDC --- --- -UPDATE edc_contract_definitions SET validity=60*60*24*365 WHERE validity IS NULL; diff --git a/extensions/postgres-flyway/src/main/resources/db/migration/V2__Delete-Transfer-Processes-Trigger.sql b/extensions/postgres-flyway/src/main/resources/db/migration/V2__Delete-Transfer-Processes-Trigger.sql deleted file mode 100644 index 5ca84691b..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/migration/V2__Delete-Transfer-Processes-Trigger.sql +++ /dev/null @@ -1,41 +0,0 @@ --- Required for reasonably fast ON DELETE CASCADE from edc_transfer_process -create index data_request_transfer_process_id_idx - on edc_data_request (transfer_process_id); --- Speed up sort + limit query --- Include transferprocess_id to enable index-only scan -create index transfer_process_created_at_idx - on edc_transfer_process (created_at) include (transferprocess_id); - --- Delete oldest row when table size exceeds 3000 rows --- The row count should mostly stabilize slightly above 3000, as the reltuples data in pg_class is only updated by VACUUM --- Unfortunately, I was not able to get conclusive results on the behavior under concurrent inserts --- One problem is that the table might still grow over time, if concurrent inserts can delete the same row --- To avoid this, we could delete two rows instead of just one --- Then the table would shrink until the next auto-vacuum detects that it is below 3000 rows again -create function transfer_process_delete_old_rows() returns trigger as $$ -begin - delete from edc_transfer_process o - using ( - select i2.transferprocess_id - from edc_transfer_process i2 - order by i2.created_at - limit 2 - ) i, - ( - -- Hack to avoid count(*), which takes several hundred milliseconds - -- Not perfectly accurate, but close enough - -- Idea taken from: https://www.cybertec-postgresql.com/en/postgresql-count-made-fast/ - select pgc.reltuples::bigint as count - from pg_catalog.pg_class pgc - where pgc.relname = 'edc_transfer_process' - ) c - where i.transferprocess_id = o.transferprocess_id and c.count > 3000; - - return null; -end; -$$ language plpgsql; - -create trigger delete_old_rows after insert - on edc_transfer_process - for each row -execute function transfer_process_delete_old_rows(); \ No newline at end of file diff --git a/extensions/postgres-flyway/src/main/resources/db/migration/V3__MS8-to-0.2.1.sql b/extensions/postgres-flyway/src/main/resources/db/migration/V3__MS8-to-0.2.1.sql deleted file mode 100644 index e08d4659c..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/migration/V3__MS8-to-0.2.1.sql +++ /dev/null @@ -1,416 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables From MS8 to 0.1.0 EDC --- --- - --- Migrates an Asset ID -create - or replace function pg_temp.migrate_asset_id(asset_id text) returns text as -$$ -begin - return replace(replace(asset_id::text, 'urn:artifact:', ''), ':', '-'); -end; -$$ - language plpgsql; - --- Migrate a contract agreement ID to EDC 0 -create - or replace function pg_temp.migrate_contract_agreement_id(contract_agreement_id text, asset_id text) returns text as -$$ -begin - return pg_temp.base64encode(split_part(contract_agreement_id, ':', 1)) || ':' || - pg_temp.base64encode(asset_id) || ':' || - pg_temp.base64encode(split_part(contract_agreement_id, ':', 2)); -end; -$$ - language plpgsql; - --- Migrates a Connector Endpoint to EDC 0 -create - or replace function pg_temp.migrate_connector_endpoint(endpoint text) returns text as -$$ -begin - return pg_temp.replace_suffix(endpoint, '/api/v1/ids/data', '/api/dsp'); -end; -$$ - language plpgsql; - --- Migrates a Participant ID to EDC 0 -create - or replace function pg_temp.migrate_participant_id(asset_id text) returns text as -$$ -begin - return replace(replace(asset_id::text, 'urn:connector:', ''), ':', '-'); -end; -$$ - language plpgsql; - --- Migrates an Asset Property Name to EDC 0 (if possible) -create - or replace function pg_temp.migrate_asset_property_name(asset_property_key text) returns text as -$$ -begin - return case asset_property_key - -- This list only contains properties that are directly mappable - -- Properties that require a new nested JSON structure are not included - when 'asset:prop:id' then 'https://w3id.org/edc/v0.0.1/ns/id' - when 'asset:prop:name' then 'http://purl.org/dc/terms/title' - when 'asset:prop:language' then 'http://purl.org/dc/terms/language' - when 'asset:prop:description' then 'http://purl.org/dc/terms/description' - when 'asset:prop:standardLicense' then 'http://purl.org/dc/terms/license' - when 'asset:prop:version' then 'http://www.w3.org/ns/dcat#version' - when 'asset:prop:keywords' then 'http://www.w3.org/ns/dcat#keyword' - when 'asset:prop:contenttype' then 'http://www.w3.org/ns/dcat#mediaType' - when 'asset:prop:endpointDocumentation' then 'http://www.w3.org/ns/dcat#landingPage' - when 'http://w3id.org/mds#dataCategory' then asset_property_key - when 'http://w3id.org/mds#dataSubcategory' then asset_property_key - when 'http://w3id.org/mds#dataModel' then asset_property_key - when 'http://w3id.org/mds#geoReferenceMethod' then asset_property_key - when 'http://w3id.org/mds#transportMode' then asset_property_key - when 'asset:prop:datasource:http:hints:proxyMethod' - then 'https://semantic.sovity.io/dcat-ext#httpDatasourceHintsProxyMethod' - when 'asset:prop:datasource:http:hints:proxyPath' - then 'https://semantic.sovity.io/dcat-ext#httpDatasourceHintsProxyPath' - when 'asset:prop:datasource:http:hints:proxyQueryParams' - then 'https://semantic.sovity.io/dcat-ext#httpDatasourceHintsProxyQueryParams' - when 'asset:prop:datasource:http:hints:proxyBody' - then 'https://semantic.sovity.io/dcat-ext#httpDatasourceHintsProxyBody' - else pg_temp.migrate_unknown_asset_property_name(asset_property_key) - end; -end; -$$ - language plpgsql; - --- Migrates an unknown Asset Property Name to EDC 0 (if possible) -create - or replace function pg_temp.migrate_unknown_asset_property_name(asset_property_key text) returns text as -$$ -begin - asset_property_key := replace(asset_property_key, 'asset:prop:', ''); - if pg_temp.starts_with(asset_property_key, 'http://') or - pg_temp.starts_with(asset_property_key, 'https://') then - return asset_property_key; - end if; - - return 'http://unknown/' || replace(asset_property_key, ':', '-'); -end; -$$ - language plpgsql; - - --- Migrates the "keywords" property value to EDC 0 --- 'a, b'::text becomes '["a", "b"]'::text -create - or replace function pg_temp.migrate_asset_keywords(keywords_comma_joined text) returns text as -$$ -begin - return (select coalesce(json_agg(to_json(trim(keyword)))::text, '[]') - from unnest(regexp_split_to_array(keywords_comma_joined, ',')) as keyword - where trim(keyword) <> ''); -end; -$$ - language plpgsql; - --- Migrates an asset property to EDC 0 -create - or replace function pg_temp.migrate_asset_property(property_name text, property_value text, property_type text) returns jsonb as -$$ -declare - name_mapped text; - value_mapped text; - type_mapped text; -begin - if property_name = 'asset:prop:id' then - name_mapped = pg_temp.migrate_asset_property_name(property_name); - value_mapped = pg_temp.migrate_asset_id(property_value); - type_mapped = property_type; - elsif property_name = 'asset:prop:keywords' then - name_mapped = pg_temp.migrate_asset_property_name(property_name); - value_mapped = pg_temp.migrate_asset_keywords(property_value); - type_mapped = 'java.util.ArrayList'; - elsif property_name = 'asset:prop:publisher' then - name_mapped = 'http://purl.org/dc/terms/publisher'; - value_mapped = jsonb_build_object('http://xmlns.com/foaf/0.1/homepage', - pg_temp.jsonld_value(property_value))::text; - type_mapped = 'java.util.LinkedHashMap'; - elsif property_name = 'asset:prop:curatorOrganizationName' or - property_name = 'asset:prop:originatorOrganization' then - name_mapped = 'http://purl.org/dc/terms/creator'; - value_mapped = jsonb_build_object('http://xmlns.com/foaf/0.1/name', - pg_temp.jsonld_value(property_value))::text; - type_mapped = 'java.util.LinkedHashMap'; - else - name_mapped = pg_temp.migrate_asset_property_name(property_name); - value_mapped = property_value; - type_mapped = property_type; - end if; - - return jsonb_build_object( - 'name', name_mapped, - 'value', value_mapped, - 'type', type_mapped - ); -end; -$$ - language plpgsql; - --- Migrates a contract definition criterion operator -create - or replace function pg_temp.migrate_criterion_operator(op text) returns text as -$$ -begin - -- due to previous mixing of the criterion operator with ODRL operators, we need to ensure the data in the db - -- is correct - return case lower(op) - when 'eq' then '=' - when 'in' then 'in' - when 'like' then 'like' - else op - end; -end; -$$ - language plpgsql; - --- Migrates a contract definition criterion to EDC 0 -create - or replace function pg_temp.migrate_criterion(criterion jsonb) returns jsonb as -$$ -declare - operand_left_mapped text; - operator_mapped text; - operand_right_mapped jsonb; -begin - operand_left_mapped = pg_temp.migrate_asset_property_name(criterion ->> 'operandLeft'); - operator_mapped = pg_temp.migrate_criterion_operator(criterion ->> 'operator'); - - if criterion ->> 'operandLeft' = 'asset:prop:id' then - if jsonb_typeof(criterion -> 'operandRight') = 'array' then - operand_right_mapped = (select jsonb_agg(to_jsonb(pg_temp.migrate_asset_id(items.item))) - from (select jsonb_array_elements_text(criterion -> 'operandRight') item) items); - else - operand_right_mapped = to_jsonb(pg_temp.migrate_asset_id(criterion ->> 'operandRight')); - end if; - else - operand_right_mapped = criterion -> 'operandRight'; - end if; - - return jsonb_build_object( - 'operandLeft', operand_left_mapped, - 'operator', operator_mapped, - 'operandRight', operand_right_mapped - ); -end; -$$ - language plpgsql; - --- Migrates a contract offer JSON to EDC 0 -create - or replace function pg_temp.migrate_negotiation_contract_offer(contract_offer jsonb) returns jsonb as -$$ -begin - return (contract_offer - '{asset,provider,consumer,offerStart,offerEnd,contractStart,contractEnd}'::text[] - || jsonb_build_object('assetId', pg_temp.migrate_asset_id(contract_offer -> 'asset' ->> 'id'))); -end; -$$ - language plpgsql; - --- Migrates a JSON array of contract offers to EDC 0 -create - or replace function pg_temp.migrate_negotiation_contract_offers(contract_offers jsonb) returns jsonb as -$$ -begin - return (select jsonb_agg(pg_temp.migrate_negotiation_contract_offer(contract_offers.contract_offer)) - from (select jsonb_array_elements(contract_offers) contract_offer) contract_offers); -end; -$$ - language plpgsql; - --- Utility Function: Wraps a value in expanded JSON-LD --- 'a'::text becomes '[{"@value": "a"}]'::jsonb -create - or replace function pg_temp.jsonld_value(value text) returns jsonb as -$$ -begin - return jsonb_build_array(jsonb_build_object('@value', to_jsonb(value))); -end; -$$ - language plpgsql; - --- Utility Function: base64 encode -create - or replace function pg_temp.base64encode(str text) returns text as -$$ -begin - return encode(str::bytea, 'base64'); -end; -$$ - language plpgsql; - --- Utility Function: replaceSuffix -create - or replace function pg_temp.replace_suffix(str text, old_suffix text, new_suffix text) returns text as -$$ -begin - return case - when pg_temp.ends_with(str, old_suffix) then - left(str, length(str) - length(old_suffix)) || new_suffix - else - str - end; -end; -$$ - language plpgsql; - --- Utility Function: endsWith -create or replace function pg_temp.ends_with(str text, suffix text) - returns boolean as -$$ -begin - return right(str, length(suffix)) = suffix; -end; -$$ language plpgsql; - --- Utility Function: startsWith -create or replace function pg_temp.starts_with(str text, prefix text) - returns boolean as -$$ -begin - return left(str, length(prefix)) = prefix; -end; -$$ language plpgsql; - --- Asset IDs -alter table edc_asset_dataaddress - drop constraint edc_asset_dataaddress_asset_id_fk_fkey; -alter table edc_asset_property - drop constraint edc_asset_property_asset_id_fk_fkey; -update edc_asset -set asset_id = pg_temp.migrate_asset_id(asset_id); -update edc_asset_dataaddress -set asset_id_fk = pg_temp.migrate_asset_id(asset_id_fk); -update edc_asset_property -set asset_id_fk = pg_temp.migrate_asset_id(asset_id_fk); -update edc_contract_agreement -set asset_id = pg_temp.migrate_asset_id(asset_id); -update edc_data_request -set asset_id = pg_temp.migrate_asset_id(asset_id); -alter table edc_asset_dataaddress - add constraint edc_asset_dataaddress_asset_id_fk_fkey foreign key (asset_id_fk) references edc_asset (asset_id) on delete cascade; -alter table edc_asset_property - add constraint edc_asset_property_asset_id_fk_fkey foreign key (asset_id_fk) references edc_asset (asset_id) on delete cascade; - --- Contract Agreement IDs -alter table edc_contract_negotiation - drop constraint contract_negotiation_contract_agreement_id_fk; -update edc_contract_negotiation -set agreement_id = pg_temp.migrate_contract_agreement_id(agreement_id, - pg_temp.migrate_asset_id(contract_offers -> 0 -> 'asset' ->> 'id')); -update edc_contract_agreement -set agr_id = pg_temp.migrate_contract_agreement_id(agr_id, asset_id); -update edc_data_request -set contract_id = pg_temp.migrate_contract_agreement_id(contract_id, asset_id); -alter table edc_contract_negotiation - add constraint contract_negotiation_contract_agreement_id_fk foreign key (agreement_id) references edc_contract_agreement (agr_id); - --- Protocol -update edc_contract_negotiation -set protocol = 'dataspace-protocol-http'; - --- Connector Endpoints -update edc_contract_negotiation -set counterparty_address = pg_temp.migrate_connector_endpoint(counterparty_address); -update edc_data_request -set connector_address = pg_temp.migrate_connector_endpoint(connector_address); - - --- Participant IDs -update edc_data_request -set connector_id = pg_temp.migrate_participant_id(connector_id); -update edc_contract_agreement -set provider_agent_id = pg_temp.migrate_participant_id(provider_agent_id), - consumer_agent_id = pg_temp.migrate_participant_id(consumer_agent_id); - --- Asset Properties -alter table edc_asset_property - add column property_is_private boolean; -delete -from edc_asset_property legacy_prop -where legacy_prop.property_name = 'asset:prop:originator'; -delete -from edc_asset_property legacy_prop -where legacy_prop.property_name = 'asset:prop:originatorOrganization' - and exists(select 1 - from edc_asset_property newer_prop - where legacy_prop.asset_id_fk = newer_prop.asset_id_fk - and newer_prop.property_name = 'asset:prop:curatorOrganizationName'); -- prevents errors from merging the legacy properties -update edc_asset_property -set property_name = pg_temp.migrate_asset_property(property_name, property_value, property_type) ->> 'name', - property_value = pg_temp.migrate_asset_property(property_name, property_value, property_type) ->> 'value', - property_type = pg_temp.migrate_asset_property(property_name, property_value, property_type) ->> 'type'; - --- Contract Negotiation Type -alter table edc_contract_negotiation - drop constraint provider_correlation_id; -alter table edc_contract_negotiation - add column "type_new" text; -update edc_contract_negotiation -set "type_new" = case "type" when 1 then 'PROVIDER' else 'CONSUMER' end; -alter table edc_contract_negotiation - drop column "type"; -alter table edc_contract_negotiation - rename column "type_new" to "type"; -alter table edc_contract_negotiation - add constraint provider_correlation_id check (type = 'CONSUMER' OR correlation_id IS NOT NULL); - --- Contract Negotiation Contract Offers -update edc_contract_negotiation -set contract_offers = pg_temp.migrate_negotiation_contract_offers(contract_offers::jsonb)::json; - --- Contract Definitions Asset Selector -alter table edc_contract_definitions - rename column selector_expression to assets_selector; -with cd_updated as (select cd.contract_definition_id, - jsonb_agg(pg_temp.migrate_criterion(criterion))::json as asset_selector - from edc_contract_definitions cd, - jsonb_array_elements(cd.assets_selector::jsonb -> 'criteria') criterion - group by cd.contract_definition_id) -update edc_contract_definitions cd -set assets_selector = cd_updated.asset_selector -from cd_updated -where cd_updated.contract_definition_id = cd.contract_definition_id; - --- Fix transfer processes stuck in running state -update edc_transfer_process -set state = 800 -where state = 600; - --- Other DDL Changes -alter table edc_contract_negotiation - add column callback_addresses json; -alter table edc_contract_negotiation - add column pending boolean default false; -alter table edc_transfer_process - add column pending boolean default false; -alter table edc_transfer_process - add column callback_addresses json; - -alter table edc_transfer_process - rename column transferprocess_properties to private_properties; - -alter table edc_contract_definitions - drop column validity; -alter table edc_data_request - drop column if exists managed_resources; -alter table edc_data_request - drop column if exists properties; -alter table edc_data_request - drop column if exists transfer_type; diff --git a/extensions/postgres-flyway/src/main/resources/db/migration/V4__MS8-to-0.2.1_bugfixes.sql b/extensions/postgres-flyway/src/main/resources/db/migration/V4__MS8-to-0.2.1_bugfixes.sql deleted file mode 100644 index ee64152ba..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/migration/V4__MS8-to-0.2.1_bugfixes.sql +++ /dev/null @@ -1,48 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - Update Tables From MS8 to 0.1.0 EDC --- --- - --- Migrates a Participant ID to EDC 0 -create - or replace function pg_temp.migrate_participant_id(asset_id text) returns text as -$$ -begin - return replace(replace(asset_id::text, 'urn:connector:', ''), ':', '-'); -end; -$$ - language plpgsql; - --- Participant IDs -update edc_contract_negotiation -set counterparty_id = pg_temp.migrate_participant_id(counterparty_id); - -update edc_contract_agreement -set provider_agent_id = neg.counterparty_id -from edc_contract_negotiation neg -where neg.agreement_id = edc_contract_agreement.agr_id - and neg.type = 'CONSUMER'; - -update edc_contract_agreement -set consumer_agent_id = neg.counterparty_id -from edc_contract_negotiation neg -where neg.agreement_id = edc_contract_agreement.agr_id - and neg.type = 'PROVIDER'; - --- Optimizations for Transfer Processes -create index transfer_process_status - on edc_transfer_process (state); - --- Fix transfer processes stuck in running state -update edc_transfer_process -set state = 800 -where state = 600; diff --git a/extensions/postgres-flyway/src/main/resources/db/migration/V5__Mobility_DCAT_Mapping.sql b/extensions/postgres-flyway/src/main/resources/db/migration/V5__Mobility_DCAT_Mapping.sql deleted file mode 100644 index 64a9ed66c..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/migration/V5__Mobility_DCAT_Mapping.sql +++ /dev/null @@ -1,76 +0,0 @@ --- --- Copyright (c) 2023 sovity GmbH --- --- 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: --- sovity GmbH - SQL Script --- --- - - --- "http://www.w3.org/ns/dcat#distribution": { --- "http://www.w3.org/ns/dcat#mediaType": "previously http://www.w3.org/ns/dcat#mediaType", --- "https://w3id.org/mobilitydcat-ap/mobilityDataStandard": { --- "@id": "previously http://w3id.org/mds#dataModel" --- } --- }, -with data as ( - select asset_id, - (select property_value from edc_asset_property p where p.property_name = 'http://www.w3.org/ns/dcat#mediaType' and p.asset_id_fk = a.asset_id) as media_type, - (select property_value from edc_asset_property p where p.property_name = 'http://w3id.org/mds#dataModel' and p.asset_id_fk = a.asset_id) as data_model - from edc_asset a -) -insert into edc_asset_property (asset_id_fk, property_name, property_type, property_value) ( - select asset_id, - 'http://www.w3.org/ns/dcat#distribution', - 'java.util.LinkedHashMap', - jsonb_build_object( - 'http://www.w3.org/ns/dcat#mediaType', media_type, - 'https://w3id.org/mobilitydcat-ap/mobilityDataStandard', jsonb_build_object('@id', data_model) - )::text - from data - where media_type is not null or data_model is not null -); -delete from edc_asset_property where property_name = 'http://www.w3.org/ns/dcat#mediaType'; -delete from edc_asset_property where property_name = 'http://w3id.org/mds#dataModel'; - - --- "https://w3id.org/mobilitydcat-ap/mobilityTheme": { --- "https://w3id.org/mobilitydcat-ap/mobility-theme/data-content-category": "previously http://w3id.org/mds#dataCategory", --- "https://w3id.org/mobilitydcat-ap/mobility-theme/data-content-sub-category": "previously http://w3id.org/mds#dataSubcategory" --- }, -with data as ( - select asset_id, - (select property_value from edc_asset_property p where p.property_name = 'http://w3id.org/mds#dataCategory' and p.asset_id_fk = a.asset_id) as data_category, - (select property_value from edc_asset_property p where p.property_name = 'http://w3id.org/mds#dataSubcategory' and p.asset_id_fk = a.asset_id) as data_subcategory - from edc_asset a -) -insert into edc_asset_property (asset_id_fk, property_name, property_type, property_value) ( - select asset_id, - 'https://w3id.org/mobilitydcat-ap/mobilityTheme', - 'java.util.LinkedHashMap', - jsonb_build_object( - 'https://w3id.org/mobilitydcat-ap/mobility-theme/data-content-category', data_category, - 'https://w3id.org/mobilitydcat-ap/mobility-theme/data-content-sub-category', data_subcategory - )::text - from data - where data_category is not null or data_subcategory is not null -); -delete from edc_asset_property where property_name = 'http://w3id.org/mds#dataCategory'; -delete from edc_asset_property where property_name = 'http://w3id.org/mds#dataSubcategory'; - - --- "https://w3id.org/mobilitydcat-ap/georeferencingMethod": "previously http://w3id.org/mds#geoReferenceMethod", -update edc_asset_property -set property_name = 'https://w3id.org/mobilitydcat-ap/georeferencingMethod' -where property_name = 'http://w3id.org/mds#geoReferenceMethod'; - --- "https://w3id.org/mobilitydcat-ap/transportMode": "previously http://w3id.org/mds#transportMode" -update edc_asset_property -set property_name = 'https://w3id.org/mobilitydcat-ap/transportMode' -where property_name = 'http://w3id.org/mds#transportMode'; diff --git a/extensions/postgres-flyway/src/main/resources/db/migration/V6__Fix_DataModel_ID_Field.sql b/extensions/postgres-flyway/src/main/resources/db/migration/V6__Fix_DataModel_ID_Field.sql deleted file mode 100644 index f8b0f7f98..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/migration/V6__Fix_DataModel_ID_Field.sql +++ /dev/null @@ -1,63 +0,0 @@ --- --- Copyright (c) 2024 sovity GmbH --- --- 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: --- sovity GmbH - SQL Script --- --- - -create - or replace function pg_temp.migrate_distribution(distribution jsonb) returns jsonb as -$$ -declare - data_standard jsonb; - data_standard_path text[]; -begin - data_standard_path := '{https://w3id.org/mobilitydcat-ap/mobilityDataStandard}'; - data_standard := distribution #> data_standard_path; - - if jsonb_typeof(data_standard) = 'object' then - data_standard := pg_temp.migrate_mobility_data_standard(data_standard); - elsif jsonb_typeof(data_standard) = 'array' then - data_standard := (select jsonb_agg(pg_temp.migrate_mobility_data_standard(it)) - from jsonb_array_elements(data_standard) as it); - end if; - - return jsonb_set(distribution, data_standard_path, data_standard, true); -end; -$$ language plpgsql; - - -create - or replace function pg_temp.migrate_mobility_data_standard(data_standard jsonb) returns jsonb as -$$ -begin - return pg_temp.remove_if_blank(data_standard, '{@id}'); -end; -$$ language plpgsql; - - -create - or replace function pg_temp.remove_if_blank(obj jsonb, path text[]) returns jsonb as -$$ -declare - value text; -begin - value := obj #>> path; - if value is null or trim(value) = '' then - obj := obj #- path; - end if; - return obj; -end; -$$ language plpgsql; - - -update edc_asset_property -set property_value = pg_temp.migrate_distribution(property_value::jsonb)::text -where property_name = 'http://www.w3.org/ns/dcat#distribution'; diff --git a/extensions/postgres-flyway/src/main/resources/db/migration/V9__legacy_cleanup.sql b/extensions/postgres-flyway/src/main/resources/db/migration/V9__legacy_cleanup.sql deleted file mode 100644 index 76f7e17f1..000000000 --- a/extensions/postgres-flyway/src/main/resources/db/migration/V9__legacy_cleanup.sql +++ /dev/null @@ -1,11 +0,0 @@ --- Clear the old migration tables if they exist once we reach this point. --- These tables don't exist with this new line of updates --- but may exist in older databases what started their lifetime with the older migration lines. -drop table if exists flyway_schema_history_asset; -drop table if exists flyway_schema_history_contractdefinition; -drop table if exists flyway_schema_history_contractnegotiation; -drop table if exists flyway_schema_history_dataplaneinstance; -drop table if exists flyway_schema_history_default; -drop table if exists flyway_schema_history_policy; -drop table if exists flyway_schema_history_transferprocess; - diff --git a/extensions/sovity-edc-extensions-package/build.gradle.kts b/extensions/sovity-edc-extensions-package/build.gradle.kts index 66c98e75c..944c3dac0 100644 --- a/extensions/sovity-edc-extensions-package/build.gradle.kts +++ b/extensions/sovity-edc-extensions-package/build.gradle.kts @@ -15,7 +15,9 @@ dependencies { api(project(":extensions:edc-ui-config")) api(project(":extensions:last-commit-info")) api(project(":extensions:wrapper:wrapper")) - api(project(":extensions:dataset-bugfix")) + + // Utilities + api(project(":extensions:vault-initializer")) } group = libs.versions.sovityEdcExtensionGroup.get() diff --git a/extensions/sovity-messenger/build.gradle.kts b/extensions/sovity-messenger/build.gradle.kts index b47765a69..e268ffbb6 100644 --- a/extensions/sovity-messenger/build.gradle.kts +++ b/extensions/sovity-messenger/build.gradle.kts @@ -9,55 +9,23 @@ dependencies { compileOnly(libs.lombok) implementation(project(":utils:json-and-jsonld-utils")) + implementation(project(":config")) implementation(libs.edc.controlPlaneCore) implementation(libs.edc.dspApiConfiguration) implementation(libs.edc.dspHttpSpi) + implementation(libs.edc.dspHttpCore) implementation(libs.edc.httpSpi) implementation(libs.edc.managementApiConfiguration) - implementation(libs.edc.transformCore) + implementation(libs.edc.transformLib) - testAnnotationProcessor(libs.lombok) + implementation(libs.jackson.jsr310) + testAnnotationProcessor(libs.lombok) testCompileOnly(libs.lombok) - testImplementation(project(":utils:test-utils")) - - testImplementation(libs.edc.junit) - testImplementation(libs.edc.dataPlaneSelectorCore) - testImplementation(libs.edc.dspApiConfiguration) - testImplementation(libs.edc.dspHttpCore) - testImplementation(libs.edc.iamMock) - testImplementation(libs.edc.jsonLd) - - testImplementation(libs.edc.http) { - exclude(group = "org.eclipse.jetty", module = "jetty-client") - exclude(group = "org.eclipse.jetty", module = "jetty-http") - exclude(group = "org.eclipse.jetty", module = "jetty-io") - exclude(group = "org.eclipse.jetty", module = "jetty-server") - exclude(group = "org.eclipse.jetty", module = "jetty-util") - exclude(group = "org.eclipse.jetty", module = "jetty-webapp") - } - - // Updated jetty versions for e.g. CVE-2023-26048 - testImplementation(libs.bundles.jetty.cve2023) - - testImplementation(libs.assertj.core) - testImplementation(libs.junit.api) - testImplementation(libs.jsonAssert) - testImplementation(libs.mockito.core) - testImplementation(libs.mockserver.netty) - testImplementation(libs.postgres) - testImplementation(libs.restAssured.restAssured) - testImplementation(libs.testcontainers.testcontainers) - testImplementation(libs.testcontainers.junitJupiter) - testImplementation(libs.testcontainers.postgresql) - - testRuntimeOnly(libs.junit.engine) -} - -tasks.getByName("test") { - useJUnitPlatform() + testImplementation(project(":launchers:utils:vanilla-control-plane")) + testImplementation(libs.edc.jsonLdLib) } publishing { diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessenger.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessenger.java index 38791ddfa..1826a9670 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessenger.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessenger.java @@ -51,6 +51,7 @@ public class SovityMessenger { * * @param resultType The result's class. * @param counterPartyAddress The base DSP URL where to send the message. e.g. https://server:port/api/dsp + * @param counterPartyId The Participant ID of the counter party EDC. e.g. MDSL1234XX.C1234XX * @param payload The message to send. * @param The outgoing message type. * @param The incoming message type. @@ -58,9 +59,9 @@ public class SovityMessenger { * @throws SovityMessengerException If a problem related to the message processing happened. */ public CompletableFuture> send( - Class resultType, String counterPartyAddress, T payload) { + Class resultType, String counterPartyAddress, String counterPartyId, T payload) { try { - val message = buildMessage(counterPartyAddress, payload); + val message = buildMessage(counterPartyAddress, counterPartyId, payload); val future = registry.dispatch(SovityMessageRequest.class, message); return future.thenApply(processResponse(resultType, payload)); } catch (URISyntaxException | MalformedURLException | JsonProcessingException e) { @@ -78,8 +79,8 @@ public String getType() { /** * Fire-and-forget messaging where you don't care about the response. */ - public void send(String counterPartyAddress, T payload) { - send(Discarded.class, counterPartyAddress, payload); + public void send(String counterPartyAddress, String counterPartyId, T payload) { + send(Discarded.class, counterPartyAddress, counterPartyId, payload); } @NotNull @@ -108,7 +109,7 @@ private Function } @NotNull - private SovityMessageRequest buildMessage(String counterPartyAddress, T payload) + private SovityMessageRequest buildMessage(String counterPartyAddress, String counterPartyId, T payload) throws MalformedURLException, URISyntaxException, JsonProcessingException { val url = new URI(counterPartyAddress).toURL(); val header1 = Json.createObjectBuilder() @@ -116,7 +117,7 @@ private SovityMessageRequest buildMessage(String count .build(); val header = JsonUtils.toJson(header1); val serialized = serializer.writeValueAsString(payload); - return new SovityMessageRequest(url, header, serialized); + return new SovityMessageRequest(url, counterPartyId, header, serialized); } } diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessengerExtension.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessengerExtension.java index 545529043..122ed2262 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessengerExtension.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessengerExtension.java @@ -19,34 +19,30 @@ import de.sovity.edc.extension.messenger.controller.SovityMessageController; import de.sovity.edc.extension.messenger.impl.JsonObjectFromSovityMessageRequest; import de.sovity.edc.extension.messenger.impl.JsonObjectFromSovityMessageResponse; -import de.sovity.edc.extension.messenger.impl.MessageEmitter; -import de.sovity.edc.extension.messenger.impl.MessageReceiver; +import de.sovity.edc.extension.messenger.impl.SovityMessageRequestFactory; import de.sovity.edc.extension.messenger.impl.ObjectMapperFactory; import de.sovity.edc.extension.messenger.impl.SovityMessageRequest; +import de.sovity.edc.extension.messenger.impl.SovityMessageRequestBodyExtractor; import lombok.val; -import org.eclipse.edc.protocol.dsp.api.configuration.DspApiConfiguration; -import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpRemoteMessageDispatcher; -import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; +import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.protocol.dsp.http.spi.dispatcher.DspHttpRemoteMessageDispatcher; +import org.eclipse.edc.protocol.dsp.http.spi.serialization.JsonLdRemoteMessageSerializer; import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.runtime.metamodel.annotation.Provides; -import org.eclipse.edc.spi.agent.ParticipantAgentService; import org.eclipse.edc.spi.iam.IdentityService; import org.eclipse.edc.spi.message.RemoteMessageDispatcherRegistry; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; -import org.eclipse.edc.spi.types.TypeManager; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import org.eclipse.edc.web.spi.WebService; +import org.eclipse.edc.web.spi.configuration.ApiContext; @Provides({SovityMessenger.class, SovityMessengerRegistry.class}) public class SovityMessengerExtension implements ServiceExtension { public static final String NAME = "SovityMessenger"; - @Inject - private DspApiConfiguration dspApiConfiguration; - @Inject private DspHttpRemoteMessageDispatcher dspHttpRemoteMessageDispatcher; @@ -62,18 +58,12 @@ public class SovityMessengerExtension implements ServiceExtension { @Inject private RemoteMessageDispatcherRegistry registry; - @Inject - private TypeManager typeManager; - @Inject private TypeTransformerRegistry typeTransformerRegistry; @Inject private WebService webService; - @Inject - private ParticipantAgentService participantAgentService; - @Override public String name() { return NAME; @@ -89,10 +79,16 @@ public void initialize(ServiceExtensionContext context) { } private void setupSovityMessengerEmitter(ServiceExtensionContext context, ObjectMapper objectMapper) { - val factory = new MessageEmitter(jsonLdRemoteMessageSerializer); - val delegate = new MessageReceiver(objectMapper); + val factory = new SovityMessageRequestFactory(jsonLdRemoteMessageSerializer); + val bodyExtractor = new SovityMessageRequestBodyExtractor(objectMapper); + + dspHttpRemoteMessageDispatcher.registerMessage(SovityMessageRequest.class, factory, bodyExtractor); - dspHttpRemoteMessageDispatcher.registerMessage(SovityMessageRequest.class, factory, delegate); + dspHttpRemoteMessageDispatcher.registerPolicyScope( + SovityMessageRequest.class, + "request.catalog", + unused -> Policy.Builder.newInstance().build() + ); typeTransformerRegistry.register(new JsonObjectFromSovityMessageRequest()); @@ -100,17 +96,20 @@ private void setupSovityMessengerEmitter(ServiceExtensionContext context, Object context.registerService(SovityMessenger.class, sovityMessenger); } - private void setupSovityMessengerReceiver(ServiceExtensionContext context, ObjectMapper objectMapper, SovityMessengerRegistry handlers) { + private void setupSovityMessengerReceiver( + ServiceExtensionContext context, + ObjectMapper objectMapper, + SovityMessengerRegistry handlers + ) { val receiver = new SovityMessageController( identityService, - dspApiConfiguration.getDspCallbackAddress(), typeTransformerRegistry, monitor, objectMapper, - participantAgentService, - handlers); + handlers + ); - webService.registerResource(dspApiConfiguration.getContextAlias(), receiver); + webService.registerResource(ApiContext.PROTOCOL, receiver); context.registerService(SovityMessengerRegistry.class, handlers); diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/controller/SovityMessageController.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/controller/SovityMessageController.java index 1981039aa..7fde56449 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/controller/SovityMessageController.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/controller/SovityMessageController.java @@ -35,12 +35,14 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.val; -import org.eclipse.edc.protocol.dsp.api.configuration.error.DspErrorResponse; +import org.eclipse.edc.connector.controlplane.services.spi.protocol.ProtocolTokenValidator; +import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.protocol.dsp.http.spi.error.DspErrorResponse; import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.agent.ParticipantAgentService; import org.eclipse.edc.spi.iam.ClaimToken; import org.eclipse.edc.spi.iam.IdentityService; import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.iam.VerificationContext; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.result.Result; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; @@ -58,12 +60,11 @@ public class SovityMessageController { public static final String PATH = "/sovity/message/generic"; - private final IdentityService identityService; - private final String callbackAddress; + private final ProtocolTokenValidator protocolTokenValidator; + private final TypeTransformerRegistry typeTransformerRegistry; private final Monitor monitor; private final ObjectMapper mapper; - private final ParticipantAgentService participant; @Getter private final SovityMessengerRegistry handlers; @@ -71,7 +72,8 @@ public class SovityMessageController { @POST public Response post( @HeaderParam(HttpHeaders.AUTHORIZATION) String authorization, - SovityMessageRequest request) { + SovityMessageRequest request + ) { val validation = validateToken(authorization); if (validation.failed()) { @@ -98,7 +100,12 @@ public Response post( .map(it -> Response.ok().type(MediaType.APPLICATION_JSON).entity(it).build()) .orElse(failure -> { var errorCode = UUID.randomUUID(); - monitor.warning(String.format("Error transforming " + response.getClass().getSimpleName() + ", error id %s: %s", errorCode, failure.getFailureDetail())); + monitor.warning(String.format( + "Error transforming %s, error id %s: %s", + response.getClass().getSimpleName(), + errorCode, + failure.getFailureDetail() + )); return DspErrorResponse .type(Prop.SovityMessageExt.REQUEST) .internalServerError(); @@ -113,17 +120,14 @@ public Response post( } } - private SovityMessageResponse processMessage(SovityMessageRequest compacted, HandlerBox handler, ClaimToken claims) throws JsonProcessingException { + private SovityMessageResponse processMessage(SovityMessageRequest compacted, HandlerBox handler, ClaimToken claims) + throws JsonProcessingException { val bodyStr = compacted.body(); val parsed = mapper.readValue(bodyStr, handler.clazz()); val result = handler.handler().apply(claims, parsed); val resultBody = mapper.writeValueAsString(result); - val response = new SovityMessageResponse( - buildOkHeader(handler.clazz()), - resultBody); - - return response; + return new SovityMessageResponse(buildOkHeader(handler.clazz()), resultBody); } private String buildOkHeader(Class clazz) { @@ -143,7 +147,10 @@ private String buildOkHeader(Class clazz) { private Result validateToken(String authorization) { val token = TokenRepresentation.Builder.newInstance().token(authorization).build(); - return identityService.verifyJwtToken(token, callbackAddress); + val verificationContext = VerificationContext.Builder.newInstance() + .policy(Policy.Builder.newInstance().build()) + .build(); + return identityService.verifyJwtToken(token, verificationContext); } private SovityMessageResponse buildErrorNoHandlerHeader(SovityMessageRequest request) { diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/JsonObjectFromSovityMessageRequest.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/JsonObjectFromSovityMessageRequest.java index 1a3f36c78..842b07adb 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/JsonObjectFromSovityMessageRequest.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/JsonObjectFromSovityMessageRequest.java @@ -33,7 +33,8 @@ public JsonObjectFromSovityMessageRequest() { @Override public @Nullable JsonObject transform( @NotNull SovityMessageRequest message, - @NotNull TransformerContext context) { + @NotNull TransformerContext context + ) { var builder = Json.createObjectBuilder(); builder.add(TYPE, Prop.SovityMessageExt.REQUEST) diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/MessageReceiver.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/MessageReceiver.java deleted file mode 100644 index ff53f5dde..000000000 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/MessageReceiver.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.extension.messenger.impl; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.RequiredArgsConstructor; -import lombok.val; -import okhttp3.Response; -import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; -import org.eclipse.edc.spi.EdcException; - -import java.io.IOException; -import java.util.function.Function; - -@RequiredArgsConstructor -public class MessageReceiver extends DspHttpDispatcherDelegate { - - private final ObjectMapper mapper; - - @Override - protected Function parseResponse() { - return res -> { - try { - val body = res.body(); - if (body == null) { - return null; - } - String content = body.string(); - return mapper.readValue(content, SovityMessageRequest.class); - } catch (IOException e) { - throw new EdcException(e); - } - }; - } -} diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequest.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequest.java index b5d330437..13e2a27ff 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequest.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequest.java @@ -17,7 +17,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import de.sovity.edc.utils.jsonld.vocab.Prop; -import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; +import org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol; import org.eclipse.edc.spi.types.domain.message.RemoteMessage; import java.net.URL; @@ -26,6 +26,9 @@ public record SovityMessageRequest( @JsonIgnore URL counterPartyAddress, + @JsonIgnore + String counterPartyId, + @JsonProperty(Prop.SovityMessageExt.HEADER) String header, @@ -44,4 +47,10 @@ public String getProtocol() { public String getCounterPartyAddress() { return counterPartyAddress.toString(); } + + @JsonIgnore + @Override + public String getCounterPartyId() { + return counterPartyId; + } } diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequestBodyExtractor.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequestBodyExtractor.java new file mode 100644 index 000000000..b3045c596 --- /dev/null +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequestBodyExtractor.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.messenger.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import okhttp3.ResponseBody; +import org.eclipse.edc.protocol.dsp.http.spi.dispatcher.response.DspHttpResponseBodyExtractor; +import org.eclipse.edc.spi.EdcException; + +import java.io.IOException; + +@RequiredArgsConstructor +public class SovityMessageRequestBodyExtractor implements DspHttpResponseBodyExtractor { + + private final ObjectMapper mapper; + + @Override + public SovityMessageRequest extractBody(ResponseBody responseBody) { + try { + if (responseBody == null) { + return null; + } + String content = responseBody.string(); + return mapper.readValue(content, SovityMessageRequest.class); + } catch (IOException e) { + throw new EdcException(e); + } + } +} diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/MessageEmitter.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequestFactory.java similarity index 66% rename from extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/MessageEmitter.java rename to extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequestFactory.java index c6350f7b3..29f24af7c 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/MessageEmitter.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequestFactory.java @@ -16,26 +16,30 @@ import de.sovity.edc.extension.messenger.controller.SovityMessageController; import lombok.RequiredArgsConstructor; +import lombok.val; import okhttp3.MediaType; import okhttp3.Request; import okhttp3.RequestBody; -import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpRequestFactory; -import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; +import org.eclipse.edc.protocol.dsp.http.spi.dispatcher.DspHttpRequestFactory; +import org.eclipse.edc.protocol.dsp.http.spi.serialization.JsonLdRemoteMessageSerializer; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; @RequiredArgsConstructor -public class MessageEmitter implements DspHttpRequestFactory { +public class SovityMessageRequestFactory implements DspHttpRequestFactory { private final JsonLdRemoteMessageSerializer serializer; @Override public Request createRequest(SovityMessageRequest message) { - String serialized = serializer.serialize(message); + val serialized = serializer.serialize(message); return new Request.Builder() .url(message.counterPartyAddress() + SovityMessageController.PATH) .post(RequestBody.create( serialized, - MediaType.get(jakarta.ws.rs.core.MediaType.APPLICATION_JSON) + MediaType.get(APPLICATION_JSON) )) + .header("Content-Type", APPLICATION_JSON) .build(); } } diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/SovityMessengerExtensionE2eTest.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/SovityMessengerExtensionE2eTest.java index 41241378c..1a0f09c9e 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/SovityMessengerExtensionE2eTest.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/SovityMessengerExtensionE2eTest.java @@ -14,16 +14,16 @@ package de.sovity.edc.extension.messenger; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.TestDatabase; -import de.sovity.edc.extension.e2e.db.TestDatabaseViaTestcontainers; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; import de.sovity.edc.extension.messenger.dto.Addition; import de.sovity.edc.extension.messenger.dto.Answer; import de.sovity.edc.extension.messenger.dto.Multiplication; import de.sovity.edc.extension.messenger.dto.UnsupportedMessage; +import de.sovity.edc.utils.config.ConfigUtils; import lombok.val; -import org.eclipse.edc.junit.extensions.EdcExtension; -import org.eclipse.edc.spi.iam.TokenDecorator; +import org.eclipse.edc.spi.system.configuration.Config; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -31,53 +31,36 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static java.util.concurrent.TimeUnit.SECONDS; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; -public class SovityMessengerExtensionE2eTest { - private static final String EMITTER_PARTICIPANT_ID = "emitter"; - private static final String RECEIVER_PARTICIPANT_ID = "receiver"; - - @RegisterExtension - static EdcExtension emitterEdcContext = new EdcExtension(); - @RegisterExtension - static EdcExtension receiverEdcContext = new EdcExtension(); - - @RegisterExtension - static final TestDatabase EMITTER_DATABASE = new TestDatabaseViaTestcontainers(); +class SovityMessengerExtensionE2eTest { @RegisterExtension - static final TestDatabase RECEIVER_DATABASE = new TestDatabaseViaTestcontainers(); - - private ConnectorConfig providerConfig; - private ConnectorConfig consumerConfig; - + static CeE2eTestExtension extension = CeE2eTestExtension.builder() + .additionalModule(":launchers:utils:vanilla-control-plane") + .skipDb(true) + .build(); private String counterPartyAddress; + private String counterPartyId; @BeforeEach - void setup() { - providerConfig = forTestDatabase(EMITTER_PARTICIPANT_ID, EMITTER_DATABASE); - emitterEdcContext.setConfiguration(providerConfig.getProperties()); - emitterEdcContext.registerServiceMock(TokenDecorator.class, (td) -> td); - - consumerConfig = forTestDatabase(RECEIVER_PARTICIPANT_ID, RECEIVER_DATABASE); - receiverEdcContext.setConfiguration(consumerConfig.getProperties()); - receiverEdcContext.registerServiceMock(TokenDecorator.class, (td) -> td); - - counterPartyAddress = consumerConfig.getProtocolApiUrl(); + void setup(@Consumer Config consumerConfig) { + counterPartyAddress = ConfigUtils.getProtocolApiUrl(consumerConfig); + counterPartyId = ConfigUtils.getParticipantId(consumerConfig); } @Test - void e2eTest() throws ExecutionException, InterruptedException, TimeoutException { - val sovityMessenger = emitterEdcContext.getContext().getService(SovityMessenger.class); - val handlers = receiverEdcContext.getContext().getService(SovityMessengerRegistry.class); - handlers.register(Addition.class, in -> new Answer(in.getOp1() + in.getOp2())); - handlers.register(Multiplication.class, in -> new Answer(in.getOp1() * in.getOp2())); + void e2eTest( + @Provider SovityMessenger providerMessenger, + @Consumer SovityMessengerRegistry consumerHandlers + ) throws ExecutionException, InterruptedException, TimeoutException { + consumerHandlers.register(Addition.class, in -> new Answer(in.getOp1() + in.getOp2())); + consumerHandlers.register(Multiplication.class, in -> new Answer(in.getOp1() * in.getOp2())); - val added = sovityMessenger.send(Answer.class, counterPartyAddress, new Addition(20, 30)); - val multiplied = sovityMessenger.send(Answer.class, counterPartyAddress, new Multiplication(20, 30)); + val added = providerMessenger.send(Answer.class, counterPartyAddress, counterPartyId, new Addition(20, 30)); + val multiplied = providerMessenger.send(Answer.class, counterPartyAddress, counterPartyId, new Multiplication(20, 30)); // assert added.get(30, SECONDS) @@ -96,10 +79,10 @@ void e2eTest() throws ExecutionException, InterruptedException, TimeoutException } @Test - void e2eNoHandlerTest() { - val sovityMessenger = emitterEdcContext.getContext().getService(SovityMessenger.class); - - val added = sovityMessenger.send(Answer.class, counterPartyAddress, new UnsupportedMessage()); + void e2eNoHandlerTest( + @Provider SovityMessenger sovityMessenger + ) { + val added = sovityMessenger.send(Answer.class, counterPartyAddress, counterPartyId, new UnsupportedMessage()); // assert val exception = assertThrows(ExecutionException.class, () -> added.get(30, SECONDS)); diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/controller/SovityMessageControllerTest.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/controller/SovityMessageControllerTest.java index 35dd978f0..a5dde591f 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/controller/SovityMessageControllerTest.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/controller/SovityMessageControllerTest.java @@ -23,13 +23,13 @@ import de.sovity.edc.extension.messenger.impl.SovityMessageRequest; import jakarta.ws.rs.core.Response; import lombok.val; -import org.eclipse.edc.core.transform.TypeTransformerRegistryImpl; import org.eclipse.edc.spi.agent.ParticipantAgent; import org.eclipse.edc.spi.agent.ParticipantAgentService; import org.eclipse.edc.spi.iam.ClaimToken; import org.eclipse.edc.spi.iam.IdentityService; import org.eclipse.edc.spi.monitor.ConsoleMonitor; import org.eclipse.edc.spi.result.Result; +import org.eclipse.edc.transform.TypeTransformerRegistryImpl; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -85,11 +85,9 @@ void canAnswerRequest() throws JsonProcessingException, MalformedURLException { val controller = new SovityMessageController( identityService, - "http://example.com/callback", transformers, monitor, objectMapper, - participantAgentService, handlers ); @@ -98,6 +96,7 @@ void canAnswerRequest() throws JsonProcessingException, MalformedURLException { val message = new SovityMessageRequest( new URL("https://example.com/api"), + "someCounterpartyId", """ { "type" : "foo" } """, @@ -120,15 +119,14 @@ void post_whenNonAuthorized_shouldReturnHttp401() throws MalformedURLException, val controller = new SovityMessageController( identityService, - "http://example.com/callback", transformers, monitor, objectMapper, - participantAgentService, handlers); val message = new SovityMessageRequest( new URL("https://example.com/api"), + "someCounterpartyId", """ { "type" : "foo" } """, @@ -151,11 +149,9 @@ void canIdentifyTheEmittingEdc() throws JsonProcessingException, MalformedURLExc val controller = new SovityMessageController( identityService, - "http://example.com/callback", transformers, monitor, objectMapper, - participantAgentService, handlers ); @@ -164,6 +160,7 @@ void canIdentifyTheEmittingEdc() throws JsonProcessingException, MalformedURLExc val message = new SovityMessageRequest( new URL("https://example.com/api"), + "someCounterpartyId", """ { "type" : "foo" } """, @@ -175,6 +172,5 @@ void canIdentifyTheEmittingEdc() throws JsonProcessingException, MalformedURLExc // assert assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode()); } - } } diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/SovityMessengerDemoTest.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/SovityMessengerDemoTest.java index 7caf8fc8c..328b148e4 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/SovityMessengerDemoTest.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/SovityMessengerDemoTest.java @@ -14,8 +14,7 @@ package de.sovity.edc.extension.messenger.demo; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; import de.sovity.edc.extension.messenger.SovityMessenger; import de.sovity.edc.extension.messenger.SovityMessengerException; import de.sovity.edc.extension.messenger.demo.message.Addition; @@ -26,42 +25,38 @@ import de.sovity.edc.extension.messenger.demo.message.Sqrt; import de.sovity.edc.extension.messenger.demo.message.UnregisteredMessage; import de.sovity.edc.extension.utils.junit.DisabledOnGithub; +import de.sovity.edc.utils.config.ConfigUtils; import lombok.SneakyThrows; import lombok.val; -import org.junit.jupiter.api.BeforeEach; +import org.eclipse.edc.spi.system.configuration.Config; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import java.util.concurrent.ExecutionException; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static java.util.concurrent.TimeUnit.SECONDS; class SovityMessengerDemoTest { + @RegisterExtension + static CeIntegrationTestExtension emitterExtension = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); + @DisabledOnGithub @Test @SneakyThrows - void demo() { - /* - * Get a reference to the SovityMessenger. This is equivalent to - * - * @Inject SovityMessenger messenger; - * - * in an extension. - * - * This messenger is already configured to accept messages in de.sovity.edc.extension.messenger.demo.SovityMessengerDemo#initialize - */ - val messenger = emitterExtension.getEdcRuntimeExtension().getContext().getService(SovityMessenger.class); - + void demo(SovityMessenger messenger, Config config) { System.out.println("START MARKER"); + var receiverId = ConfigUtils.getParticipantId(config); + var receiverAddress = ConfigUtils.getProtocolApiUrl(config); // Send messages - val added = messenger.send(Answer.class, receiverAddress, new Addition(20, 30)); - val rooted = messenger.send(Answer.class, receiverAddress, new Sqrt(9.0)); - val withClaims = messenger.send(Answer.class, receiverAddress, new Counterparty()); - val unregistered = messenger.send(Answer.class, receiverAddress, new UnregisteredMessage()); - messenger.send(receiverAddress, new Signal()); + val added = messenger.send(Answer.class, receiverAddress, receiverId, new Addition(20, 30)); + val rooted = messenger.send(Answer.class, receiverAddress, receiverId, new Sqrt(9.0)); + val withClaims = messenger.send(Answer.class, receiverAddress, receiverId, new Counterparty()); + val unregistered = messenger.send(Answer.class, receiverAddress, receiverId, new UnregisteredMessage()); + messenger.send(receiverAddress, receiverId, new Signal()); try { // Wait for the answers @@ -77,8 +72,8 @@ void demo() { } try { - val failing1 = messenger.send(Answer.class, receiverAddress, new Failing("Some content 1")); - val failing2 = messenger.send(Answer.class, receiverAddress, new Failing("Some content 2")); + val failing1 = messenger.send(Answer.class, receiverAddress, receiverId, new Failing("Some content 1")); + val failing2 = messenger.send(Answer.class, receiverAddress, receiverId, new Failing("Some content 2")); failing1.get(2, SECONDS); failing2.get(2, SECONDS); } catch (ExecutionException e) { @@ -93,34 +88,4 @@ void demo() { System.out.println("END MARKER"); } - - @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase emitterExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "emitter", - testDatabase -> { - ConnectorConfig emitterConfig = forTestDatabase("emitter", testDatabase); - return emitterConfig.getProperties(); - } - ); - - - private static ConnectorConfig receiverConfig; - - @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase receiverExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "receiver", - testDatabase -> { - receiverConfig = forTestDatabase("receiver", testDatabase); - return receiverConfig.getProperties(); - } - ); - - private String receiverAddress; - - @BeforeEach - void setup() { - receiverAddress = receiverConfig.getProtocolApiUrl(); - } } diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/echo/SovityMessageRequestTest.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/echo/SovityMessageRequestTest.java index 89cb3308c..f777c422e 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/echo/SovityMessageRequestTest.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/echo/SovityMessageRequestTest.java @@ -18,22 +18,20 @@ import de.sovity.edc.extension.messenger.impl.ObjectMapperFactory; import de.sovity.edc.extension.messenger.impl.SovityMessageRequest; import lombok.val; -import org.json.JSONException; +import net.javacrumbs.jsonunit.assertj.JsonAssertions; import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; -import org.skyscreamer.jsonassert.JSONCompareMode; import java.net.MalformedURLException; import java.net.URL; class SovityMessageRequestTest { - @Test - void canSerialize() throws MalformedURLException, JsonProcessingException, JSONException { + void canSerialize() throws MalformedURLException, JsonProcessingException { // arrange val message = new SovityMessageRequest( new URL("https://example.com"), + "someCountrerPartyId", "{\"type\":\"foo\"}", "body content" ); @@ -44,15 +42,14 @@ void canSerialize() throws MalformedURLException, JsonProcessingException, JSONE val serialized = mapper.writeValueAsString(message); // assert - JSONAssert.assertEquals( - """ + JsonAssertions.assertThatJson(serialized) + .isEqualTo( + """ { "https://semantic.sovity.io/message/generic/header": "{\\"type\\":\\"foo\\"}", "https://semantic.sovity.io/message/generic/body": "body content" } - """, - serialized, - JSONCompareMode.STRICT - ); + """ + ); } } diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/MessageEmitterTest.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequestFactoryTest.java similarity index 73% rename from extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/MessageEmitterTest.java rename to extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequestFactoryTest.java index 1d27a3f88..1513cb45d 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/MessageEmitterTest.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/SovityMessageRequestFactoryTest.java @@ -15,12 +15,11 @@ package de.sovity.edc.extension.messenger.impl; import lombok.val; -import org.eclipse.edc.core.transform.TypeTransformerRegistryImpl; import org.eclipse.edc.jsonld.TitaniumJsonLd; -import org.eclipse.edc.protocol.dsp.serialization.JsonLdRemoteMessageSerializerImpl; -import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; +import org.eclipse.edc.protocol.dsp.http.serialization.JsonLdRemoteMessageSerializerImpl; +import org.eclipse.edc.protocol.dsp.http.spi.serialization.JsonLdRemoteMessageSerializer; import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.transform.spi.TypeTransformerRegistry; +import org.eclipse.edc.transform.TypeTransformerRegistryImpl; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -29,25 +28,27 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; -class MessageEmitterTest { +class SovityMessageRequestFactoryTest { private final ObjectMapperFactory mapperFactory = new ObjectMapperFactory(); @Test void emitValidMessage_whenEmpty_shouldSucceed() throws IOException { // arrange - TypeTransformerRegistry registry = new TypeTransformerRegistryImpl(); + var registry = new TypeTransformerRegistryImpl(); registry.register(new JsonObjectFromSovityMessageRequest()); JsonLdRemoteMessageSerializer serializer = new JsonLdRemoteMessageSerializerImpl( registry, mapperFactory.createObjectMapper(), - new TitaniumJsonLd(mock(Monitor.class)) + new TitaniumJsonLd(mock(Monitor.class)), + "scope" ); - val emitter = new MessageEmitter(serializer); + val emitter = new SovityMessageRequestFactory(serializer); // act val request = emitter.createRequest(new SovityMessageRequest( new URL("https://example.com/api"), + "example", "header", "body" )); diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/SovityMessengerTest.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/SovityMessengerTest.java index 272d9e642..6e8b4db6c 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/SovityMessengerTest.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/SovityMessengerTest.java @@ -43,6 +43,7 @@ void send_whenNoHandler_shouldThrowSovityMessengerException() throws MalformedUR StatusResult.success( new SovityMessageRequest( new URL("https://example.com/api/dsp"), + "counter-party-id", """ { "status": "no_handler", @@ -53,7 +54,7 @@ void send_whenNoHandler_shouldThrowSovityMessengerException() throws MalformedUR when(registry.dispatch(any(), any())).thenReturn(future); val messenger = new SovityMessenger(registry, new ObjectMapperFactory().createObjectMapper(), new ConsoleMonitor()); - val answer = messenger.send(Answer.class, "https://example.com/api/dsp", new UnsupportedMessage()); + val answer = messenger.send(Answer.class, "https://example.com/api/dsp", "counterPartyId", new UnsupportedMessage()); // act val exception = assertThrows(ExecutionException.class, answer::get); diff --git a/extensions/transfer-process-status-checker/build.gradle.kts b/extensions/transfer-process-status-checker/build.gradle.kts deleted file mode 100644 index e420cbdaf..000000000 --- a/extensions/transfer-process-status-checker/build.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -plugins { - `java-library` - `maven-publish` -} - -dependencies { - api(libs.edc.transferSpi) - testImplementation(libs.edc.junit) -} - -group = libs.versions.sovityEdcExtensionGroup.get() - -publishing { - publications { - create(project.name) { - from(components["java"]) - } - } -} diff --git a/extensions/transfer-process-status-checker/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/transfer-process-status-checker/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension deleted file mode 100644 index 0183251a9..000000000 --- a/extensions/transfer-process-status-checker/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension +++ /dev/null @@ -1 +0,0 @@ -de.sovity.edc.extension.transfer.TransferProcessStatusCheckerExtension diff --git a/extensions/transfer-process-status-checker/README.md b/extensions/vault-initializer/README.md similarity index 68% rename from extensions/transfer-process-status-checker/README.md rename to extensions/vault-initializer/README.md index 359aea3a8..ca6fd760b 100644 --- a/extensions/transfer-process-status-checker/README.md +++ b/extensions/vault-initializer/README.md @@ -5,7 +5,7 @@ Logo -

EDC-Connector Extension:
Transfer Process Status Checker

+

EDC-Connector Extension:
Vault Initializer

Report Bug @@ -16,11 +16,11 @@ ## About this Extension -Bugfix extension for `Eclipse EDC [0.2.1, 0.3)`, marks transfer processes as `COMPLETED`. +This extension populates the vault from config properties on startup ## Why does this extension exist? -We cannot directly upgrade to `Eclipse EDC >=0.3` now, but will of course do so soon. +The in-memory vault in test and dev environments might want to be initialized from config properties on startup. This extension provides a way to do that. ## License diff --git a/extensions/vault-initializer/build.gradle.kts b/extensions/vault-initializer/build.gradle.kts new file mode 100644 index 000000000..3a80a3bbc --- /dev/null +++ b/extensions/vault-initializer/build.gradle.kts @@ -0,0 +1,36 @@ + +plugins { + `java-library` + `maven-publish` +} + +dependencies { + annotationProcessor(libs.lombok) + compileOnly(libs.lombok) + + api(libs.edc.coreSpi) + api(libs.edc.controlPlaneSpi) + + implementation(project(":config")) + implementation(libs.apache.commonsLang) + + testAnnotationProcessor(libs.lombok) + testCompileOnly(libs.lombok) + + testImplementation(libs.edc.controlPlaneCore) + testImplementation(libs.edc.junit) + testImplementation(libs.edc.dataPlaneSelectorCore) + testImplementation(libs.mockito.core) + testImplementation(libs.junit.api) + testRuntimeOnly(libs.junit.engine) +} + +group = libs.versions.sovityEdcExtensionGroup.get() + +publishing { + publications { + create(project.name) { + from(components["java"]) + } + } +} diff --git a/extensions/transfer-process-status-checker/src/main/java/de/sovity/edc/extension/transfer/TransferProcessStatusCheckerExtension.java b/extensions/vault-initializer/src/main/java/de/sovity/edc/extension/vaultinit/VaultInitializerExtension.java similarity index 53% rename from extensions/transfer-process-status-checker/src/main/java/de/sovity/edc/extension/transfer/TransferProcessStatusCheckerExtension.java rename to extensions/vault-initializer/src/main/java/de/sovity/edc/extension/vaultinit/VaultInitializerExtension.java index a69def634..a27fc0543 100644 --- a/extensions/transfer-process-status-checker/src/main/java/de/sovity/edc/extension/transfer/TransferProcessStatusCheckerExtension.java +++ b/extensions/vault-initializer/src/main/java/de/sovity/edc/extension/vaultinit/VaultInitializerExtension.java @@ -12,20 +12,18 @@ * */ -package de.sovity.edc.extension.transfer; +package de.sovity.edc.extension.vaultinit; -import org.eclipse.edc.connector.transfer.spi.status.StatusCheckerRegistry; import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.security.Vault; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; -import java.util.List; - -public class TransferProcessStatusCheckerExtension implements ServiceExtension { - private static final String EXTENSION_NAME = "Transfer Process Status Checker"; +public class VaultInitializerExtension implements ServiceExtension { + public static final String EXTENSION_NAME = "VaultInitializer"; @Inject - private StatusCheckerRegistry statusCheckerRegistry; + private Vault vault; @Override public String name() { @@ -34,10 +32,11 @@ public String name() { @Override public void initialize(ServiceExtensionContext context) { - List.of("HttpProxy", "HttpData").forEach(this::registerStatusChecker); - } - - private void registerStatusChecker(String transferType) { - statusCheckerRegistry.register(transferType, (transferProcess, resources) -> true); + var vaultInitializerService = new VaultInitializerService( + context.getMonitor(), + context.getConfig(), + vault + ); + vaultInitializerService.initializeVault(); } } diff --git a/extensions/vault-initializer/src/main/java/de/sovity/edc/extension/vaultinit/VaultInitializerService.java b/extensions/vault-initializer/src/main/java/de/sovity/edc/extension/vaultinit/VaultInitializerService.java new file mode 100644 index 000000000..641457d38 --- /dev/null +++ b/extensions/vault-initializer/src/main/java/de/sovity/edc/extension/vaultinit/VaultInitializerService.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.vaultinit; + +import de.sovity.edc.utils.config.CeConfigProps; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.security.Vault; +import org.eclipse.edc.spi.system.configuration.Config; + +@RequiredArgsConstructor +public class VaultInitializerService { + + private final Monitor monitor; + private final Config config; + private final Vault vault; + + public void initializeVault() { + if (!CeConfigProps.MY_EDC_VAULT_INIT_ENABLED.getBoolean(config)) { + monitor.info("Vault initialization is disabled."); + return; + } + monitor.info("Vault initialization is enabled."); + + var entries = CeConfigProps.MY_EDC_VAULT_INIT_ENTRIES_WILDCARD.getWildcardSubconfig(config); + entries.getRelativeEntries().forEach(this::initializeVaultValue); + } + + private void initializeVaultValue(String key, String value) { + if (StringUtils.isBlank(key) || StringUtils.isBlank(value) || key.equals("*")) { + return; + } + + var currentValue = vault.resolveSecret(key); + if (StringUtils.isNotBlank(currentValue)) { + if (!currentValue.equals(value)) { + monitor.info("Vault value is already present and different, skipping initialization: %s".formatted(key)); + } + return; + } + + vault.storeSecret(key, value); + monitor.info("Initialized vault entry: %s".formatted(key)); + } +} diff --git a/extensions/vault-initializer/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/vault-initializer/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 000000000..f31f10571 --- /dev/null +++ b/extensions/vault-initializer/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1 @@ +de.sovity.edc.extension.vaultinit.VaultInitializerExtension diff --git a/extensions/wrapper/wrapper-api/build.gradle.kts b/extensions/wrapper/wrapper-api/build.gradle.kts index 48644fa8b..9caf6799e 100644 --- a/extensions/wrapper/wrapper-api/build.gradle.kts +++ b/extensions/wrapper/wrapper-api/build.gradle.kts @@ -1,3 +1,4 @@ +import com.diffplug.gradle.spotless.SpotlessTask plugins { `java-library` @@ -5,6 +6,7 @@ plugins { alias(libs.plugins.swagger.plugin) //./gradlew clean resolve alias(libs.plugins.hidetake.swaggerGenerator) //./gradlew generateSwaggerUI alias(libs.plugins.openapi.generator6) //./gradlew openApiValidate && ./gradlew openApiGenerate + alias(libs.plugins.spotless) } dependencies { @@ -41,6 +43,14 @@ tasks.withType { resourcePackages = setOf("de.sovity.edc.ext.wrapper.api") } +spotless { + yaml { + target("src/**/*.yaml") + jackson() + .feature("ORDER_MAP_ENTRIES_BY_KEYS", true) + } +} + val copyOpenapiYamlToDocs by tasks.registering(Copy::class) { dependsOn("resolve") from(openapiFile) @@ -51,11 +61,13 @@ val openApiGenerateTypeScriptClient by tasks.registering(org.openapitools.genera dependsOn("resolve") dependsOn(copyOpenapiYamlToDocs) generatorName.set("typescript-fetch") - configOptions.set(mutableMapOf( + configOptions.set( + mutableMapOf( "supportsES6" to "true", "npmVersion" to "8.15.0", "typescriptThreePlus" to "true", - )) + ) + ) inputSpec.set(openapiFile) val outputDirectory = buildFile.parentFile.resolve("../clients/typescript-client/src/generated").normalize() @@ -68,6 +80,8 @@ val openApiGenerateTypeScriptClient by tasks.registering(org.openapitools.genera doLast { outputDirectory.resolve("src/generated").renameTo(outputDirectory) } + + finalizedBy(tasks.withType()) } tasks.withType { diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java index 71895a4b0..a8c08b03e 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java @@ -148,7 +148,7 @@ interface UiResource { @Path("pages/catalog-page/data-offers") @Produces(MediaType.APPLICATION_JSON) @Operation(description = "Fetch a connector's data offers") - List getCatalogPageDataOffers(@QueryParam("connectorEndpoint") String connectorEndpoint); + List getCatalogPageDataOffers(@QueryParam("participantId") String participantId, @QueryParam("connectorEndpoint") String connectorEndpoint); @POST @Path("pages/catalog-page/contract-negotiations") diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementDirection.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementDirection.java index ef40b8edd..01d51fc5b 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementDirection.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementDirection.java @@ -17,7 +17,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; import java.util.Arrays; diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractNegotiationRequest.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractNegotiationRequest.java index fe2279644..247a05307 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractNegotiationRequest.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractNegotiationRequest.java @@ -30,12 +30,12 @@ @Schema(description = "Data for initiating a Contract Negotiation") public class ContractNegotiationRequest { + @Schema(description = "Counter Party Id", requiredMode = Schema.RequiredMode.REQUIRED) + private String counterPartyId; + @Schema(description = "Counter Party Address", requiredMode = Schema.RequiredMode.REQUIRED) private String counterPartyAddress; - @Schema(description = "Counter Party Participant ID", requiredMode = Schema.RequiredMode.REQUIRED) - private String counterPartyParticipantId; - @Schema(description = "Contract Offer Dto ", requiredMode = Schema.RequiredMode.REQUIRED) private String contractOfferId; diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/DashboardCxDidConfig.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/DashboardCxDidConfig.java new file mode 100644 index 000000000..b1b656bc3 --- /dev/null +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/DashboardCxDidConfig.java @@ -0,0 +1,26 @@ +package de.sovity.edc.ext.wrapper.api.ui.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@NoArgsConstructor +@Schema(description = "Managed Identity Wallet (MIW) Config") +public class DashboardCxDidConfig { + @Schema(description = "My DID / edc.iam.issuer.id", requiredMode = Schema.RequiredMode.REQUIRED) + private String myDid; + + @Schema(description = "Wallet Token Url / edc.iam.sts.oauth.token.url", requiredMode = Schema.RequiredMode.REQUIRED) + private String walletTokenUrl; + + @Schema(description = "Trusted VC Issuer / edc.iam.trusted-issuer.cofinity.id", requiredMode = Schema.RequiredMode.REQUIRED) + private String trustedVcIssuer; + + @Schema(description = "BDRS Url / tx.iam.iatp.bdrs.server.url", requiredMode = Schema.RequiredMode.REQUIRED) + private String bdrsUrl; + + @Schema(description = "STS DIM Url / edc.iam.sts.dim.url", requiredMode = Schema.RequiredMode.REQUIRED) + private String dimUrl; +} diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/DashboardMiwConfig.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/DashboardMiwConfig.java deleted file mode 100644 index 05b24fa1d..000000000 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/DashboardMiwConfig.java +++ /dev/null @@ -1,20 +0,0 @@ -package de.sovity.edc.ext.wrapper.api.ui.model; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.NoArgsConstructor; - - -@Data -@NoArgsConstructor -@Schema(description = "Managed Identity Wallet (MIW) Config") -public class DashboardMiwConfig { - @Schema(description = "Your Connector's MIW's URL", requiredMode = Schema.RequiredMode.REQUIRED) - private String url; - - @Schema(description = "Your Connector's MIW's Token URL", requiredMode = Schema.RequiredMode.REQUIRED) - private String tokenUrl; - - @Schema(description = "Your Connector's MIW's Authority ID", requiredMode = Schema.RequiredMode.REQUIRED) - private String authorityId; -} diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/DashboardPage.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/DashboardPage.java index 78056c9a7..490a8e087 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/DashboardPage.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/DashboardPage.java @@ -64,6 +64,6 @@ public class DashboardPage { @Schema(description = "Your Connector's DAPS Configuration (if present)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private DashboardDapsConfig connectorDapsConfig; - @Schema(description = "Your Connector's MIW Configuration (if present)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) - private DashboardMiwConfig connectorMiwConfig; + @Schema(description = "Your Connector's Catena-X Web-DID Configuration (if present)", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private DashboardCxDidConfig connectorCxDidConfig; } diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/InitiateTransferRequest.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/InitiateTransferRequest.java index d6eed17f1..835398bcc 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/InitiateTransferRequest.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/InitiateTransferRequest.java @@ -33,6 +33,12 @@ public class InitiateTransferRequest { @Schema(description = "Contract Agreement ID", requiredMode = Schema.RequiredMode.REQUIRED) private String contractAgreementId; + @Schema(description = "Transfer Type. Used to select a compatible DataPlane. " + + "Examples are 'HttpData-PUSH', 'HttpData-PULL'. " + + "Not to be confused with the 'type' of the data source, or the 'type' of the data sink found in the 'properties'", + requiredMode = Schema.RequiredMode.REQUIRED) + private String transferType; + @Schema(description = "Data Sink / Data Address", requiredMode = Schema.RequiredMode.REQUIRED) private Map dataSinkProperties; diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/UiCriterionOperator.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/UiCriterionOperator.java index 20289bfe9..6660a2075 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/UiCriterionOperator.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/UiCriterionOperator.java @@ -18,7 +18,7 @@ /** * Contract Definition Criterion - * See

org.eclipse.edc.connector.defaults.storage.CriterionToPredicateConverterImpl
+ * See
org.eclipse.edc.connector.controlplane.defaults.storage.CriterionToPredicateConverterImpl
*/ @Schema(description = "Operator for constraints", enumAsRef = true) diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/CatalogQuery.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/CatalogQuery.java index ed11ed655..c1606a293 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/CatalogQuery.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/CatalogQuery.java @@ -30,9 +30,14 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @Schema(description = "Catalog query parameters") public class CatalogQuery { - @Schema(description = "Target EDC DSP endpoint URL", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "Target EDC DSP endpoint URL. Can contain a queryParam 'participantId', which is provided by default in the " + + "Connector Endpoint in the EDC UI.", requiredMode = Schema.RequiredMode.REQUIRED) private String connectorEndpoint; + @Schema(description = "Target EDC Participant ID. It is required if the connector endpoint does not contain the queryParam " + + "'participantId'.", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String participantId; + @Schema(description = "Limit the number of results", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private Integer limit; diff --git a/extensions/wrapper/wrapper-common-mappers/build.gradle.kts b/extensions/wrapper/wrapper-common-mappers/build.gradle.kts index 909ba8dbe..e7ee20e35 100644 --- a/extensions/wrapper/wrapper-common-mappers/build.gradle.kts +++ b/extensions/wrapper/wrapper-common-mappers/build.gradle.kts @@ -10,11 +10,15 @@ dependencies { api(libs.edc.policyModel) api(libs.edc.coreSpi) - api(libs.edc.transformCore) + api(libs.edc.controlPlaneSpi) api(libs.edc.transformSpi) + api(libs.edc.jsonLdLib) + api(libs.edc.jsonLdSpi) + api(libs.edc.assetSpi) api(project(":extensions:wrapper:wrapper-common-api")) api(project(":utils:json-and-jsonld-utils")) + implementation(project(":config")) implementation(libs.apache.commonsLang) implementation(libs.apache.commonsCollections) diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/AssetMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/AssetMapper.java index 4ac252075..9ab9ad994 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/AssetMapper.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/AssetMapper.java @@ -24,10 +24,11 @@ import de.sovity.edc.utils.jsonld.vocab.Prop; import jakarta.json.Json; import jakarta.json.JsonObject; +import jakarta.json.JsonValue; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; import org.eclipse.edc.jsonld.spi.JsonLd; -import org.eclipse.edc.spi.types.domain.asset.Asset; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import java.util.Optional; @@ -92,6 +93,7 @@ public Asset buildAsset( ) { var expanded = jsonLd.expand(assetJsonLd) .orElseThrow(FailedMappingException::ofFailure); + return typeTransformerRegistry.transform(expanded, Asset.class) .orElseThrow(FailedMappingException::ofFailure); } diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java index 3b69efa56..bea285a24 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java @@ -22,12 +22,15 @@ import de.sovity.edc.ext.wrapper.api.common.model.UiPolicy; import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyExpression; import de.sovity.edc.utils.JsonUtils; +import de.sovity.edc.utils.config.ConfigUtils; import jakarta.json.JsonObject; import lombok.RequiredArgsConstructor; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.policy.model.Action; import org.eclipse.edc.policy.model.Permission; import org.eclipse.edc.policy.model.Policy; import org.eclipse.edc.policy.model.PolicyType; +import org.eclipse.edc.spi.system.configuration.Config; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import static de.sovity.edc.utils.JsonUtils.toJson; @@ -37,6 +40,8 @@ public class PolicyMapper { private final ExpressionExtractor expressionExtractor; private final ExpressionMapper expressionMapper; private final TypeTransformerRegistry typeTransformerRegistry; + private final JsonLd jsonLd; + private final Config config; /** * Builds a simplified UI Policy Model from an ODRL Policy. @@ -79,6 +84,7 @@ public Policy buildPolicy(UiPolicyExpression expression) { return Policy.Builder.newInstance() .type(PolicyType.SET) .permission(permission) + .assigner(ConfigUtils.getParticipantId(config)) .build(); } @@ -91,7 +97,10 @@ public Policy buildPolicy(UiPolicyExpression expression) { * @return {@link Policy} */ public Policy buildPolicy(JsonObject policyJsonLd) { - return typeTransformerRegistry.transform(policyJsonLd, Policy.class) + var expanded = jsonLd.expand(policyJsonLd) + .orElseThrow(FailedMappingException::ofFailure); + + return typeTransformerRegistry.transform(expanded, Policy.class) .orElseThrow(FailedMappingException::ofFailure); } diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetJsonLdBuilder.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetJsonLdBuilder.java index e8c7cd00b..f6acddd40 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetJsonLdBuilder.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetJsonLdBuilder.java @@ -65,7 +65,6 @@ public JsonObject createAssetJsonLd( @SneakyThrows - @Nullable public JsonObject editAssetJsonLd( JsonObject assetJsonLd, UiAssetEditRequest editRequest @@ -159,7 +158,7 @@ private void addDataSourceHints(JsonObjectBuilder properties, JsonObject dataAdd private void addDistribution(JsonObjectBuilder properties, UiAssetCreateRequest request) { var distribution = buildDistribution(request); - addNonNullJsonValue(properties, Prop.Dcat.DISTRIBUTION, distribution); + addNonNullJsonValue(properties, Prop.SovityDcatExt.DISTRIBUTION, distribution); } private void addMobilityTheme(JsonObjectBuilder properties, UiAssetCreateRequest request) { diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetJsonLdParser.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetJsonLdParser.java index 4ce35bc5c..b2ba7b0f4 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetJsonLdParser.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetJsonLdParser.java @@ -47,7 +47,7 @@ public UiAsset buildUiAsset(JsonObject assetJsonLd, String connectorEndpoint, St var id = assetJsonLdUtils.getId(assetJsonLd); var title = assetJsonLdUtils.getTitle(assetJsonLd); - var distribution = JsonLdUtils.object(properties, Prop.Dcat.DISTRIBUTION); + var distribution = JsonLdUtils.object(properties, Prop.SovityDcatExt.DISTRIBUTION); uiAsset.setMediaType(JsonLdUtils.string(distribution, Prop.Dcat.MEDIATYPE)); uiAsset.setDataSampleUrls(JsonLdUtils.stringList(distribution, Prop.Adms.SAMPLE)); var rights = JsonLdUtils.object(distribution, Prop.Dcterms.RIGHTS); @@ -129,7 +129,7 @@ private String getCustomJsonLd(JsonObject properties) { Prop.Dcterms.IDENTIFIER, // Explicitly handled - Prop.Dcat.DISTRIBUTION, + Prop.Dcat.DISTRIBUTION_WILL_BE_OVERWRITTEN_BY_CATALOG, Prop.Dcat.KEYWORDS, Prop.Dcat.LANDING_PAGE, Prop.Dcat.VERSION, @@ -155,7 +155,8 @@ private String getCustomJsonLd(JsonObject properties) { Prop.SovityDcatExt.CUSTOM_JSON, Prop.SovityDcatExt.DATA_SOURCE_AVAILABILITY, Prop.SovityDcatExt.CONTACT_EMAIL, - Prop.SovityDcatExt.CONTACT_PREFERRED_EMAIL_SUBJECT + Prop.SovityDcatExt.CONTACT_PREFERRED_EMAIL_SUBJECT, + Prop.SovityDcatExt.DISTRIBUTION )); // custom properties diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/PolicyValidator.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/PolicyValidator.java index 743781dbe..755a21fe6 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/PolicyValidator.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/PolicyValidator.java @@ -80,14 +80,6 @@ public void validateOtherPermissionFieldsUnset(Permission permission, MappingErr errors.add("Permission has duties, which is currently unsupported."); } - if (isNotBlank(permission.getAssigner())) { - errors.add("Permission has an assigner, which is currently unsupported."); - } - - if (isNotBlank(permission.getAssignee())) { - errors.add("Permission has an assignee, which is currently unsupported."); - } - validateAction(permission.getAction(), errors.forChildObject("action")); } diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapperTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapperTest.java index adfcbbe2a..193ac0172 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapperTest.java +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapperTest.java @@ -18,12 +18,14 @@ import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ExpressionMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.MappingErrors; import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyExpression; +import de.sovity.edc.utils.config.CeConfigProps; import jakarta.json.Json; import jakarta.json.JsonObject; import org.eclipse.edc.policy.model.Constraint; import org.eclipse.edc.policy.model.Policy; import org.eclipse.edc.policy.model.PolicyType; import org.eclipse.edc.spi.result.Result; +import org.eclipse.edc.spi.system.configuration.Config; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -31,6 +33,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.util.Map; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; @@ -42,13 +45,15 @@ @ExtendWith(MockitoExtension.class) class PolicyMapperTest { @InjectMocks - PolicyMapper policyMapper; + private PolicyMapper policyMapper; @Mock - ExpressionExtractor expressionExtractor; + private ExpressionExtractor expressionExtractor; @Mock - ExpressionMapper expressionMapper; + private ExpressionMapper expressionMapper; @Mock - TypeTransformerRegistry typeTransformerRegistry; + private TypeTransformerRegistry typeTransformerRegistry; + @Mock + private Config config; @Test void buildUiPolicy() { @@ -96,6 +101,10 @@ void buildPolicy_constraintExtracted() { @Test void buildPolicy_noConstraint() { // arrange + when(config.getEntries()).thenReturn( + Map.of(CeConfigProps.EDC_PARTICIPANT_ID.getProperty(), "foo") + ); + var uiExpression = mock(UiPolicyExpression.class); when(expressionMapper.buildConstraint(uiExpression)) .thenReturn(Optional.empty()); diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetJsonLdBuilderTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetJsonLdBuilderTest.java index 060c29d03..0e678fbf7 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetJsonLdBuilderTest.java +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetJsonLdBuilderTest.java @@ -129,7 +129,7 @@ void test_create_distribution_withMediaType() { .build(); var expectedProperties = Json.createObjectBuilder() - .add(Prop.Dcat.DISTRIBUTION, Json.createObjectBuilder() + .add(Prop.SovityDcatExt.DISTRIBUTION, Json.createObjectBuilder() .add(Prop.Dcat.MEDIATYPE, "B")); // act @@ -149,7 +149,7 @@ void test_create_distribution_withConditionsForUse() { .build(); var expectedProperties = Json.createObjectBuilder() - .add(Prop.Dcat.DISTRIBUTION, Json.createObjectBuilder() + .add(Prop.SovityDcatExt.DISTRIBUTION, Json.createObjectBuilder() .add(Prop.Dcterms.RIGHTS, Json.createObjectBuilder() .add(Prop.Rdfs.LABEL, "B"))); @@ -170,7 +170,7 @@ void test_create_distribution_withDataModel() { .build(); var expectedProperties = Json.createObjectBuilder() - .add(Prop.Dcat.DISTRIBUTION, Json.createObjectBuilder() + .add(Prop.SovityDcatExt.DISTRIBUTION, Json.createObjectBuilder() .add(Prop.MobilityDcatAp.MOBILITY_DATA_STANDARD, Json.createObjectBuilder() .add(Prop.ID, "B"))); @@ -191,7 +191,7 @@ void test_create_distribution_withReferenceFileDescription() { .build(); var expectedProperties = Json.createObjectBuilder() - .add(Prop.Dcat.DISTRIBUTION, Json.createObjectBuilder() + .add(Prop.SovityDcatExt.DISTRIBUTION, Json.createObjectBuilder() .add(Prop.MobilityDcatAp.MOBILITY_DATA_STANDARD, Json.createObjectBuilder() .add(Prop.MobilityDcatAp.SCHEMA, Json.createObjectBuilder() .add(Prop.Rdfs.LITERAL, "B")))); @@ -250,7 +250,7 @@ void test_create_distribution_dataModelBlank_withReferenceFilesDesc() { .build(); var expectedProperties = Json.createObjectBuilder() - .add(Prop.Dcat.DISTRIBUTION, Json.createObjectBuilder() + .add(Prop.SovityDcatExt.DISTRIBUTION, Json.createObjectBuilder() .add(Prop.MobilityDcatAp.MOBILITY_DATA_STANDARD, Json.createObjectBuilder() .add(Prop.MobilityDcatAp.SCHEMA, Json.createObjectBuilder() .add(Prop.Rdfs.LITERAL, "test")))); @@ -273,7 +273,7 @@ void test_create_distribution_dataModelBlank_withReferenceFileUrls() { .build(); var expectedProperties = Json.createObjectBuilder() - .add(Prop.Dcat.DISTRIBUTION, Json.createObjectBuilder() + .add(Prop.SovityDcatExt.DISTRIBUTION, Json.createObjectBuilder() .add(Prop.MobilityDcatAp.MOBILITY_DATA_STANDARD, Json.createObjectBuilder() .add(Prop.MobilityDcatAp.SCHEMA, Json.createObjectBuilder() .add(Prop.Dcat.DOWNLOAD_URL, Json.createArrayBuilder().add("http://test"))))); diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/PolicyValidatorTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/PolicyValidatorTest.java index 829d10c52..8b4537e8d 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/PolicyValidatorTest.java +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/PolicyValidatorTest.java @@ -163,9 +163,6 @@ void testPermission_full() { .build(); var permission = Permission.Builder.newInstance() .duty(mock(Duty.class)) - .assigner("assigner") - .assignee("assignee") - .target("target") .action(action) .build(); @@ -175,8 +172,6 @@ void testPermission_full() { // assert assertThat(errors.getErrors()).containsExactlyInAnyOrder( "$: Permission has duties, which is currently unsupported.", - "$: Permission has an assigner, which is currently unsupported.", - "$: Permission has an assignee, which is currently unsupported.", "$.action: Action has a type that is not 'USE', but 'idk'.", "$.action: Action has a value for includedIn, which is currently unsupported.", "$.action: Action has a constraint, which is currently unsupported." diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/resources/example-asset-json-ld.json b/extensions/wrapper/wrapper-common-mappers/src/test/resources/example-asset-json-ld.json index f63271a20..49ffbf98a 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/test/resources/example-asset-json-ld.json +++ b/extensions/wrapper/wrapper-common-mappers/src/test/resources/example-asset-json-ld.json @@ -11,7 +11,7 @@ "@type": "http://xmlns.com/foaf/0.1/Organization", "http://xmlns.com/foaf/0.1/name": "My Organization Name" }, - "http://www.w3.org/ns/dcat#distribution": { + "https://semantic.sovity.io/dcat-ext#distribution": { "@type": "http://www.w3.org/ns/dcat#Distribution", "http://www.w3.org/ns/dcat#mediaType": "application/json", "https://w3id.org/mobilitydcat-ap/mobilityDataStandard": { diff --git a/extensions/wrapper/wrapper/build.gradle.kts b/extensions/wrapper/wrapper/build.gradle.kts index cfacde2a6..9cbe8e05f 100644 --- a/extensions/wrapper/wrapper/build.gradle.kts +++ b/extensions/wrapper/wrapper/build.gradle.kts @@ -18,6 +18,7 @@ dependencies { api(libs.edc.contractDefinitionApi) api(libs.edc.controlPlaneSpi) + api(libs.edc.assetSpi) api(libs.edc.coreSpi) api(libs.edc.policyDefinitionApi) api(libs.edc.transferProcessApi) @@ -49,17 +50,7 @@ dependencies { testImplementation(libs.edc.dsp) testImplementation(libs.edc.iamMock) testImplementation(libs.edc.junit) - testImplementation(libs.edc.http) { - exclude(group = "org.eclipse.jetty", module = "jetty-client") - exclude(group = "org.eclipse.jetty", module = "jetty-http") - exclude(group = "org.eclipse.jetty", module = "jetty-io") - exclude(group = "org.eclipse.jetty", module = "jetty-server") - exclude(group = "org.eclipse.jetty", module = "jetty-util") - exclude(group = "org.eclipse.jetty", module = "jetty-webapp") - } - - // Updated jetty versions for e.g. CVE-2023-26048 - testImplementation(libs.bundles.jetty.cve2023) + testImplementation(libs.edc.http) testImplementation(libs.edc.controlPlaneSql) testImplementation(libs.edc.contractNegotiationStoreSql) diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java index 5dbd5e9e9..885463415 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java @@ -19,30 +19,29 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import de.sovity.edc.extension.contacttermination.ContractAgreementTerminationService; import de.sovity.edc.extension.db.directaccess.DslContextFactory; -import org.eclipse.edc.connector.api.management.configuration.ManagementApiConfiguration; -import org.eclipse.edc.connector.api.management.configuration.transform.ManagementApiTypeTransformerRegistry; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.contract.spi.offer.store.ContractDefinitionStore; -import org.eclipse.edc.connector.policy.spi.store.PolicyDefinitionStore; -import org.eclipse.edc.connector.spi.asset.AssetService; -import org.eclipse.edc.connector.spi.catalog.CatalogService; -import org.eclipse.edc.connector.spi.contractagreement.ContractAgreementService; -import org.eclipse.edc.connector.spi.contractdefinition.ContractDefinitionService; -import org.eclipse.edc.connector.spi.contractnegotiation.ContractNegotiationService; -import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService; -import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; -import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; +import org.eclipse.edc.connector.controlplane.asset.spi.index.AssetIndex; +import org.eclipse.edc.connector.controlplane.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.controlplane.contract.spi.offer.store.ContractDefinitionStore; +import org.eclipse.edc.connector.controlplane.policy.spi.store.PolicyDefinitionStore; +import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; +import org.eclipse.edc.connector.controlplane.services.spi.catalog.CatalogService; +import org.eclipse.edc.connector.controlplane.services.spi.contractagreement.ContractAgreementService; +import org.eclipse.edc.connector.controlplane.services.spi.contractdefinition.ContractDefinitionService; +import org.eclipse.edc.connector.controlplane.services.spi.contractnegotiation.ContractNegotiationService; +import org.eclipse.edc.connector.controlplane.services.spi.policydefinition.PolicyDefinitionService; +import org.eclipse.edc.connector.controlplane.services.spi.transferprocess.TransferProcessService; +import org.eclipse.edc.connector.controlplane.transfer.spi.store.TransferProcessStore; import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.policy.engine.spi.PolicyEngine; import org.eclipse.edc.policy.engine.spi.RuleBindingRegistry; -import org.eclipse.edc.protocol.dsp.api.configuration.DspApiConfiguration; import org.eclipse.edc.runtime.metamodel.annotation.Inject; -import org.eclipse.edc.spi.CoreConstants; -import org.eclipse.edc.spi.asset.AssetIndex; +import org.eclipse.edc.spi.constants.CoreConstants; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import org.eclipse.edc.web.spi.WebService; +import org.eclipse.edc.web.spi.configuration.ApiContext; public class WrapperExtension implements ServiceExtension { @@ -67,10 +66,6 @@ public class WrapperExtension implements ServiceExtension { @Inject private DslContextFactory dslContextFactory; @Inject - private DspApiConfiguration dspApiConfiguration; - @Inject - private ManagementApiConfiguration dataManagementApiConfiguration; - @Inject private PolicyDefinitionStore policyDefinitionStore; @Inject private PolicyEngine policyEngine; @@ -83,7 +78,7 @@ public class WrapperExtension implements ServiceExtension { @Inject private TypeManager typeManager; @Inject - private ManagementApiTypeTransformerRegistry typeTransformerRegistry; + private TypeTransformerRegistry typeTransformerRegistry; @Inject private WebService webService; @Inject @@ -128,10 +123,10 @@ public void initialize(ServiceExtensionContext context) { ); wrapperExtensionContext.managementApiResources().forEach(resource -> - webService.registerResource(dataManagementApiConfiguration.getContextAlias(), resource)); + webService.registerResource(ApiContext.MANAGEMENT, resource)); wrapperExtensionContext.dspApiResources().forEach(resource -> - webService.registerResource(dspApiConfiguration.getContextAlias(), resource)); + webService.registerResource(ApiContext.PROTOCOL, resource)); } private void fixObjectMapperDateSerialization(ObjectMapper objectMapper) { diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java index 6df3d7068..0cbc20909 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java @@ -59,9 +59,9 @@ import de.sovity.edc.ext.wrapper.api.ui.pages.contract_negotiations.ContractNegotiationStateService; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_negotiations.ContractOfferMapper; import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.DashboardPageApiService; +import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.CxDidConfigService; import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.DapsConfigService; import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.DashboardDataFetcher; -import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.MiwConfigService; import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.OwnConnectorEndpointServiceImpl; import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.SelfDescriptionService; import de.sovity.edc.ext.wrapper.api.ui.pages.data_offer.DataOfferPageApiService; @@ -82,25 +82,25 @@ import de.sovity.edc.extension.policy.services.AlwaysTruePolicyDefinitionService; import de.sovity.edc.utils.catalog.DspCatalogService; import de.sovity.edc.utils.catalog.mapper.DspDataOfferBuilder; -import de.sovity.edc.utils.config.ConfigProps; +import de.sovity.edc.utils.config.CeConfigProps; import lombok.NoArgsConstructor; import lombok.val; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.contract.spi.offer.store.ContractDefinitionStore; -import org.eclipse.edc.connector.policy.spi.store.PolicyDefinitionStore; -import org.eclipse.edc.connector.spi.asset.AssetService; -import org.eclipse.edc.connector.spi.catalog.CatalogService; -import org.eclipse.edc.connector.spi.contractagreement.ContractAgreementService; -import org.eclipse.edc.connector.spi.contractdefinition.ContractDefinitionService; -import org.eclipse.edc.connector.spi.contractnegotiation.ContractNegotiationService; -import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService; -import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; -import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; +import org.eclipse.edc.connector.controlplane.asset.spi.index.AssetIndex; +import org.eclipse.edc.connector.controlplane.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.controlplane.contract.spi.offer.store.ContractDefinitionStore; +import org.eclipse.edc.connector.controlplane.policy.spi.store.PolicyDefinitionStore; +import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; +import org.eclipse.edc.connector.controlplane.services.spi.catalog.CatalogService; +import org.eclipse.edc.connector.controlplane.services.spi.contractagreement.ContractAgreementService; +import org.eclipse.edc.connector.controlplane.services.spi.contractdefinition.ContractDefinitionService; +import org.eclipse.edc.connector.controlplane.services.spi.contractnegotiation.ContractNegotiationService; +import org.eclipse.edc.connector.controlplane.services.spi.policydefinition.PolicyDefinitionService; +import org.eclipse.edc.connector.controlplane.services.spi.transferprocess.TransferProcessService; +import org.eclipse.edc.connector.controlplane.transfer.spi.store.TransferProcessStore; import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.policy.engine.spi.PolicyEngine; import org.eclipse.edc.policy.engine.spi.RuleBindingRegistry; import org.eclipse.edc.runtime.metamodel.annotation.Inject; -import org.eclipse.edc.spi.asset.AssetIndex; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.system.configuration.Config; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; @@ -141,7 +141,7 @@ public static WrapperExtensionContext buildContext( RuleBindingRegistry ruleBindingRegistry, TransferProcessService transferProcessService, TransferProcessStore transferProcessStore, - TypeTransformerRegistry typeTransformerRegistry + TypeTransformerRegistry rootTypeTransformerRegistry ) { // UI API var operatorMapper = new OperatorMapper(); @@ -152,10 +152,21 @@ public static WrapperExtensionContext buildContext( var selfDescriptionService = new SelfDescriptionService(config); var ownConnectorEndpointService = new OwnConnectorEndpointServiceImpl(selfDescriptionService); var placeholderEndpointService = new PlaceholderEndpointService( - ConfigProps.MY_EDC_DATASOURCE_PLACEHOLDER_BASEURL.getStringOrThrow(config) + CeConfigProps.MY_EDC_DATASOURCE_PLACEHOLDER_BASEURL.getStringOrThrow(config) + ); + var managementApiTypeTransformerRegistry = rootTypeTransformerRegistry.forContext("management-api"); + var assetMapper = newAssetMapper( + managementApiTypeTransformerRegistry, + jsonLd, + ownConnectorEndpointService, + placeholderEndpointService + ); + var policyMapper = newPolicyMapper( + objectMapper, + jsonLd, + managementApiTypeTransformerRegistry, + operatorMapper, config ); - var assetMapper = newAssetMapper(typeTransformerRegistry, jsonLd, ownConnectorEndpointService, placeholderEndpointService); - var policyMapper = newPolicyMapper(objectMapper, typeTransformerRegistry, operatorMapper); var transferProcessStateService = new TransferProcessStateService(); var contractNegotiationUtils = new ContractNegotiationUtils( contractNegotiationService, @@ -209,7 +220,7 @@ public static WrapperExtensionContext buildContext( contractAgreementUtils, contractNegotiationUtils, edcPropertyUtils, - typeTransformerRegistry, + managementApiTypeTransformerRegistry, parameterizationCompatibilityUtils ); var contractAgreementTransferApiService = new ContractAgreementTransferApiService( @@ -238,8 +249,8 @@ public static WrapperExtensionContext buildContext( contractNegotiationBuilder, contractNegotiationStateService ); - var miwConfigBuilder = new MiwConfigService(config); - var dapsConfigBuilder = new DapsConfigService(config); + var cxDidConfigService = new CxDidConfigService(config); + var dapsConfigService = new DapsConfigService(config); var dashboardDataFetcher = new DashboardDataFetcher( contractNegotiationStore, transferProcessService, @@ -250,8 +261,8 @@ public static WrapperExtensionContext buildContext( var dashboardApiService = new DashboardPageApiService( dashboardDataFetcher, transferProcessStateService, - dapsConfigBuilder, - miwConfigBuilder, + dapsConfigService, + cxDidConfigService, selfDescriptionService ); var alwaysTruePolicyService = new AlwaysTruePolicyDefinitionService( @@ -354,8 +365,10 @@ private static AssetMapper newAssetMapper( @NotNull private static PolicyMapper newPolicyMapper( ObjectMapper objectMapper, + JsonLd jsonLd, TypeTransformerRegistry typeTransformerRegistry, - OperatorMapper operatorMapper + OperatorMapper operatorMapper, + Config config ) { var literalMapper = new LiteralMapper(objectMapper); var atomicConstraintMapper = new AtomicConstraintMapper(literalMapper, operatorMapper); @@ -365,7 +378,9 @@ private static PolicyMapper newPolicyMapper( return new PolicyMapper( constraintExtractor, expressionMapper, - typeTransformerRegistry + typeTransformerRegistry, + jsonLd, + config ); } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ServiceException.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ServiceException.java index 3a4af30d5..dde8bddbc 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ServiceException.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ServiceException.java @@ -15,16 +15,8 @@ package de.sovity.edc.ext.wrapper.api; import jakarta.ws.rs.WebApplicationException; -import org.eclipse.edc.service.spi.result.ServiceResult; import org.eclipse.edc.spi.result.Failure; -import java.util.function.Function; - -/** - * Exception for handling {@link ServiceResult} {@link Failure}s. - * - * @see ServiceResult#orElseThrow(Function) - */ public class ServiceException extends WebApplicationException { public ServiceException(Failure failure) { super(failure.getFailureDetail(), 500); diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResourceImpl.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResourceImpl.java index 4bd6ee056..c6c234a8b 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResourceImpl.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResourceImpl.java @@ -142,8 +142,8 @@ public IdResponseDto createDataOffer(DataOfferCreationRequest dataOfferCreationR } @Override - public List getCatalogPageDataOffers(String connectorEndpoint) { - return catalogApiService.fetchDataOffers(connectorEndpoint); + public List getCatalogPageDataOffers(String participantId, String connectorEndpoint) { + return catalogApiService.fetchDataOffers(participantId, connectorEndpoint); } @Override diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/asset/AssetApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/asset/AssetApiService.java index 04a0a8f58..0265d9ac8 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/asset/AssetApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/asset/AssetApiService.java @@ -24,9 +24,9 @@ import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.SelfDescriptionService; import lombok.RequiredArgsConstructor; import lombok.val; -import org.eclipse.edc.connector.spi.asset.AssetService; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; +import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; import org.eclipse.edc.spi.query.QuerySpec; -import org.eclipse.edc.spi.types.domain.asset.Asset; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -64,7 +64,7 @@ public IdResponseDto editAsset(String assetId, UiAssetEditRequest request) { Objects.requireNonNull(foundAsset, "Asset with ID %s not found".formatted(assetId)); val editedAsset = assetMapper.editAsset(foundAsset, request); val updatedAsset = assetService.update(editedAsset).orElseThrow(ServiceException::new); - assetService.update(editedAsset.getId(), editedAsset.getDataAddress()); + assetService.update(editedAsset); return new IdResponseDto(updatedAsset.getId()); } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiService.java index 05fc378b2..f2d23543d 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiService.java @@ -25,8 +25,8 @@ public class CatalogApiService { private final UiDataOfferBuilder uiDataOfferBuilder; private final DspCatalogService dspCatalogService; - public List fetchDataOffers(String connectorEndpoint) { - var dspCatalog = dspCatalogService.fetchDataOffers(connectorEndpoint); + public List fetchDataOffers(String participantId, String connectorEndpoint) { + var dspCatalog = dspCatalogService.fetchDataOffers(participantId, connectorEndpoint); return uiDataOfferBuilder.buildUiDataOffers(dspCatalog); } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/ContractAgreementTransferApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/ContractAgreementTransferApiService.java index a839f3180..af8b789db 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/ContractAgreementTransferApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/ContractAgreementTransferApiService.java @@ -19,9 +19,9 @@ import de.sovity.edc.ext.wrapper.api.ui.model.InitiateTransferRequest; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.services.TransferRequestBuilder; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; -import org.eclipse.edc.connector.transfer.spi.types.TransferRequest; +import org.eclipse.edc.connector.controlplane.services.spi.transferprocess.TransferProcessService; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferRequest; import org.jetbrains.annotations.NotNull; import static org.eclipse.edc.web.spi.exception.ServiceResultHandler.exceptionMapper; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementData.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementData.java index 47801afaf..108b10bb8 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementData.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementData.java @@ -15,10 +15,10 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.services; import de.sovity.edc.ext.db.jooq.tables.records.SovityContractTerminationRecord; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; -import org.eclipse.edc.spi.types.domain.asset.Asset; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; +import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; import java.util.List; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementDataFetcher.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementDataFetcher.java index e0e9b1e14..04569c446 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementDataFetcher.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementDataFetcher.java @@ -19,15 +19,15 @@ import de.sovity.edc.ext.wrapper.utils.MapUtils; import lombok.RequiredArgsConstructor; import lombok.val; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.spi.contractagreement.ContractAgreementService; -import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; -import org.eclipse.edc.spi.asset.AssetIndex; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; +import org.eclipse.edc.connector.controlplane.asset.spi.index.AssetIndex; +import org.eclipse.edc.connector.controlplane.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.services.spi.contractagreement.ContractAgreementService; +import org.eclipse.edc.connector.controlplane.services.spi.transferprocess.TransferProcessService; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; import org.eclipse.edc.spi.query.QuerySpec; -import org.eclipse.edc.spi.types.domain.asset.Asset; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -62,7 +62,7 @@ public List getContractAgreements(DSLContext dsl) { .collect(groupingBy(it -> it.getContractAgreement().getId())); var transfers = getAllTransferProcesses().stream() - .collect(groupingBy(it -> it.getDataRequest().getContractId())); + .collect(groupingBy(TransferProcess::getContractId)); var agreementIds = agreements.stream().map(ContractAgreement::getId).toList(); @@ -91,7 +91,7 @@ public ContractAgreementData getContractAgreement(DSLContext dsl, String contrac .orElseThrow( () -> new IllegalStateException("Can't find any negotiation for contract agreement id %s".formatted(contractAgreementId))); - val transfers = getAllTransferProcesses().stream().collect(groupingBy(it -> it.getDataRequest().getContractId())); + val transfers = getAllTransferProcesses().stream().collect(groupingBy(TransferProcess::getContractId)); val terminations = fetchTerminations(dsl, agreement.getId()); diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementPageCardBuilder.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementPageCardBuilder.java index 87ba240d3..464b1a08a 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementPageCardBuilder.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementPageCardBuilder.java @@ -25,10 +25,10 @@ import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferProcessStateService; import lombok.NonNull; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; -import org.eclipse.edc.spi.types.domain.asset.Asset; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; +import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; import org.jetbrains.annotations.NotNull; import java.util.Comparator; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementUtils.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementUtils.java index 9344797e9..04f8fdd5b 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementUtils.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractAgreementUtils.java @@ -15,8 +15,8 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.services; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.spi.contractagreement.ContractAgreementService; +import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.controlplane.services.spi.contractagreement.ContractAgreementService; import org.eclipse.edc.spi.EdcException; import java.util.Optional; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractNegotiationUtils.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractNegotiationUtils.java index 878053ec3..298272c90 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractNegotiationUtils.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ContractNegotiationUtils.java @@ -17,8 +17,8 @@ import de.sovity.edc.ext.wrapper.api.ServiceException; import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.SelfDescriptionService; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.spi.contractnegotiation.ContractNegotiationService; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.services.spi.contractnegotiation.ContractNegotiationService; import org.eclipse.edc.spi.EdcException; import org.eclipse.edc.spi.query.Criterion; import org.eclipse.edc.spi.query.QuerySpec; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ParameterizationCompatibilityUtils.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ParameterizationCompatibilityUtils.java index 0a3dd04d8..51d57f56f 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ParameterizationCompatibilityUtils.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/ParameterizationCompatibilityUtils.java @@ -21,7 +21,7 @@ import java.util.HashMap; import java.util.Map; -import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; +import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE; public class ParameterizationCompatibilityUtils { private static final String WORKAROUND = "https://sovity.de/workaround/proxy/param/"; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/TransferRequestBuilder.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/TransferRequestBuilder.java index 559eef1a2..55c66865e 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/TransferRequestBuilder.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/TransferRequestBuilder.java @@ -24,9 +24,9 @@ import jakarta.json.Json; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.Validate; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.transfer.spi.types.TransferRequest; -import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferRequest; +import org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import java.util.List; @@ -44,7 +44,6 @@ public TransferRequest buildCustomTransferRequest( InitiateTransferRequest request ) { var contractId = request.getContractAgreementId(); - var agreement = contractAgreementUtils.findByIdOrThrow(contractId); var negotiation = contractNegotiationUtils.findByContractAgreementIdOrThrow(contractId); var address = parameterizationCompatibilityUtils.enrich(edcPropertyUtils.buildDataAddress(request.getDataSinkProperties()), request.getTransferProcessProperties()); assertIsConsuming(negotiation); @@ -52,13 +51,12 @@ public TransferRequest buildCustomTransferRequest( return TransferRequest.Builder.newInstance() .id(UUID.randomUUID().toString()) .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) - .connectorAddress(negotiation.getCounterPartyAddress()) - .connectorId(negotiation.getCounterPartyId()) + .counterPartyAddress(negotiation.getCounterPartyAddress()) .contractId(contractId) - .assetId(agreement.getAssetId()) .dataDestination(address) .privateProperties(edcPropertyUtils.toMapOfObject(request.getTransferProcessProperties())) .callbackAddresses(List.of()) + .transferType(request.getTransferType()) .build(); } @@ -87,7 +85,7 @@ public TransferRequest buildCustomTransferRequest( .add(Prop.Edc.ASSET_ID, agreement.getAssetId()) .add(Prop.Edc.CONTRACT_ID, agreement.getId()) .add(Prop.Edc.CONNECTOR_ID, negotiation.getCounterPartyId()) - .add(Prop.Edc.CONNECTOR_ADDRESS, negotiation.getCounterPartyAddress()) + .add(Prop.Edc.COUNTER_PARTY_ADDRESS, negotiation.getCounterPartyAddress()) .build(); return typeTransformerRegistry.transform(requestJsonLd, TransferRequest.class) diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionApiService.java index ca49905b1..5a933b964 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionApiService.java @@ -19,11 +19,15 @@ import de.sovity.edc.ext.wrapper.api.ui.model.ContractDefinitionRequest; import de.sovity.edc.ext.wrapper.api.ui.model.IdResponseDto; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.types.offer.ContractDefinition; -import org.eclipse.edc.connector.spi.contractdefinition.ContractDefinitionService; +import lombok.SneakyThrows; +import org.eclipse.edc.connector.controlplane.contract.spi.types.offer.ContractDefinition; +import org.eclipse.edc.connector.controlplane.services.spi.contractdefinition.ContractDefinitionService; +import org.eclipse.edc.spi.entity.Entity; import org.eclipse.edc.spi.query.QuerySpec; import org.jetbrains.annotations.NotNull; +import java.io.File; +import java.io.FileWriter; import java.util.Comparator; import java.util.List; @@ -34,8 +38,10 @@ public class ContractDefinitionApiService { private final CriterionMapper criterionMapper; private final ContractDefinitionBuilder contractDefinitionBuilder; + @SneakyThrows public List getContractDefinitions() { var definitions = getAllContractDefinitions(); + return definitions.stream() .sorted(Comparator.comparing(ContractDefinition::getCreatedAt).reversed()) .map(this::buildContractDefinitionEntry) diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionBuilder.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionBuilder.java index b948eed0d..5f60bfd43 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionBuilder.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionBuilder.java @@ -17,7 +17,7 @@ import de.sovity.edc.ext.wrapper.api.ui.model.ContractDefinitionRequest; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.types.offer.ContractDefinition; +import org.eclipse.edc.connector.controlplane.contract.spi.types.offer.ContractDefinition; @RequiredArgsConstructor diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/CriterionOperatorMapper.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/CriterionOperatorMapper.java index ec153385e..b2dfbe2f8 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/CriterionOperatorMapper.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/CriterionOperatorMapper.java @@ -26,7 +26,7 @@ @RequiredArgsConstructor public class CriterionOperatorMapper { /** - * @see org.eclipse.edc.connector.defaults.storage.CriterionToPredicateConverterImpl + * @see org.eclipse.edc.connector.controlplane.defaults.storage.CriterionToPredicateConverterImpl */ private final Map mappings = Map.of( UiCriterionOperator.EQ, "=", diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationApiService.java index 373318a85..cbb9ca07c 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationApiService.java @@ -17,9 +17,9 @@ import de.sovity.edc.ext.wrapper.api.ui.model.ContractNegotiationRequest; import de.sovity.edc.ext.wrapper.api.ui.model.UiContractNegotiation; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.spi.contractnegotiation.ContractNegotiationService; +import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.services.spi.contractnegotiation.ContractNegotiationService; import org.jetbrains.annotations.NotNull; import java.util.Optional; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationBuilder.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationBuilder.java index 9d098fc00..2072056ca 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationBuilder.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationBuilder.java @@ -17,8 +17,8 @@ import de.sovity.edc.ext.wrapper.api.ui.model.ContractNegotiationRequest; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractRequest; -import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractRequest; +import org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol; @RequiredArgsConstructor @@ -28,12 +28,12 @@ public class ContractNegotiationBuilder { public ContractRequest buildContractNegotiation(ContractNegotiationRequest request) { var counterPartyAddress = request.getCounterPartyAddress(); + var contractOffer = contractOfferMapper.buildContractOffer(request); return ContractRequest.Builder.newInstance() - .counterPartyAddress(counterPartyAddress) - .providerId(request.getCounterPartyParticipantId()) - .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) - .contractOffer(contractOfferMapper.buildContractOffer(request)) - .build(); + .counterPartyAddress(counterPartyAddress) + .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) + .contractOffer(contractOffer) + .build(); } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationStateService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationStateService.java index f95e4b501..6548070ac 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationStateService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationStateService.java @@ -17,8 +17,8 @@ import de.sovity.edc.ext.wrapper.api.ui.model.ContractNegotiationSimplifiedState; import de.sovity.edc.ext.wrapper.api.ui.model.ContractNegotiationState; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationStates; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiationStates; import org.jetbrains.annotations.NotNull; @@ -26,9 +26,9 @@ public class ContractNegotiationStateService { /** - * Interpret {@link org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation#getState()} for use in our UI. + * Interpret {@link org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation#getState()} for use in our UI. * - * @param code {@link org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation#getState()}, see {@link org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationStates#code()} + * @param code {@link org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation#getState()}, see {@link org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiationStates#code()} * @return if running */ @NotNull diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractOfferMapper.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractOfferMapper.java index e4a5073bf..bc93e0b71 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractOfferMapper.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractOfferMapper.java @@ -18,7 +18,8 @@ import de.sovity.edc.ext.wrapper.api.common.mappers.PolicyMapper; import de.sovity.edc.ext.wrapper.api.ui.model.ContractNegotiationRequest; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.types.offer.ContractOffer; +import org.eclipse.edc.connector.controlplane.contract.spi.types.offer.ContractOffer; +import org.eclipse.edc.policy.model.Policy; @RequiredArgsConstructor @@ -26,9 +27,19 @@ public class ContractOfferMapper { private final PolicyMapper policyMapper; public ContractOffer buildContractOffer(ContractNegotiationRequest contractRequest) { + var policy = policyMapper.buildPolicy(contractRequest.getPolicyJsonLd()); + + // Required or Eclipse EDC Validation in DSP panics + // despite assetId being a field on the ContractOffer + // despite the catalog not putting it out while policies aren't asset specific + policy = policy.toBuilder() + .target(contractRequest.getAssetId()) + .assigner(contractRequest.getCounterPartyId()) + .build(); + return ContractOffer.Builder.newInstance() .id(contractRequest.getContractOfferId()) - .policy(policyMapper.buildPolicy(contractRequest.getPolicyJsonLd())) + .policy(policy) .assetId(contractRequest.getAssetId()) .build(); } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/DashboardPageApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/DashboardPageApiService.java index 80333f78b..9aef2059d 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/DashboardPageApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/DashboardPageApiService.java @@ -16,15 +16,15 @@ import de.sovity.edc.ext.wrapper.api.ui.model.DashboardPage; import de.sovity.edc.ext.wrapper.api.ui.model.DashboardTransferAmounts; +import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.CxDidConfigService; import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.DapsConfigService; import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.DashboardDataFetcher; -import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.MiwConfigService; import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.SelfDescriptionService; import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferProcessStateService; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; +import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -41,7 +41,7 @@ public class DashboardPageApiService { private final DashboardDataFetcher dashboardDataFetcher; private final TransferProcessStateService transferProcessStateService; private final DapsConfigService dapsConfigService; - private final MiwConfigService miwConfigService; + private final CxDidConfigService cxDidConfigService; private final SelfDescriptionService selfDescriptionService; @NotNull @@ -83,7 +83,7 @@ public DashboardPage dashboardPage() { dashboardPage.setConnectorMaintainerUrl(selfDescriptionService.getMaintainerUrl()); dashboardPage.setConnectorMaintainerName(selfDescriptionService.getMaintainerName()); - dashboardPage.setConnectorMiwConfig(miwConfigService.buildMiwConfigOrNull()); + dashboardPage.setConnectorCxDidConfig(cxDidConfigService.buildCxDidConfigOrNull()); dashboardPage.setConnectorDapsConfig(dapsConfigService.buildDapsConfigOrNull()); return dashboardPage; } @@ -93,21 +93,21 @@ DashboardTransferAmounts getTransferAmounts( Set agreements ) { var numTotal = transferProcesses.stream() - .filter(transferProcess -> agreements.contains(transferProcess.getDataRequest().getContractId())) + .filter(transferProcess -> agreements.contains(transferProcess.getContractId())) .count(); var numOk = transferProcesses.stream() - .filter(transferProcess -> agreements.contains(transferProcess.getDataRequest().getContractId())) + .filter(transferProcess -> agreements.contains(transferProcess.getContractId())) .filter(transferProcess -> transferProcessStateService.getSimplifiedState(transferProcess.getState()).equals(OK)) .count(); var numRunning = transferProcesses.stream() - .filter(transferProcess -> agreements.contains(transferProcess.getDataRequest().getContractId())) + .filter(transferProcess -> agreements.contains(transferProcess.getContractId())) .filter(transferProcess -> transferProcessStateService.getSimplifiedState(transferProcess.getState()).equals(RUNNING)) .count(); var numError = transferProcesses.stream() - .filter(transferProcess -> agreements.contains(transferProcess.getDataRequest().getContractId())) + .filter(transferProcess -> agreements.contains(transferProcess.getContractId())) .filter(transferProcess -> transferProcessStateService.getSimplifiedState(transferProcess.getState()).equals(ERROR)) .count(); diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/CxDidConfigService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/CxDidConfigService.java new file mode 100644 index 000000000..a5c5e6457 --- /dev/null +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/CxDidConfigService.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services; + +import de.sovity.edc.ext.wrapper.api.ui.model.DashboardCxDidConfig; +import lombok.RequiredArgsConstructor; +import org.eclipse.edc.spi.system.configuration.Config; + +import static com.apicatalog.jsonld.StringUtils.isBlank; + +@RequiredArgsConstructor +public class CxDidConfigService { + private final Config config; + + /** + * Wallet Token Url + */ + private static final String EDC_IAM_STS_OAUTH_TOKEN_URL = "edc.iam.sts.oauth.token.url"; + + + /** + * Trusted VC Issuer + */ + private static final String EDC_IAM_TRUSTED_ISSUER_COFINITY_ID = "edc.iam.trusted-issuer.cofinity.id"; + + + /** + * BDRS Url + */ + + private static final String TX_IAM_IATP_BDRS_SERVER_URL = "tx.iam.iatp.bdrs.server.url"; + + + /** + * My DID + */ + private static final String EDC_IAM_ISSUER_ID = "edc.iam.issuer.id"; + + + /** + * DIM Url + */ + private static final String EDC_IAM_STS_DIM_URL = "edc.iam.sts.dim.url"; + + public DashboardCxDidConfig buildCxDidConfigOrNull() { + var cxDidConfig = new DashboardCxDidConfig(); + cxDidConfig.setMyDid(configValue(EDC_IAM_ISSUER_ID)); + cxDidConfig.setWalletTokenUrl(configValue(EDC_IAM_STS_OAUTH_TOKEN_URL)); + cxDidConfig.setTrustedVcIssuer(configValue(EDC_IAM_TRUSTED_ISSUER_COFINITY_ID)); + cxDidConfig.setDimUrl(configValue(EDC_IAM_STS_DIM_URL)); + cxDidConfig.setBdrsUrl(configValue(TX_IAM_IATP_BDRS_SERVER_URL)); + return isBlank(cxDidConfig.getMyDid()) ? null : cxDidConfig; + } + + private String configValue(String configKey) { + return config.getString(configKey, ""); + } +} diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/DapsConfigService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/DapsConfigService.java index 41ed3c03c..73915302a 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/DapsConfigService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/DapsConfigService.java @@ -15,7 +15,7 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services; import de.sovity.edc.ext.wrapper.api.ui.model.DashboardDapsConfig; -import de.sovity.edc.utils.config.ConfigProps; +import de.sovity.edc.utils.config.CeConfigProps; import lombok.RequiredArgsConstructor; import org.eclipse.edc.spi.system.configuration.Config; @@ -27,8 +27,8 @@ public class DapsConfigService { public DashboardDapsConfig buildDapsConfigOrNull() { var dapsConfig = new DashboardDapsConfig(); - dapsConfig.setTokenUrl(ConfigProps.EDC_OAUTH_TOKEN_URL.getStringOrNull(config)); - dapsConfig.setJwksUrl(ConfigProps.EDC_OAUTH_PROVIDER_JWKS_URL.getStringOrNull(config)); + dapsConfig.setTokenUrl(CeConfigProps.EDC_OAUTH_TOKEN_URL.getStringOrNull(config)); + dapsConfig.setJwksUrl(CeConfigProps.EDC_OAUTH_PROVIDER_JWKS_URL.getStringOrNull(config)); return isBlank(dapsConfig.getTokenUrl()) ? null : dapsConfig; } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/DashboardDataFetcher.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/DashboardDataFetcher.java index 0eee91dbc..57fb856ce 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/DashboardDataFetcher.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/DashboardDataFetcher.java @@ -16,13 +16,13 @@ import de.sovity.edc.ext.wrapper.api.ServiceException; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.spi.contractdefinition.ContractDefinitionService; -import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService; -import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; -import org.eclipse.edc.spi.asset.AssetIndex; +import org.eclipse.edc.connector.controlplane.asset.spi.index.AssetIndex; +import org.eclipse.edc.connector.controlplane.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.services.spi.contractdefinition.ContractDefinitionService; +import org.eclipse.edc.connector.controlplane.services.spi.policydefinition.PolicyDefinitionService; +import org.eclipse.edc.connector.controlplane.services.spi.transferprocess.TransferProcessService; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; import org.eclipse.edc.spi.query.QuerySpec; import org.jetbrains.annotations.NotNull; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/MiwConfigService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/MiwConfigService.java deleted file mode 100644 index 61e6556f4..000000000 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/MiwConfigService.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services; - -import de.sovity.edc.ext.wrapper.api.ui.model.DashboardMiwConfig; -import lombok.RequiredArgsConstructor; -import org.eclipse.edc.spi.system.configuration.Config; - -import static com.apicatalog.jsonld.StringUtils.isBlank; - -@RequiredArgsConstructor -public class MiwConfigService { - private final Config config; - - private static final String MIW_AUTHORITY_ID = configKey("TX_SSI_MIW_AUTHORITY_ID"); - - private static final String MIW_URL = configKey("TX_SSI_MIW_URL"); - - private static final String MIW_TOKEN_URL = configKey("TX_SSI_OAUTH_TOKEN_URL"); - - public DashboardMiwConfig buildMiwConfigOrNull() { - var miwConfig = new DashboardMiwConfig(); - miwConfig.setUrl(configValue(MIW_URL)); - miwConfig.setAuthorityId(configValue(MIW_AUTHORITY_ID)); - miwConfig.setTokenUrl(configValue(MIW_TOKEN_URL)); - return isBlank(miwConfig.getUrl()) ? null : miwConfig; - } - - String configValue(String configKey) { - return config.getString(configKey, ""); - } - - /** - * Maps a {@literal CONFIG_KEY} to {@literal config.key} - * - * @param envVarKey {@literal CONFIG_KEY} - * @return {@literal config.key} - */ - public static String configKey(String envVarKey) { - return String.join(".", envVarKey.split("_")).toLowerCase(); - } -} diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/SelfDescriptionService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/SelfDescriptionService.java index 4121170a8..6a90178d2 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/SelfDescriptionService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/services/SelfDescriptionService.java @@ -14,7 +14,7 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services; -import de.sovity.edc.utils.config.ConfigProps; +import de.sovity.edc.utils.config.CeConfigProps; import lombok.RequiredArgsConstructor; import org.eclipse.edc.spi.system.configuration.Config; @@ -23,34 +23,34 @@ public class SelfDescriptionService { private final Config config; public String getParticipantId() { - return ConfigProps.EDC_PARTICIPANT_ID.getStringOrThrow(config); + return CeConfigProps.EDC_PARTICIPANT_ID.getStringOrThrow(config); } public String getConnectorEndpoint() { - return ConfigProps.EDC_DSP_CALLBACK_ADDRESS.getStringOrThrow(config); + return CeConfigProps.EDC_DSP_CALLBACK_ADDRESS.getStringOrThrow(config); } public String getConnectorTitle() { - return ConfigProps.MY_EDC_TITLE.getStringOrThrow(config); + return CeConfigProps.MY_EDC_TITLE.getStringOrThrow(config); } public String getConnectorDescription() { - return ConfigProps.MY_EDC_DESCRIPTION.getStringOrThrow(config); + return CeConfigProps.MY_EDC_DESCRIPTION.getStringOrThrow(config); } public String getCuratorUrl() { - return ConfigProps.MY_EDC_CURATOR_URL.getStringOrThrow(config); + return CeConfigProps.MY_EDC_CURATOR_URL.getStringOrThrow(config); } public String getCuratorName() { - return ConfigProps.MY_EDC_CURATOR_NAME.getStringOrThrow(config); + return CeConfigProps.MY_EDC_CURATOR_NAME.getStringOrThrow(config); } public String getMaintainerUrl() { - return ConfigProps.MY_EDC_MAINTAINER_URL.getStringOrThrow(config); + return CeConfigProps.MY_EDC_MAINTAINER_URL.getStringOrThrow(config); } public String getMaintainerName() { - return ConfigProps.MY_EDC_MAINTAINER_NAME.getStringOrThrow(config); + return CeConfigProps.MY_EDC_MAINTAINER_NAME.getStringOrThrow(config); } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/data_offer/DataOfferPageApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/data_offer/DataOfferPageApiService.java index 81fd36c2e..a19ec1316 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/data_offer/DataOfferPageApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/data_offer/DataOfferPageApiService.java @@ -17,7 +17,7 @@ import de.sovity.edc.extension.policy.services.AlwaysTruePolicyDefinitionService; import lombok.RequiredArgsConstructor; import lombok.val; -import org.eclipse.edc.spi.types.domain.asset.Asset; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; import org.eclipse.edc.web.spi.exception.InvalidRequestException; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiService.java index 87a17cbcb..1837bfbb9 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiService.java @@ -23,11 +23,13 @@ import de.sovity.edc.ext.wrapper.api.ui.model.PolicyDefinitionCreateDto; import de.sovity.edc.ext.wrapper.api.ui.model.PolicyDefinitionCreateRequest; import de.sovity.edc.ext.wrapper.api.ui.model.PolicyDefinitionDto; +import de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.services.SelfDescriptionService; import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.policy.spi.PolicyDefinition; -import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService; +import org.eclipse.edc.connector.controlplane.policy.spi.PolicyDefinition; +import org.eclipse.edc.connector.controlplane.services.spi.policydefinition.PolicyDefinitionService; import org.eclipse.edc.spi.query.QuerySpec; +import org.eclipse.edc.spi.system.configuration.Config; import java.util.Comparator; import java.util.List; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiService.java index 30340044c..50c0760d5 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiService.java @@ -20,16 +20,16 @@ import de.sovity.edc.utils.jsonld.vocab.Prop; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.spi.asset.AssetService; -import org.eclipse.edc.connector.spi.contractagreement.ContractAgreementService; -import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; +import org.eclipse.edc.connector.controlplane.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; +import org.eclipse.edc.connector.controlplane.services.spi.contractagreement.ContractAgreementService; +import org.eclipse.edc.connector.controlplane.services.spi.transferprocess.TransferProcessService; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; import org.eclipse.edc.spi.entity.Entity; import org.eclipse.edc.spi.query.QuerySpec; -import org.eclipse.edc.spi.types.domain.asset.Asset; import org.jetbrains.annotations.NotNull; import java.util.Comparator; @@ -79,8 +79,8 @@ public List getTransferHistoryEntries() { var transferProcesses = getAllTransferProcesses(); return transferProcesses.stream().map(process -> { - var agreement = Optional.ofNullable(agreementsById.get(process.getDataRequest().getContractId())); - var negotiation = Optional.ofNullable(negotiationsById.get(process.getDataRequest().getContractId())); + var agreement = Optional.ofNullable(agreementsById.get(process.getContractId())); + var negotiation = Optional.ofNullable(negotiationsById.get(process.getContractId())); var asset = assetLookup(assetsById, process); var direction = negotiation.map(ContractNegotiation::getType).map(ContractAgreementDirection::fromType); var transferHistoryEntry = new TransferHistoryEntry(); @@ -115,7 +115,7 @@ public List getTransferHistoryEntries() { } private Asset assetLookup(Map assetsById, TransferProcess process) { - var assetId = process.getDataRequest().getAssetId(); + var assetId = process.getAssetId(); var asset = assetsById.get(assetId); if (asset == null) { return Asset.Builder.newInstance().id(assetId).build(); diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageAssetFetcherService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageAssetFetcherService.java index f3a295e4d..b68585907 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageAssetFetcherService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageAssetFetcherService.java @@ -18,13 +18,13 @@ import de.sovity.edc.ext.wrapper.api.common.model.UiAsset; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.services.ContractNegotiationUtils; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.spi.asset.AssetService; -import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; +import org.eclipse.edc.connector.controlplane.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; +import org.eclipse.edc.connector.controlplane.services.spi.transferprocess.TransferProcessService; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.types.domain.asset.Asset; import org.jetbrains.annotations.NotNull; @RequiredArgsConstructor @@ -55,8 +55,8 @@ private UiAsset getAssetFromTransferProcess(TransferProcess process) { } private Asset getTransferProcessAsset(TransferProcess process) { - var assetId = process.getDataRequest().getAssetId(); - var asset = assetService.findById(process.getDataRequest().getAssetId()); + var assetId = process.getAssetId(); + var asset = assetService.findById(process.getAssetId()); if (asset == null) { asset = Asset.Builder.newInstance().id(assetId).build(); } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessStateService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessStateService.java index a3dfac07c..578326337 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessStateService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessStateService.java @@ -17,8 +17,8 @@ import de.sovity.edc.ext.wrapper.api.ui.model.TransferProcessSimplifiedState; import de.sovity.edc.ext.wrapper.api.ui.model.TransferProcessState; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcessStates; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcessStates; import org.jetbrains.annotations.NotNull; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/pages/catalog/FilterExpressionOperatorMapper.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/pages/catalog/FilterExpressionOperatorMapper.java index 5712d38f4..d93e6f442 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/pages/catalog/FilterExpressionOperatorMapper.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/pages/catalog/FilterExpressionOperatorMapper.java @@ -25,7 +25,7 @@ @RequiredArgsConstructor public class FilterExpressionOperatorMapper { /** - * @see org.eclipse.edc.connector.defaults.storage.CriterionToPredicateConverterImpl + * @see org.eclipse.edc.connector.controlplane.defaults.storage.CriterionToPredicateConverterImpl */ private final Map mappings = Map.of( CatalogFilterExpressionOperator.EQ, "=", diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/pages/catalog/UseCaseCatalogApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/pages/catalog/UseCaseCatalogApiService.java index 49da44363..4d6fe6a41 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/pages/catalog/UseCaseCatalogApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/pages/catalog/UseCaseCatalogApiService.java @@ -32,7 +32,10 @@ public class UseCaseCatalogApiService { public List fetchDataOffers(CatalogQuery catalogQuery) { var querySpec = buildQuerySpec(catalogQuery); - var dspCatalog = dspCatalogService.fetchDataOffersWithFilters(catalogQuery.getConnectorEndpoint(), querySpec); + var dspCatalog = dspCatalogService.fetchDataOffersWithFilters( + catalogQuery.getParticipantId(), + catalogQuery.getConnectorEndpoint(), + querySpec); return uiDataOfferBuilder.buildUiDataOffers(dspCatalog); } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/services/KpiApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/services/KpiApiService.java index 65bb5a272..16fea5e6b 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/services/KpiApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/services/KpiApiService.java @@ -20,12 +20,12 @@ import de.sovity.edc.ext.wrapper.api.usecase.model.KpiResult; import de.sovity.edc.ext.wrapper.api.usecase.model.TransferProcessStatesDto; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.offer.store.ContractDefinitionStore; -import org.eclipse.edc.connector.policy.spi.store.PolicyDefinitionStore; -import org.eclipse.edc.connector.spi.contractagreement.ContractAgreementService; -import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; -import org.eclipse.edc.spi.asset.AssetIndex; +import org.eclipse.edc.connector.controlplane.asset.spi.index.AssetIndex; +import org.eclipse.edc.connector.controlplane.contract.spi.offer.store.ContractDefinitionStore; +import org.eclipse.edc.connector.controlplane.policy.spi.store.PolicyDefinitionStore; +import org.eclipse.edc.connector.controlplane.services.spi.contractagreement.ContractAgreementService; +import org.eclipse.edc.connector.controlplane.transfer.spi.store.TransferProcessStore; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; import org.eclipse.edc.spi.query.QuerySpec; import java.util.List; diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementTransferApiServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementTransferApiServiceTest.java deleted file mode 100644 index 58be55de4..000000000 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementTransferApiServiceTest.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreement; - -import de.sovity.edc.client.EdcClient; -import de.sovity.edc.client.gen.model.InitiateCustomTransferRequest; -import de.sovity.edc.client.gen.model.InitiateTransferRequest; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; -import de.sovity.edc.utils.JsonUtils; -import de.sovity.edc.utils.jsonld.vocab.Prop; -import jakarta.json.Json; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationStates; -import org.eclipse.edc.connector.contract.spi.types.offer.ContractOffer; -import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; -import org.eclipse.edc.junit.annotations.ApiTest; -import org.eclipse.edc.policy.model.Policy; -import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import java.util.Map; -import java.util.UUID; - -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; -import static org.assertj.core.api.Assertions.assertThat; - -@ApiTest -class ContractAgreementTransferApiServiceTest { - - private static final String DATA_SINK = "http://my-data-sink/api/stuff"; - private static final String COUNTER_PARTY_ADDRESS = - "http://some-other-connector/api/v1/ids/data"; - - private static ConnectorConfig config; - private static EdcClient client; - - @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "provider", - testDatabase -> { - config = forTestDatabase("my-edc-participant-id", testDatabase); - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - return config.getProperties(); - } - ); - - @Test - void startTransferProcessForAgreementId( - ContractNegotiationStore store, - TransferProcessStore transferProcessStore - ) { - // arrange - var contractId = UUID.randomUUID().toString(); - createContractNegotiation(store, COUNTER_PARTY_ADDRESS, contractId); - - var request = new InitiateTransferRequest( - contractId, - Map.of( - "type", "HttpData", - "baseUrl", DATA_SINK - ), - Map.of("privateProperty", "privateValue") - ); - - // act - var result = client.uiApi().initiateTransfer(request); - - // then - var transferProcess = transferProcessStore.findById(result.getId()); - assertThat(transferProcess).isNotNull(); - assertThat(transferProcess.getPrivateProperties()).containsAllEntriesOf(Map.of( - "privateProperty", "privateValue" - )); - - var dataRequest = transferProcess.getDataRequest(); - assertThat(dataRequest.getContractId()).isEqualTo(contractId); - assertThat(dataRequest.getConnectorAddress()).isEqualTo(COUNTER_PARTY_ADDRESS); - assertThat(dataRequest.getDataDestination().getProperties()).containsAllEntriesOf(Map.of( - "https://w3id.org/edc/v0.0.1/ns/type", "HttpData", - "baseUrl", DATA_SINK - )); - } - - @Test - void startCustomTransferProcessForAgreementId( - ContractNegotiationStore store, - TransferProcessStore transferProcessStore - ) { - // arrange - var contractId = UUID.randomUUID().toString(); - createContractNegotiation(store, COUNTER_PARTY_ADDRESS, contractId); - - var customRequestJson = Json.createObjectBuilder() - .add(Prop.Edc.DATA_DESTINATION, Json.createObjectBuilder() - .add(Prop.Edc.TYPE, "HttpData") - .add(Prop.Edc.BASE_URL, DATA_SINK)) - .add(Prop.Edc.PRIVATE_PROPERTIES, Json.createObjectBuilder() - .add(Prop.Edc.RECEIVER_HTTP_ENDPOINT, "http://my-pull-backend") - .add("this-will-disappear", "because-its-not-an-url") - .add("http://unknown/custom-prop", "value")) - .add(Prop.Edc.CTX + "protocol", HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) - .build(); - var request = new InitiateCustomTransferRequest( - contractId, - JsonUtils.toJson(customRequestJson) - ); - - // act - var result = client.uiApi().initiateCustomTransfer(request); - - // then - var transferProcess = transferProcessStore.findById(result.getId()); - assertThat(transferProcess).isNotNull(); - assertThat(transferProcess.getPrivateProperties()).containsAllEntriesOf(Map.of( - Prop.Edc.RECEIVER_HTTP_ENDPOINT, "http://my-pull-backend", - "http://unknown/custom-prop", "value" - )); - - var dataRequest = transferProcess.getDataRequest(); - assertThat(dataRequest.getContractId()).isEqualTo(contractId); - assertThat(dataRequest.getConnectorAddress()).isEqualTo(COUNTER_PARTY_ADDRESS); - assertThat(dataRequest.getDataDestination().getProperties()).containsAllEntriesOf(Map.of( - Prop.Edc.TYPE, "HttpData", - Prop.Edc.BASE_URL, DATA_SINK - )); - } - - private ContractNegotiation createContractNegotiation( - ContractNegotiationStore store, - String counterPartyAddress, - String agreementId - ) { - var assetId = UUID.randomUUID().toString(); - var agreement = ContractAgreement.Builder.newInstance() - .id(agreementId) - .providerId(UUID.randomUUID().toString()) - .consumerId(UUID.randomUUID().toString()) - .assetId(assetId) - .policy(getPolicy()) - .build(); - - var negotiation = ContractNegotiation.Builder.newInstance() - .id(UUID.randomUUID().toString()) - .counterPartyId(UUID.randomUUID().toString()) - .counterPartyAddress(counterPartyAddress) - .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) - .contractAgreement(agreement) - .contractOffer(createContractOffer(assetId)) - .state(ContractNegotiationStates.FINALIZED.code()) - .build(); - - store.save(negotiation); - return negotiation; - } - - private Policy getPolicy() { - return Policy.Builder.newInstance().build(); - } - - private ContractOffer createContractOffer(String assetId) { - return ContractOffer.Builder.newInstance() - .id(UUID.randomUUID().toString()) - .assetId(assetId) - .policy(getPolicy()) - .build(); - } -} diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionPageApiServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionPageApiServiceTest.java deleted file mode 100644 index b0bc2a953..000000000 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionPageApiServiceTest.java +++ /dev/null @@ -1,195 +0,0 @@ -package de.sovity.edc.ext.wrapper.api.ui.pages.contract_definitions; - -import de.sovity.edc.client.EdcClient; -import de.sovity.edc.client.gen.model.ContractDefinitionEntry; -import de.sovity.edc.client.gen.model.ContractDefinitionRequest; -import de.sovity.edc.client.gen.model.UiCriterion; -import de.sovity.edc.client.gen.model.UiCriterionLiteral; -import de.sovity.edc.client.gen.model.UiCriterionLiteralType; -import de.sovity.edc.client.gen.model.UiCriterionOperator; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; -import org.eclipse.edc.connector.contract.spi.types.offer.ContractDefinition; -import org.eclipse.edc.connector.spi.contractdefinition.ContractDefinitionService; -import org.eclipse.edc.junit.annotations.ApiTest; -import org.eclipse.edc.spi.query.Criterion; -import org.eclipse.edc.spi.query.QuerySpec; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import java.util.List; - -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; -import static org.assertj.core.api.Assertions.assertThat; - -@ApiTest -class ContractDefinitionPageApiServiceTest { - - private static final String PARTICIPANT_ID = "my-edc-participant-id"; - - private static ConnectorConfig config; - private static EdcClient client; - - @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "edc", - testDatabase -> { - config = forTestDatabase(PARTICIPANT_ID, testDatabase); - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - return config.getProperties(); - } - ); - - @Test - void contractDefinitionPage(ContractDefinitionService contractDefinitionService) { - // arrange - - var criterion = new Criterion("exampleLeft1", "=", "abc"); - createContractDefinition(contractDefinitionService, "contractDefinition-id-1", "contractPolicy-id-1", "accessPolicy-id-1", criterion); - - // act - var result = client.uiApi().getContractDefinitionPage(); - - // assert - var contractDefinitions = result.getContractDefinitions(); - assertThat(contractDefinitions).hasSize(1); - var contractDefinition = contractDefinitions.get(0); - assertThat(contractDefinition.getContractDefinitionId()).isEqualTo("contractDefinition-id-1"); - assertThat(contractDefinition.getContractPolicyId()).isEqualTo("contractPolicy-id-1"); - assertThat(contractDefinition.getAccessPolicyId()).isEqualTo("accessPolicy-id-1"); - assertThat(contractDefinition.getAssetSelector()).hasSize(1); - - var criterionEntry = contractDefinition.getAssetSelector().get(0); - assertThat(criterionEntry.getOperandLeft()).isEqualTo("exampleLeft1"); - assertThat(criterionEntry.getOperator()).isEqualTo(UiCriterionOperator.EQ); - assertThat(criterionEntry.getOperandRight().getType()).isEqualTo(UiCriterionLiteralType.VALUE); - assertThat(criterionEntry.getOperandRight().getValue()).isEqualTo("abc"); - } - - @Test - void contractDefinitionPageSorting(ContractDefinitionService contractDefinitionService) { - // arrange - - createContractDefinition( - contractDefinitionService, - "contractDefinition-id-1", - "contractPolicy-id-1", - "accessPolicy-id-1", - new Criterion("exampleLeft1", "=", "abc"), - 1628956800000L); - createContractDefinition( - contractDefinitionService, - "contractDefinition-id-2", - "contractPolicy-id-2", - "accessPolicy-id-2", - new Criterion("exampleLeft1", "=", "abc"), - 1628956801000L); - createContractDefinition( - contractDefinitionService, - "contractDefinition-id-3", - "contractPolicy-id-3", - "accessPolicy-id-3", - new Criterion("exampleLeft1", "=", "abc"), - 1628956802000L); - - // act - var result = client.uiApi().getContractDefinitionPage(); - - // assert - assertThat(result.getContractDefinitions()) - .extracting(ContractDefinitionEntry::getContractPolicyId) - .containsExactly("contractPolicy-id-3", "contractPolicy-id-2", "contractPolicy-id-1"); - - } - - @Test - void testContractDefinitionCreation(ContractDefinitionService contractDefinitionService) { - // arrange - - var criterion = new UiCriterion( - "exampleLeft1", - UiCriterionOperator.EQ, - new UiCriterionLiteral(UiCriterionLiteralType.VALUE, "test", null)); - - var contractDefinition = ContractDefinitionRequest.builder() - .contractDefinitionId("contractDefinition-id-1") - .contractPolicyId("contractPolicy-id-1") - .accessPolicyId("accessPolicy-id-1") - .assetSelector(List.of(criterion)) - .build(); - - // act - var response = client.uiApi().createContractDefinition(contractDefinition); - - // assert - assertThat(response).isNotNull(); - var contractDefinitions = contractDefinitionService.query(QuerySpec.max()).getContent().toList(); - assertThat(contractDefinitions).hasSize(1); - var contractDefinitionEntry = contractDefinitions.get(0); - assertThat(contractDefinitionEntry.getId()).isEqualTo("contractDefinition-id-1"); - assertThat(contractDefinitionEntry.getContractPolicyId()).isEqualTo("contractPolicy-id-1"); - assertThat(contractDefinitionEntry.getAccessPolicyId()).isEqualTo("accessPolicy-id-1"); - - var criterionEntry = contractDefinition.getAssetSelector().get(0); - assertThat(criterionEntry.getOperandLeft()).isEqualTo("exampleLeft1"); - assertThat(criterionEntry.getOperator()).isEqualTo(UiCriterionOperator.EQ); - assertThat(criterionEntry.getOperandRight().getType()).isEqualTo(UiCriterionLiteralType.VALUE); - assertThat(criterionEntry.getOperandRight().getValue()).isEqualTo("test"); - } - - @Test - void testDeleteContractDefinition(ContractDefinitionService contractDefinitionService) { - // arrange - - var criterion = new Criterion("exampleLeft1", "=", "exampleRight1"); - createContractDefinition(contractDefinitionService, "contractDefinition-id-1", "contractPolicy-id-1", "accessPolicy-id-1", criterion); - assertThat(contractDefinitionService.query(QuerySpec.max()).getContent().toList()).hasSize(1); - var contractDefinition = contractDefinitionService.query(QuerySpec.max()).getContent().toList().get(0); - - // act - var response = client.uiApi().deleteContractDefinition(contractDefinition.getId()); - - // assert - assertThat(response.getId()).isEqualTo(contractDefinition.getId()); - assertThat(contractDefinitionService.query(QuerySpec.max()).getContent()).isEmpty(); - } - - private void createContractDefinition( - ContractDefinitionService contractDefinitionService, - String contractDefinitionId, - String contractPolicyId, - String accessPolicyId, - Criterion criteria, - long createdAt - ) { - - var contractDefinition = ContractDefinition.Builder.newInstance() - .id(contractDefinitionId) - .contractPolicyId(contractPolicyId) - .accessPolicyId(accessPolicyId) - .assetsSelector(List.of(criteria)) - .createdAt(createdAt) - .build(); - contractDefinitionService.create(contractDefinition); - } - - private void createContractDefinition( - ContractDefinitionService contractDefinitionService, - String contractDefinitionId, - String contractPolicyId, - String accessPolicyId, - Criterion criteria - ) { - var contractDefinition = ContractDefinition.Builder.newInstance() - .id(contractDefinitionId) - .contractPolicyId(contractPolicyId) - .accessPolicyId(accessPolicyId) - .assetsSelector(List.of(criteria)) - .build(); - contractDefinitionService.create(contractDefinition); - } -} diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationStateServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationStateServiceTest.java index fbc022ea2..7a8543161 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationStateServiceTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_negotiations/ContractNegotiationStateServiceTest.java @@ -15,7 +15,7 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.contract_negotiations; import de.sovity.edc.ext.wrapper.api.ui.model.ContractNegotiationSimplifiedState; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationStates; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiationStates; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/DashboardPageApiServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/DashboardPageApiServiceTest.java deleted file mode 100644 index 2ffe93446..000000000 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/DashboardPageApiServiceTest.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.ext.wrapper.api.ui.pages.dashboard; - -import de.sovity.edc.client.EdcClient; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; -import de.sovity.edc.utils.config.ConfigProps; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.contract.spi.types.offer.ContractDefinition; -import org.eclipse.edc.connector.policy.spi.PolicyDefinition; -import org.eclipse.edc.connector.spi.contractdefinition.ContractDefinitionService; -import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService; -import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; -import org.eclipse.edc.connector.transfer.spi.types.DataRequest; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcessStates; -import org.eclipse.edc.junit.annotations.ApiTest; -import org.eclipse.edc.junit.extensions.EdcExtension; -import org.eclipse.edc.service.spi.result.ServiceResult; -import org.eclipse.edc.spi.asset.AssetIndex; -import org.eclipse.edc.spi.query.QuerySpec; -import org.eclipse.edc.spi.types.domain.asset.Asset; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.mockito.Mockito; - -import java.util.Collection; -import java.util.List; -import java.util.Random; -import java.util.function.Supplier; -import java.util.stream.IntStream; - -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; -import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation.Type.CONSUMER; -import static org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation.Type.PROVIDER; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@ApiTest -class DashboardPageApiServiceTest { - private static ConnectorConfig config; - private static EdcClient client; - - @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "provider", - testDatabase -> { - config = forTestDatabase("my-edc-participant-id", testDatabase); - - config.setProperty(ConfigProps.EDC_OAUTH_TOKEN_URL, "https://token-url.daps"); - config.setProperty(ConfigProps.EDC_OAUTH_PROVIDER_JWKS_URL, "https://jwks-url.daps"); - - config.setProperty("tx.ssi.oauth.token.url", "https://token.miw"); - config.setProperty("tx.ssi.miw.url", "https://miw"); - config.setProperty("tx.ssi.miw.authority.id", "my-authority-id"); - - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - return config.getProperties(); - } - ); - - AssetIndex assetIndex; - PolicyDefinitionService policyDefinitionService; - TransferProcessService transferProcessService; - ContractNegotiationStore contractNegotiationStore; - ContractDefinitionService contractDefinitionService; - - private final Random random = new Random(); - - @BeforeEach - void setUp(EdcExtension context) { - - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - - - assetIndex = mock(); - context.registerServiceMock(AssetIndex.class, assetIndex); - - policyDefinitionService = mock(); - context.registerServiceMock(PolicyDefinitionService.class, policyDefinitionService); - - transferProcessService = mock(); - context.registerServiceMock(TransferProcessService.class, transferProcessService); - - contractNegotiationStore = mock(); - context.registerServiceMock(ContractNegotiationStore.class, contractNegotiationStore); - - contractDefinitionService = mock(); - context.registerServiceMock(ContractDefinitionService.class, contractDefinitionService); - } - - @Test - void testKpis() { - // arrange - mockAmounts( - repeat(7, Mockito::mock), - repeat(8, Mockito::mock), - repeat(9, Mockito::mock), - List.of( - mockContractNegotiation(1, CONSUMER), - mockContractNegotiation(2, PROVIDER), - mockContractNegotiation(3, PROVIDER), - mockContractNegotiationInProgress(CONSUMER), - mockContractNegotiationInProgress(PROVIDER) - ), - flat(List.of( - repeat(1, () -> mockTransferProcess(1, TransferProcessStates.REQUESTING.code())), - repeat(2, () -> mockTransferProcess(1, TransferProcessStates.TERMINATED.code())), - repeat(3, () -> mockTransferProcess(1, TransferProcessStates.COMPLETED.code())), - repeat(4, () -> mockTransferProcess(2, TransferProcessStates.REQUESTING.code())), - repeat(5, () -> mockTransferProcess(2, TransferProcessStates.TERMINATED.code())), - repeat(6, () -> mockTransferProcess(2, TransferProcessStates.COMPLETED.code())) - )) - ); - - // act - var dashboardPage = client.uiApi().getDashboardPage(); - assertThat(dashboardPage.getNumAssets()).isEqualTo(7); - assertThat(dashboardPage.getNumPolicies()).isEqualTo(8); - assertThat(dashboardPage.getNumContractDefinitions()).isEqualTo(9); - assertThat(dashboardPage.getNumContractAgreementsConsuming()).isEqualTo(1); - assertThat(dashboardPage.getNumContractAgreementsProviding()).isEqualTo(2); - assertThat(dashboardPage.getTransferProcessesConsuming().getNumTotal()).isEqualTo(1 + 2 + 3); - assertThat(dashboardPage.getTransferProcessesConsuming().getNumRunning()).isEqualTo(1); - assertThat(dashboardPage.getTransferProcessesConsuming().getNumError()).isEqualTo(2); - assertThat(dashboardPage.getTransferProcessesConsuming().getNumOk()).isEqualTo(3); - assertThat(dashboardPage.getTransferProcessesProviding().getNumTotal()).isEqualTo(4 + 5 + 6); - assertThat(dashboardPage.getTransferProcessesProviding().getNumRunning()).isEqualTo(4); - assertThat(dashboardPage.getTransferProcessesProviding().getNumError()).isEqualTo(5); - assertThat(dashboardPage.getTransferProcessesProviding().getNumOk()).isEqualTo(6); - } - - @Test - void testConnectorMetadata() { - // arrange - mockAmounts(List.of(), List.of(), List.of(), List.of(), List.of()); - - // act - var dashboardPage = client.uiApi().getDashboardPage(); - - // assert - assertThat(dashboardPage.getConnectorParticipantId()).isEqualTo("my-edc-participant-id"); - assertThat(dashboardPage.getConnectorDescription()).isEqualTo("Connector Description my-edc-participant-id"); - assertThat(dashboardPage.getConnectorTitle()).isEqualTo("Connector Title my-edc-participant-id"); - - assertThat(dashboardPage.getConnectorEndpoint()).isEqualTo(config.getProtocolApiUrl()); - assertThat(dashboardPage.getConnectorCuratorName()).isEqualTo("Curator Name my-edc-participant-id"); - assertThat(dashboardPage.getConnectorCuratorUrl()).isEqualTo("http://curator.my-edc-participant-id"); - assertThat(dashboardPage.getConnectorMaintainerName()).isEqualTo("Maintainer Name my-edc-participant-id"); - assertThat(dashboardPage.getConnectorMaintainerUrl()).isEqualTo("http://maintainer.my-edc-participant-id"); - - assertThat(dashboardPage.getConnectorDapsConfig()).isNotNull(); - assertThat(dashboardPage.getConnectorDapsConfig().getTokenUrl()).isEqualTo("https://token-url.daps"); - assertThat(dashboardPage.getConnectorDapsConfig().getJwksUrl()).isEqualTo("https://jwks-url.daps"); - - assertThat(dashboardPage.getConnectorMiwConfig()).isNotNull(); - assertThat(dashboardPage.getConnectorMiwConfig().getAuthorityId()).isEqualTo("my-authority-id"); - assertThat(dashboardPage.getConnectorMiwConfig().getUrl()).isEqualTo("https://miw"); - assertThat(dashboardPage.getConnectorMiwConfig().getTokenUrl()).isEqualTo("https://token.miw"); - } - - private Asset mockAsset() { - return mock(); - } - - private PolicyDefinition mockPolicyDefinition() { - return mock(); - } - - private ContractDefinition mockContractDefinition() { - return mock(); - } - - private ContractNegotiation mockContractNegotiation(int contract, ContractNegotiation.Type type) { - var contractAgreement = mock(ContractAgreement.class); - when(contractAgreement.getId()).thenReturn("ca-" + contract); - - var contractNegotiation = mock(ContractNegotiation.class); - when(contractNegotiation.getType()).thenReturn(type); - when(contractNegotiation.getContractAgreement()).thenReturn(contractAgreement); - - return contractNegotiation; - } - - private ContractNegotiation mockContractNegotiationInProgress(ContractNegotiation.Type type) { - var contractNegotiation = mock(ContractNegotiation.class); - when(contractNegotiation.getType()).thenReturn(type); - return contractNegotiation; - } - - private TransferProcess mockTransferProcess(int contractId, int state) { - DataRequest dataRequest = mock(); - when(dataRequest.getContractId()).thenReturn("ca-" + contractId); - - TransferProcess transferProcess = mock(); - when(transferProcess.getId()).thenReturn(String.valueOf(random.nextInt())); - when(transferProcess.getDataRequest()).thenReturn(dataRequest); - when(transferProcess.getState()).thenReturn(state); - return transferProcess; - } - - private void mockAmounts( - List assets, - List policyDefinitions, - List contractDefinitions, - List contractNegotiations, - List transferProcesses - ) { - when(assetIndex.queryAssets(eq(QuerySpec.max()))).thenAnswer(i -> assets.stream()); - when(transferProcessService.query(eq(QuerySpec.max()))) - .thenAnswer(i -> ServiceResult.success(transferProcesses.stream())); - when(policyDefinitionService.query(eq(QuerySpec.max()))) - .thenAnswer(i -> ServiceResult.success(policyDefinitions.stream())); - when(contractNegotiationStore.queryNegotiations(eq(QuerySpec.max()))) - .thenAnswer(i -> contractNegotiations.stream()); - when(contractDefinitionService.query(eq(QuerySpec.max()))) - .thenAnswer(i -> ServiceResult.success(contractDefinitions.stream())); - } - - private List repeat(int times, Supplier supplier) { - return IntStream.range(0, times).mapToObj(i -> supplier.get()).toList(); - } - - private List flat(Collection> collections) { - return collections.stream().flatMap(Collection::stream).toList(); - } -} diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessStateServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessStateServiceTest.java index 977244ec3..2e4dc07d1 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessStateServiceTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessStateServiceTest.java @@ -15,7 +15,7 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory; import de.sovity.edc.ext.wrapper.api.ui.model.TransferProcessSimplifiedState; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcessStates; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcessStates; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessTestUtils.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessTestUtils.java deleted file mode 100644 index 66ab4ddbf..000000000 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessTestUtils.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - init - * - */ - -package de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory; - -import de.sovity.edc.utils.jsonld.vocab.Prop; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationStates; -import org.eclipse.edc.connector.spi.asset.AssetService; -import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; -import org.eclipse.edc.connector.transfer.spi.types.DataRequest; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; -import org.eclipse.edc.policy.model.Policy; -import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; -import org.eclipse.edc.spi.types.domain.DataAddress; -import org.eclipse.edc.spi.types.domain.asset.Asset; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.UUID; - -public class TransferProcessTestUtils { - public static final String DATA_SINK = "http://my-data-sink/api/stuff"; - public static final String COUNTER_PARTY_ADDRESS = "http://some-other-connector/api/v1/ids/data"; - public static final String COUNTER_PARTY_ID = "some-other-connector"; - public static final String PROVIDING_CONTRACT_ID = "provider-contract:eb934d1f-6582-4bab-85e6-af19a76f7e2b"; - public static final String CONSUMING_CONTRACT_ID = "consumer-contract:f52a5d30-6356-4a55-a75a-3c45d7a88c3e"; - public static final String PROVIDING_ASSET_ID = "my-asset"; - public static final String CONSUMING_ASSET_ID = "some-asset-on-another-connector"; - public static final String PROVIDING_ASSET_NAME = "Test asset"; - public static final String PROVIDING_TRANSFER_PROCESS_ID = "81cdf4cf-8427-480f-9662-8a29d66ddd3b"; - public static final String CONSUMING_TRANSFER_PROCESS_ID = "be0cac12-bb43-420e-aa29-d66bb3d0e0ac"; - - public static void createProvidingTransferProcesses(ContractNegotiationStore store, TransferProcessStore transferProcessStore, AssetService assetStore) throws ParseException { - DataAddress dataAddress = getDataAddress(); - createAsset(assetStore, dataAddress, PROVIDING_ASSET_ID, PROVIDING_ASSET_NAME); - - // preparing providing transfer process - var providerAgreement = createContractAgreement(PROVIDING_CONTRACT_ID, PROVIDING_ASSET_ID); - createContractNegotiation(store, COUNTER_PARTY_ADDRESS, providerAgreement, ContractNegotiation.Type.PROVIDER); - createTransferProcess(PROVIDING_ASSET_ID, - PROVIDING_CONTRACT_ID, - dataAddress, - TransferProcess.Type.PROVIDER, - PROVIDING_TRANSFER_PROCESS_ID, - "2023-07-08", - "TransferProcessManager: attempt #8 failed to send transfer", - transferProcessStore); - } - - public static void createConsumingTransferProcesses(ContractNegotiationStore store, TransferProcessStore transferProcessStore) throws ParseException { - DataAddress dataAddress = getDataAddress(); - - // preparing consuming transfer process - var consumerAgreement = createContractAgreement(CONSUMING_CONTRACT_ID, CONSUMING_ASSET_ID); - createContractNegotiation(store, COUNTER_PARTY_ADDRESS, consumerAgreement, ContractNegotiation.Type.CONSUMER); - createTransferProcess(CONSUMING_ASSET_ID, - CONSUMING_CONTRACT_ID, - dataAddress, - TransferProcess.Type.CONSUMER, - CONSUMING_TRANSFER_PROCESS_ID, - "2023-07-10", - "", - transferProcessStore); - } - - private static DataAddress getDataAddress() { - return DataAddress.Builder.newInstance() - .type("HttpData") - .property("baseUrl", DATA_SINK) - .build(); - } - - private static void createAsset(AssetService assetStore, DataAddress dataAddress, String assetId, String assetName) throws ParseException { - var asset = Asset.Builder.newInstance() - .id(assetId) - .property(Prop.Dcterms.TITLE, assetName) - .dataAddress(dataAddress) - .createdAt(dateFormatterToLong("2023-06-01")) - .build(); - - assetStore.create(asset); - } - - private static ContractAgreement createContractAgreement( - String agreementId, - String assetId - ) { - return ContractAgreement.Builder.newInstance() - .id(agreementId) - .providerId(UUID.randomUUID().toString()) - .consumerId(UUID.randomUUID().toString()) - .assetId(assetId) - .policy(Policy.Builder.newInstance().build()) - .build(); - } - - private static void createContractNegotiation( - ContractNegotiationStore store, - String counterPartyAddress, - ContractAgreement agreement, - ContractNegotiation.Type type - ) { - var negotiation = ContractNegotiation.Builder.newInstance() - .id(UUID.randomUUID().toString()) - .counterPartyId(COUNTER_PARTY_ID) - .counterPartyAddress(counterPartyAddress) - .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) - .contractAgreement(agreement) - .type(type) - .correlationId(UUID.randomUUID().toString()) - .state(ContractNegotiationStates.FINALIZED.code()) - .build(); - - store.save(negotiation); - } - - private static void createTransferProcess( - String assetId, - String contractId, - DataAddress dataAddress, - TransferProcess.Type type, - String transferProcessId, - String lastUpdateDateForTransferProcess, - String errorMessage, - TransferProcessStore transferProcessStore - ) throws ParseException { - - var dataRequestForTransfer = DataRequest.Builder.newInstance() - .id(UUID.randomUUID().toString()) - .assetId(assetId) - .contractId(contractId) - .dataDestination(dataAddress) - .connectorAddress(COUNTER_PARTY_ADDRESS) - .connectorId(COUNTER_PARTY_ID) - .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) - .build(); - - var transferProcess = TransferProcess.Builder.newInstance() - .id(transferProcessId) - .type(type) - .dataRequest(dataRequestForTransfer) - .createdAt(dateFormatterToLong("2023-07-08")) - .updatedAt(dateFormatterToLong(lastUpdateDateForTransferProcess)) - .state(800) - .errorDetail(errorMessage) - .build(); - - transferProcessStore.save(transferProcess); - } - - private static long dateFormatterToLong(String date) throws ParseException { - SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); - return formatter.parse(date).getTime(); - } -} diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/SupportedPolicyApiTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/SupportedPolicyApiTest.java deleted file mode 100644 index 509c2ce0f..000000000 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/SupportedPolicyApiTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.ext.wrapper.api.usecase; - -import de.sovity.edc.client.EdcClient; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; -import org.eclipse.edc.junit.annotations.ApiTest; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; -import static org.assertj.core.api.Assertions.assertThat; - -@ApiTest -class SupportedPolicyApiTest { - - private static ConnectorConfig config; - private static EdcClient client; - - @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "provider", - testDatabase -> { - config = forTestDatabase("my-edc-participant-id", testDatabase); - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - return config.getProperties(); - } - ); - - @Test - void supportedPolicies() { - // act - var actual = client.useCaseApi().getSupportedFunctions(); - - // assert - assertThat(actual).contains("ALWAYS_TRUE", "https://w3id.org/edc/v0.0.1/ns/inForceDate"); - } -} diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseApiWrapperTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseApiWrapperTest.java deleted file mode 100644 index c638d38e0..000000000 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseApiWrapperTest.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.ext.wrapper.api.usecase; - -import de.sovity.edc.client.EdcClient; -import de.sovity.edc.client.gen.model.CatalogFilterExpression; -import de.sovity.edc.client.gen.model.CatalogFilterExpressionLiteral; -import de.sovity.edc.client.gen.model.CatalogFilterExpressionLiteralType; -import de.sovity.edc.client.gen.model.CatalogFilterExpressionOperator; -import de.sovity.edc.client.gen.model.CatalogQuery; -import de.sovity.edc.client.gen.model.ContractDefinitionRequest; -import de.sovity.edc.client.gen.model.DataSourceType; -import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; -import de.sovity.edc.client.gen.model.UiAssetCreateRequest; -import de.sovity.edc.client.gen.model.UiCriterion; -import de.sovity.edc.client.gen.model.UiCriterionLiteral; -import de.sovity.edc.client.gen.model.UiCriterionLiteralType; -import de.sovity.edc.client.gen.model.UiCriterionOperator; -import de.sovity.edc.client.gen.model.UiDataSource; -import de.sovity.edc.client.gen.model.UiDataSourceHttpData; -import de.sovity.edc.client.gen.model.UiPolicyExpression; -import de.sovity.edc.client.gen.model.UiPolicyExpressionType; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; -import de.sovity.edc.extension.utils.junit.DisabledOnGithub; -import de.sovity.edc.utils.jsonld.vocab.Prop; -import org.eclipse.edc.junit.annotations.ApiTest; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import java.util.List; - -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; -import static org.assertj.core.api.Assertions.assertThat; - -@ApiTest -class UseCaseApiWrapperTest { - - private static ConnectorConfig config; - private static EdcClient client; - - @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "provider", - testDatabase -> { - config = forTestDatabase("my-edc-participant-id", testDatabase); - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - return config.getProperties(); - } - ); - - private static String assetId1 = "test-asset-1"; - private static String assetId2 = "test-asset-2"; - private static String policyId = "policy-1"; - - @Test - @DisabledOnGithub - void shouldFetchFilteredDataOffersWithEq() { - // arrange - setupAssets(); - buildContractDefinition(policyId, assetId1, "cd-1"); - buildContractDefinition(policyId, assetId2, "cd-2"); - - // act - var catalogQueryParamsEq = criterion(Prop.Edc.ID, CatalogFilterExpressionOperator.EQ, "test-asset-1"); - var dataOffers = client.useCaseApi().queryCatalog(catalogQueryParamsEq); - - // assert - assertThat(dataOffers).hasSize(1); - assertThat(dataOffers.get(0).getAsset().getAssetId()).isEqualTo(assetId1); - assertThat(dataOffers.get(0).getAsset().getTitle()).isEqualTo("Test Asset 1"); - - } - - @Test - @DisabledOnGithub - void shouldFetchFilteredDataOffersWithIn() { - // arrange - setupAssets(); - buildContractDefinition(policyId, assetId1, "cd-1"); - buildContractDefinition(policyId, assetId2, "cd-2"); - - // act - var catalogQueryParamsEq = criterion(Prop.Edc.ID, CatalogFilterExpressionOperator.IN, List.of("test-asset-1", "test-asset-2")); - var dataOffers = client.useCaseApi().queryCatalog(catalogQueryParamsEq); - - // assert - assertThat(dataOffers).hasSize(2); - assertThat(dataOffers) - .extracting(it -> it.getAsset().getAssetId()) - .containsExactlyInAnyOrder(assetId1, assetId2); - } - - @Test - @DisabledOnGithub - void shouldFetchWithoutFilterButWithLimit() { - // arrange - setupAssets(); - buildContractDefinition(policyId, assetId1, "cd-1"); - buildContractDefinition(policyId, assetId2, "cd-2"); - - // act - var catalogQueryParamsEq = criterion(1, 0); - var dataOffers = client.useCaseApi().queryCatalog(catalogQueryParamsEq); - - // assert - assertThat(dataOffers).hasSize(1); - assertThat(dataOffers) - .extracting(it -> it.getAsset().getAssetId()) - .containsAnyOf(assetId1, assetId2); - } - - private CatalogQuery criterion(String leftOperand, CatalogFilterExpressionOperator operator, String rightOperand) { - return CatalogQuery.builder() - .connectorEndpoint(config.getProtocolApiUrl()) - .filterExpressions( - List.of( - CatalogFilterExpression.builder() - .operandLeft(leftOperand) - .operator(operator) - .operandRight(CatalogFilterExpressionLiteral.builder().value(rightOperand).type(CatalogFilterExpressionLiteralType.VALUE).build()) - .build() - ) - ) - .build(); - } - - private CatalogQuery criterion(String leftOperand, CatalogFilterExpressionOperator operator, List rightOperand) { - return CatalogQuery.builder() - .connectorEndpoint(config.getProtocolApiUrl()) - .filterExpressions( - List.of( - CatalogFilterExpression.builder() - .operandLeft(leftOperand) - .operator(operator) - .operandRight(CatalogFilterExpressionLiteral.builder().valueList(rightOperand).type(CatalogFilterExpressionLiteralType.VALUE_LIST).build()) - .build() - ) - ) - .build(); - } - - private CatalogQuery criterion(Integer limit, Integer offset) { - return CatalogQuery.builder() - .connectorEndpoint(config.getProtocolApiUrl()) - .limit(limit) - .offset(offset) - .build(); - } - - private void buildContractDefinition(String policyId, String assetId1, String cdId) { - client.uiApi().createContractDefinition(ContractDefinitionRequest.builder() - .contractDefinitionId(cdId) - .accessPolicyId(policyId) - .contractPolicyId(policyId) - .assetSelector(List.of(UiCriterion.builder() - .operandLeft(Prop.Edc.ID) - .operator(UiCriterionOperator.EQ) - .operandRight(UiCriterionLiteral.builder() - .type(UiCriterionLiteralType.VALUE) - .value(assetId1) - .build()) - .build())) - .build()); - } - - private void setupAssets() { - var dataSource = UiDataSource.builder() - .type(DataSourceType.HTTP_DATA) - .httpData(UiDataSourceHttpData.builder() - .baseUrl(config.getProtocolApiUrl()) - .build()) - .build(); - - assetId1 = client.uiApi().createAsset(UiAssetCreateRequest.builder() - .id("test-asset-1") - .title("Test Asset 1") - .dataSource(dataSource) - .mediaType("application/json") - .build()).getId(); - - assetId2 = client.uiApi().createAsset(UiAssetCreateRequest.builder() - .id("test-asset-2") - .title("Test Asset 2") - .dataSource(dataSource) - .mediaType("application/json") - .build()).getId(); - - policyId = client.uiApi().createPolicyDefinitionV2(PolicyDefinitionCreateDto.builder() - .policyDefinitionId("policy-1") - .expression(UiPolicyExpression.builder() - .type(UiPolicyExpressionType.EMPTY) - .build()) - .build()).getId(); - } -} diff --git a/gradle.properties b/gradle.properties index c8b6c834e..ade87506f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,2 @@ -sovityEdcExtensionsVersion=0.0.1-SNAPSHOT - org.gradle.jvmargs=-Xmx1024m org.gradle.parallel=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 78b2f222d..7e39faded 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,45 +1,51 @@ [versions] -# groups -edcGroup = "org.eclipse.edc" +# Publishing sovityEdcExtensionGroup = "de.sovity.edc.ext" sovityEdcGroup = "de.sovity.edc" +sovityCeVersion = "0.0.1-SNAPSHOT" -# images +# Eclipse EDC Version +edc = "0.7.2" + +# Eclipse EDC Version for Modules not contained in our fork +edcUniverse = "0.7.2" + +# Tractus-X Version +# Used for using bugfixes of the Tractus-X EDC +tractus = "0.7.6" + +# Testcontainers, JooQ Codegen postgresDbImage = "postgres:15-alpine" -# versions +# Other Libraries assertj = "3.23.1" awaitility = "4.2.0" commonsCompress = "1.26.1" commonsCollections = "4.4" commonsIo = "2.14.0" commonsLang = "3.13.0" -edc = "0.2.1.4" findbugs = "3.0.2" flexmark = "0.64.8" flyway = "9.0.1" flywayPlugin = "9.21.1" gson = "2.10.1" gsonFire = "1.8.5" -guava = "33.1.0-jre" hibernateValidator = "8.0.1.Final" hidetakeSwagger = "2.19.2" hikari = "5.0.1" +jackson = "2.17.1" jakartaAnnotation = "1.3.5" jakartaEl = "4.0.2" jakartaJson = "2.0.1" jakartaRs = "3.1.0" jakartaServletApi = "5.0.0" jakartaValidation = "3.0.2" -java = "17" javapoet = "1.13.0" jersey = "3.1.3" jetty = "11.0.15" jooq = "3.18.7" jooqPostgresqlJson = "4.0.0" jooqPlugin = "7.1.1" -json = "20220924" -jsonAssert = "1.5.1" jsonUnit = "3.2.7" junit = "5.10.0" loggingHouse = "v1.2.0-alpha.1" @@ -54,58 +60,71 @@ openapiJackson = "0.2.6" postgres = "42.4.5" quarkus = "2.16.6.Final" quartz = "2.3.2" -restAssured = "5.4.0" +restAssured = "5.5.0" shadow = "7.1.2" +spotless = "6.25.0" swagger = "1.6.12" swaggerCore = "2.2.18" testcontainers = "1.19.1" titaniumLd = "1.3.2" -tractus = "0.5.3" - [libraries] -apache-commonsCollections = { module = "org.apache.commons:commons-collections4", version.ref = "commonsCollections" } -apache-commonsCompress = { module = "org.apache.commons:commons-compress", version.ref = "commonsCompress" } -apache-commonsIo = { module = "commons-io:commons-io", version.ref = "commonsIo" } -apache-commonsLang = { module = "org.apache.commons:commons-lang3", version.ref = "commonsLang" } - -apicatalog-titaniumJsonLd = { module = "com.apicatalog:titanium-json-ld", version.ref = "titaniumLd" } - -assertj-core = { module = "org.assertj:assertj-core", version.ref = "assertj" } - -awaitility-java = { module = "org.awaitility:awaitility", version.ref = "awaitility" } +# Core EDC Libraries +edc-accesstokendataStoreSql = { module = "org.eclipse.edc:accesstokendata-store-sql", version.ref = "edc" } edc-apiCore = { module = "org.eclipse.edc:api-core", version.ref = "edc" } edc-apiObservability = { module = "org.eclipse.edc:api-observability", version.ref = "edc" } +edc-assetSpi = { module = "org.eclipse.edc:asset-spi", version.ref = "edc" } edc-authSpi = { module = "org.eclipse.edc:auth-spi", version.ref = "edc" } edc-authTokenbased = { module = "org.eclipse.edc:auth-tokenbased", version.ref = "edc" } edc-boot = { module = "org.eclipse.edc:boot", version.ref = "edc" } +edc-bootLib = { module = "org.eclipse.edc:boot-lib", version.ref = "edc" } +edc-bootSpi = { module = "org.eclipse.edc:boot-spi", version.ref = "edc" } +edc-callbackEventDispatcher = { module = "org.eclipse.edc:callback-event-dispatcher", version.ref = "edc" } +edc-callbackHttpDispatcher = { module = "org.eclipse.edc:callback-http-dispatcher", version.ref = "edc" } +edc-callbackStaticEndpoint = { module = "org.eclipse.edc:callback-static-endpoint", version.ref = "edc" } edc-configurationFilesystem = { module = "org.eclipse.edc:configuration-filesystem", version.ref = "edc" } edc-connectorCore = { module = "org.eclipse.edc:connector-core", version.ref = "edc" } edc-contractDefinitionApi = { module = "org.eclipse.edc:contract-definition-api", version.ref = "edc" } edc-contractNegotiationStoreSql = { module = "org.eclipse.edc:contract-negotiation-store-sql", version.ref = "edc" } edc-contractSpi = { module = "org.eclipse.edc:contract-spi", version.ref = "edc" } +edc-controlApiConfiguration = { module = "org.eclipse.edc:control-api-configuration", version.ref = "edc" } edc-controlPlaneAggregateServices = { module = "org.eclipse.edc:control-plane-aggregate-services", version.ref = "edc" } +edc-controlPlaneApi = { module = "org.eclipse.edc:control-plane-api", version.ref = "edc" } +edc-controlPlaneApiClient = { module = "org.eclipse.edc:control-plane-api-client", version.ref = "edc" } +edc-controlPlaneApiClientSpi = { module = "org.eclipse.edc:control-plane-api-client-spi", version.ref = "edc" } edc-controlPlaneCore = { module = "org.eclipse.edc:control-plane-core", version.ref = "edc" } +edc-controlPlaneContract = { module = "org.eclipse.edc:control-plane-contract", version.ref = "edc" } edc-controlPlaneSpi = { module = "org.eclipse.edc:control-plane-spi", version.ref = "edc" } edc-controlPlaneSql = { module = "org.eclipse.edc:control-plane-sql", version.ref = "edc" } edc-coreSpi = { module = "org.eclipse.edc:core-spi", version.ref = "edc" } +edc-dataPlaneClient = { module = "org.eclipse.edc:data-plane-client", version.ref = "edc" } +edc-dataPlaneControlApi = { module = "org.eclipse.edc:data-plane-control-api", version.ref = "edc" } edc-dataPlaneCore = { module = "org.eclipse.edc:data-plane-core", version.ref = "edc" } -edc-dataPlaneFramework = { module = "org.eclipse.edc:data-plane-framework", version.ref = "edc" } edc-dataPlaneHttp = { module = "org.eclipse.edc:data-plane-http", version.ref = "edc" } +edc-dataPlaneHttpOauth2 = { module = "org.eclipse.edc:data-plane-http-oauth2", version.ref = "edc" } +edc-dataPlaneInstanceStoreSql = { module = "org.eclipse.edc:data-plane-instance-store-sql", version.ref = "edc" } +edc-dataPlanePublicApiV2 = { module = "org.eclipse.edc:data-plane-public-api-v2", version.ref = "edc" } +edc-dataPlaneSelectorApi = { module = "org.eclipse.edc:data-plane-selector-api", version.ref = "edc" } edc-dataPlaneSelectorClient = { module = "org.eclipse.edc:data-plane-selector-client", version.ref = "edc" } edc-dataPlaneSelectorCore = { module = "org.eclipse.edc:data-plane-selector-core", version.ref = "edc" } +edc-dataPlaneSignalingApi = { module = "org.eclipse.edc:data-plane-signaling-api", version.ref = "edc" } +edc-dataPlaneStoreSql = { module = "org.eclipse.edc:data-plane-store-sql", version.ref = "edc" } edc-dataPlaneUtil = { module = "org.eclipse.edc:data-plane-util", version.ref = "edc" } edc-dsp = { module = "org.eclipse.edc:dsp", version.ref = "edc" } -edc-dspApiConfiguration = { module = "org.eclipse.edc:dsp-api-configuration", version.ref = "edc" } -edc-dspNegotiationTransform = { module = "org.eclipse.edc:dsp-negotiation-transform", version.ref = "edc" } -edc-dspHttpSpi = { module = "org.eclipse.edc:dsp-http-spi", version.ref = "edc" } +edc-dspApiConfiguration = { module = "org.eclipse.edc:dsp-http-api-configuration", version.ref = "edc" } edc-dspHttpCore = { module = "org.eclipse.edc:dsp-http-core", version.ref = "edc" } +edc-dspHttpSpi = { module = "org.eclipse.edc:dsp-http-spi", version.ref = "edc" } +edc-dspNegotiationTransform = { module = "org.eclipse.edc:dsp-negotiation-transform", version.ref = "edc" } +edc-edrIndexSql = { module = "org.eclipse.edc:edr-index-sql", version.ref = "edc" } +edc-edrStoreCore = { module = "org.eclipse.edc:edr-store-core", version.ref = "edc" } +edc-edrStoreReceiver = { module = "org.eclipse.edc:edr-store-receiver", version.ref = "edc" } edc-http = { module = "org.eclipse.edc:http", version.ref = "edc" } edc-httpSpi = { module = "org.eclipse.edc:http-spi", version.ref = "edc" } edc-iamMock = { module = "org.eclipse.edc:iam-mock", version.ref = "edc" } edc-jsonLd = { module = "org.eclipse.edc:json-ld", version.ref = "edc" } +edc-jsonLdLib = { module = "org.eclipse.edc:json-ld-lib", version.ref = "edc" } edc-jsonLdSpi = { module = "org.eclipse.edc:json-ld-spi", version.ref = "edc" } edc-junit = { module = "org.eclipse.edc:junit", version.ref = "edc" } edc-managementApi = { module = "org.eclipse.edc:management-api", version.ref = "edc" } @@ -115,109 +134,97 @@ edc-oauth2Core = { module = "org.eclipse.edc:oauth2-core", version.ref = "edc" } edc-policyDefinitionApi = { module = "org.eclipse.edc:policy-definition-api", version.ref = "edc" } edc-policyEngineSpi = { module = "org.eclipse.edc:policy-engine-spi", version.ref = "edc" } edc-policyModel = { module = "org.eclipse.edc:policy-model", version.ref = "edc" } +edc-policyMonitorCore = { module = "org.eclipse.edc:policy-monitor-core", version.ref = "edc" } +edc-policyMonitorStoreSql = { module = "org.eclipse.edc:policy-monitor-store-sql", version.ref = "edc" } edc-policySpi = { module = "org.eclipse.edc:policy-spi", version.ref = "edc" } edc-runtimeMetamodel = { module = "org.eclipse.edc:runtime-metamodel", version = "0.2.1" } +edc-secretsApi = { module = "org.eclipse.edc:secrets-api", version.ref = "edc" } edc-sqlCore = { module = "org.eclipse.edc:sql-core", version.ref = "edc" } +edc-sqlPoolApacheCommons = { module = "org.eclipse.edc:sql-pool-apache-commons", version.ref = "edc" } edc-transactionLocal = { module = "org.eclipse.edc:transaction-local", version.ref = "edc" } edc-transferDataPlane = { module = "org.eclipse.edc:transfer-data-plane", version.ref = "edc" } edc-transferProcessApi = { module = "org.eclipse.edc:transfer-process-api", version.ref = "edc" } edc-transferProcessStoreSql = { module = "org.eclipse.edc:transfer-process-store-sql", version.ref = "edc" } +edc-transferPullHttpDynamicReceiver = { module = "org.eclipse.edc:transfer-pull-http-dynamic-receiver", version.ref = "edc" } edc-transferSpi = { module = "org.eclipse.edc:transfer-spi", version.ref = "edc" } -edc-transformCore = { module = "org.eclipse.edc:transform-core", version.ref = "edc" } +edc-transformLib = { module = "org.eclipse.edc:transform-lib", version.ref = "edc" } edc-transformSpi = { module = "org.eclipse.edc:transform-spi", version.ref = "edc" } edc-vaultFilesystem = { module = "org.eclipse.edc:vault-filesystem", version.ref = "edc" } +edc-validatorDataAddressHttpData = { module = "org.eclipse.edc:validator-data-address-http-data", version.ref = "edc" } edc-webSpi = { module = "org.eclipse.edc:web-spi", version.ref = "edc" } -findbugs-jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "findbugs" } +# EDC Extended Universe Libraries -flexmark-all = { module = "com.vladsch.flexmark:flexmark-all", version.ref = "flexmark" } +edc-aws-dataPlaneAwsS3 = { module = "org.eclipse.edc.aws:data-plane-aws-s3", version.ref = "edcUniverse" } +edc-azure-dataPlaneAzureStorage = { module = "org.eclipse.edc.azure:data-plane-azure-storage", version.ref = "edcUniverse" } -flyway-core = { module = "org.flywaydb:flyway-core", version.ref = "flyway" } +# Catena Libraries -gson = { module = "com.google.code.gson:gson", version.ref = "gson" } - -gsonFire = { module = "io.gsonfire:gson-fire", version.ref = "gsonFire" } +tractus-azblobProvisioner = { module = "org.eclipse.tractusx.edc:azblob-provisioner", version.ref = "tractus" } +tractus-datasetBugfix = { module = "org.eclipse.tractusx.edc:dataset-bugfix", version.ref = "tractus" } +tractus-pipelineService = { module = "org.eclipse.tractusx.edc:pipeline-service", version.ref = "tractus" } +tractus-transferDataplaneSignaling = { module = "org.eclipse.tractusx.edc:transfer-dataplane-signaling", version.ref = "tractus" } -guava = { module = "com.google.guava:guava", version.ref = "guava" } +# Other Libraries +apache-commonsCollections = { module = "org.apache.commons:commons-collections4", version.ref = "commonsCollections" } +apache-commonsCompress = { module = "org.apache.commons:commons-compress", version.ref = "commonsCompress" } +apache-commonsIo = { module = "commons-io:commons-io", version.ref = "commonsIo" } +apache-commonsLang = { module = "org.apache.commons:commons-lang3", version.ref = "commonsLang" } +apicatalog-titaniumJsonLd = { module = "com.apicatalog:titanium-json-ld", version.ref = "titaniumLd" } +findbugs-jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "findbugs" } +flexmark-all = { module = "com.vladsch.flexmark:flexmark-all", version.ref = "flexmark" } +flyway-core = { module = "org.flywaydb:flyway-core", version.ref = "flyway" } +gson = { module = "com.google.code.gson:gson", version.ref = "gson" } +gsonFire = { module = "io.gsonfire:gson-fire", version.ref = "gsonFire" } hibernate-validation = { module = "org.hibernate.validator:hibernate-validator", version.ref = "hibernateValidator" } - hikari = { module = "com.zaxxer:HikariCP", version.ref = "hikari" } - +jackson-jsr310 = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310", version.ref = "jackson" } jakarta-annotationApi = { module = "jakarta.annotation:jakarta.annotation-api", version.ref = "jakartaAnnotation" } jakarta-el = { module = "org.glassfish:jakarta.el", version.ref = "jakartaEl" } jakarta-json = { module = "org.glassfish:jakarta.json", version.ref = "jakartaJson" } jakarta-rsApi = { module = "jakarta.ws.rs:jakarta.ws.rs-api", version.ref = "jakartaRs" } jakarta-servletApi = { module = "jakarta.servlet:jakarta.servlet-api", version.ref = "jakartaServletApi" } jakarta-validationApi = { module = "jakarta.validation:jakarta.validation-api", version.ref = "jakartaValidation" } - jersey-mediaMultipart = { module = "org.glassfish.jersey.media:jersey-media-multipart", version.ref = "jersey" } - jetty-client = { module = "org.eclipse.jetty:jetty-client", version.ref = "jetty" } jetty-http = { module = "org.eclipse.jetty:jetty-http", version.ref = "jetty" } jetty-io = { module = "org.eclipse.jetty:jetty-io", version.ref = "jetty" } jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "jetty" } jetty-util = { module = "org.eclipse.jetty:jetty-util", version.ref = "jetty" } jetty-webapp = { module = "org.eclipse.jetty:jetty-webapp", version.ref = "jetty" } - jooq-jooq = { module = "org.jooq:jooq", version.ref = "jooq" } - -jsonAssert = { module = "org.skyscreamer:jsonassert", version.ref = "jsonAssert" } - -jsonUnit-assertj = { module = "net.javacrumbs.json-unit:json-unit-assertj", version.ref = "jsonUnit" } - -junit-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } -junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } -junit-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" } - loggingHouse-client = { module = "logging-house:logging-house-client", version.ref = "loggingHouse" } - lombok = { module = "org.projectlombok:lombok", version.ref = "lombok" } - -mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" } -mockito-inline = { module = "org.mockito:mockito-inline", version.ref = "mockito" } -mockito-junitJupiter = { module = "org.mockito:mockito-junit-jupiter", version.ref = "mockito" } - -mockserver-netty = { module = "org.mock-server:mockserver-netty", version.ref = "mockserver" } - -okhttp-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } okhttp-loggingInterceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" } - +okhttp-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } okio-jvm = { module = "com.squareup.okio:okio-jvm", version.ref = "okio" } - openapi-jacksonDatabindNullable = { module = "org.openapitools:jackson-databind-nullable", version.ref = "openapiJackson" } - postgres = { module = "org.postgresql:postgresql", version.ref = "postgres" } - quarkus-bom = { module = "io.quarkus.platform:quarkus-bom", version.ref = "quarkus" } - quartz-quartz = { module = "org.quartz-scheduler:quartz", version.ref = "quartz" } - -restAssured-restAssured = { module = "io.rest-assured:rest-assured", version.ref = "restAssured" } - squareup-javapoet = { module = "com.squareup:javapoet", version.ref = "javapoet" } - swagger-annotations = { module = "io.swagger:swagger-annotations", version.ref = "swagger" } swagger-annotationsJakarta = { module = "io.swagger.core.v3:swagger-annotations-jakarta", version.ref = "swaggerCore" } swagger-jaxrs2Jakarta = { module = "io.swagger.core.v3:swagger-jaxrs2-jakarta", version.ref = "swaggerCore" } - t9tJooq-jooqPostgresqlJson = { module = "com.github.t9t.jooq:jooq-postgresql-json", version.ref = "jooqPostgresqlJson" } - -testcontainers-testcontainers = { module = "org.testcontainers:testcontainers", version.ref = "testcontainers" } testcontainers-junitJupiter = { module = "org.testcontainers:junit-jupiter", version.ref = "testcontainers" } testcontainers-postgresql = { module = "org.testcontainers:postgresql", version.ref = "testcontainers" } +testcontainers-testcontainers = { module = "org.testcontainers:testcontainers", version.ref = "testcontainers" } -tractus-sqlPool = { module = "org.eclipse.tractusx.edc:sql-pool", version.ref = "tractus" } +# Test Utils -[bundles] -jetty-cve2023 = [ - "jetty-client", - "jetty-http", - "jetty-io", - "jetty-server", - "jetty-util", - "jetty-webapp", -] +assertj-core = { module = "org.assertj:assertj-core", version.ref = "assertj" } +awaitility-java = { module = "org.awaitility:awaitility", version.ref = "awaitility" } +junit-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } +junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } +junit-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" } +jsonUnit-assertj = { module = "net.javacrumbs.json-unit:json-unit-assertj", version.ref = "jsonUnit" } +mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" } +mockito-inline = { module = "org.mockito:mockito-inline", version.ref = "mockito" } +mockito-junitJupiter = { module = "org.mockito:mockito-junit-jupiter", version.ref = "mockito" } +mockserver-netty = { module = "org.mock-server:mockserver-netty", version.ref = "mockserver" } +restAssured-restAssured = { module = "io.rest-assured:rest-assured", version.ref = "restAssured" } [plugins] hidetake-swaggerGenerator = { id = "org.hidetake.swagger.generator", version.ref = "hidetakeSwagger" } @@ -225,6 +232,7 @@ openapi-generator6 = { id = "org.openapi.generator", version.ref = "openapiGener openapi-generator7 = { id = "org.openapi.generator", version.ref = "openapiGenerator7" } quarkus = { id = "io.quarkus", version.ref = "quarkus" } shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" } +spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } swagger-plugin = { id = "io.swagger.core.v3.swagger-gradle-plugin", version.ref = "swaggerCore" } jooq = { id = "nu.studer.jooq", version.ref = "jooqPlugin" } flyway = { id = "org.flywaydb.flyway", version.ref = "flywayPlugin" } diff --git a/launchers/common/auth-daps/build.gradle.kts b/launchers/common/auth-daps/build.gradle.kts index 8781e7e2a..6080d8222 100644 --- a/launchers/common/auth-daps/build.gradle.kts +++ b/launchers/common/auth-daps/build.gradle.kts @@ -5,7 +5,6 @@ plugins { dependencies { // OAuth2 IAM api(libs.edc.oauth2Core) - api(libs.edc.vaultFilesystem) } group = libs.versions.sovityEdcGroup.get() diff --git a/launchers/common/base-mds/build.gradle.kts b/launchers/common/base-mds/build.gradle.kts index 89d1a8bd8..4e5ab81fc 100644 --- a/launchers/common/base-mds/build.gradle.kts +++ b/launchers/common/base-mds/build.gradle.kts @@ -3,8 +3,7 @@ plugins { } dependencies { - implementation(libs.loggingHouse.client) - implementation(project(":extensions:mds-logginghouse-binder")) + // TODO: Re-add logging house once it has been migrated to Eclipse EDC 0.7.2 } group = libs.versions.sovityEdcGroup.get() diff --git a/launchers/common/base/build.gradle.kts b/launchers/common/base/build.gradle.kts index dfb0f3a23..a92a54108 100644 --- a/launchers/common/base/build.gradle.kts +++ b/launchers/common/base/build.gradle.kts @@ -6,34 +6,66 @@ dependencies { // For Custom Launcher Code implementation(project(":config")) - // Control-Plane - api(libs.edc.controlPlaneCore) - api(libs.edc.managementApi) - api(libs.edc.apiObservability) - api(libs.edc.configurationFilesystem) - api(libs.edc.controlPlaneAggregateServices) - api(libs.edc.http) - api(libs.edc.dsp) - api(libs.edc.jsonLd) - - // Data Management API Key + // Management API Key api(libs.edc.authTokenbased) // sovity Extensions Package api(project(":extensions:sovity-edc-extensions-package")) api(project(":extensions:postgres-flyway")) - api(project(":extensions:transfer-process-status-checker")) - - // Control-plane to Data-plane - api(libs.edc.transferDataPlane) - api(libs.edc.dataPlaneSelectorCore) - api(libs.edc.dataPlaneSelectorClient) - - // Data-plane - api(libs.edc.dataPlaneHttp) - api(libs.edc.dataPlaneFramework) - api(libs.edc.dataPlaneCore) - api(libs.edc.dataPlaneUtil) + + // Control Plane + implementation(libs.edc.jsonLd) + implementation(libs.edc.connectorCore) + implementation(libs.edc.policyMonitorCore) + implementation(libs.edc.validatorDataAddressHttpData) + implementation(libs.edc.callbackEventDispatcher) + implementation(libs.edc.callbackHttpDispatcher) + implementation(libs.edc.callbackStaticEndpoint) + + implementation(libs.edc.controlPlaneCore) + implementation(libs.edc.managementApi) + implementation(libs.edc.secretsApi) + implementation(libs.edc.controlApiConfiguration) + implementation(libs.edc.controlPlaneApi) + implementation(libs.edc.http) + implementation(libs.edc.dsp) + implementation(libs.edc.configurationFilesystem) + + // data-plane-selector + implementation(libs.edc.dataPlaneSelectorCore) + implementation(libs.edc.dataPlaneSelectorApi) + + // Data Transfer + implementation(libs.edc.transferPullHttpDynamicReceiver) + implementation(libs.edc.edrStoreCore) + implementation(libs.edc.edrStoreReceiver) + implementation(libs.tractus.transferDataplaneSignaling) + implementation(libs.tractus.azblobProvisioner) + // fix CVE in Catalog, see: https://github.com/eclipse-tractusx/tractusx-edc/pull/1584 + implementation(libs.tractus.datasetBugfix) + + // Integrated Data Plane + implementation(libs.edc.webSpi) + implementation(libs.edc.dataPlaneCore) + // normally the pipeline service is provided by the data-plane-core dependency + // however there is a TX version, which contains some fixes + // see: https://github.com/eclipse-tractusx/tractusx-edc/pull/1520 + implementation(libs.tractus.pipelineService) + implementation(libs.edc.dataPlaneControlApi) + implementation(libs.edc.dataPlanePublicApiV2) + implementation(libs.edc.controlPlaneApiClient) + implementation(project(":extensions:integrated-data-plane-initializer")) + implementation(libs.edc.dataPlaneSignalingApi) + + // transfer-types + implementation(libs.edc.dataPlaneHttp) + implementation(libs.edc.dataPlaneHttpOauth2) + implementation(libs.edc.azure.dataPlaneAzureStorage) + implementation(libs.edc.aws.dataPlaneAwsS3) + + // persistence-db + implementation(libs.edc.dataPlaneStoreSql) + implementation(libs.edc.accesstokendataStoreSql) } group = libs.versions.sovityEdcGroup.get() diff --git a/launchers/connectors/mds-ce/build.gradle.kts b/launchers/connectors/mds-ce/build.gradle.kts index 171112ac3..ed3e9788e 100644 --- a/launchers/connectors/mds-ce/build.gradle.kts +++ b/launchers/connectors/mds-ce/build.gradle.kts @@ -12,7 +12,7 @@ dependencies { } application { - mainClass.set("de.sovity.edc.Main") + mainClass.set("de.sovity.edc.utils.config.CeMain") } tasks.withType { diff --git a/launchers/connectors/sovity-ce/build.gradle.kts b/launchers/connectors/sovity-ce/build.gradle.kts index 684f46c29..e5c3f5712 100644 --- a/launchers/connectors/sovity-ce/build.gradle.kts +++ b/launchers/connectors/sovity-ce/build.gradle.kts @@ -11,7 +11,7 @@ dependencies { } application { - mainClass.set("de.sovity.edc.Main") + mainClass.set("de.sovity.edc.utils.config.CeMain") } tasks.withType { diff --git a/launchers/connectors/sovity-dev/build.gradle.kts b/launchers/connectors/sovity-dev/build.gradle.kts index 7548d3047..59124aa83 100644 --- a/launchers/connectors/sovity-dev/build.gradle.kts +++ b/launchers/connectors/sovity-dev/build.gradle.kts @@ -8,10 +8,11 @@ dependencies { api(project(":launchers:common:base")) api(project(":launchers:common:auth-mock")) api(project(":launchers:common:observability")) + api(libs.edc.controlPlaneContract) } application { - mainClass.set("de.sovity.edc.Main") + mainClass.set("de.sovity.edc.utils.config.CeMain") } tasks.withType { diff --git a/launchers/connectors/test-backend/build.gradle.kts b/launchers/connectors/test-backend/build.gradle.kts index c74086d51..d15100574 100644 --- a/launchers/connectors/test-backend/build.gradle.kts +++ b/launchers/connectors/test-backend/build.gradle.kts @@ -14,7 +14,7 @@ dependencies { } application { - mainClass.set("de.sovity.edc.Main") + mainClass.set("de.sovity.edc.utils.config.CeMain") } tasks.withType { diff --git a/launchers/utils/vanilla-control-plane/build.gradle.kts b/launchers/utils/vanilla-control-plane/build.gradle.kts new file mode 100644 index 000000000..3181c7c86 --- /dev/null +++ b/launchers/utils/vanilla-control-plane/build.gradle.kts @@ -0,0 +1,48 @@ + +plugins { + `java-library` + `maven-publish` +} + +dependencies { + // EDC Base + api(libs.edc.jsonLd) + api(libs.edc.connectorCore) + api(libs.edc.policyMonitorCore) + + // EDC CP + api(libs.edc.controlPlaneCore) + api(libs.edc.managementApi) + api(libs.edc.controlApiConfiguration) + api(libs.edc.controlPlaneApi) + api(libs.edc.http) + api(libs.edc.dsp) + api(libs.edc.dataPlaneClient) + api(libs.edc.iamMock) + + // data-plane-selector + api(libs.edc.dataPlaneSelectorCore) + api(libs.edc.dataPlaneSelectorApi) + + // Test Dependencies + api(libs.edc.junit) + api(project(":utils:versions")) + api(project(":utils:test-utils")) + + // Junit / Mockito / AssertJ + api(libs.junit.api) + api(libs.jsonUnit.assertj) + api(libs.restAssured.restAssured) + api(libs.mockito.core) + api(libs.assertj.core) +} + +group = libs.versions.sovityEdcExtensionGroup.get() + +publishing { + publications { + create(project.name) { + from(components["java"]) + } + } +} diff --git a/migration_notes.md b/migration_notes.md new file mode 100644 index 000000000..b64448041 --- /dev/null +++ b/migration_notes.md @@ -0,0 +1,87 @@ + +# Migration notes + +### Assigner added in policy when negotiating + +`ContractNegotiationRequest` now needs a `counterPartyId` because it's missing from the offerId's policy and must later be patched in `de.sovity.edc.ext.wrapper.api.ui.pages.contract_negotiations.ContractOfferMapper.buildContractOffer` + +### Changes in the DCat prop + +[http://www.w3.org/ns/dcat`#`] + +no more + +[http://www.w3.org/ns/dcat`/`] + +### dataSinkProperties + +Must NOT use the shorthand `baseUrl`, `type`, ... + +Must use the FQDN `https://w3id.org/edc/v0.0.1/ns/baseUrl`, `https://w3id.org/edc/v0.0.1/ns/type`, ... + +### DB reset + +Some tests depended on the DB's reset `@BeforeEach` method. + +In some cases if was fixed with `@Order`ing, in others with deletion of the problematic asset, or changing queries to be more selective. + +### Port re-use + +``` +CanGetAgreementPageForTerminatedContractTest > initializationError FAILED + org.eclipse.edc.spi.EdcException: Failed to start EDC runtime + org.eclipse.edc.spi.EdcException: org.eclipse.edc.spi.EdcException: Error starting Jetty service + org.eclipse.edc.spi.EdcException: Error starting Jetty service + java.io.IOException: Failed to bind to 0.0.0.0/0.0.0.0:49678 + java.net.BindException: Address already in use +``` + +Why? The port seems to be allocated randomly. + +### Provider push parameterization is deprecated + +ProviderPushTransferDataFlowController is deprecated since 0.5.1. + +See `git show aa30b4805268821c0852d50950b69e78a3f7efcb` in core EDC. + +### Management API v2/v3 + +All the management API calls should be done on `v3`. + +### Distribution key + +The distribution key was moved from `http://www.w3.org/ns/dcat#distribution` to `https://semantic.sovity.io/dcat-ext#distribution`. + +### Different answers + +in contract negotiation answer: + +`edc:contractAgreementId` -> `contractAgreementId`, same for other fields. + +in contract negotiation state: + +`edc:state` -> `state`, same for other fields. + +### EDC conflicting tables declarations + +`edc_lease` is declared 6 times. + +Once with `lease_duration INTEGER DEFAULT 60000 NOT NULL` +5 times with `lease_duration INTEGER NOT NULL` + +Using the second option for the baseline. + +## TODOs + +### Media type went missing + +Play whack-a-mole between the new EDC usage of distribution, the `Media Type` assertion and the catalog fetching. + +### Attribute deprecation + +The attribute https://w3id.org/edc/v0.0.1/ns/providerId has been deprecated in type https://w3id.org/edc/v0.0.1/ns/ContractRequest, please use http://www.w3.org/ns/odrl/2/assigner + +### + +Release as 0.0.1-20241025-2408-alpha1 + diff --git a/partial_validator.sh b/partial_validator.sh new file mode 100755 index 000000000..8bd44c82b --- /dev/null +++ b/partial_validator.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +gradle \ + :extensions:contract-termination:test \ + :extensions:edc-ui-config:test \ + :extensions:last-commit-info:test \ + :extensions:policy-always-true:test \ + :extensions:policy-referring-connector:test \ + :extensions:sovity-messenger:test \ + :extensions:wrapper:wrapper:test \ + :extensions:wrapper:wrapper-common-mappers:test \ + :utils:catalog-parser:test \ + :tests:test \ + --tests 'de.sovity.edc.e2e.wrapper.RecreateAlwaysTruePolicyTest' \ + --tests 'de.sovity.edc.e2e.ApiWrapperDemoTest' \ + --tests 'de.sovity.edc.e2e.AssetApiServiceTest' \ + --tests 'de.sovity.edc.e2e.CatalogApiTest' \ + --tests 'de.sovity.edc.e2e.ContractAgreementTerminationDetailsQueryTest' \ + --tests 'de.sovity.edc.e2e.DataSourceQueryParamsTest' \ + --tests 'de.sovity.edc.e2e.ManagementApiTransferTest' \ + --tests 'de.sovity.edc.e2e.PlaceholderDataSourceExtensionTest' \ + --tests 'de.sovity.edc.e2e.PolicyDefinitionApiServiceTest' \ + --tests 'de.sovity.edc.e2e.UiApiWrapperTest' \ + --tests 'de.sovity.edc.e2e.UseCaseApiWrapperTest' \ + --tests 'de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreement.ContractAgreementPageTest' \ + --tests 'de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreement.ContractAgreementTransferApiServiceTest' \ + --tests 'de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.services.TransferRequestBuilderTest' \ + --tests 'de.sovity.edc.ext.wrapper.api.ui.pages.contract_definitions.ContractDefinitionPageApiServiceTest' \ + --tests 'de.sovity.edc.ext.wrapper.api.ui.pages.dashboard.DashboardPageApiServiceTest' \ + --tests 'de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferHistoryPageApiServiceTest' \ + --tests 'de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferProcessAssetApiServiceTest' \ + --tests 'de.sovity.edc.ext.wrapper.api.usecase.KpiApiTest' \ + --tests 'de.sovity.edc.ext.wrapper.api.usecase.SupportedPolicyApiTest' \ + --tests 'de.sovity.edc.extension.contacttermination.CanGetAgreementPageForNonTerminatedContractTest' \ + --tests 'de.sovity.edc.extension.contacttermination.CanGetAgreementPageForTerminatedContractTest' \ + --tests 'de.sovity.edc.extension.contacttermination.CanTerminateFromConsumerTest' \ + --tests 'de.sovity.edc.extension.contacttermination.ContractTerminationTest' \ + --tests 'de.sovity.edc.extension.contacttermination.ContractTerminationTestUtils' \ diff --git a/settings.gradle.kts b/settings.gradle.kts index 838efe587..9b49145a8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,10 +3,9 @@ rootProject.name = "sovity-ce-edc" include(":config") include(":extensions:contract-termination") include(":extensions:database-direct-access") -include(":extensions:dataset-bugfix") include(":extensions:edc-ui-config") +include(":extensions:integrated-data-plane-initializer") include(":extensions:last-commit-info") -include(":extensions:mds-logginghouse-binder") include(":extensions:policy-always-true") include(":extensions:policy-referring-connector") include(":extensions:policy-time-interval") @@ -16,6 +15,7 @@ include(":extensions:sovity-messenger") include(":extensions:sovity-edc-extensions-package") include(":extensions:test-backend-controller") include(":extensions:transfer-process-status-checker") +include(":extensions:vault-initializer") include(":extensions:wrapper:clients:java-client") include(":extensions:wrapper:clients:java-client-example") include(":extensions:wrapper:wrapper") @@ -32,6 +32,7 @@ include(":launchers:connectors:mds-ce") include(":launchers:connectors:sovity-ce") include(":launchers:connectors:sovity-dev") include(":launchers:connectors:test-backend") +include(":launchers:utils:vanilla-control-plane") include(":tests") include(":utils:catalog-parser") include(":utils:jooq-database-access") diff --git a/tests/build.gradle.kts b/tests/build.gradle.kts index 255718f4b..d479a5b1f 100644 --- a/tests/build.gradle.kts +++ b/tests/build.gradle.kts @@ -11,8 +11,12 @@ dependencies { testAnnotationProcessor(libs.lombok) testCompileOnly(libs.lombok) + testImplementation(libs.edc.dspHttpSpi) + + testImplementation(project(":extensions:database-direct-access")) testImplementation(project(":extensions:test-backend-controller")) testImplementation(project(":extensions:wrapper:clients:java-client")) + testImplementation(project(":utils:jooq-database-access")) testImplementation(project(":utils:test-utils")) testImplementation(libs.jsonUnit.assertj) testImplementation(libs.mockito.core) diff --git a/tests/src/test/java/de/sovity/edc/e2e/AlwaysTrueMigrationReversedTest.java b/tests/src/test/java/de/sovity/edc/e2e/AlwaysTrueMigrationReversedTest.java deleted file mode 100644 index 55973ac88..000000000 --- a/tests/src/test/java/de/sovity/edc/e2e/AlwaysTrueMigrationReversedTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.e2e; - -import de.sovity.edc.client.EdcClient; -import de.sovity.edc.extension.e2e.extension.Consumer; -import de.sovity.edc.extension.e2e.extension.E2eScenario; -import de.sovity.edc.extension.e2e.extension.E2eTestExtension; -import de.sovity.edc.extension.e2e.extension.Provider; -import de.sovity.edc.extension.utils.junit.DisabledOnGithub; -import de.sovity.edc.utils.config.ConfigProps; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.mockserver.integration.ClientAndServer; - -import static de.sovity.edc.e2e.AlwaysTrueMigrationTest.testTransfer; -import static de.sovity.edc.extension.e2e.extension.CeE2eTestExtensionConfigFactory.defaultBuilder; - -class AlwaysTrueMigrationReversedTest { - - @RegisterExtension - private static final E2eTestExtension E2E_TEST_EXTENSION = new E2eTestExtension( - defaultBuilder().toBuilder() - .consumerConfigCustomizer(config -> config.setProperty( - ConfigProps.EDC_FLYWAY_ADDITIONAL_MIGRATION_LOCATIONS, "classpath:db/additional-test-data/always-true-policy-legacy" - )) - .providerConfigCustomizer(config -> config.setProperty( - ConfigProps.EDC_FLYWAY_ADDITIONAL_MIGRATION_LOCATIONS, "classpath:db/additional-test-data/always-true-policy-migrated" - )) - .build() - ); - - @Test - @DisabledOnGithub - void test_migrated_policy_working_test_legacy_policy_working( - E2eScenario scenario, - ClientAndServer mockServer, - @Provider EdcClient providerClient, - @Consumer EdcClient consumerClient - ) { - // assert correct policies - testTransfer(scenario, mockServer, consumerClient); - } -} diff --git a/tests/src/test/java/de/sovity/edc/e2e/AlwaysTrueMigrationTest.java b/tests/src/test/java/de/sovity/edc/e2e/AlwaysTrueMigrationTest.java deleted file mode 100644 index d3bdc53ce..000000000 --- a/tests/src/test/java/de/sovity/edc/e2e/AlwaysTrueMigrationTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.e2e; - -import de.sovity.edc.client.EdcClient; -import de.sovity.edc.client.gen.model.InitiateTransferRequest; -import de.sovity.edc.client.gen.model.OperatorDto; -import de.sovity.edc.client.gen.model.TransferProcessSimplifiedState; -import de.sovity.edc.client.gen.model.UiPolicyExpressionType; -import de.sovity.edc.extension.e2e.extension.Consumer; -import de.sovity.edc.extension.e2e.extension.E2eScenario; -import de.sovity.edc.extension.e2e.extension.E2eTestExtension; -import de.sovity.edc.extension.e2e.extension.Provider; -import de.sovity.edc.extension.policy.AlwaysTruePolicyConstants; -import de.sovity.edc.extension.utils.junit.DisabledOnGithub; -import de.sovity.edc.utils.config.ConfigProps; -import de.sovity.edc.utils.jsonld.vocab.Prop; -import jakarta.ws.rs.HttpMethod; -import lombok.val; -import org.assertj.core.api.AssertionsForClassTypes; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.mockserver.integration.ClientAndServer; -import org.mockserver.model.HttpRequest; -import org.mockserver.model.HttpResponse; - -import java.util.Map; - -import static de.sovity.edc.extension.e2e.extension.CeE2eTestExtensionConfigFactory.withModule; -import static org.assertj.core.api.Assertions.assertThat; - -class AlwaysTrueMigrationTest { - - @RegisterExtension - private static final E2eTestExtension E2E_TEST_EXTENSION = new E2eTestExtension( - withModule(":launchers:connectors:sovity-dev").toBuilder() - .consumerConfigCustomizer(config -> config.setProperty( - ConfigProps.EDC_FLYWAY_ADDITIONAL_MIGRATION_LOCATIONS, "classpath:db/additional-test-data/always-true-policy-migrated" - )) - .providerConfigCustomizer(config -> config.setProperty( - ConfigProps.EDC_FLYWAY_ADDITIONAL_MIGRATION_LOCATIONS, "classpath:db/additional-test-data/always-true-policy-legacy" - )) - .build() - ); - - @Test - @DisabledOnGithub - void test_migrated_policy_working_test_legacy_policy_working( - E2eScenario scenario, - ClientAndServer mockServer, - @Provider EdcClient providerClient, - @Consumer EdcClient consumerClient - ) { - // assert correct policies - val oldAlwaysTruePolicyCreatedAfterMigration = providerClient.uiApi().getPolicyDefinitionPage().getPolicies().stream().filter( - policy -> policy.getPolicyDefinitionId().equals(AlwaysTruePolicyConstants.POLICY_DEFINITION_ID) - ).findFirst().orElseThrow().getPolicy().getExpression(); - - val migratedAlwaysTruePolicy = consumerClient.uiApi().getPolicyDefinitionPage().getPolicies().stream().filter( - policy -> policy.getPolicyDefinitionId().equals(AlwaysTruePolicyConstants.POLICY_DEFINITION_ID) - ).findFirst().orElseThrow().getPolicy().getExpression(); - - assertThat(oldAlwaysTruePolicyCreatedAfterMigration.getType()).isEqualTo(UiPolicyExpressionType.CONSTRAINT); - assertThat(oldAlwaysTruePolicyCreatedAfterMigration.getConstraint().getLeft()).isEqualTo( - AlwaysTruePolicyConstants.EXPRESSION_LEFT_VALUE); - assertThat(oldAlwaysTruePolicyCreatedAfterMigration.getConstraint().getRight().getValue()).isEqualTo( - AlwaysTruePolicyConstants.EXPRESSION_RIGHT_VALUE); - assertThat(oldAlwaysTruePolicyCreatedAfterMigration.getConstraint().getOperator()).isEqualTo(OperatorDto.EQ); - - assertThat(migratedAlwaysTruePolicy.getType()).isEqualTo(UiPolicyExpressionType.EMPTY); - assertThat(migratedAlwaysTruePolicy.getConstraint()).isNull(); - - testTransfer(scenario, mockServer, consumerClient); - } - - public static void testTransfer(E2eScenario scenario, ClientAndServer mockServer, EdcClient consumerClient) { - // arrange - val destinationPath = "/destination/some/path/"; - val destinationUrl = "http://localhost:" + mockServer.getPort() + destinationPath; - mockServer.when(HttpRequest.request(destinationPath).withMethod("POST")).respond(it -> HttpResponse.response().withStatusCode(200)); - - val asset = scenario.createAsset(); - scenario.createContractDefinition(asset); //this automatically uses the always-true policy - val negotiation = scenario.negotiateAssetAndAwait(asset); - - // act - val transfer = scenario.transferAndAwait( - InitiateTransferRequest.builder() - .contractAgreementId(negotiation.getContractAgreementId()) - .dataSinkProperties( - Map.of( - Prop.Edc.BASE_URL, destinationUrl, - Prop.Edc.METHOD, HttpMethod.POST, - Prop.Edc.TYPE, "HttpData" - ) - ) - .build() - ); - val transferProcess = consumerClient.uiApi().getTransferHistoryPage().getTransferEntries().stream().filter( - process -> process.getTransferProcessId().equals(transfer) - ).findFirst().orElseThrow(); - - // assert - AssertionsForClassTypes.assertThat(transferProcess.getState().getSimplifiedState()).isEqualTo(TransferProcessSimplifiedState.OK); - } -} diff --git a/tests/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java b/tests/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java index 44f9b2604..d5d697c43 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java @@ -37,75 +37,54 @@ import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.client.gen.model.UiPolicyLiteral; import de.sovity.edc.client.gen.model.UiPolicyLiteralType; -import de.sovity.edc.extension.e2e.connector.ConnectorRemote; -import de.sovity.edc.extension.e2e.connector.MockDataAddressRemote; -import de.sovity.edc.extension.e2e.db.TestDatabase; -import de.sovity.edc.extension.e2e.db.TestDatabaseViaTestcontainers; +import de.sovity.edc.extension.e2e.connector.remotes.test_backend_controller.TestBackendRemote; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; import de.sovity.edc.extension.utils.junit.DisabledOnGithub; +import de.sovity.edc.utils.config.ConfigUtils; import de.sovity.edc.utils.jsonld.vocab.Prop; import org.awaitility.Awaitility; -import org.eclipse.edc.junit.extensions.EdcExtension; +import org.eclipse.edc.spi.system.configuration.Config; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import java.time.Duration; import java.time.OffsetDateTime; import java.util.List; -import static de.sovity.edc.extension.e2e.connector.DataTransferTestUtil.validateDataTransferred; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorRemoteConfig.fromConnectorConfig; +import static de.sovity.edc.extension.e2e.connector.remotes.management_api.DataTransferTestUtil.validateDataTransferred; import static org.assertj.core.api.Assertions.assertThat; class ApiWrapperDemoTest { - private static final String PROVIDER_PARTICIPANT_ID = "provider"; - private static final String CONSUMER_PARTICIPANT_ID = "consumer"; - - @RegisterExtension - static EdcExtension providerEdcContext = new EdcExtension(); - @RegisterExtension - static EdcExtension consumerEdcContext = new EdcExtension(); - @RegisterExtension - static final TestDatabase PROVIDER_DATABASE = new TestDatabaseViaTestcontainers(); - @RegisterExtension - static final TestDatabase CONSUMER_DATABASE = new TestDatabaseViaTestcontainers(); - - private ConnectorRemote providerConnector; - private ConnectorRemote consumerConnector; - - private EdcClient providerClient; - private EdcClient consumerClient; - private MockDataAddressRemote dataAddress; + private static CeE2eTestExtension e2eTestExtension = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); private final String dataOfferData = "expected data 123"; - private final String dataOfferId = "my-data-offer-2023-11"; - @BeforeEach - void setup() { - // set up provider EDC + Client - var providerConfig = forTestDatabase(PROVIDER_PARTICIPANT_ID, PROVIDER_DATABASE); - providerEdcContext.setConfiguration(providerConfig.getProperties()); - providerConnector = new ConnectorRemote(fromConnectorConfig(providerConfig)); - - providerClient = EdcClient.builder() - .managementApiUrl(providerConfig.getManagementApiUrl()) - .managementApiKey(providerConfig.getManagementApiKey()) - .build(); - - // set up consumer EDC + Client - var consumerConfig = forTestDatabase(CONSUMER_PARTICIPANT_ID, CONSUMER_DATABASE); - consumerEdcContext.setConfiguration(consumerConfig.getProperties()); - consumerConnector = new ConnectorRemote(fromConnectorConfig(consumerConfig)); - - consumerClient = EdcClient.builder() - .managementApiUrl(consumerConfig.getManagementApiUrl()) - .managementApiKey(consumerConfig.getManagementApiKey()) - .build(); + TestBackendRemote dataAddress; + EdcClient consumerClient; + EdcClient providerClient; + Config consumerConfig; + Config providerConfig; - // We use the provider EDC as data sink / data source (it has the test-backend-controller extension) - dataAddress = new MockDataAddressRemote(providerConfig.getDefaultApiUrl()); + @BeforeEach + void setup( + TestBackendRemote dataAddress, + @Consumer EdcClient consumerClient, + @Consumer Config consumerConfig, + @Provider EdcClient providerClient, + @Provider Config providerConfig + ) { + this.dataAddress = dataAddress; + this.consumerClient = consumerClient; + this.consumerConfig = consumerConfig; + this.providerClient = providerClient; + this.providerConfig = providerConfig; } @Test @@ -117,7 +96,8 @@ void provide_and_consume() { createContractDefinition(); // consumer: negotiate contract and transfer data - var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(getProtocolEndpoint(providerConnector)); + var participantId = ConfigUtils.getParticipantId(providerConfig); + var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(participantId, ConfigUtils.getProtocolApiUrl(providerConfig)); var negotiation = initiateNegotiation(dataOffers.get(0), dataOffers.get(0).getContractOffers().get(0)); negotiation = awaitNegotiationDone(negotiation.getContractNegotiationId()); initiateTransfer(negotiation); @@ -206,8 +186,8 @@ private void createContractDefinition() { private UiContractNegotiation initiateNegotiation(UiDataOffer dataOffer, UiContractOffer contractOffer) { var negotiationRequest = ContractNegotiationRequest.builder() + .counterPartyId(dataOffer.getParticipantId()) .counterPartyAddress(dataOffer.getEndpoint()) - .counterPartyParticipantId(dataOffer.getParticipantId()) .assetId(dataOffer.getAsset().getAssetId()) .contractOfferId(contractOffer.getContractOfferId()) .policyJsonLd(contractOffer.getPolicy().getPolicyJsonLd()) @@ -217,7 +197,7 @@ private UiContractNegotiation initiateNegotiation(UiDataOffer dataOffer, UiContr } private UiContractNegotiation awaitNegotiationDone(String negotiationId) { - var negotiation = Awaitility.await().atMost(consumerConnector.timeout).until( + var negotiation = Awaitility.await().atMost(Duration.ofSeconds(15)).until( () -> consumerClient.uiApi().getContractNegotiation(negotiationId), it -> it.getState().getSimplifiedState() != ContractNegotiationSimplifiedState.IN_PROGRESS ); @@ -230,12 +210,9 @@ private void initiateTransfer(UiContractNegotiation negotiation) { var contractAgreementId = negotiation.getContractAgreementId(); var transferRequest = InitiateTransferRequest.builder() .contractAgreementId(contractAgreementId) + .transferType("HttpData-PUSH") .dataSinkProperties(dataAddress.getDataSinkProperties()) .build(); consumerClient.uiApi().initiateTransfer(transferRequest); } - - private String getProtocolEndpoint(ConnectorRemote connector) { - return connector.getConfig().getProtocolApiUrl(); - } } diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/asset/AssetApiServiceTest.java b/tests/src/test/java/de/sovity/edc/e2e/AssetApiServiceTest.java similarity index 84% rename from extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/asset/AssetApiServiceTest.java rename to tests/src/test/java/de/sovity/edc/e2e/AssetApiServiceTest.java index 791bdc550..e533924b8 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/asset/AssetApiServiceTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/AssetApiServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 sovity GmbH + * Copyright (c) 2023 sovity GmbH * * This program and the accompanying materials are made available under the * terms of the Apache License, Version 2.0 which is available at @@ -11,8 +11,8 @@ * sovity GmbH - initial API and implementation * */ -package de.sovity.edc.ext.wrapper.api.ui.pages.asset; +package de.sovity.edc.e2e; import de.sovity.edc.client.EdcClient; import de.sovity.edc.client.gen.model.DataSourceType; @@ -23,15 +23,14 @@ import de.sovity.edc.client.gen.model.UiDataSourceHttpData; import de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils.EdcPropertyUtils; import de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils.FailedMappingException; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; +import de.sovity.edc.extension.e2e.junit.Janitor; import de.sovity.edc.utils.jsonld.vocab.Prop; import lombok.SneakyThrows; -import lombok.val; -import org.eclipse.edc.connector.spi.asset.AssetService; -import org.eclipse.edc.junit.annotations.ApiTest; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; +import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.spi.types.domain.DataAddress; -import org.eclipse.edc.spi.types.domain.asset.Asset; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -42,30 +41,18 @@ import java.util.List; import java.util.Map; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; import static org.assertj.core.api.Assertions.assertThat; -@ApiTest public class AssetApiServiceTest { - private static EdcClient client; + public static final String DATA_SINK = "http://my-data-sink/api/stuff"; @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "edc", - testDatabase -> { - val config = forTestDatabase("MyEDC", testDatabase); - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - return config.getProperties(); - } - ); - - public static final String DATA_SINK = "http://my-data-sink/api/stuff"; + static CeIntegrationTestExtension providerExtension = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .participantId("MyEDC") + .build(); EdcPropertyUtils edcPropertyUtils; @BeforeEach @@ -74,15 +61,13 @@ void setup() { } @Test - void assetPage() { - val assetService = providerExtension.getEdcRuntimeExtension().getContext().getService(AssetService.class); - + void assetPage(EdcClient client, AssetService assetService, Janitor janitor) { // arrange var properties = Map.of( - Asset.PROPERTY_ID, "asset-11", + Asset.PROPERTY_ID, "asset-1", Prop.Dcat.LANDING_PAGE, "https://data-source.my-org/docs" ); - createAsset(assetService, "2023-06-01", properties); + createAsset(janitor, assetService, "2023-06-01", properties); // act var result = client.uiApi().getAssetPage(); @@ -96,13 +81,11 @@ void assetPage() { } @Test - void assetPageSorting() { - val assetService = providerExtension.getEdcRuntimeExtension().getContext().getService(AssetService.class); - + void assetPageSorting(EdcClient client, AssetService assetService, Janitor janitor) { // arrange - createAsset(assetService, "2023-06-01", Map.of(Asset.PROPERTY_ID, "asset-21")); - createAsset(assetService, "2023-06-03", Map.of(Asset.PROPERTY_ID, "asset-23")); - createAsset(assetService, "2023-06-02", Map.of(Asset.PROPERTY_ID, "asset-22")); + createAsset(janitor, assetService, "2023-06-01", Map.of(Asset.PROPERTY_ID, "asset-1")); + createAsset(janitor, assetService, "2023-06-03", Map.of(Asset.PROPERTY_ID, "asset-3")); + createAsset(janitor, assetService, "2023-06-02", Map.of(Asset.PROPERTY_ID, "asset-2")); // act var result = client.uiApi().getAssetPage(); @@ -110,13 +93,11 @@ void assetPageSorting() { // assert assertThat(result.getAssets()) .extracting(UiAsset::getAssetId) - .containsExactly("asset-23", "asset-22", "asset-21"); + .containsExactly("asset-3", "asset-2", "asset-1"); } @Test - void testAssetCreation() { - val assetService = providerExtension.getEdcRuntimeExtension().getContext().getService(AssetService.class); - + void testAssetCreation(EdcClient client, AssetService assetService, Janitor janitor) { // arrange var dataSource = UiDataSource.builder() .type(DataSourceType.HTTP_DATA) @@ -129,8 +110,9 @@ void testAssetCreation() { .build()) .customProperties(Map.of("oauth2:tokenUrl", "https://token-url")) .build(); + var uiAssetRequest = UiAssetCreateRequest.builder() - .id("asset-31") + .id("asset-1") .title("AssetTitle") .description("AssetDescription") .licenseUrl("https://license-url") @@ -180,15 +162,15 @@ void testAssetCreation() { .build(); // act - var response = client.uiApi().createAsset(uiAssetRequest); + var response = janitor.withClient(client).createAsset(uiAssetRequest); // assert - assertThat(response.getId()).isEqualTo("asset-31"); + assertThat(response.getId()).isEqualTo("asset-1"); var assets = client.uiApi().getAssetPage().getAssets(); assertThat(assets).hasSize(1); var asset = assets.get(0); - assertThat(asset.getAssetId()).isEqualTo("asset-31"); + assertThat(asset.getAssetId()).isEqualTo("asset-1"); assertThat(asset.getTitle()).isEqualTo("AssetTitle"); assertThat(asset.getDescription()).isEqualTo("AssetDescription"); assertThat(asset.getVersion()).isEqualTo("1.0.0"); @@ -245,9 +227,7 @@ void testAssetCreation() { } @Test - void testeditAsset() { - val assetService = providerExtension.getEdcRuntimeExtension().getContext().getService(AssetService.class); - + void testeditAsset(EdcClient client, AssetService assetService, Janitor janitor) { // arrange var dataSource = UiDataSource.builder() .type(DataSourceType.HTTP_DATA) @@ -261,7 +241,7 @@ void testeditAsset() { .customProperties(Map.of("oauth2:tokenUrl", "https://token-url")) .build(); var createRequest = UiAssetCreateRequest.builder() - .id("asset-41") + .id("asset-1") .title("AssetTitle") .description("AssetDescription") .licenseUrl("https://license-url") @@ -297,7 +277,8 @@ void testeditAsset() { """) .build(); - client.uiApi().createAsset(createRequest); + janitor.withClient(client).createAsset(createRequest); + var dataAddressBeforeEdit = assetService.query(QuerySpec.max()) .orElseThrow(FailedMappingException::ofFailure).toList().get(0) .getDataAddress() @@ -339,15 +320,15 @@ void testeditAsset() { .build(); // act - var response = client.uiApi().editAsset("asset-41", editRequest); + var response = client.uiApi().editAsset("asset-1", editRequest); // assert - assertThat(response.getId()).isEqualTo("asset-41"); + assertThat(response.getId()).isEqualTo("asset-1"); var assets = client.uiApi().getAssetPage().getAssets(); assertThat(assets).hasSize(1); var asset = assets.get(0); - assertThat(asset.getAssetId()).isEqualTo("asset-41"); + assertThat(asset.getAssetId()).isEqualTo("asset-1"); assertThat(asset.getTitle()).isEqualTo("AssetTitle 2"); assertThat(asset.getDescription()).isEqualTo("AssetDescription 2"); assertThat(asset.getVersion()).isEqualTo("2.0.0"); @@ -391,7 +372,7 @@ void testeditAsset() { } @Test - void testAssetCreation_noProxying() { + void testAssetCreation_noProxying(EdcClient client, Janitor janitor) { // arrange var dataSource = UiDataSource.builder() .type(DataSourceType.HTTP_DATA) @@ -399,16 +380,17 @@ void testAssetCreation_noProxying() { .baseUrl(DATA_SINK) .build()) .build(); + var uiAssetRequest = UiAssetCreateRequest.builder() - .id("asset-51") + .id("asset-1") .dataSource(dataSource) .build(); // act - var response = client.uiApi().createAsset(uiAssetRequest); + var response = janitor.withClient(client).createAsset(uiAssetRequest); // assert - assertThat(response.getId()).isEqualTo("asset-51"); + assertThat(response.getId()).isEqualTo("asset-1"); var assets = client.uiApi().getAssetPage().getAssets(); assertThat(assets).hasSize(1); var asset = assets.get(0); @@ -419,7 +401,7 @@ void testAssetCreation_noProxying() { } @Test - void testAssetCreation_differentDataAddressType() { + void testAssetCreation_differentDataAddressType(EdcClient client, Janitor janitor) { // arrange var dataSource = UiDataSource.builder() .type(DataSourceType.CUSTOM) @@ -428,15 +410,15 @@ void testAssetCreation_differentDataAddressType() { )) .build(); var uiAssetRequest = UiAssetCreateRequest.builder() - .id("asset-61") + .id("asset-1") .dataSource(dataSource) .build(); // act - var response = client.uiApi().createAsset(uiAssetRequest); + var response = janitor.withClient(client).createAsset(uiAssetRequest); // assert - assertThat(response.getId()).isEqualTo("asset-61"); + assertThat(response.getId()).isEqualTo("asset-1"); var assets = client.uiApi().getAssetPage().getAssets(); assertThat(assets).hasSize(1); var asset = assets.get(0); @@ -447,22 +429,21 @@ void testAssetCreation_differentDataAddressType() { } @Test - void testDeleteAsset() { - val assetService = providerExtension.getEdcRuntimeExtension().getContext().getService(AssetService.class); - + void testDeleteAsset(EdcClient client, AssetService assetService, Janitor janitor) { // arrange - createAsset(assetService, "2023-06-01", Map.of(Asset.PROPERTY_ID, "asset-71")); + createAsset(janitor, assetService, "2023-06-01", Map.of(Asset.PROPERTY_ID, "asset-1")); assertThat(assetService.query(QuerySpec.max()).getContent()).isNotEmpty(); // act - var response = client.uiApi().deleteAsset("asset-71"); + var response = client.uiApi().deleteAsset("asset-1"); // assert - assertThat(response.getId()).isEqualTo("asset-71"); - assertThat(assetService.query(QuerySpec.max()).getContent()).isEmpty(); + assertThat(response.getId()).isEqualTo("asset-1"); + assertThat(assetService.query(QuerySpec.max()).getContent()).hasSize(0); } private void createAsset( + Janitor janitor, AssetService assetService, String date, Map properties @@ -478,7 +459,8 @@ private void createAsset( .dataAddress(dataAddress) .createdAt(dateFormatterToLong(date)) .build(); - assetService.create(asset); + + janitor.withAssetService(assetService).create(asset); } @SneakyThrows diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiTest.java b/tests/src/test/java/de/sovity/edc/e2e/CatalogApiTest.java similarity index 74% rename from extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiTest.java rename to tests/src/test/java/de/sovity/edc/e2e/CatalogApiTest.java index ecec4a5bd..d159a057d 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/CatalogApiTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 sovity GmbH + * Copyright (c) 2024 sovity GmbH * * This program and the accompanying materials are made available under the * terms of the Apache License, Version 2.0 which is available at @@ -12,7 +12,7 @@ * */ -package de.sovity.edc.ext.wrapper.api.ui.pages.catalog; +package de.sovity.edc.e2e; import de.sovity.edc.client.EdcClient; import de.sovity.edc.client.gen.model.ContractDefinitionRequest; @@ -27,39 +27,24 @@ import de.sovity.edc.client.gen.model.UiDataSourceHttpData; import de.sovity.edc.client.gen.model.UiPolicyExpression; import de.sovity.edc.client.gen.model.UiPolicyExpressionType; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; import de.sovity.edc.extension.utils.junit.DisabledOnGithub; +import de.sovity.edc.utils.config.ConfigUtils; import de.sovity.edc.utils.jsonld.vocab.Prop; import lombok.SneakyThrows; -import org.eclipse.edc.junit.annotations.ApiTest; +import org.eclipse.edc.spi.system.configuration.Config; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import java.util.List; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static org.assertj.core.api.Assertions.assertThat; - -@ApiTest class CatalogApiTest { - private static ConnectorConfig config; - private static EdcClient client; - @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "provider", - testDatabase -> { - config = forTestDatabase("my-edc-participant-id", testDatabase); - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - return config.getProperties(); - } - ); + static CeIntegrationTestExtension providerExtension = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); private final String dataOfferId = "my-data-offer-2023-11"; @@ -70,21 +55,25 @@ class CatalogApiTest { @DisabledOnGithub @Test @SneakyThrows - void testDistributionKey() { + void testDistributionKey(EdcClient client, Config config) { + var protocolApiUrl = ConfigUtils.getProtocolApiUrl(config); + var participantId = ConfigUtils.getParticipantId(config); + // arrange - createAsset(); - createPolicy(); - createContractDefinition(); + createAsset(client); + createPolicy(client); + createContractDefinition(client); + // act - var catalogPageDataOffers = client.uiApi().getCatalogPageDataOffers(config.getProtocolApiUrl()); + var catalogPageDataOffers = client.uiApi().getCatalogPageDataOffers(participantId, protocolApiUrl); // assert - assertThat(catalogPageDataOffers.size()).isEqualTo(1); + assertThat(catalogPageDataOffers).hasSize(1); assertThat(catalogPageDataOffers.get(0).getAsset().getTitle()).isEqualTo("My Data Offer"); assertThat(catalogPageDataOffers.get(0).getAsset().getMediaType()).isEqualTo("Media Type"); } - private void createAsset() { + private void createAsset(EdcClient client) { var dataSource = UiDataSource.builder() .type(DataSourceType.HTTP_DATA) .httpData(UiDataSourceHttpData.builder() @@ -107,7 +96,7 @@ private void createAsset() { client.uiApi().createAsset(asset); } - private void createPolicy() { + private void createPolicy(EdcClient client) { var policyDefinition = PolicyDefinitionCreateDto.builder() .policyDefinitionId(dataOfferId) .expression(UiPolicyExpression.builder().type(UiPolicyExpressionType.EMPTY).build()) @@ -116,7 +105,7 @@ private void createPolicy() { client.uiApi().createPolicyDefinitionV2(policyDefinition); } - private void createContractDefinition() { + private void createContractDefinition(EdcClient client) { var contractDefinition = ContractDefinitionRequest.builder() .contractDefinitionId(dataOfferId) .accessPolicyId(dataOfferId) diff --git a/extensions/contract-termination/src/test/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementTerminationDetailsQueryTest.java b/tests/src/test/java/de/sovity/edc/e2e/ContractAgreementTerminationDetailsQueryTest.java similarity index 80% rename from extensions/contract-termination/src/test/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementTerminationDetailsQueryTest.java rename to tests/src/test/java/de/sovity/edc/e2e/ContractAgreementTerminationDetailsQueryTest.java index b937b9131..95234927d 100644 --- a/extensions/contract-termination/src/test/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementTerminationDetailsQueryTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/ContractAgreementTerminationDetailsQueryTest.java @@ -12,36 +12,40 @@ * */ -package de.sovity.edc.extension.contacttermination.query; +package de.sovity.edc.e2e; import de.sovity.edc.client.gen.model.ContractTerminationRequest; import de.sovity.edc.ext.db.jooq.enums.ContractTerminatedBy; import de.sovity.edc.extension.contacttermination.ContractAgreementTerminationDetails; +import de.sovity.edc.extension.contacttermination.query.ContractAgreementTerminationDetailsQuery; import de.sovity.edc.extension.db.directaccess.DslContextFactory; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.extension.Consumer; -import de.sovity.edc.extension.e2e.extension.E2eScenario; -import de.sovity.edc.extension.e2e.extension.E2eTestExtension; -import de.sovity.edc.extension.e2e.extension.Provider; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenario; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; import de.sovity.edc.extension.utils.junit.DisabledOnGithub; +import de.sovity.edc.utils.config.ConfigUtils; import lombok.val; +import org.eclipse.edc.spi.system.configuration.Config; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation.Type.CONSUMER; +import static org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation.Type.CONSUMER; class ContractAgreementTerminationDetailsQueryTest { @RegisterExtension - private static E2eTestExtension e2eTestExtension = new E2eTestExtension(":launchers:connectors:sovity-dev"); + private static CeE2eTestExtension e2eTestExtension = CeE2eTestExtension.builder() + .additionalModule(":launchers:utils:vanilla-control-plane") + .build(); @DisabledOnGithub @Test void fetchAgreementDetailsOrThrow_whenAgreementIsPresent_shouldReturnTheAgreementDetails( - E2eScenario scenario, + E2eTestScenario scenario, @Consumer DslContextFactory dslContextFactory, - @Provider ConnectorConfig providerConfig + @Provider Config providerConfig ) { // arrange @@ -60,7 +64,7 @@ void fetchAgreementDetailsOrThrow_whenAgreementIsPresent_shouldReturnTheAgreemen assertThat(details).isEqualTo(ContractAgreementTerminationDetails.builder() .contractAgreementId(agreementId) .counterpartyId("provider") - .counterpartyAddress(providerConfig.getProtocolApiUrl()) + .counterpartyAddress(ConfigUtils.getProtocolApiUrl(providerConfig)) .type(CONSUMER) .providerAgentId("provider") .consumerAgentId("consumer") @@ -91,9 +95,9 @@ void fetchAgreementDetailsOrThrow_whenAgreementIsMissing_shouldReturnEmptyOption @Test void fetchAgreementDetailsOrThrow_whenTerminationAlreadyExists_shouldReturnOptionalWithTerminationData( - E2eScenario scenario, + E2eTestScenario scenario, @Consumer DslContextFactory dslContextFactory, - @Provider ConnectorConfig providerConfig + @Provider Config providerConfig ) { // arrange @@ -113,7 +117,7 @@ void fetchAgreementDetailsOrThrow_whenTerminationAlreadyExists_shouldReturnOptio // assert assertThat(details.contractAgreementId()).isEqualTo(agreementId); assertThat(details.counterpartyId()).isEqualTo("provider"); - assertThat(details.counterpartyAddress()).isEqualTo(providerConfig.getProtocolApiUrl()); + assertThat(details.counterpartyAddress()).isEqualTo(ConfigUtils.getProtocolApiUrl(providerConfig)); assertThat(details.type()).isEqualTo(CONSUMER); assertThat(details.providerAgentId()).isEqualTo("provider"); assertThat(details.consumerAgentId()).isEqualTo("consumer"); diff --git a/tests/src/test/java/de/sovity/edc/e2e/DataSourceParameterizationTest.java b/tests/src/test/java/de/sovity/edc/e2e/DataSourceParameterizationTest.java index 984780806..401bf0e82 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/DataSourceParameterizationTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/DataSourceParameterizationTest.java @@ -35,14 +35,14 @@ import de.sovity.edc.client.gen.model.UiDataSourceHttpData; import de.sovity.edc.client.gen.model.UiPolicyExpression; import de.sovity.edc.client.gen.model.UiPolicyExpressionType; -import de.sovity.edc.extension.e2e.connector.ConnectorRemote; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.extension.Consumer; -import de.sovity.edc.extension.e2e.extension.E2eScenario; -import de.sovity.edc.extension.e2e.extension.E2eTestExtension; -import de.sovity.edc.extension.e2e.extension.Provider; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenario; +import de.sovity.edc.extension.e2e.connector.remotes.management_api.ManagementApiConnectorRemote; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; import de.sovity.edc.extension.utils.junit.DisabledOnGithub; import de.sovity.edc.utils.JsonUtils; +import de.sovity.edc.utils.config.ConfigUtils; import de.sovity.edc.utils.jsonld.vocab.Prop; import jakarta.json.Json; import jakarta.ws.rs.HttpMethod; @@ -50,10 +50,12 @@ import lombok.val; import okhttp3.HttpUrl; import org.awaitility.Awaitility; -import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; +import org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol; +import org.eclipse.edc.spi.system.configuration.Config; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.mockserver.integration.ClientAndServer; @@ -76,26 +78,22 @@ import javax.annotation.Nullable; import static de.sovity.edc.client.gen.model.TransferProcessSimplifiedState.OK; -import static de.sovity.edc.extension.e2e.extension.Helpers.defaultE2eTestExtension; import static java.time.Duration.ofSeconds; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Fail.fail; -import static org.eclipse.edc.connector.dataplane.spi.schema.DataFlowRequestSchema.BODY; -import static org.eclipse.edc.connector.dataplane.spi.schema.DataFlowRequestSchema.MEDIA_TYPE; -import static org.eclipse.edc.connector.dataplane.spi.schema.DataFlowRequestSchema.METHOD; -import static org.eclipse.edc.connector.dataplane.spi.schema.DataFlowRequestSchema.PATH; -import static org.eclipse.edc.connector.dataplane.spi.schema.DataFlowRequestSchema.QUERY_PARAMS; -import static org.eclipse.edc.junit.testfixtures.TestUtils.getFreePort; -import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; +import static org.eclipse.edc.util.io.Ports.getFreePort; import static org.mockserver.matchers.Times.once; import static org.mockserver.model.HttpRequest.request; import static org.mockserver.stop.Stop.stopQuietly; - +// Disabled until further evaluation of this workaround for EDC versions 0.7+ +@Disabled class DataSourceParameterizationTest { @RegisterExtension - private static E2eTestExtension e2eTestExtension = defaultE2eTestExtension(); + private static CeE2eTestExtension e2eTestExtension = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); private final int port = getFreePort(); private final String sourcePath = "/source/some/path/"; @@ -132,9 +130,9 @@ public void stopServer() { @Test @DisabledOnGithub void canUseTheWorkaroundInCustomTransferRequest( - E2eScenario scenario, + E2eTestScenario scenario, @Consumer EdcClient consumerClient, - @Provider ConnectorConfig providerConfig, + @Provider Config providerConfig, @Provider EdcClient providerClient ) { // arrange @@ -154,8 +152,9 @@ void canUseTheWorkaroundInCustomTransferRequest( createData(providerClient, testCase, context); // act - val providerEndpoint = providerConfig.getProtocolApiUrl(); - val dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerEndpoint); + val providerEndpoint = ConfigUtils.getProtocolApiUrl(providerConfig); + var participantId = ConfigUtils.getParticipantId(providerConfig); + val dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(participantId, providerEndpoint); val startNegotiation = initiateNegotiation(consumerClient, dataOffers.get(0), dataOffers.get(0).getContractOffers().get(0)); val negotiation = awaitNegotiationDone(consumerClient, startNegotiation.getContractNegotiationId()); @@ -225,10 +224,10 @@ private void createData(EdcClient providerClient, TestCase testCase, Context con @Test void sendWithEdcManagementApi( - E2eScenario scenario, - @Consumer ConnectorRemote consumerConnector, + E2eTestScenario scenario, + @Consumer ManagementApiConnectorRemote consumerConnector, @Consumer EdcClient consumerClient, - @Provider ConnectorConfig providerConfig, + @Provider Config providerConfig, @Provider EdcClient providerClient ) { // arrange @@ -248,8 +247,9 @@ void sendWithEdcManagementApi( createData(providerClient, testCase, context); // act - val providerEndpoint = providerConfig.getProtocolApiUrl(); - val dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerEndpoint); + val providerEndpoint = ConfigUtils.getProtocolApiUrl(providerConfig); + val providerParticipantId = ConfigUtils.getParticipantId(providerConfig); + val dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerParticipantId, providerEndpoint); val startNegotiation = initiateNegotiation(consumerClient, dataOffers.get(0), dataOffers.get(0).getContractOffers().get(0)); val negotiation = awaitNegotiationDone(consumerClient, startNegotiation.getContractNegotiationId()); @@ -286,9 +286,9 @@ void sendWithEdcManagementApi( @DisabledOnGithub @Test void canTransferParameterizedAsset( - E2eScenario scenario, + E2eTestScenario scenario, @Consumer EdcClient consumerClient, - @Provider ConnectorConfig providerConfig, + @Provider Config providerConfig, @Provider EdcClient providerClient) { source().parallel().forEach(testCase -> { @@ -300,8 +300,9 @@ void canTransferParameterizedAsset( createData(providerClient, testCase, context); // act - val connectorEndpoint = providerConfig.getProtocolApiUrl(); - val dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(connectorEndpoint); + val connectorEndpoint = ConfigUtils.getProtocolApiUrl(providerConfig); + val participantId = ConfigUtils.getParticipantId(providerConfig); + val dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(participantId, connectorEndpoint); val dataOffer = dataOffers.stream().filter(it -> it.getAsset().getAssetId().equals(testCase.id)).findFirst().get(); val negotiationInit = initiateNegotiation(consumerClient, dataOffer, dataOffer.getContractOffers().get(0)); val negotiation = awaitNegotiationDone(consumerClient, negotiationInit.getContractNegotiationId()); @@ -484,7 +485,6 @@ private String createContractDefinition(EdcClient providerClient, TestCase testC private UiContractNegotiation initiateNegotiation(EdcClient consumerClient, UiDataOffer dataOffer, UiContractOffer contractOffer) { var negotiationRequest = ContractNegotiationRequest.builder() .counterPartyAddress(dataOffer.getEndpoint()) - .counterPartyParticipantId(dataOffer.getParticipantId()) .assetId(dataOffer.getAsset().getAssetId()) .contractOfferId(contractOffer.getContractOfferId()) .policyJsonLd(contractOffer.getPolicy().getPolicyJsonLd()) @@ -515,20 +515,20 @@ private String initiateTransferWithParameters( var contractAgreementId = negotiation.getContractAgreementId(); Map dataSinkProperties = new HashMap<>(); - dataSinkProperties.put(EDC_NAMESPACE + "baseUrl", context.destinationUrl); - dataSinkProperties.put(EDC_NAMESPACE + "method", HttpMethod.PUT); - dataSinkProperties.put(EDC_NAMESPACE + "type", "HttpData"); - transferProcessProperties.put(rootKey + METHOD, testCase.method); + dataSinkProperties.put(Prop.Edc.BASE_URL, context.destinationUrl); + dataSinkProperties.put(Prop.Edc.METHOD, HttpMethod.PUT); + dataSinkProperties.put(Prop.Edc.TYPE, "HttpData"); + transferProcessProperties.put(Prop.Edc.METHOD, testCase.method); if (testCase.body != null) { - dataSinkProperties.put("https://w3id.org/edc/v0.0.1/ns/body", testCase.body); - transferProcessProperties.put(rootKey + BODY, testCase.body); - transferProcessProperties.put(rootKey + MEDIA_TYPE, testCase.mediaType); - transferProcessProperties.put(rootKey + "contentType", testCase.mediaType); + dataSinkProperties.put(Prop.Edc.BODY, testCase.body); + transferProcessProperties.put(Prop.Edc.BODY, testCase.body); + transferProcessProperties.put(Prop.Edc.MEDIA_TYPE, testCase.mediaType); + transferProcessProperties.put(Prop.Edc.CONTENT_TYPE, testCase.mediaType); } if (testCase.path != null) { - transferProcessProperties.put(rootKey + PATH, testCase.path); + transferProcessProperties.put(Prop.Edc.PATH, testCase.path); } if (!testCase.queryParams.isEmpty()) { @@ -544,12 +544,13 @@ private String initiateTransferWithParameters( val allQueryParams = builder.build().encodedQuery(); - transferProcessProperties.put(rootKey + QUERY_PARAMS, allQueryParams); + transferProcessProperties.put(Prop.Edc.QUERY_PARAMS, allQueryParams); } var transferRequest = InitiateTransferRequest.builder() .contractAgreementId(contractAgreementId) .dataSinkProperties(dataSinkProperties) + .transferType("HttpData-PUSH") .transferProcessProperties(transferProcessProperties) .build(); return consumerClient.uiApi().initiateTransfer(transferRequest).getId(); diff --git a/tests/src/test/java/de/sovity/edc/e2e/DataSourceQueryParamsTest.java b/tests/src/test/java/de/sovity/edc/e2e/DataSourceQueryParamsTest.java index 061594233..d0a932c25 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/DataSourceQueryParamsTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/DataSourceQueryParamsTest.java @@ -18,35 +18,37 @@ import de.sovity.edc.client.gen.model.InitiateTransferRequest; import de.sovity.edc.client.gen.model.UiContractNegotiation; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; -import de.sovity.edc.extension.e2e.connector.MockDataAddressRemote; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.extension.Consumer; -import de.sovity.edc.extension.e2e.extension.E2eScenario; -import de.sovity.edc.extension.e2e.extension.E2eTestExtension; -import de.sovity.edc.extension.e2e.extension.Provider; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenario; +import de.sovity.edc.extension.e2e.connector.remotes.test_backend_controller.TestBackendRemote; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; import de.sovity.edc.extension.utils.junit.DisabledOnGithub; +import de.sovity.edc.utils.config.ConfigUtils; import lombok.val; +import org.eclipse.edc.spi.system.configuration.Config; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import java.util.HashMap; -import static de.sovity.edc.extension.e2e.connector.DataTransferTestUtil.validateDataTransferred; -import static de.sovity.edc.extension.e2e.extension.Helpers.defaultE2eTestExtension; +import static de.sovity.edc.extension.e2e.connector.remotes.management_api.DataTransferTestUtil.validateDataTransferred; class DataSourceQueryParamsTest { @RegisterExtension - private static E2eTestExtension e2eTestExtension = defaultE2eTestExtension(); + private static CeE2eTestExtension e2eTestExtension = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); - private MockDataAddressRemote dataAddress; + private TestBackendRemote dataAddress; private final String encodedParam = "a=%25"; // Unencoded param "a=%" @BeforeEach - void setup(@Provider ConnectorConfig providerConfig) { + void setup(@Provider Config providerConfig) { // We use the provider EDC as data sink / data source (it has the test-backend-controller extension) - dataAddress = new MockDataAddressRemote(providerConfig.getDefaultApiUrl()); + dataAddress = new TestBackendRemote(ConfigUtils.getDefaultApiUrl(providerConfig)); } @Test @@ -67,7 +69,7 @@ void testDirectQuerying() { */ @DisabledOnGithub @Test - void testQueryParamsDoubleEncoded(E2eScenario scenario, @Consumer EdcClient consumerClient) { + void testQueryParamsDoubleEncoded(E2eTestScenario scenario, @Consumer EdcClient consumerClient) { // arrange val assetId = "asset-1"; @@ -91,6 +93,7 @@ private void initiateTransfer(EdcClient consumerClient, UiContractNegotiation ne var contractAgreementId = negotiation.getContractAgreementId(); var transferRequest = InitiateTransferRequest.builder() .contractAgreementId(contractAgreementId) + .transferType("HttpData-PUSH") .dataSinkProperties(dataAddress.getDataSinkProperties()) .build(); consumerClient.uiApi().initiateTransfer(transferRequest); diff --git a/tests/src/test/java/de/sovity/edc/e2e/DatasetTest.java b/tests/src/test/java/de/sovity/edc/e2e/DatasetTest.java deleted file mode 100644 index 7849715eb..000000000 --- a/tests/src/test/java/de/sovity/edc/e2e/DatasetTest.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - init - * - */ - -package de.sovity.edc.e2e; - -import de.sovity.edc.extension.e2e.connector.ConnectorRemote; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.extension.Consumer; -import de.sovity.edc.extension.e2e.extension.E2eTestExtension; -import de.sovity.edc.extension.e2e.extension.Provider; -import io.restassured.response.Response; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import java.util.Map; -import java.util.UUID; - -import static de.sovity.edc.extension.e2e.extension.Helpers.defaultE2eTestExtension; -import static io.restassured.http.ContentType.JSON; -import static jakarta.json.Json.createObjectBuilder; -import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; -import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; -import static org.eclipse.edc.spi.CoreConstants.EDC_PREFIX; -import static org.hamcrest.Matchers.equalTo; - -class DatasetTest { - - @RegisterExtension - private static E2eTestExtension e2eTestExtension = defaultE2eTestExtension(); - - @Test - void canRetrieveOfferedDataset( - @Consumer ConnectorRemote consumerConnector, - @Provider ConnectorConfig providerConfig, - @Provider ConnectorRemote providerConnector) { - // arrange - var assetId = UUID.randomUUID().toString(); - providerConnector.createDataOffer(assetId, "http://example.com"); - - // act & assert - prepareDatasetApiCall( - consumerConnector, - providerConfig.getProtocolApiUrl(), - assetId) - .then() - .statusCode(200) - .body("'edc:description'", equalTo("description")); - } - - @Test - void canNotRetrieveNotOfferedDataset( - @Consumer ConnectorRemote consumerConnector, - @Provider ConnectorConfig providerConfig, - @Provider ConnectorRemote providerConnector) { - // arrange - Map dataSource = Map.of( - EDC_NAMESPACE + "type", "HttpData", - EDC_NAMESPACE + "baseUrl", "http://localhost"); - var assetId = UUID.randomUUID().toString(); - providerConnector.createAsset(assetId, dataSource); - - // act & assert - prepareDatasetApiCall( - consumerConnector, - providerConfig.getProtocolApiUrl(), - assetId) - .then() - .statusCode(502); - } - - @Test - void canNotRetrieveNotOfferedDatasetIfValidOfferAvailable( - @Consumer ConnectorRemote consumerConnector, - @Provider ConnectorConfig providerConfig, - @Provider ConnectorRemote providerConnector) { - // arrange - Map dataSource = Map.of( - EDC_NAMESPACE + "type", "HttpData", - EDC_NAMESPACE + "baseUrl", "http://localhost"); - var notOfferedAssetId = UUID.randomUUID().toString(); - var offeredAssetId = UUID.randomUUID().toString(); - providerConnector.createAsset(notOfferedAssetId, dataSource); - providerConnector.createDataOffer(offeredAssetId, "http://localhost"); - - // act & assert - prepareDatasetApiCall( - consumerConnector, - providerConfig.getProtocolApiUrl(), - notOfferedAssetId) - .then() - .statusCode(502); - - prepareDatasetApiCall( - consumerConnector, - providerConfig.getProtocolApiUrl(), - offeredAssetId) - .then() - .statusCode(200) - .body("'edc:description'", equalTo("description")); - } - - private static Response prepareDatasetApiCall( - ConnectorRemote consumerConnector, - String providerProtocolUrl, - String assetId) { - var requestBody = createObjectBuilder() - .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) - .add(EDC_NAMESPACE + "counterPartyAddress", providerProtocolUrl) - .add(EDC_NAMESPACE + "protocol", "dataspace-protocol-http") - .add("@id", assetId) - .build(); - return consumerConnector.prepareManagementApiCall() - .contentType(JSON) - .body(requestBody) - .when() - .post("/v2/catalog/dataset/request"); - } -} diff --git a/tests/src/test/java/de/sovity/edc/e2e/Edc07MigrationBaselineTest.java b/tests/src/test/java/de/sovity/edc/e2e/Edc07MigrationBaselineTest.java new file mode 100644 index 000000000..e6c698f1a --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/e2e/Edc07MigrationBaselineTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.e2e; + +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.sql.Connection; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class Edc07MigrationBaselineTest { + + @RegisterExtension + private static final CeIntegrationTestExtension INTEGRATION_TEST_EXTENSION = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .skipDb(false) + .build(); + + @SneakyThrows + @Test + void smokeTest(Connection cnx) { + // arrange + + // act + cnx.createStatement().executeQuery("SELECT * from edc.public.edc_asset"); + cnx.createStatement().executeQuery("SELECT * from edc.public.sovity_contract_termination"); + + // assert + assertThrows(Exception.class, () -> cnx.createStatement().executeQuery("SELECT * from edc.public.doesntExist")); + } +} diff --git a/tests/src/test/java/de/sovity/edc/e2e/ManagementApiTransferTest.java b/tests/src/test/java/de/sovity/edc/e2e/ManagementApiTransferTest.java index 358cc8b4f..66d430282 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/ManagementApiTransferTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/ManagementApiTransferTest.java @@ -14,48 +14,46 @@ package de.sovity.edc.e2e; -import de.sovity.edc.extension.e2e.connector.ConnectorRemote; -import de.sovity.edc.extension.e2e.connector.MockDataAddressRemote; -import de.sovity.edc.extension.e2e.extension.Consumer; -import de.sovity.edc.extension.e2e.extension.E2eTestExtension; -import de.sovity.edc.extension.e2e.extension.Provider; -import org.junit.jupiter.api.BeforeEach; +import de.sovity.edc.extension.e2e.connector.remotes.management_api.ManagementApiConnectorRemote; +import de.sovity.edc.extension.e2e.connector.remotes.test_backend_controller.TestBackendRemote; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import java.util.UUID; -import static de.sovity.edc.extension.e2e.connector.DataTransferTestUtil.validateDataTransferred; -import static de.sovity.edc.extension.e2e.extension.Helpers.defaultE2eTestExtension; +import static de.sovity.edc.extension.e2e.connector.remotes.management_api.DataTransferTestUtil.validateDataTransferred; class ManagementApiTransferTest { @RegisterExtension - private static E2eTestExtension e2eTestExtension = defaultE2eTestExtension(); + private static final CeE2eTestExtension E2E_TEST_EXTENSION = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); - private MockDataAddressRemote dataAddress; private static final String TEST_BACKEND_TEST_DATA = UUID.randomUUID().toString(); - @BeforeEach - void setup(@Provider ConnectorRemote providerConnector) { - // We use the provider EDC as data sink / data source (it has the test-backend-controller extension) - dataAddress = new MockDataAddressRemote(providerConnector.getConfig().getDefaultApiUrl()); - } - @Test - void testDataTransfer(@Consumer ConnectorRemote consumerConnector, @Provider ConnectorRemote providerConnector) { + void testDataTransfer( + @Consumer ManagementApiConnectorRemote consumerConnector, + @Provider ManagementApiConnectorRemote providerConnector, + TestBackendRemote testBackend + ) { // arrange var assetId = UUID.randomUUID().toString(); - providerConnector.createDataOffer(assetId, dataAddress.getDataSourceUrl(TEST_BACKEND_TEST_DATA)); + + providerConnector.createDataOffer(assetId, testBackend.getDataSourceUrl(TEST_BACKEND_TEST_DATA)); // act consumerConnector.consumeOffer( providerConnector.getParticipantId(), providerConnector.getConfig().getProtocolApiUrl(), assetId, - dataAddress.getDataSinkJsonLd()); + testBackend.getDataSinkJsonLd()); // assert - validateDataTransferred(dataAddress.getDataSinkSpyUrl(), TEST_BACKEND_TEST_DATA); + validateDataTransferred(testBackend.getDataSinkSpyUrl(), TEST_BACKEND_TEST_DATA); } } diff --git a/tests/src/test/java/de/sovity/edc/e2e/PlaceholderDataSourceExtensionTest.java b/tests/src/test/java/de/sovity/edc/e2e/PlaceholderDataSourceExtensionTest.java index c2d4b875c..15ae4a8e7 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/PlaceholderDataSourceExtensionTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/PlaceholderDataSourceExtensionTest.java @@ -20,9 +20,9 @@ import de.sovity.edc.client.gen.model.UiAssetCreateRequest; import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceOnRequest; -import de.sovity.edc.extension.e2e.extension.E2eScenario; -import de.sovity.edc.extension.e2e.extension.E2eTestExtension; -import de.sovity.edc.extension.e2e.extension.Provider; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenario; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Provider; import jakarta.ws.rs.HttpMethod; import lombok.SneakyThrows; import lombok.val; @@ -33,23 +33,22 @@ import org.mockserver.model.HttpResponse; import org.mockserver.model.HttpStatusCode; -import java.util.Base64; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; -import static de.sovity.edc.extension.e2e.extension.Helpers.defaultE2eTestExtension; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; +import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE; class PlaceholderDataSourceExtensionTest { - @RegisterExtension - private static E2eTestExtension e2eTestExtension = defaultE2eTestExtension(); + private static final CeE2eTestExtension E2E_TEST_EXTENSION = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); @SneakyThrows @Test void shouldAccessDummyEndpoint( - E2eScenario scenario, + E2eTestScenario scenario, ClientAndServer clientAndServer, @Provider EdcClient providerClient ) { @@ -86,6 +85,7 @@ void shouldAccessDummyEndpoint( scenario.transferAndAwait(InitiateTransferRequest.builder() .contractAgreementId(negotiation.getContractAgreementId()) + .transferType("HttpData-PUSH") .dataSinkProperties(Map.of( EDC_NAMESPACE + "baseUrl", destinationUrl, EDC_NAMESPACE + "method", HttpMethod.POST, @@ -94,7 +94,7 @@ void shouldAccessDummyEndpoint( .build()); // assert - assertThat(new String(Base64.getDecoder().decode(accessed.get()))) + assertThat(accessed.get()) .contains("This is not real data.") .contains(email) .contains(subject); diff --git a/tests/src/test/java/de/sovity/edc/e2e/UiApiWrapperTest.java b/tests/src/test/java/de/sovity/edc/e2e/UiApiWrapperTest.java index c4d6950fa..9c247fbb5 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/UiApiWrapperTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/UiApiWrapperTest.java @@ -48,22 +48,23 @@ import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.client.gen.model.UiPolicyLiteral; import de.sovity.edc.client.gen.model.UiPolicyLiteralType; -import de.sovity.edc.extension.e2e.connector.ConnectorRemote; -import de.sovity.edc.extension.e2e.connector.MockDataAddressRemote; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.extension.Consumer; -import de.sovity.edc.extension.e2e.extension.E2eScenario; -import de.sovity.edc.extension.e2e.extension.E2eTestExtension; -import de.sovity.edc.extension.e2e.extension.Provider; -import de.sovity.edc.extension.policy.AlwaysTruePolicyConstants; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenario; +import de.sovity.edc.extension.e2e.connector.remotes.management_api.ManagementApiConnectorRemote; +import de.sovity.edc.extension.e2e.connector.remotes.test_backend_controller.TestBackendRemote; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.CeE2eTestSide; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; import de.sovity.edc.extension.utils.junit.DisabledOnGithub; import de.sovity.edc.utils.JsonUtils; +import de.sovity.edc.utils.config.ConfigUtils; import de.sovity.edc.utils.jsonld.vocab.Prop; import jakarta.json.Json; import jakarta.json.JsonObject; import lombok.val; import org.awaitility.Awaitility; -import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; +import org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol; +import org.eclipse.edc.spi.system.configuration.Config; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -74,43 +75,47 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.concurrent.TimeUnit; import static de.sovity.edc.client.gen.model.ContractAgreementDirection.CONSUMING; import static de.sovity.edc.client.gen.model.ContractAgreementDirection.PROVIDING; -import static de.sovity.edc.extension.e2e.connector.DataTransferTestUtil.validateDataTransferred; -import static de.sovity.edc.extension.e2e.extension.Helpers.defaultE2eTestExtension; +import static de.sovity.edc.e2e.WrapperApiUtils.getAssetsWithId; +import static de.sovity.edc.e2e.WrapperApiUtils.getContractDefinitionWithAssetId; +import static de.sovity.edc.extension.e2e.connector.remotes.management_api.DataTransferTestUtil.validateDataTransferred; import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; import static org.junit.jupiter.api.Assertions.assertThrows; - class UiApiWrapperTest { - private static final String PROVIDER_PARTICIPANT_ID = "provider"; - private static final String CONSUMER_PARTICIPANT_ID = "consumer"; + private static final String PROVIDER_PARTICIPANT_ID = CeE2eTestSide.PROVIDER.getParticipantId(); + private static final String CONSUMER_PARTICIPANT_ID = CeE2eTestSide.CONSUMER.getParticipantId(); + private static final Random RANDOM = new Random(); @RegisterExtension - private static E2eTestExtension e2eTestExtension = defaultE2eTestExtension(); + private static final CeE2eTestExtension E2E_TEST_EXTENSION = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); - private MockDataAddressRemote dataAddress; + private TestBackendRemote dataAddress; @BeforeEach - void setup(@Provider ConnectorRemote providerConnector) { + void setup(@Provider ManagementApiConnectorRemote providerConnector) { // We use the provider EDC as data sink / data source (it has the test-backend-controller extension) - dataAddress = new MockDataAddressRemote(providerConnector.getConfig().getDefaultApiUrl()); + dataAddress = new TestBackendRemote(providerConnector.getConfig().getDefaultApiUrl()); } @DisabledOnGithub @Test void provide_consume_assetMapping_policyMapping_agreements( - @Consumer ConnectorConfig consumerConfig, - @Consumer ConnectorRemote consumerConnector, + @Consumer Config consumerConfig, + @Consumer ManagementApiConnectorRemote consumerConnector, @Consumer EdcClient consumerClient, - @Provider ConnectorConfig providerConfig, - @Provider EdcClient providerClient) { - + @Provider Config providerConfig, + @Provider EdcClient providerClient + ) { // arrange var data = "expected data 123"; var yesterday = OffsetDateTime.now().minusDays(1); @@ -178,8 +183,10 @@ void provide_consume_assetMapping_policyMapping_agreements( {"https://private/some#key": "private LD value"} """) .build()).getId(); + assertThat(assetId).isEqualTo("asset-1"); + providerClient.uiApi().createContractDefinition(ContractDefinitionRequest.builder() .contractDefinitionId("cd-1") .accessPolicyId(policyId) @@ -194,12 +201,19 @@ void provide_consume_assetMapping_policyMapping_agreements( .build())) .build()); - var assets = providerClient.uiApi().getAssetPage().getAssets(); - assertThat(assets).hasSize(1); - var asset = assets.get(0); - var providerProtocolEndpoint = providerConfig.getProtocolApiUrl(); - var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerProtocolEndpoint); + val createdAsset = getAssetsWithId(providerClient, assetId); + + assertThat(createdAsset).hasSize(1); + var asset = createdAsset.stream().filter(it -> it.getAssetId().equals("asset-1")).findFirst().get(); + + var providerProtocolEndpoint = ConfigUtils.getProtocolApiUrl(providerConfig); + var providerParticipantId = ConfigUtils.getParticipantId(providerConfig); + var dataOffers = consumerClient.uiApi() + .getCatalogPageDataOffers(providerParticipantId, providerProtocolEndpoint) + .stream() + .filter(it -> it.getAsset().getAssetId().equals(assetId)) + .toList(); assertThat(dataOffers).hasSize(1); var dataOffer = dataOffers.get(0); assertThat(dataOffer.getContractOffers()).hasSize(1); @@ -208,8 +222,19 @@ void provide_consume_assetMapping_policyMapping_agreements( // act var negotiation = negotiate(consumerClient, consumerConnector, dataOffer, contractOffer); initiateTransfer(consumerClient, negotiation); - var providerAgreements = providerClient.uiApi().getContractAgreementPage(null).getContractAgreements(); - var consumerAgreements = consumerClient.uiApi().getContractAgreementPage(null).getContractAgreements(); + var providerAgreements = providerClient.uiApi() + .getContractAgreementPage(null) + .getContractAgreements() + .stream() + .filter(it -> it.getContractAgreementId().equals(negotiation.getContractAgreementId())) + .toList(); + var consumerAgreements = consumerClient + .uiApi() + .getContractAgreementPage(null) + .getContractAgreements() + .stream() + .filter(it -> it.getContractAgreementId().equals(negotiation.getContractAgreementId())) + .toList(); // assert assertThat(dataOffer.getEndpoint()).isEqualTo(providerProtocolEndpoint); @@ -217,7 +242,7 @@ void provide_consume_assetMapping_policyMapping_agreements( assertThat(dataOffer.getAsset().getAssetId()).isEqualTo(assetId); assertThat(dataOffer.getAsset().getTitle()).isEqualTo("AssetName"); assertThat(dataOffer.getAsset().getConnectorEndpoint()).isEqualTo(providerProtocolEndpoint); - assertThat(dataOffer.getAsset().getParticipantId()).isEqualTo(providerConfig.getProperties().get("edc.participant.id")); + assertThat(dataOffer.getAsset().getParticipantId()).isEqualTo(ConfigUtils.getParticipantId(providerConfig)); assertThat(dataOffer.getAsset().getKeywords()).isEqualTo(List.of("keyword1", "keyword2")); assertThat(dataOffer.getAsset().getDescription()).isEqualTo("AssetDescription"); assertThat(dataOffer.getAsset().getVersion()).isEqualTo("1.0.0"); @@ -259,7 +284,7 @@ void provide_consume_assetMapping_policyMapping_agreements( assertThat(asset.getAssetId()).isEqualTo(assetId); assertThat(asset.getTitle()).isEqualTo("AssetName"); assertThat(asset.getConnectorEndpoint()).isEqualTo(providerProtocolEndpoint); - assertThat(asset.getParticipantId()).isEqualTo(providerConfig.getProperties().get("edc.participant.id")); + assertThat(asset.getParticipantId()).isEqualTo(ConfigUtils.getParticipantId(providerConfig)); assertThatJson(asset.getCustomJsonAsString()).isEqualTo(""" { "test": "value" } @@ -286,7 +311,7 @@ void provide_consume_assetMapping_policyMapping_agreements( // Provider Contract Agreement assertThat(providerAgreement.getContractAgreementId()).isEqualTo(negotiation.getContractAgreementId()); assertThat(providerAgreement.getDirection()).isEqualTo(PROVIDING); - assertThat(providerAgreement.getCounterPartyAddress()).isEqualTo(consumerConfig.getProtocolApiUrl()); + assertThat(providerAgreement.getCounterPartyAddress()).isEqualTo(ConfigUtils.getProtocolApiUrl(consumerConfig)); assertThat(providerAgreement.getCounterPartyId()).isEqualTo(CONSUMER_PARTICIPANT_ID); assertThat(providerAgreement.getAsset().getAssetId()).isEqualTo(assetId); @@ -335,7 +360,7 @@ void canOverrideTheWellKnowPropertiesUsingTheCustomProperties(@Provider EdcClien .build(); var assetId = providerClient.uiApi().createAsset(UiAssetCreateRequest.builder() - .id("asset-1") + .id("asset-2") .title("will be overridden") .dataSource(dataSource) .customJsonLdAsString(""" @@ -348,12 +373,14 @@ void canOverrideTheWellKnowPropertiesUsingTheCustomProperties(@Provider EdcClien } """) .build()).getId(); - assertThat(assetId).isEqualTo("asset-1"); + assertThat(assetId).isEqualTo("asset-2"); // act - val assets = providerClient.uiApi().getAssetPage().getAssets(); - assertThat(assets).hasSize(1); - val asset = assets.get(0); + + val createdAsset = getAssetsWithId(providerClient, assetId); + + assertThat(createdAsset).hasSize(1); + val asset = createdAsset.get(0); // assert @@ -374,11 +401,11 @@ void canOverrideTheWellKnowPropertiesUsingTheCustomProperties(@Provider EdcClien @DisabledOnGithub @Test void customTransferRequest( - @Consumer ConnectorRemote consumerConnector, + @Consumer ManagementApiConnectorRemote consumerConnector, @Consumer EdcClient consumerClient, - @Provider ConnectorConfig providerConfig, - @Provider EdcClient providerClient) { - + @Provider Config providerConfig, + @Provider EdcClient providerClient + ) { // arrange var data = "expected data 123"; @@ -390,27 +417,29 @@ void customTransferRequest( .build(); var assetId = providerClient.uiApi().createAsset(UiAssetCreateRequest.builder() - .id("asset-1") + .id("asset-3") .dataSource(dataSource) .build()).getId(); - assertThat(assetId).isEqualTo("asset-1"); + + assertThat(assetId).isEqualTo("asset-3"); var policyId = providerClient.uiApi().createPolicyDefinitionV2(PolicyDefinitionCreateDto.builder() - .policyDefinitionId("policy-1") + .policyDefinitionId("policy-3") .expression(UiPolicyExpression.builder() .type(UiPolicyExpressionType.EMPTY) .build()) .build()).getId(); - providerClient.uiApi().createContractDefinition(ContractDefinitionRequest.builder() - .contractDefinitionId("cd-1") + val contractDefinitionId = providerClient.uiApi().createContractDefinition(ContractDefinitionRequest.builder() + .contractDefinitionId("cd-3") .accessPolicyId(policyId) .contractPolicyId(policyId) .assetSelector(List.of()) .build()); - val providerProtocolEndpoint = providerConfig.getProtocolApiUrl(); - var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerProtocolEndpoint); + val providerProtocolEndpoint = ConfigUtils.getProtocolApiUrl(providerConfig); + val providerParticipantId = ConfigUtils.getParticipantId(providerConfig); + var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerParticipantId, providerProtocolEndpoint); assertThat(dataOffers).hasSize(1); var dataOffer = dataOffers.get(0); assertThat(dataOffer.getContractOffers()).hasSize(1); @@ -419,14 +448,8 @@ void customTransferRequest( // act var negotiation = negotiate(consumerClient, consumerConnector, dataOffer, contractOffer); var transferRequestJsonLd = Json.createObjectBuilder() - .add( - Prop.Edc.DATA_DESTINATION, - getDatasinkPropertiesJsonObject() - ) - .add(Prop.Edc.CTX + "transferType", Json.createObjectBuilder() - .add(Prop.Edc.CTX + "contentType", "application/octet-stream") - .add(Prop.Edc.CTX + "isFinite", true) - ) + .add(Prop.Edc.DATA_DESTINATION, getDatasinkPropertiesJsonObject()) + .add(Prop.Edc.CTX + "transferType", Json.createValue("HttpData-PUSH")) .add(Prop.Edc.CTX + "protocol", HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) .add(Prop.Edc.CTX + "managedResources", false) .build(); @@ -437,16 +460,19 @@ void customTransferRequest( consumerClient.uiApi().initiateCustomTransfer(transferRequest); validateDataTransferred(dataAddress.getDataSinkSpyUrl(), data); + + providerClient.uiApi().deleteContractDefinition(contractDefinitionId.getId()); + providerClient.uiApi().deletePolicyDefinition(policyId); } @DisabledOnGithub @Test void editAssetOnLiveContract( - @Consumer ConnectorRemote consumerConnector, + @Consumer ManagementApiConnectorRemote consumerConnector, @Consumer EdcClient consumerClient, - @Provider ConnectorConfig providerConfig, - @Provider EdcClient providerClient) { - + @Provider Config providerConfig, + @Provider EdcClient providerClient + ) { // arrange var data = "expected data 123"; @@ -458,7 +484,7 @@ void editAssetOnLiveContract( .build(); var assetId = providerClient.uiApi().createAsset(UiAssetCreateRequest.builder() - .id("asset-1") + .id("asset-4") .title("Bad Asset Title") .dataSource(dataSource) .customJsonAsString(""" @@ -488,7 +514,7 @@ void editAssetOnLiveContract( .build()).getId(); providerClient.uiApi().createContractDefinition(ContractDefinitionRequest.builder() - .contractDefinitionId("cd-1") + .contractDefinitionId("cd-4") .accessPolicyId("always-true") .contractPolicyId("always-true") .assetSelector(List.of(UiCriterion.builder() @@ -501,8 +527,13 @@ void editAssetOnLiveContract( .build())) .build()); - val providerProtocolEndpoint = providerConfig.getProtocolApiUrl(); - var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerProtocolEndpoint); + val providerProtocolEndpoint = ConfigUtils.getProtocolApiUrl(providerConfig); + val providerParticipantId = ConfigUtils.getParticipantId(providerConfig); + var dataOffers = consumerClient.uiApi() + .getCatalogPageDataOffers(providerParticipantId, providerProtocolEndpoint) + .stream() + .filter(it -> it.getAsset().getAssetId().equals(assetId)) + .toList(); assertThat(dataOffers).hasSize(1); var dataOffer = dataOffers.get(0); assertThat(dataOffer.getContractOffers()).hasSize(1); @@ -542,7 +573,17 @@ void editAssetOnLiveContract( initiateTransfer(consumerClient, negotiation); // assert - assertThat(consumerClient.uiApi().getCatalogPageDataOffers(providerProtocolEndpoint).get(0).getAsset().getTitle()) + String asset4title = consumerClient.uiApi() + .getCatalogPageDataOffers(providerParticipantId, providerProtocolEndpoint) + .stream() + .filter(it -> it.getAsset().getAssetId().equals("asset-4")) + .findFirst() + .get() + .getAsset() + .getTitle(); + + assertThat( + asset4title) .isEqualTo("Good Asset Title"); val firstAsset = providerClient.uiApi().getContractAgreementPage(null).getContractAgreements().get(0).getAsset(); assertThat(firstAsset.getTitle()).isEqualTo("Good Asset Title"); @@ -576,7 +617,7 @@ void editAssetOnLiveContract( @Test @DisabledOnGithub - void checkIdAvailability(E2eScenario scenario, @Provider EdcClient providerClient) { + void checkIdAvailability(E2eTestScenario scenario, @Provider EdcClient providerClient) { // arrange var assetId = scenario.createAsset(); var policyId = "policy-id"; @@ -604,7 +645,7 @@ void checkIdAvailability(E2eScenario scenario, @Provider EdcClient providerClien @DisabledOnGithub @Test void retrieveSingleContractAgreement( - E2eScenario scenario, + E2eTestScenario scenario, @Provider EdcClient providerClient ) { // arrange @@ -646,7 +687,7 @@ void retrieveSingleContractAgreement( @Test @DisabledOnGithub void canMakeAnOnDemandDataSourceAvailable( - E2eScenario scenario, + E2eTestScenario scenario, @Provider EdcClient providerClient ) { // arrange @@ -658,7 +699,7 @@ void canMakeAnOnDemandDataSourceAvailable( .contactPreferredEmailSubject("Subject") .build()) .build()) - .id("asset") + .id("asset-" + RANDOM.nextInt()) .title("foo") .build()); @@ -723,7 +764,7 @@ void canCreateDataOfferWithoutAnyNewPolicyNotContractDefinition( .first() .isEqualTo(assetId); - assertThat(getAllPoliciesExceptTheAlwaysTruePolicy(providerClient)).hasSize(0); + assertThat(getPolicyNamed(assetId, providerClient)).hasSize(0); assertThat(providerClient.uiApi().getContractDefinitionPage().getContractDefinitions()) .hasSize(0); @@ -742,7 +783,7 @@ void canCreateDataOfferWithNewPolicy( .type(DataSourceType.HTTP_DATA) .build(); - val assetId = "asset"; + val assetId = "asset-" + RANDOM.nextInt(); val asset = UiAssetCreateRequest.builder() .dataSource(dataSource) .id(assetId) @@ -774,7 +815,7 @@ void canCreateDataOfferWithNewPolicy( .first() .isEqualTo(assetId); - assertThat(getAllPoliciesExceptTheAlwaysTruePolicy(providerClient)) + assertThat(getPolicyNamed(assetId, providerClient)) .hasSize(1) .extracting(PolicyDefinitionDto::getPolicyDefinitionId) .first() @@ -799,7 +840,7 @@ void canCreateDataOfferWithNewEmptyPolicyAndRestrictedPublishing( .type(DataSourceType.HTTP_DATA) .build(); - val assetId = "asset"; + val assetId = "asset-" + RANDOM.nextInt(); val asset = UiAssetCreateRequest.builder() .dataSource(dataSource) .id(assetId) @@ -823,7 +864,7 @@ void canCreateDataOfferWithNewEmptyPolicyAndRestrictedPublishing( .first() .isEqualTo(assetId); - assertThat(getAllPoliciesExceptTheAlwaysTruePolicy(providerClient)) + assertThat(getPolicyNamed(assetId, providerClient)) .hasSize(1) .extracting(PolicyDefinitionDto::getPolicyDefinitionId) .first() @@ -837,7 +878,7 @@ void canCreateDataOfferWithNewEmptyPolicyAndRestrictedPublishing( @Test void dontCreateAnythingIfTheAssetAlreadyExists( - E2eScenario scenario, + E2eTestScenario scenario, @Provider EdcClient providerClient ) { // arrange @@ -861,23 +902,29 @@ void dontCreateAnythingIfTheAssetAlreadyExists( .build())); // assert - assertThat(providerClient.uiApi().getAssetPage().getAssets()) + + val createdAsset = getAssetsWithId(providerClient, assetId); + + assertThat(createdAsset) .hasSize(1) .extracting(UiAsset::getAssetId) .first() .isEqualTo(assetId); - assertThat(getAllPoliciesExceptTheAlwaysTruePolicy(providerClient)).hasSize(0); - assertThat(providerClient.uiApi().getContractDefinitionPage().getContractDefinitions()).hasSize(0); + assertThat(getPolicyNamed(assetId, providerClient)).hasSize(0); + + val createdContractDefinition = getContractDefinitionWithAssetId(providerClient, assetId); + + assertThat(createdContractDefinition).hasSize(0); } @Test void dontCreateAnythingIfThePolicyAlreadyExists( - E2eScenario scenario, + E2eTestScenario scenario, @Provider EdcClient providerClient ) { // arrange - val assetId = "assetId"; + val assetId = "assetId-" + RANDOM.nextInt(); scenario.createPolicy(assetId, OffsetDateTime.now(), OffsetDateTime.now()); // act @@ -898,26 +945,31 @@ void dontCreateAnythingIfThePolicyAlreadyExists( .build())); // assert - assertThat(providerClient.uiApi().getAssetPage().getAssets()).hasSize(0); - assertThat(getAllPoliciesExceptTheAlwaysTruePolicy(providerClient)).hasSize(1) + val createdAsset = getAssetsWithId(providerClient, assetId); + + assertThat(createdAsset).hasSize(0); + + assertThat(getPolicyNamed(assetId, providerClient)).hasSize(1) .extracting(PolicyDefinitionDto::getPolicyDefinitionId) .first() - .isEqualTo("assetId"); + .isEqualTo(assetId); - assertThat(providerClient.uiApi().getContractDefinitionPage().getContractDefinitions()).hasSize(0); + val createdContractDefinition = getContractDefinitionWithAssetId(providerClient, assetId); + + assertThat(createdContractDefinition).hasSize(0); } @Test void dontCreateAnythingIfTheContractDefinitionAlreadyExists( - E2eScenario scenario, + E2eTestScenario scenario, @Provider EdcClient providerClient ) { // arrange - val assetId = "assetId"; - val placeholder = scenario.createAsset(); + val id = "assetId"; + val assetId = scenario.createAsset(); providerClient.uiApi().createContractDefinition(ContractDefinitionRequest.builder() - .contractDefinitionId(assetId) + .contractDefinitionId(id) .accessPolicyId("always-true") .contractPolicyId("always-true") .assetSelector(List.of(UiCriterion.builder() @@ -925,7 +977,7 @@ void dontCreateAnythingIfTheContractDefinitionAlreadyExists( .operator(UiCriterionOperator.EQ) .operandRight(UiCriterionLiteral.builder() .type(UiCriterionLiteralType.VALUE) - .value(placeholder) + .value(assetId) .build()) .build())) .build()); @@ -936,7 +988,7 @@ void dontCreateAnythingIfTheContractDefinitionAlreadyExists( () -> providerClient.uiApi() .createDataOffer(DataOfferCreationRequest.builder() .uiAssetCreateRequest(UiAssetCreateRequest.builder() - .id(assetId) + .id(id) .dataSource(UiDataSource.builder() .type(DataSourceType.ON_REQUEST) .onRequest(UiDataSourceOnRequest.builder() @@ -948,22 +1000,24 @@ void dontCreateAnythingIfTheContractDefinitionAlreadyExists( .build())); // assert - assertThat(providerClient.uiApi().getAssetPage().getAssets()) + val createdAsset = getAssetsWithId(providerClient, assetId); + + assertThat(createdAsset) // the asset used for the placeholder contract definition .hasSize(1) .extracting(UiAsset::getAssetId) .first() - .isEqualTo(placeholder); + .isEqualTo(assetId); - assertThat(getAllPoliciesExceptTheAlwaysTruePolicy(providerClient)).hasSize(0); + assertThat(getPolicyNamed(id, providerClient)).hasSize(0); assertThat(providerClient.uiApi().getContractDefinitionPage().getContractDefinitions()) .hasSize(1) - .filteredOn(it -> it.getContractDefinitionId().equals(assetId)) + .filteredOn(it -> it.getContractDefinitionId().equals(id)) .extracting(ContractDefinitionEntry::getContractDefinitionId) .first() // the already existing one, before the data offer creation attempt - .isEqualTo(assetId); + .isEqualTo(id); } @Test @@ -971,7 +1025,7 @@ void reuseTheAlwaysTruePolicyWhenPublishingUnrestricted( @Provider EdcClient providerClient ) { // arrange - val assetId = "assetId"; + val assetId = "assetId-" + RANDOM.nextInt(); // act providerClient.uiApi() @@ -990,16 +1044,20 @@ void reuseTheAlwaysTruePolicyWhenPublishingUnrestricted( .build()); // assert - assertThat(providerClient.uiApi().getAssetPage().getAssets()) + val createdAsset = getAssetsWithId(providerClient, assetId); + + assertThat(createdAsset) // the asset used for the placeholder contract definition .hasSize(1) .extracting(UiAsset::getAssetId) .first() .isEqualTo(assetId); - assertThat(getAllPoliciesExceptTheAlwaysTruePolicy(providerClient)).hasSize(0); + assertThat(getPolicyNamed(assetId, providerClient)).hasSize(0); - assertThat(providerClient.uiApi().getContractDefinitionPage().getContractDefinitions()) + val createdContractDefinition = getContractDefinitionWithAssetId(providerClient, assetId); + + assertThat(createdContractDefinition) .hasSize(1) .filteredOn(it -> it.getContractDefinitionId().equals(assetId)) .extracting(ContractDefinitionEntry::getContractDefinitionId) @@ -1032,88 +1090,39 @@ void onlyCreateTheAssetWhenDontPublish( .build()); // assert - assertThat(providerClient.uiApi().getAssetPage().getAssets()) - // the asset used for the placeholder contract definition - .hasSize(1) - .extracting(UiAsset::getAssetId) - .first() - .isEqualTo(assetId); - - assertThat(getAllPoliciesExceptTheAlwaysTruePolicy(providerClient)).hasSize(0); - - assertThat(providerClient.uiApi().getContractDefinitionPage().getContractDefinitions()) - .hasSize(0); - } - - @Test - void recreateTheAlwaysTruePolicyIfDeleted( - @Provider EdcClient providerClient - ) { - // arrange - val assetId = "assetId"; - providerClient.uiApi().deletePolicyDefinition(AlwaysTruePolicyConstants.POLICY_DEFINITION_ID); - - List withoutDefaultAlwaysTrue = - providerClient.uiApi() - .getPolicyDefinitionPage() - .getPolicies() - .stream() - .filter(it -> !it.getPolicyDefinitionId().equals(AlwaysTruePolicyConstants.POLICY_DEFINITION_ID)) - .toList(); - - assertThat(withoutDefaultAlwaysTrue).hasSize(0); + val createdAsset = getAssetsWithId(providerClient, assetId); - // act - providerClient.uiApi() - .createDataOffer(DataOfferCreationRequest.builder() - .uiAssetCreateRequest(UiAssetCreateRequest.builder() - .id(assetId) - .dataSource(UiDataSource.builder() - .type(DataSourceType.ON_REQUEST) - .onRequest(UiDataSourceOnRequest.builder() - .contactEmail("foo@example.com") - .contactPreferredEmailSubject("Subject") - .build()) - .build()) - .build()) - .policy(DataOfferCreationRequest.PolicyEnum.PUBLISH_UNRESTRICTED) - .build()); - - // assert - assertThat(providerClient.uiApi().getAssetPage().getAssets()) + assertThat(createdAsset) // the asset used for the placeholder contract definition .hasSize(1) .extracting(UiAsset::getAssetId) .first() .isEqualTo(assetId); - List policies = - providerClient.uiApi() - .getPolicyDefinitionPage() - .getPolicies() - .stream() - .toList(); - - assertThat(policies).hasSize(1); + assertThat(getPolicyNamed(assetId, providerClient)).hasSize(0); assertThat(providerClient.uiApi().getContractDefinitionPage().getContractDefinitions()) - .hasSize(1); + .hasSize(0); } - private static @NotNull List getAllPoliciesExceptTheAlwaysTruePolicy(EdcClient edcClient) { - return edcClient.uiApi().getPolicyDefinitionPage().getPolicies().stream().filter(it -> !it.getPolicyDefinitionId().equals( - AlwaysTruePolicyConstants.POLICY_DEFINITION_ID)).toList(); + private static @NotNull List getPolicyNamed(String name, EdcClient edcClient) { + return edcClient.uiApi() + .getPolicyDefinitionPage() + .getPolicies() + .stream() + .filter(it -> it.getPolicyDefinitionId().equals(name)) + .toList(); } private UiContractNegotiation negotiate( EdcClient consumerClient, - ConnectorRemote consumerConnector, + ManagementApiConnectorRemote consumerConnector, UiDataOffer dataOffer, - UiContractOffer contractOffer) { - + UiContractOffer contractOffer + ) { var negotiationRequest = ContractNegotiationRequest.builder() .counterPartyAddress(dataOffer.getEndpoint()) - .counterPartyParticipantId(dataOffer.getParticipantId()) + .counterPartyId(dataOffer.getParticipantId()) .assetId(dataOffer.getAsset().getAssetId()) .contractOfferId(contractOffer.getContractOfferId()) .policyJsonLd(contractOffer.getPolicy().getPolicyJsonLd()) @@ -1135,6 +1144,7 @@ private void initiateTransfer(EdcClient consumerClient, UiContractNegotiation ne var contractAgreementId = negotiation.getContractAgreementId(); var transferRequest = InitiateTransferRequest.builder() .contractAgreementId(contractAgreementId) + .transferType("HttpData-PUSH") .dataSinkProperties(dataAddress.getDataSinkProperties()) .build(); consumerClient.uiApi().initiateTransfer(transferRequest); diff --git a/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapper2Test.java b/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapper2Test.java new file mode 100644 index 000000000..c71e8858e --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapper2Test.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.e2e; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.client.gen.model.CatalogFilterExpression; +import de.sovity.edc.client.gen.model.CatalogFilterExpressionLiteral; +import de.sovity.edc.client.gen.model.CatalogFilterExpressionLiteralType; +import de.sovity.edc.client.gen.model.CatalogFilterExpressionOperator; +import de.sovity.edc.client.gen.model.CatalogQuery; +import de.sovity.edc.client.gen.model.ContractDefinitionRequest; +import de.sovity.edc.client.gen.model.DataSourceType; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; +import de.sovity.edc.client.gen.model.UiAssetCreateRequest; +import de.sovity.edc.client.gen.model.UiCriterion; +import de.sovity.edc.client.gen.model.UiCriterionLiteral; +import de.sovity.edc.client.gen.model.UiCriterionLiteralType; +import de.sovity.edc.client.gen.model.UiCriterionOperator; +import de.sovity.edc.client.gen.model.UiDataSource; +import de.sovity.edc.client.gen.model.UiDataSourceHttpData; +import de.sovity.edc.client.gen.model.UiPolicyExpression; +import de.sovity.edc.client.gen.model.UiPolicyExpressionType; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; +import de.sovity.edc.extension.e2e.junit.Janitor; +import de.sovity.edc.extension.utils.junit.DisabledOnGithub; +import de.sovity.edc.utils.config.ConfigUtils; +import de.sovity.edc.utils.jsonld.vocab.Prop; +import org.eclipse.edc.spi.system.configuration.Config; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class UseCaseApiWrapper2Test { + String protocolApiUrl; + + @RegisterExtension + static CeIntegrationTestExtension providerExtension = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); + + @BeforeEach + public void setup(Config config) { + protocolApiUrl = ConfigUtils.getProtocolApiUrl(config); + } + + private static String assetId1 = "test-asset-1"; + private static String assetId2 = "test-asset-2"; + private static String policyId = "policy-1"; + + @Test + @DisabledOnGithub + void shouldFetchFilteredDataOffersWithEq( + EdcClient client, + Janitor janitor + ) { + // arrange + setupAssets(client, janitor); + + // act + var catalogQueryParamsEq = criterion(Prop.Edc.ID, CatalogFilterExpressionOperator.EQ, "test-asset-1"); + var dataOffers = client.useCaseApi().queryCatalog(catalogQueryParamsEq); + + // assert + assertThat(dataOffers).hasSize(1); + assertThat(dataOffers.get(0).getAsset().getAssetId()).isEqualTo(assetId1); + assertThat(dataOffers.get(0).getAsset().getTitle()).isEqualTo("Test Asset 1"); + } + + @Test + @DisabledOnGithub + void shouldFetchFilteredDataOffersWithIn( + EdcClient client, + Janitor janitor + ) { + // arrange + setupAssets(client, janitor); + + // act + var catalogQueryParamsEq = criterion(Prop.Edc.ID, CatalogFilterExpressionOperator.IN, List.of("test-asset-1", "test-asset-2")); + var dataOffers = client.useCaseApi().queryCatalog(catalogQueryParamsEq); + + // assert + assertThat(dataOffers).hasSize(2); + assertThat(dataOffers) + .extracting(it -> it.getAsset().getAssetId()) + .containsExactlyInAnyOrder(assetId1, assetId2); + } + + @Test + @DisabledOnGithub + void shouldFetchWithoutFilterButWithLimit( + EdcClient client, + Janitor janitor + ) { + // arrange + setupAssets(client, janitor); + + // act + var catalogQueryParamsEq = criterion(1, 0); + var dataOffers = client.useCaseApi().queryCatalog(catalogQueryParamsEq); + + // assert + assertThat(dataOffers).hasSize(1); + assertThat(dataOffers) + .extracting(it -> it.getAsset().getAssetId()) + .containsAnyOf(assetId1, assetId2); + } + + private CatalogQuery criterion( + String leftOperand, + CatalogFilterExpressionOperator operator, + String rightOperand + ) { + return CatalogQuery.builder() + .connectorEndpoint(protocolApiUrl) + .filterExpressions( + List.of( + CatalogFilterExpression.builder() + .operandLeft(leftOperand) + .operator(operator) + .operandRight( + CatalogFilterExpressionLiteral.builder().value(rightOperand).type(CatalogFilterExpressionLiteralType.VALUE) + .build()) + .build() + ) + ) + .build(); + } + + private CatalogQuery criterion(String leftOperand, CatalogFilterExpressionOperator operator, List rightOperand) { + return CatalogQuery.builder() + .connectorEndpoint(protocolApiUrl) + .filterExpressions( + List.of( + CatalogFilterExpression.builder() + .operandLeft(leftOperand) + .operator(operator) + .operandRight(CatalogFilterExpressionLiteral.builder().valueList(rightOperand) + .type(CatalogFilterExpressionLiteralType.VALUE_LIST).build()) + .build() + ) + ) + .build(); + } + + private CatalogQuery criterion(Integer limit, Integer offset) { + return CatalogQuery.builder() + .connectorEndpoint(protocolApiUrl) + .limit(limit) + .offset(offset) + .build(); + } + + private void buildContractDefinition(Janitor janitor, EdcClient client, String policyId, String assetId1, String cdId) { + janitor.withClient(client) + .createContractDefinition(ContractDefinitionRequest.builder() + .contractDefinitionId(cdId) + .accessPolicyId(policyId) + .contractPolicyId(policyId) + .assetSelector(List.of(UiCriterion.builder() + .operandLeft(Prop.Edc.ID) + .operator(UiCriterionOperator.EQ) + .operandRight(UiCriterionLiteral.builder() + .type(UiCriterionLiteralType.VALUE) + .value(assetId1) + .build()) + .build())) + .build()); + } + + private void setupAssets(EdcClient client, Janitor janitor) { + var dataSource = UiDataSource.builder() + .type(DataSourceType.HTTP_DATA) + .httpData(UiDataSourceHttpData.builder() + .baseUrl(protocolApiUrl) + .build()) + .build(); + + int offset = 0; + int firstIndex = offset + 1; + + assetId1 = janitor.withClient(client).createAsset(UiAssetCreateRequest.builder() + .id("test-asset-" + firstIndex) + .title("Test Asset " + firstIndex) + .dataSource(dataSource) + .mediaType("application/json") + .build()).getId(); + + int secondIndex = offset + 2; + assetId2 = janitor.withClient(client).createAsset(UiAssetCreateRequest.builder() + .id("test-asset-" + secondIndex) + .title("Test Asset " + secondIndex) + .dataSource(dataSource) + .mediaType("application/json") + .build()).getId(); + + policyId = janitor.withClient(client).createPolicyDefinitionV2(PolicyDefinitionCreateDto.builder() + .policyDefinitionId("policy-" + offset) + .expression(UiPolicyExpression.builder() + .type(UiPolicyExpressionType.EMPTY) + .build()) + .build()).getId(); + + buildContractDefinition(janitor, client, policyId, assetId1, "cd-1"); + buildContractDefinition(janitor, client, policyId, assetId2, "cd-2"); + } +} diff --git a/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapperTest.java b/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapperTest.java index e9f521f16..1c707a6a1 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapperTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapperTest.java @@ -36,11 +36,11 @@ import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.client.gen.model.UiPolicyLiteral; import de.sovity.edc.client.gen.model.UiPolicyLiteralType; -import de.sovity.edc.extension.e2e.connector.ConnectorRemote; -import de.sovity.edc.extension.e2e.connector.MockDataAddressRemote; -import de.sovity.edc.extension.e2e.extension.Consumer; -import de.sovity.edc.extension.e2e.extension.E2eTestExtension; -import de.sovity.edc.extension.e2e.extension.Provider; +import de.sovity.edc.extension.e2e.connector.remotes.management_api.ManagementApiConnectorRemote; +import de.sovity.edc.extension.e2e.connector.remotes.test_backend_controller.TestBackendRemote; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; import de.sovity.edc.extension.utils.junit.DisabledOnGithub; import de.sovity.edc.utils.jsonld.vocab.Prop; import org.junit.jupiter.api.BeforeEach; @@ -50,31 +50,33 @@ import java.time.OffsetDateTime; import java.util.List; -import static de.sovity.edc.extension.e2e.extension.Helpers.defaultE2eTestExtension; import static org.assertj.core.api.Assertions.assertThat; class UseCaseApiWrapperTest { @RegisterExtension - private static E2eTestExtension e2eTestExtension = defaultE2eTestExtension(); + private static CeE2eTestExtension e2eTestExtension = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); - private MockDataAddressRemote dataAddress; + private TestBackendRemote dataAddress; private final String dataOfferData = "expected data 123"; private final String dataOfferId = "my-data-offer-2023-11"; @BeforeEach - void setup(@Provider ConnectorRemote providerConnector) { + void setup(@Provider ManagementApiConnectorRemote providerConnector) { // We use the provider EDC as data sink / data source (it has the test-backend-controller extension) - dataAddress = new MockDataAddressRemote(providerConnector.getConfig().getDefaultApiUrl()); + dataAddress = new TestBackendRemote(providerConnector.getConfig().getDefaultApiUrl()); } @DisabledOnGithub @Test void catalog_filtering_by_like( @Consumer EdcClient consumerClient, - @Provider ConnectorRemote providerConnector, - @Provider EdcClient providerClient) { + @Provider ManagementApiConnectorRemote providerConnector, + @Provider EdcClient providerClient + ) { // arrange createPolicy(providerClient); @@ -94,10 +96,11 @@ void catalog_filtering_by_like( } private CatalogQuery criterion( - ConnectorRemote providerConnector, + ManagementApiConnectorRemote providerConnector, String leftOperand, CatalogFilterExpressionOperator operator, - String rightOperand) { + String rightOperand + ) { return CatalogQuery.builder() .connectorEndpoint(getProtocolEndpoint(providerConnector)) @@ -193,7 +196,7 @@ private void createContractDefinition(EdcClient providerClient) { providerClient.uiApi().createContractDefinition(contractDefinition); } - private String getProtocolEndpoint(ConnectorRemote connector) { + private String getProtocolEndpoint(ManagementApiConnectorRemote connector) { return connector.getConfig().getProtocolApiUrl(); } } diff --git a/tests/src/test/java/de/sovity/edc/e2e/WrapperApiUtils.java b/tests/src/test/java/de/sovity/edc/e2e/WrapperApiUtils.java new file mode 100644 index 000000000..1aa0f53c1 --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/e2e/WrapperApiUtils.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.e2e; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.client.gen.model.ContractDefinitionEntry; +import de.sovity.edc.client.gen.model.UiAsset; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +@UtilityClass +public class WrapperApiUtils { + + public static @NotNull List getAssetsWithId(EdcClient providerClient, String assetId) { + return providerClient.uiApi() + .getAssetPage() + .getAssets() + .stream() + .filter(it -> it.getAssetId().equals(assetId)) + .toList(); + } + + public static @NotNull List getContractDefinitionWithAssetId( + EdcClient providerClient, + String assetId + ) { + return providerClient.uiApi() + .getContractDefinitionPage() + .getContractDefinitions() + .stream().filter(it -> it.getContractDefinitionId().equals(assetId)) + .toList(); + } + + public static List getContractDefinitionWithId(EdcClient client, String id) { + return client.uiApi() + .getContractDefinitionPage() + .getContractDefinitions() + .stream() + .filter(it -> it.getContractDefinitionId().equals(id)) + .toList(); + } +} diff --git a/tests/src/test/java/de/sovity/edc/e2e/wrapper/RecreateAlwaysTruePolicyTest.java b/tests/src/test/java/de/sovity/edc/e2e/wrapper/RecreateAlwaysTruePolicyTest.java new file mode 100644 index 000000000..7c8c0f1df --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/e2e/wrapper/RecreateAlwaysTruePolicyTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.e2e.wrapper; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.client.gen.model.DataOfferCreationRequest; +import de.sovity.edc.client.gen.model.DataSourceType; +import de.sovity.edc.client.gen.model.PolicyDefinitionDto; +import de.sovity.edc.client.gen.model.UiAsset; +import de.sovity.edc.client.gen.model.UiAssetCreateRequest; +import de.sovity.edc.client.gen.model.UiDataSource; +import de.sovity.edc.client.gen.model.UiDataSourceOnRequest; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Provider; +import de.sovity.edc.extension.policy.AlwaysTruePolicyConstants; +import lombok.val; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RecreateAlwaysTruePolicyTest { + + @RegisterExtension + private static CeE2eTestExtension e2eTestExtension = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); + + @Test + void recreateTheAlwaysTruePolicyIfDeleted(@Provider EdcClient providerClient) { + // arrange + val assetId = "assetId"; + providerClient.uiApi().deletePolicyDefinition(AlwaysTruePolicyConstants.POLICY_DEFINITION_ID); + + List withoutDefaultAlwaysTrue = + providerClient.uiApi() + .getPolicyDefinitionPage() + .getPolicies() + .stream() + .filter(it -> !it.getPolicyDefinitionId().equals(AlwaysTruePolicyConstants.POLICY_DEFINITION_ID)) + .toList(); + + assertThat(withoutDefaultAlwaysTrue).hasSize(0); + + // act + providerClient.uiApi() + .createDataOffer(DataOfferCreationRequest.builder() + .uiAssetCreateRequest(UiAssetCreateRequest.builder() + .id(assetId) + .dataSource(UiDataSource.builder() + .type(DataSourceType.ON_REQUEST) + .onRequest(UiDataSourceOnRequest.builder() + .contactEmail("foo@example.com") + .contactPreferredEmailSubject("Subject") + .build()) + .build()) + .build()) + .policy(DataOfferCreationRequest.PolicyEnum.PUBLISH_UNRESTRICTED) + .build()); + + // assert + assertThat(providerClient.uiApi().getAssetPage().getAssets()) + // the asset used for the placeholder contract definition + .hasSize(1) + .extracting(UiAsset::getAssetId) + .first() + .isEqualTo(assetId); + + List policies = + providerClient.uiApi() + .getPolicyDefinitionPage() + .getPolicies() + .stream() + .toList(); + + assertThat(policies).hasSize(1); + + assertThat(providerClient.uiApi().getContractDefinitionPage().getContractDefinitions()) + .hasSize(1); + } + +} diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java similarity index 75% rename from extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java rename to tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java index 016222283..8ada988a2 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java +++ b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 sovity GmbH + * Copyright (c) 2024 sovity GmbH * * This program and the accompanying materials are made available under the * terms of the Apache License, Version 2.0 which is available at @@ -19,29 +19,25 @@ import de.sovity.edc.client.gen.model.OperatorDto; import de.sovity.edc.client.gen.model.TransferProcessSimplifiedState; import de.sovity.edc.client.gen.model.UiPolicyExpressionType; -import de.sovity.edc.extension.e2e.connector.ConnectorRemote; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; import de.sovity.edc.utils.jsonld.vocab.Prop; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; -import org.eclipse.edc.connector.contract.spi.types.offer.ContractOffer; -import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; -import org.eclipse.edc.connector.transfer.spi.types.DataRequest; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcessStates; -import org.eclipse.edc.junit.annotations.ApiTest; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; +import org.eclipse.edc.connector.controlplane.asset.spi.index.AssetIndex; +import org.eclipse.edc.connector.controlplane.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.contract.spi.types.offer.ContractOffer; +import org.eclipse.edc.connector.controlplane.transfer.spi.store.TransferProcessStore; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcessStates; import org.eclipse.edc.policy.model.Action; import org.eclipse.edc.policy.model.AtomicConstraint; import org.eclipse.edc.policy.model.LiteralExpression; import org.eclipse.edc.policy.model.Operator; import org.eclipse.edc.policy.model.Permission; import org.eclipse.edc.policy.model.Policy; -import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; -import org.eclipse.edc.spi.asset.AssetIndex; +import org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol; import org.eclipse.edc.spi.types.domain.DataAddress; -import org.eclipse.edc.spi.types.domain.asset.Asset; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -53,32 +49,9 @@ import java.util.Map; import java.util.UUID; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorRemoteConfig.fromConnectorConfig; import static org.assertj.core.api.Assertions.assertThat; -@ApiTest class ContractAgreementPageTest { - - private static ConnectorConfig config; - private static ConnectorRemote connector; - private static EdcClient client; - - @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "provider", - testDatabase -> { - config = forTestDatabase("provider", testDatabase); - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - connector = new ConnectorRemote(fromConnectorConfig(config)); - return config.getProperties(); - } - ); - private static final int CONTRACT_DEFINITION_ID = 1; private static final String ASSET_ID = UUID.randomUUID().toString(); @@ -87,11 +60,18 @@ class ContractAgreementPageTest { long todayEpochMillis = todayAsZonedDateTime.toInstant().toEpochMilli(); long todayEpochSeconds = todayAsZonedDateTime.toInstant().getEpochSecond(); + @RegisterExtension + static CeIntegrationTestExtension providerExtension = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); + @Test void testContractAgreementPage( + EdcClient client, ContractNegotiationStore contractNegotiationStore, TransferProcessStore transferProcessStore, - AssetIndex assetIndex) { + AssetIndex assetIndex + ) { // arrange assetIndex.create(asset(ASSET_ID)).orElseThrow(storeFailure -> new RuntimeException("Failed to create asset")); @@ -139,22 +119,15 @@ private DataAddress dataAddress() { } private TransferProcess transferProcess(int contract, int transfer, int code) { - var dataRequest = DataRequest.Builder.newInstance() - .contractId("my-contract-agreement-" + contract) - .assetId("my-asset-" + contract) - .processId("my-transfer-" + contract + "-" + transfer) - .id("my-data-request-" + contract + "-" + transfer) - .processId("my-transfer-" + contract + "-" + transfer) - .connectorAddress("http://other-connector") - .connectorId("urn:connector:other-connector") - .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) - .dataDestination(DataAddress.Builder.newInstance().type("HttpData").build()) - .build(); return TransferProcess.Builder.newInstance() .id("my-transfer-" + contract + "-" + transfer) .state(code) .type(TransferProcess.Type.PROVIDER) - .dataRequest(dataRequest) + .contractId("my-contract-agreement-" + contract) + .assetId("my-asset-" + contract) + .counterPartyAddress("http://other-connector") + .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) + .dataDestination(DataAddress.Builder.newInstance().type("HttpData").build()) .contentDataAddress(DataAddress.Builder.newInstance().type("HttpData").build()) .errorDetail("my-error-message-" + transfer) .build(); diff --git a/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementTransferApiServiceTest.java b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementTransferApiServiceTest.java new file mode 100644 index 000000000..0fd41f396 --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementTransferApiServiceTest.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreement; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.client.gen.model.InitiateCustomTransferRequest; +import de.sovity.edc.client.gen.model.InitiateTransferRequest; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; +import de.sovity.edc.utils.JsonUtils; +import de.sovity.edc.utils.jsonld.vocab.Prop; +import jakarta.json.Json; +import org.eclipse.edc.connector.controlplane.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiationStates; +import org.eclipse.edc.connector.controlplane.contract.spi.types.offer.ContractOffer; +import org.eclipse.edc.connector.controlplane.transfer.spi.store.TransferProcessStore; +import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.util.Map; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +class ContractAgreementTransferApiServiceTest { + + private static final String DATA_SINK = "http://my-data-sink/api/stuff"; + private static final String COUNTER_PARTY_ADDRESS = + "http://some-other-connector/api/v1/ids/data"; + + @RegisterExtension + static CeIntegrationTestExtension providerExtension = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); + + @Test + void startTransferProcessForAgreementId( + EdcClient client, + ContractNegotiationStore store, + TransferProcessStore transferProcessStore + ) { + // arrange + var contractId = UUID.randomUUID().toString(); + createContractNegotiation(store, COUNTER_PARTY_ADDRESS, contractId); + + var request = InitiateTransferRequest.builder() + .contractAgreementId(contractId) + .transferType("HttpData-PUSH") + .dataSinkProperties(Map.of( + Prop.Edc.TYPE, "HttpData", + Prop.Edc.BASE_URL, DATA_SINK + )) + .transferProcessProperties(Map.of("privateProperty", "privateValue")) + .build(); + + // act + var result = client.uiApi().initiateTransfer(request); + + // then + var transferProcess = transferProcessStore.findById(result.getId()); + assertThat(transferProcess).isNotNull(); + assertThat(transferProcess.getPrivateProperties()).containsAllEntriesOf(Map.of( + "privateProperty", "privateValue" + )); + + assertThat(transferProcess.getContractId()).isEqualTo(contractId); + assertThat(transferProcess.getCounterPartyAddress()).isEqualTo(COUNTER_PARTY_ADDRESS); + assertThat(transferProcess.getDataDestination().getProperties()).containsAllEntriesOf(Map.of( + Prop.Edc.TYPE, "HttpData", + Prop.Edc.BASE_URL, DATA_SINK + )); + } + + @Test + void startCustomTransferProcessForAgreementId( + EdcClient client, + ContractNegotiationStore store, + TransferProcessStore transferProcessStore + ) { + // arrange + var contractId = UUID.randomUUID().toString(); + createContractNegotiation(store, COUNTER_PARTY_ADDRESS, contractId); + + var customRequestJson = Json.createObjectBuilder() + .add(Prop.Edc.DATA_DESTINATION, Json.createObjectBuilder() + .add(Prop.Edc.TYPE, "HttpData") + .add(Prop.Edc.BASE_URL, DATA_SINK)) + .add(Prop.Edc.PRIVATE_PROPERTIES, Json.createObjectBuilder() + .add(Prop.Edc.RECEIVER_HTTP_ENDPOINT, "http://my-pull-backend") + .add("this-will-disappear", "because-its-not-an-url") + .add("http://unknown/custom-prop", "value")) + .add(Prop.Edc.CTX + "protocol", HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) + .build(); + var request = new InitiateCustomTransferRequest( + contractId, + JsonUtils.toJson(customRequestJson) + ); + + // act + var result = client.uiApi().initiateCustomTransfer(request); + + // then + var transferProcess = transferProcessStore.findById(result.getId()); + assertThat(transferProcess).isNotNull(); + assertThat(transferProcess.getPrivateProperties()).containsAllEntriesOf(Map.of( + Prop.Edc.RECEIVER_HTTP_ENDPOINT, "http://my-pull-backend", + "http://unknown/custom-prop", "value" + )); + + assertThat(transferProcess.getContractId()).isEqualTo(contractId); + assertThat(transferProcess.getCounterPartyAddress()).isEqualTo(COUNTER_PARTY_ADDRESS); + assertThat(transferProcess.getDataDestination().getProperties()).containsAllEntriesOf(Map.of( + Prop.Edc.TYPE, "HttpData", + Prop.Edc.BASE_URL, DATA_SINK + )); + } + + private ContractNegotiation createContractNegotiation( + ContractNegotiationStore store, + String counterPartyAddress, + String agreementId + ) { + var assetId = UUID.randomUUID().toString(); + var agreement = ContractAgreement.Builder.newInstance() + .id(agreementId) + .providerId(UUID.randomUUID().toString()) + .consumerId(UUID.randomUUID().toString()) + .assetId(assetId) + .policy(getPolicy()) + .build(); + + var negotiation = ContractNegotiation.Builder.newInstance() + .id(UUID.randomUUID().toString()) + .counterPartyId(UUID.randomUUID().toString()) + .counterPartyAddress(counterPartyAddress) + .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) + .contractAgreement(agreement) + .contractOffer(createContractOffer(assetId)) + .state(ContractNegotiationStates.FINALIZED.code()) + .build(); + + store.save(negotiation); + return negotiation; + } + + private Policy getPolicy() { + return Policy.Builder.newInstance().build(); + } + + private ContractOffer createContractOffer(String assetId) { + return ContractOffer.Builder.newInstance() + .id(UUID.randomUUID().toString()) + .assetId(assetId) + .policy(getPolicy()) + .build(); + } +} diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/TransferRequestBuilderTest.java b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/TransferRequestBuilderTest.java similarity index 77% rename from extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/TransferRequestBuilderTest.java rename to tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/TransferRequestBuilderTest.java index 455eed2e0..0bf8c820b 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/TransferRequestBuilderTest.java +++ b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/services/TransferRequestBuilderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 sovity GmbH + * Copyright (c) 2024 sovity GmbH * * This program and the accompanying materials are made available under the * terms of the Apache License, Version 2.0 which is available at @@ -16,9 +16,10 @@ import de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils.EdcPropertyUtils; import de.sovity.edc.ext.wrapper.api.ui.model.InitiateTransferRequest; +import de.sovity.edc.utils.jsonld.vocab.Prop; import lombok.val; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; import org.eclipse.edc.policy.model.Policy; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import org.jetbrains.annotations.NotNull; @@ -27,7 +28,7 @@ import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; +import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -36,20 +37,21 @@ class TransferRequestBuilderTest { @Test void ensureThatThePreviousCustomPropertiesAreCopiedOverToTheDataSource() { // arrange - var request = new InitiateTransferRequest( - "contract-id", - Map.of( - "type", "HttpData", - "baseUrl", "http://example.com/segment0" - ), - Map.of( - EDC_NAMESPACE + "pathSegments", "my-endpoint", - EDC_NAMESPACE + "method", "METHOD", - EDC_NAMESPACE + "queryParams", "queryParams", - EDC_NAMESPACE + "contentType", "mimetype", - EDC_NAMESPACE + "body", "[]" - ) - ); + var request = InitiateTransferRequest.builder() + .contractAgreementId("contract-id") + .transferType("HttpData-PUSH") + .dataSinkProperties(Map.of( + Prop.Edc.TYPE, "HttpData", + Prop.Edc.BASE_URL, "http://example.com/segment0" + )) + .transferProcessProperties(Map.of( + EDC_NAMESPACE + "pathSegments", "my-endpoint", + EDC_NAMESPACE + "method", "METHOD", + EDC_NAMESPACE + "queryParams", "queryParams", + EDC_NAMESPACE + "contentType", "mimetype", + EDC_NAMESPACE + "body", "[]" + )) + .build(); final var transformer = createTransferRequestBuilder(); diff --git a/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionPageApiServiceTest.java b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionPageApiServiceTest.java new file mode 100644 index 000000000..9d6ddb6bf --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_definitions/ContractDefinitionPageApiServiceTest.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.ext.wrapper.api.ui.pages.contract_definitions; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.client.gen.model.ContractDefinitionEntry; +import de.sovity.edc.client.gen.model.ContractDefinitionRequest; +import de.sovity.edc.client.gen.model.UiCriterion; +import de.sovity.edc.client.gen.model.UiCriterionLiteral; +import de.sovity.edc.client.gen.model.UiCriterionLiteralType; +import de.sovity.edc.client.gen.model.UiCriterionOperator; +import de.sovity.edc.e2e.WrapperApiUtils; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; +import de.sovity.edc.extension.e2e.junit.Janitor; +import lombok.val; +import org.eclipse.edc.connector.controlplane.contract.spi.types.offer.ContractDefinition; +import org.eclipse.edc.connector.controlplane.services.spi.contractdefinition.ContractDefinitionService; +import org.eclipse.edc.spi.query.Criterion; +import org.eclipse.edc.spi.query.QuerySpec; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.byLessThan; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +class ContractDefinitionPageApiServiceTest { + + @RegisterExtension + static CeIntegrationTestExtension providerExtension = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); + + @Test + void contractDefinitionPage(EdcClient client, ContractDefinitionService contractDefinitionService, Janitor janitor) { + // arrange + + var criterion = new Criterion("exampleLeft1", "=", "abc"); + createContractDefinition(janitor, contractDefinitionService, "contractDefinition-id-1", "contractPolicy-id-1", "accessPolicy-id-1", + criterion); + + // act + var result = client.uiApi().getContractDefinitionPage(); + + // assert + var contractDefinitions = WrapperApiUtils.getContractDefinitionWithId(client, "contractDefinition-id-1"); + assertThat(contractDefinitions).hasSize(1); + var contractDefinition = contractDefinitions.get(0); + assertThat(contractDefinition.getContractDefinitionId()).isEqualTo("contractDefinition-id-1"); + assertThat(contractDefinition.getContractPolicyId()).isEqualTo("contractPolicy-id-1"); + assertThat(contractDefinition.getAccessPolicyId()).isEqualTo("accessPolicy-id-1"); + assertThat(contractDefinition.getAssetSelector()).hasSize(1); + + var criterionEntry = contractDefinition.getAssetSelector().get(0); + assertThat(criterionEntry.getOperandLeft()).isEqualTo("exampleLeft1"); + assertThat(criterionEntry.getOperator()).isEqualTo(UiCriterionOperator.EQ); + assertThat(criterionEntry.getOperandRight().getType()).isEqualTo(UiCriterionLiteralType.VALUE); + assertThat(criterionEntry.getOperandRight().getValue()).isEqualTo("abc"); + } + + @Order(1) + @Test + void contractDefinitionPageSorting(EdcClient client, ContractDefinitionService contractDefinitionService, Janitor janitor) { + // arrange + + createContractDefinition( + janitor, + contractDefinitionService, + "contractDefinition-id-1", + "contractPolicy-id-1", + "accessPolicy-id-1", + new Criterion("exampleLeft1", "=", "abc"), + 1628000000000L); + + createContractDefinition( + janitor, + contractDefinitionService, + "contractDefinition-id-2", + "contractPolicy-id-2", + "accessPolicy-id-2", + new Criterion("exampleLeft1", "=", "abc"), + 1628000001000L); + + createContractDefinition( + janitor, + contractDefinitionService, + "contractDefinition-id-3", + "contractPolicy-id-3", + "accessPolicy-id-3", + new Criterion("exampleLeft1", "=", "abc"), + 1628000002000L); + + // act + var result = client.uiApi().getContractDefinitionPage(); + + + // assert + assertThat(result.getContractDefinitions()) + .extracting(ContractDefinitionEntry::getContractPolicyId) + .containsExactly("contractPolicy-id-3", "contractPolicy-id-2", "contractPolicy-id-1"); + + } + + @Test + void testContractDefinitionCreation(EdcClient client, ContractDefinitionService contractDefinitionService) { + // arrange + + var criterion = new UiCriterion( + "exampleLeft1", + UiCriterionOperator.EQ, + new UiCriterionLiteral(UiCriterionLiteralType.VALUE, "test", null)); + + var contractDefinition = ContractDefinitionRequest.builder() + .contractDefinitionId("contractDefinition-id-10") + .contractPolicyId("contractPolicy-id-10") + .accessPolicyId("accessPolicy-id-10") + .assetSelector(List.of(criterion)) + .build(); + + // act + var response = client.uiApi().createContractDefinition(contractDefinition); + + // assert + assertThat(response).isNotNull(); + + var selector = QuerySpec.Builder.newInstance() + .filter(Criterion.criterion("id", "=", "contractDefinition-id-10")) + .build(); + + var contractDefinitions = contractDefinitionService.query(selector).getContent().toList(); + assertThat(contractDefinitions).hasSize(1); + var contractDefinitionEntry = contractDefinitions.get(0); + assertThat(contractDefinitionEntry.getId()).isEqualTo("contractDefinition-id-10"); + assertThat(contractDefinitionEntry.getContractPolicyId()).isEqualTo("contractPolicy-id-10"); + assertThat(contractDefinitionEntry.getAccessPolicyId()).isEqualTo("accessPolicy-id-10"); + + var criterionEntry = contractDefinition.getAssetSelector().get(0); + assertThat(criterionEntry.getOperandLeft()).isEqualTo("exampleLeft1"); + assertThat(criterionEntry.getOperator()).isEqualTo(UiCriterionOperator.EQ); + assertThat(criterionEntry.getOperandRight().getType()).isEqualTo(UiCriterionLiteralType.VALUE); + assertThat(criterionEntry.getOperandRight().getValue()).isEqualTo("test"); + } + + @Test + void testDeleteContractDefinition(EdcClient client, ContractDefinitionService contractDefinitionService, Janitor janitor) { + // arrange + + val criterion = new Criterion("exampleLeft1", "=", "exampleRight1"); + createContractDefinition( + janitor, + contractDefinitionService, + "contractDefinition-id-20", + "contractPolicy-id-20", + "accessPolicy-id-20", + criterion); + + val selectId20 = QuerySpec.Builder.newInstance() + .filter(Criterion.criterion("id", "=", "contractDefinition-id-20")) + .build(); + + val contractDefinitions = contractDefinitionService.query(selectId20).getContent().toList(); + + assertThat(contractDefinitions).hasSize(1); + + val contractDefinition = contractDefinitions.get(0); + + // act + val response = client.uiApi().deleteContractDefinition(contractDefinition.getId()); + + // assert + assertThat(response.getId()).isEqualTo(contractDefinition.getId()); + assertThat(contractDefinitionService.query(selectId20).getContent()).isEmpty(); + } + + private void createContractDefinition( + Janitor janitor, + ContractDefinitionService contractDefinitionService, + String contractDefinitionId, + String contractPolicyId, + String accessPolicyId, + Criterion criteria, + long createdAt + ) { + var contractDefinition = ContractDefinition.Builder.newInstance() + .id(contractDefinitionId) + .contractPolicyId(contractPolicyId) + .accessPolicyId(accessPolicyId) + .assetsSelector(List.of(criteria)) + .createdAt(createdAt) + .build(); + + contractDefinitionService.create(contractDefinition); + + janitor.afterEach(() -> contractDefinitionService.delete(contractDefinitionId)); + } + + private void createContractDefinition( + Janitor janitor, + ContractDefinitionService contractDefinitionService, + String contractDefinitionId, + String contractPolicyId, + String accessPolicyId, + Criterion criteria + ) { + var contractDefinition = ContractDefinition.Builder.newInstance() + .id(contractDefinitionId) + .contractPolicyId(contractPolicyId) + .accessPolicyId(accessPolicyId) + .assetsSelector(List.of(criteria)) + .build(); + + contractDefinitionService.create(contractDefinition); + + janitor.afterEach(() -> contractDefinitionService.delete(contractDefinitionId)); + } +} diff --git a/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/DashboardPageApiServiceTest.java b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/DashboardPageApiServiceTest.java new file mode 100644 index 000000000..389f91c03 --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/dashboard/DashboardPageApiServiceTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.ext.wrapper.api.ui.pages.dashboard; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; +import de.sovity.edc.utils.config.CeConfigProps; +import de.sovity.edc.utils.config.ConfigUtils; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; +import org.eclipse.edc.connector.controlplane.asset.spi.index.AssetIndex; +import org.eclipse.edc.connector.controlplane.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.contract.spi.types.offer.ContractDefinition; +import org.eclipse.edc.connector.controlplane.policy.spi.PolicyDefinition; +import org.eclipse.edc.connector.controlplane.services.spi.contractdefinition.ContractDefinitionService; +import org.eclipse.edc.connector.controlplane.services.spi.policydefinition.PolicyDefinitionService; +import org.eclipse.edc.connector.controlplane.services.spi.transferprocess.TransferProcessService; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcessStates; +import org.eclipse.edc.spi.query.QuerySpec; +import org.eclipse.edc.spi.result.ServiceResult; +import org.eclipse.edc.spi.system.configuration.Config; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.Mockito; + +import java.util.Collection; +import java.util.List; +import java.util.Random; +import java.util.function.Supplier; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation.Type.CONSUMER; +import static org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation.Type.PROVIDER; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class DashboardPageApiServiceTest { + + private static final AssetIndex assetIndex = mock(); + private static final PolicyDefinitionService policyDefinitionService = mock(); + private static final TransferProcessService transferProcessService = mock(); + private static final ContractNegotiationStore contractNegotiationStore = mock(); + private static final ContractDefinitionService contractDefinitionService = mock(); + + @RegisterExtension + static CeIntegrationTestExtension providerExtension = CeIntegrationTestExtension.builder() + .participantId("my-edc-participant-id") + .additionalModule(":launchers:connectors:sovity-dev") + .configOverrides(config -> config + .property(CeConfigProps.EDC_OAUTH_TOKEN_URL, "https://token-url.daps") + .property(CeConfigProps.EDC_OAUTH_PROVIDER_JWKS_URL, "https://jwks-url.daps") + .property("edc.iam.sts.oauth.token.url", "tokenUrl") + .property("edc.iam.trusted-issuer.cofinity.id", "myTrustedIssuer") + .property("edc.iam.issuer.id", "myDid") + .property("tx.iam.iatp.bdrs.server.url", "bdrsUrl") + .property("edc.iam.sts.dim.url", "dimUrl") + ) + .beforeEdcStartup(runtime -> { + runtime.registerServiceMock(AssetIndex.class, assetIndex); + runtime.registerServiceMock(PolicyDefinitionService.class, policyDefinitionService); + runtime.registerServiceMock(TransferProcessService.class, transferProcessService); + runtime.registerServiceMock(ContractNegotiationStore.class, contractNegotiationStore); + runtime.registerServiceMock(ContractDefinitionService.class, contractDefinitionService); + }) + .build(); + + private final Random random = new Random(); + + @Test + void testKpis(EdcClient client) { + // arrange + mockAmounts( + repeat(7, Mockito::mock), + repeat(8, Mockito::mock), + repeat(9, Mockito::mock), + List.of( + mockContractNegotiation(1, CONSUMER), + mockContractNegotiation(2, PROVIDER), + mockContractNegotiation(3, PROVIDER), + mockContractNegotiationInProgress(CONSUMER), + mockContractNegotiationInProgress(PROVIDER) + ), + flat(List.of( + repeat(1, () -> mockTransferProcess(1, TransferProcessStates.REQUESTING.code())), + repeat(2, () -> mockTransferProcess(1, TransferProcessStates.TERMINATED.code())), + repeat(3, () -> mockTransferProcess(1, TransferProcessStates.COMPLETED.code())), + repeat(4, () -> mockTransferProcess(2, TransferProcessStates.REQUESTING.code())), + repeat(5, () -> mockTransferProcess(2, TransferProcessStates.TERMINATED.code())), + repeat(6, () -> mockTransferProcess(2, TransferProcessStates.COMPLETED.code())) + )) + ); + + // act + var dashboardPage = client.uiApi().getDashboardPage(); + assertThat(dashboardPage.getNumAssets()).isEqualTo(7); + assertThat(dashboardPage.getNumPolicies()).isEqualTo(8); + assertThat(dashboardPage.getNumContractDefinitions()).isEqualTo(9); + assertThat(dashboardPage.getNumContractAgreementsConsuming()).isEqualTo(1); + assertThat(dashboardPage.getNumContractAgreementsProviding()).isEqualTo(2); + assertThat(dashboardPage.getTransferProcessesConsuming().getNumTotal()).isEqualTo(1 + 2 + 3); + assertThat(dashboardPage.getTransferProcessesConsuming().getNumRunning()).isEqualTo(1); + assertThat(dashboardPage.getTransferProcessesConsuming().getNumError()).isEqualTo(2); + assertThat(dashboardPage.getTransferProcessesConsuming().getNumOk()).isEqualTo(3); + assertThat(dashboardPage.getTransferProcessesProviding().getNumTotal()).isEqualTo(4 + 5 + 6); + assertThat(dashboardPage.getTransferProcessesProviding().getNumRunning()).isEqualTo(4); + assertThat(dashboardPage.getTransferProcessesProviding().getNumError()).isEqualTo(5); + assertThat(dashboardPage.getTransferProcessesProviding().getNumOk()).isEqualTo(6); + } + + @Test + void testConnectorMetadata(EdcClient client, Config config) { + // arrange + mockAmounts(List.of(), List.of(), List.of(), List.of(), List.of()); + + // act + var dashboardPage = client.uiApi().getDashboardPage(); + + // assert + assertThat(dashboardPage.getConnectorParticipantId()).isEqualTo("my-edc-participant-id"); + assertThat(dashboardPage.getConnectorDescription()).isEqualTo("Connector Description my-edc-participant-id"); + assertThat(dashboardPage.getConnectorTitle()).isEqualTo("Connector Title my-edc-participant-id"); + + assertThat(dashboardPage.getConnectorEndpoint()).isEqualTo(ConfigUtils.getProtocolApiUrl(config)); + assertThat(dashboardPage.getConnectorCuratorName()).isEqualTo("Curator Name my-edc-participant-id"); + assertThat(dashboardPage.getConnectorCuratorUrl()).isEqualTo("http://curator.my-edc-participant-id"); + assertThat(dashboardPage.getConnectorMaintainerName()).isEqualTo("Maintainer Name my-edc-participant-id"); + assertThat(dashboardPage.getConnectorMaintainerUrl()).isEqualTo("http://maintainer.my-edc-participant-id"); + + assertThat(dashboardPage.getConnectorDapsConfig()).isNotNull(); + assertThat(dashboardPage.getConnectorDapsConfig().getTokenUrl()).isEqualTo("https://token-url.daps"); + assertThat(dashboardPage.getConnectorDapsConfig().getJwksUrl()).isEqualTo("https://jwks-url.daps"); + + assertThat(dashboardPage.getConnectorCxDidConfig()).isNotNull(); + assertThat(dashboardPage.getConnectorCxDidConfig().getMyDid()).isEqualTo("myDid"); + assertThat(dashboardPage.getConnectorCxDidConfig().getWalletTokenUrl()).isEqualTo("tokenUrl"); + assertThat(dashboardPage.getConnectorCxDidConfig().getTrustedVcIssuer()).isEqualTo("myTrustedIssuer"); + assertThat(dashboardPage.getConnectorCxDidConfig().getBdrsUrl()).isEqualTo("bdrsUrl"); + assertThat(dashboardPage.getConnectorCxDidConfig().getDimUrl()).isEqualTo("dimUrl"); + } + + private ContractNegotiation mockContractNegotiation(int contract, ContractNegotiation.Type type) { + var contractAgreement = mock(ContractAgreement.class); + when(contractAgreement.getId()).thenReturn("ca-" + contract); + + var contractNegotiation = mock(ContractNegotiation.class); + when(contractNegotiation.getType()).thenReturn(type); + when(contractNegotiation.getContractAgreement()).thenReturn(contractAgreement); + + return contractNegotiation; + } + + private ContractNegotiation mockContractNegotiationInProgress(ContractNegotiation.Type type) { + var contractNegotiation = mock(ContractNegotiation.class); + when(contractNegotiation.getType()).thenReturn(type); + return contractNegotiation; + } + + private TransferProcess mockTransferProcess(int contractId, int state) { + TransferProcess transferProcess = mock(); + when(transferProcess.getId()).thenReturn(String.valueOf(random.nextInt())); + when(transferProcess.getContractId()).thenReturn("ca-" + contractId); + when(transferProcess.getState()).thenReturn(state); + return transferProcess; + } + + private void mockAmounts( + List assets, + List policyDefinitions, + List contractDefinitions, + List contractNegotiations, + List transferProcesses + ) { + when(assetIndex.queryAssets(eq(QuerySpec.max()))).thenAnswer(i -> assets.stream()); + when(transferProcessService.query(eq(QuerySpec.max()))) + .thenAnswer(i -> ServiceResult.success(transferProcesses.stream())); + when(policyDefinitionService.query(eq(QuerySpec.max()))) + .thenAnswer(i -> ServiceResult.success(policyDefinitions.stream())); + when(contractNegotiationStore.queryNegotiations(eq(QuerySpec.max()))) + .thenAnswer(i -> contractNegotiations.stream()); + when(contractDefinitionService.query(eq(QuerySpec.max()))) + .thenAnswer(i -> ServiceResult.success(contractDefinitions.stream())); + } + + private List repeat(int times, Supplier supplier) { + return IntStream.range(0, times).mapToObj(i -> supplier.get()).toList(); + } + + private List flat(Collection> collections) { + return collections.stream().flatMap(Collection::stream).toList(); + } +} diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java similarity index 62% rename from extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java rename to tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java index f0c03f615..4907bdec8 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java +++ b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 sovity GmbH + * Copyright (c) 2024 sovity GmbH * * This program and the accompanying materials are made available under the * terms of the Apache License, Version 2.0 which is available at @@ -14,7 +14,6 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.policy; - import de.sovity.edc.client.EdcClient; import de.sovity.edc.client.gen.model.OperatorDto; import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; @@ -26,40 +25,26 @@ import de.sovity.edc.client.gen.model.UiPolicyLiteralType; import de.sovity.edc.ext.db.jooq.Tables; import de.sovity.edc.extension.db.directaccess.DslContextFactory; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; import lombok.val; -import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService; -import org.eclipse.edc.junit.annotations.ApiTest; +import org.eclipse.edc.connector.controlplane.services.spi.policydefinition.PolicyDefinitionService; import org.eclipse.edc.spi.entity.Entity; import org.eclipse.edc.spi.query.QuerySpec; import org.jooq.DSLContext; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import java.util.List; import java.util.Map; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static org.assertj.core.api.Assertions.assertThat; -@ApiTest class PolicyDefinitionApiServiceTest { - private static ConnectorConfig config; - private static EdcClient client; @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "provider", - testDatabase -> { - config = forTestDatabase("my-edc-participant-id", testDatabase); - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - return config.getProperties(); - } - ); + private static final CeIntegrationTestExtension INTEGRATION_TEST_EXTENSION = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); UiPolicyExpression expression = UiPolicyExpression.builder() .type(UiPolicyExpressionType.CONSTRAINT) @@ -74,9 +59,10 @@ class PolicyDefinitionApiServiceTest { .build(); @Test - void getPolicyList() { + void getPolicyList(EdcClient client) { // arrange - createPolicyDefinition("my-policy-def-1"); + val policyDefinitionId = "my-policy-def-1"; + createPolicyDefinition(client, policyDefinitionId); // act var response = client.uiApi().getPolicyDefinitionPage(); @@ -85,24 +71,27 @@ void getPolicyList() { var policyDefinitions = response.getPolicies(); assertThat(policyDefinitions).hasSize(2); var policyDefinition = policyDefinitions.stream() - .filter(it -> it.getPolicyDefinitionId().equals("my-policy-def-1")) + .filter(it -> it.getPolicyDefinitionId().equals(policyDefinitionId)) .findFirst().get(); - assertThat(policyDefinition.getPolicyDefinitionId()).isEqualTo("my-policy-def-1"); + assertThat(policyDefinition.getPolicyDefinitionId()).isEqualTo(policyDefinitionId); assertThat(policyDefinition.getPolicy().getExpression()).usingRecursiveComparison().isEqualTo(expression); + + // cleanup + client.uiApi().deletePolicyDefinition(policyDefinitionId); } @Test - void sortPoliciesFromNewestToOldest(DslContextFactory dslContextFactory) { + void sortPoliciesFromNewestToOldest(EdcClient client, DslContextFactory dslContextFactory) { // arrange - createPolicyDefinition("my-policy-def-0"); - createPolicyDefinition("my-policy-def-1"); - createPolicyDefinition("my-policy-def-2"); + createPolicyDefinition(client, "my-policy-def-10"); + createPolicyDefinition(client, "my-policy-def-11"); + createPolicyDefinition(client, "my-policy-def-12"); dslContextFactory.transaction(dsl -> Map.of( - "my-policy-def-0", 1628956800000L, - "my-policy-def-1", 1628956801000L, - "my-policy-def-2", 1628956802000L + "my-policy-def-10", 1628956800000L, + "my-policy-def-11", 1628956801000L, + "my-policy-def-12", 1628956802000L ).forEach((id, time) -> setPolicyDefCreatedAt(dsl, id, time))); // act @@ -113,9 +102,16 @@ void sortPoliciesFromNewestToOldest(DslContextFactory dslContextFactory) { .extracting(PolicyDefinitionDto::getPolicyDefinitionId) .containsExactly( "always-true", - "my-policy-def-2", - "my-policy-def-1", - "my-policy-def-0"); + "my-policy-def-12", + "my-policy-def-11", + "my-policy-def-10"); + + // cleanup + List.of( + "my-policy-def-12", + "my-policy-def-11", + "my-policy-def-10" + ).forEach(id -> client.uiApi().deletePolicyDefinition(id)); } private static void setPolicyDefCreatedAt(DSLContext dsl, String id, Long time) { @@ -127,22 +123,23 @@ private static void setPolicyDefCreatedAt(DSLContext dsl, String id, Long time) } @Test - void test_delete(PolicyDefinitionService policyDefinitionService) { + void test_delete(EdcClient client, PolicyDefinitionService policyDefinitionService) { // arrange - createPolicyDefinition("my-policy-def-1"); + String policyDefinitionId = "my-policy-def-21"; + createPolicyDefinition(client, policyDefinitionId); assertThat(policyDefinitionService.query(QuerySpec.max()).getContent().toList()) - .extracting(Entity::getId).contains("always-true", "my-policy-def-1"); + .extracting(Entity::getId).contains("always-true", policyDefinitionId); // act - var response = client.uiApi().deletePolicyDefinition("my-policy-def-1"); + var response = client.uiApi().deletePolicyDefinition(policyDefinitionId); // assert - assertThat(response.getId()).isEqualTo("my-policy-def-1"); + assertThat(response.getId()).isEqualTo(policyDefinitionId); assertThat(policyDefinitionService.query(QuerySpec.max()).getContent()) .extracting(Entity::getId).containsExactly("always-true"); } - private void createPolicyDefinition(String policyDefinitionId) { + private void createPolicyDefinition(EdcClient client, String policyDefinitionId) { var policyDefinition = new PolicyDefinitionCreateDto(policyDefinitionId, expression); client.uiApi().createPolicyDefinitionV2(policyDefinition); } diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiServiceTest.java b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiServiceTest.java similarity index 70% rename from extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiServiceTest.java rename to tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiServiceTest.java index 6254c318b..762b0a757 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiServiceTest.java +++ b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 sovity GmbH + * Copyright (c) 2024 sovity GmbH * * This program and the accompanying materials are made available under the * terms of the Apache License, Version 2.0 which is available at @@ -16,52 +16,33 @@ import de.sovity.edc.client.EdcClient; import de.sovity.edc.client.gen.model.ContractAgreementDirection; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.spi.asset.AssetService; -import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; -import org.eclipse.edc.junit.annotations.ApiTest; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; +import org.eclipse.edc.connector.controlplane.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; +import org.eclipse.edc.connector.controlplane.transfer.spi.store.TransferProcessStore; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.RegisterExtension; import java.text.ParseException; import static de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferProcessTestUtils.createConsumingTransferProcesses; import static de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferProcessTestUtils.createProvidingTransferProcesses; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static org.assertj.core.api.Assertions.assertThat; -@ApiTest +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) class TransferHistoryPageApiServiceTest { - private static ConnectorConfig config; - private static EdcClient client; - @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "provider", - testDatabase -> { - config = forTestDatabase("my-edc-participant-id", testDatabase); - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - return config.getProperties(); - } - ); + static CeIntegrationTestExtension providerExtension = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); + @Order(3) @Test - void transferHistoryTest( - ContractNegotiationStore negotiationStore, - TransferProcessStore transferProcessStore, - AssetService assetStore - ) throws ParseException { - // arrange - createProvidingTransferProcesses(negotiationStore, transferProcessStore, assetStore); - createConsumingTransferProcesses(negotiationStore, transferProcessStore); - + void transferHistoryTest(EdcClient client) { // act var actual = client.uiApi().getTransferHistoryPage().getTransferEntries(); @@ -90,11 +71,13 @@ void transferHistoryTest( assertThat(providingProcess.getErrorMessage()).isEqualTo("TransferProcessManager: attempt #8 failed to send transfer"); } + @Order(2) @Test void transferProcessAssetTest_providing( - ContractNegotiationStore negotiationStore, - TransferProcessStore transferProcessStore, - AssetService assetStore + EdcClient client, + ContractNegotiationStore negotiationStore, + TransferProcessStore transferProcessStore, + AssetService assetStore ) throws ParseException { // arrange createProvidingTransferProcesses(negotiationStore, transferProcessStore, assetStore); @@ -107,10 +90,12 @@ void transferProcessAssetTest_providing( assertThat(result.getTitle()).isEqualTo(TransferProcessTestUtils.PROVIDING_ASSET_NAME); } + @Order(1) @Test void transferProcessAssetTest_consuming( - ContractNegotiationStore negotiationStore, - TransferProcessStore transferProcessStore + EdcClient client, + ContractNegotiationStore negotiationStore, + TransferProcessStore transferProcessStore ) throws ParseException { // arrange createConsumingTransferProcesses(negotiationStore, transferProcessStore); diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessAssetApiServiceTest.java b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessAssetApiServiceTest.java similarity index 58% rename from extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessAssetApiServiceTest.java rename to tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessAssetApiServiceTest.java index 31b60758d..d644e646e 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessAssetApiServiceTest.java +++ b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessAssetApiServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 sovity GmbH + * Copyright (c) 2024 sovity GmbH * * This program and the accompanying materials are made available under the * terms of the Apache License, Version 2.0 which is available at @@ -15,12 +15,10 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory; import de.sovity.edc.client.EdcClient; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.spi.asset.AssetService; -import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; -import org.eclipse.edc.junit.annotations.ApiTest; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; +import org.eclipse.edc.connector.controlplane.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; +import org.eclipse.edc.connector.controlplane.transfer.spi.store.TransferProcessStore; import org.eclipse.edc.spi.monitor.Monitor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -29,34 +27,22 @@ import static de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferProcessTestUtils.createConsumingTransferProcesses; import static de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferProcessTestUtils.createProvidingTransferProcesses; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static org.assertj.core.api.Assertions.assertThat; -@ApiTest class TransferProcessAssetApiServiceTest { - private static ConnectorConfig config; - private static EdcClient client; @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "provider", - testDatabase -> { - config = forTestDatabase("my-edc-participant-id", testDatabase); - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - return config.getProperties(); - } - ); + static CeIntegrationTestExtension providerExtension = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); @Test void testProviderTransferProcess( - ContractNegotiationStore negotiationStore, - TransferProcessStore transferProcessStore, - AssetService assetStore, - Monitor monitor + EdcClient client, + ContractNegotiationStore negotiationStore, + TransferProcessStore transferProcessStore, + AssetService assetStore, + Monitor monitor ) throws ParseException { monitor.info("Hello World from TransferProcessAssetApiServiceTest#testProviderTransferProcess!"); // arrange @@ -71,8 +57,11 @@ void testProviderTransferProcess( } @Test - void testConsumerTransferProcess(ContractNegotiationStore negotiationStore, - TransferProcessStore transferProcessStore) throws ParseException { + void testConsumerTransferProcess( + EdcClient client, + ContractNegotiationStore negotiationStore, + TransferProcessStore transferProcessStore + ) throws ParseException { // arrange createConsumingTransferProcesses(negotiationStore, transferProcessStore); diff --git a/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessTestUtils.java b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessTestUtils.java new file mode 100644 index 000000000..831870d80 --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessTestUtils.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory; + +import de.sovity.edc.utils.jsonld.vocab.Prop; +import lombok.val; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; +import org.eclipse.edc.connector.controlplane.contract.spi.negotiation.store.ContractNegotiationStore; +import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiationStates; +import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; +import org.eclipse.edc.connector.controlplane.transfer.spi.store.TransferProcessStore; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; +import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.protocol.dsp.http.spi.types.HttpMessageProtocol; +import org.eclipse.edc.spi.types.domain.DataAddress; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.UUID; + +public class TransferProcessTestUtils { + public static final String DATA_SINK = "http://my-data-sink/api/stuff"; + public static final String COUNTER_PARTY_ADDRESS = "http://some-other-connector/api/v1/ids/data"; + public static final String COUNTER_PARTY_ID = "some-other-connector"; + public static final String PROVIDING_CONTRACT_ID = "provider-contract:eb934d1f-6582-4bab-85e6-af19a76f7e2b"; + public static final String CONSUMING_CONTRACT_ID = "consumer-contract:f52a5d30-6356-4a55-a75a-3c45d7a88c3e"; + public static final String PROVIDING_ASSET_ID = "my-asset"; + public static final String CONSUMING_ASSET_ID = "some-asset-on-another-connector"; + public static final String PROVIDING_ASSET_NAME = "Test asset"; + public static final String PROVIDING_TRANSFER_PROCESS_ID = "81cdf4cf-8427-480f-9662-8a29d66ddd3b"; + public static final String CONSUMING_TRANSFER_PROCESS_ID = "be0cac12-bb43-420e-aa29-d66bb3d0e0ac"; + + public static void createProvidingTransferProcesses( + ContractNegotiationStore store, + TransferProcessStore transferProcessStore, + AssetService assetStore + ) throws ParseException { + DataAddress dataAddress = getDataAddress(); + createAsset(assetStore, dataAddress, PROVIDING_ASSET_ID, PROVIDING_ASSET_NAME); + + // preparing providing transfer process + var providerAgreement = createContractAgreement(PROVIDING_CONTRACT_ID, PROVIDING_ASSET_ID); + createContractNegotiation(store, COUNTER_PARTY_ADDRESS, providerAgreement, ContractNegotiation.Type.PROVIDER); + createTransferProcess(PROVIDING_ASSET_ID, + PROVIDING_CONTRACT_ID, + dataAddress, + TransferProcess.Type.PROVIDER, + PROVIDING_TRANSFER_PROCESS_ID, + "2023-07-08", + "TransferProcessManager: attempt #8 failed to send transfer", + transferProcessStore); + } + + public static void createConsumingTransferProcesses(ContractNegotiationStore store, TransferProcessStore transferProcessStore) + throws ParseException { + DataAddress dataAddress = getDataAddress(); + + // preparing consuming transfer process + var consumerAgreement = createContractAgreement(CONSUMING_CONTRACT_ID, CONSUMING_ASSET_ID); + createContractNegotiation(store, COUNTER_PARTY_ADDRESS, consumerAgreement, ContractNegotiation.Type.CONSUMER); + createTransferProcess(CONSUMING_ASSET_ID, + CONSUMING_CONTRACT_ID, + dataAddress, + TransferProcess.Type.CONSUMER, + CONSUMING_TRANSFER_PROCESS_ID, + "2023-07-10", + "", + transferProcessStore); + } + + private static DataAddress getDataAddress() { + return DataAddress.Builder.newInstance() + .type("HttpData") + .property(Prop.Edc.BASE_URL, DATA_SINK) + .build(); + } + + private static void createAsset(AssetService assetStore, DataAddress dataAddress, String assetId, String assetName) + throws ParseException { + var asset = Asset.Builder.newInstance() + .id(assetId) + .property(Prop.Dcterms.TITLE, assetName) + .dataAddress(dataAddress) + .createdAt(dateFormatterToLong("2023-06-01")) + .build(); + + val result = assetStore.create(asset); + if(result.failed()) { + throw new IllegalStateException(result.reason().toString()); + } + } + + private static ContractAgreement createContractAgreement( + String agreementId, + String assetId + ) { + return ContractAgreement.Builder.newInstance() + .id(agreementId) + .providerId(UUID.randomUUID().toString()) + .consumerId(UUID.randomUUID().toString()) + .assetId(assetId) + .policy(Policy.Builder.newInstance().build()) + .build(); + } + + private static void createContractNegotiation( + ContractNegotiationStore store, + String counterPartyAddress, + ContractAgreement agreement, + ContractNegotiation.Type type + ) { + var negotiation = ContractNegotiation.Builder.newInstance() + .id(UUID.randomUUID().toString()) + .counterPartyId(COUNTER_PARTY_ID) + .counterPartyAddress(counterPartyAddress) + .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) + .contractAgreement(agreement) + .type(type) + .correlationId(UUID.randomUUID().toString()) + .state(ContractNegotiationStates.FINALIZED.code()) + .build(); + + store.save(negotiation); + } + + private static void createTransferProcess( + String assetId, + String contractId, + DataAddress dataAddress, + TransferProcess.Type type, + String transferProcessId, + String lastUpdateDateForTransferProcess, + String errorMessage, + TransferProcessStore transferProcessStore + ) throws ParseException { + var transferProcess = TransferProcess.Builder.newInstance() + .id(transferProcessId) + .type(type) + .correlationId(UUID.randomUUID().toString()) + .contractId(contractId) + .assetId(assetId) + .counterPartyAddress(COUNTER_PARTY_ADDRESS) + .dataDestination(dataAddress) + .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) + .createdAt(dateFormatterToLong("2023-07-08")) + .updatedAt(dateFormatterToLong(lastUpdateDateForTransferProcess)) + .state(800) + .errorDetail(errorMessage) + .build(); + + transferProcessStore.save(transferProcess); + } + + private static long dateFormatterToLong(String date) throws ParseException { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + return formatter.parse(date).getTime(); + } +} diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java similarity index 55% rename from extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java rename to tests/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java index b3a24f5e2..72817026c 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java +++ b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 sovity GmbH + * Copyright (c) 2024 sovity GmbH * * This program and the accompanying materials are made available under the * terms of the Apache License, Version 2.0 which is available at @@ -12,39 +12,25 @@ * */ + package de.sovity.edc.ext.wrapper.api.usecase; import de.sovity.edc.client.EdcClient; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; -import org.eclipse.edc.junit.annotations.ApiTest; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static org.assertj.core.api.Assertions.assertThat; -@ApiTest class KpiApiTest { - private static ConnectorConfig config; - private static EdcClient client; @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "provider", - testDatabase -> { - config = forTestDatabase("my-edc-participant-id", testDatabase); - client = EdcClient.builder() - .managementApiUrl(config.getManagementApiUrl()) - .managementApiKey(config.getManagementApiKey()) - .build(); - return config.getProperties(); - } - ); + static CeIntegrationTestExtension providerExtension = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); @Test - void getKpis() { + void getKpis(EdcClient client) { // act var actual = client.useCaseApi().getKpis(); diff --git a/tests/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/SupportedPolicyApiTest.java b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/SupportedPolicyApiTest.java new file mode 100644 index 000000000..dd0ac360a --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/SupportedPolicyApiTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + + +package de.sovity.edc.ext.wrapper.api.usecase; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.extension.e2e.junit.CeIntegrationTestExtension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static org.assertj.core.api.Assertions.assertThat; + +class SupportedPolicyApiTest { + + @RegisterExtension + static CeIntegrationTestExtension providerExtension = CeIntegrationTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); + + @Test + void supportedPolicies(EdcClient client) { + // act + var actual = client.useCaseApi().getSupportedFunctions(); + + // assert + assertThat(actual).contains("ALWAYS_TRUE", "https://w3id.org/edc/v0.0.1/ns/inForceDate"); + } +} diff --git a/tests/src/test/java/de/sovity/edc/extension/contacttermination/CanGetAgreementPageForNonTerminatedContractTest.java b/tests/src/test/java/de/sovity/edc/extension/contacttermination/CanGetAgreementPageForNonTerminatedContractTest.java new file mode 100644 index 000000000..55ef9ac5d --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/extension/contacttermination/CanGetAgreementPageForNonTerminatedContractTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.contacttermination; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.client.gen.model.ContractAgreementPageQuery; +import de.sovity.edc.client.gen.model.ContractTerminationRequest; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenario; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; +import de.sovity.edc.extension.utils.junit.DisabledOnGithub; +import lombok.val; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.util.stream.IntStream; + +import static de.sovity.edc.client.gen.model.ContractTerminationStatus.ONGOING; +import static de.sovity.edc.client.gen.model.ContractTerminationStatus.TERMINATED; +import static de.sovity.edc.extension.contacttermination.ContractTerminationTestUtils.awaitTerminationCount; +import static org.assertj.core.api.Assertions.assertThat; + +public class CanGetAgreementPageForNonTerminatedContractTest { + + @RegisterExtension + private static final CeE2eTestExtension E2E_TEST_EXTENSION = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); + + @Test + @DisabledOnGithub + void canGetAgreementPageForNonTerminatedContract( + E2eTestScenario scenario, + @Consumer EdcClient consumerClient, + @Provider EdcClient providerClient + ) { + val assets = IntStream.range(0, 3).mapToObj((it) -> scenario.createAsset()); + + val agreements = assets + .peek(scenario::createContractDefinition) + .map(scenario::negotiateAssetAndAwait) + .toList(); + + consumerClient.uiApi().terminateContractAgreement( + agreements.get(0).getContractAgreementId(), + ContractTerminationRequest.builder() + .detail("detail 0") + .reason("reason 0") + .build() + ); + + consumerClient.uiApi().terminateContractAgreement( + agreements.get(1).getContractAgreementId(), + ContractTerminationRequest.builder() + .detail("detail 1") + .reason("reason 1") + .build() + ); + + awaitTerminationCount(consumerClient, 2); + awaitTerminationCount(providerClient, 2); + + // act + // don't terminate the contract + val allAgreements = consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); + val terminatedAgreements = + consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().terminationStatus(TERMINATED).build()); + val ongoingAgreements = + consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().terminationStatus(ONGOING).build()); + + // assert + assertThat(allAgreements.getContractAgreements()).hasSize(3); + assertThat(terminatedAgreements.getContractAgreements()).hasSize(2); + assertThat(ongoingAgreements.getContractAgreements()).hasSize(1); + } + +} diff --git a/tests/src/test/java/de/sovity/edc/extension/contacttermination/CanGetAgreementPageForTerminatedContractTest.java b/tests/src/test/java/de/sovity/edc/extension/contacttermination/CanGetAgreementPageForTerminatedContractTest.java new file mode 100644 index 000000000..bea31aa3d --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/extension/contacttermination/CanGetAgreementPageForTerminatedContractTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.contacttermination; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.client.gen.model.ContractAgreementPageQuery; +import de.sovity.edc.client.gen.model.ContractTerminationRequest; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenario; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; +import de.sovity.edc.extension.utils.junit.DisabledOnGithub; +import lombok.SneakyThrows; +import lombok.val; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static de.sovity.edc.client.gen.model.ContractTerminatedBy.SELF; +import static de.sovity.edc.extension.contacttermination.ContractTerminationTestUtils.assertTermination; +import static de.sovity.edc.extension.contacttermination.ContractTerminationTestUtils.awaitTerminationCount; + +public class CanGetAgreementPageForTerminatedContractTest { + + @RegisterExtension + private static final CeE2eTestExtension E2E_TEST_EXTENSION = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); + + @DisabledOnGithub + @Test + @SneakyThrows + void test( + E2eTestScenario scenario, + @Consumer EdcClient consumerClient, + @Provider EdcClient providerClient + ) { + val assetId = scenario.createAsset(); + scenario.createContractDefinition(assetId); + scenario.negotiateAssetAndAwait(assetId); + + val agreements = consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); + + // act + + val reason = "Reason"; + val details = "Details"; + consumerClient.uiApi().terminateContractAgreement( + agreements.getContractAgreements().get(0).getContractAgreementId(), + ContractTerminationRequest.builder().reason(reason).detail(details).build()); + + awaitTerminationCount(consumerClient, 1); + awaitTerminationCount(providerClient, 1); + + val agreementsAfterTermination = consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); + + // assert + assertTermination(agreementsAfterTermination, details, reason, SELF); + } + +} diff --git a/tests/src/test/java/de/sovity/edc/extension/contacttermination/CanTerminateFromConsumerTest.java b/tests/src/test/java/de/sovity/edc/extension/contacttermination/CanTerminateFromConsumerTest.java new file mode 100644 index 000000000..46f554342 --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/extension/contacttermination/CanTerminateFromConsumerTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.contacttermination; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.client.gen.model.ContractAgreementPageQuery; +import de.sovity.edc.client.gen.model.ContractTerminationRequest; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenario; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; +import de.sovity.edc.extension.utils.junit.DisabledOnGithub; +import lombok.SneakyThrows; +import lombok.val; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static de.sovity.edc.client.gen.model.ContractTerminatedBy.COUNTERPARTY; +import static de.sovity.edc.client.gen.model.ContractTerminatedBy.SELF; +import static de.sovity.edc.extension.contacttermination.ContractTerminationTestUtils.assertTermination; +import static de.sovity.edc.extension.contacttermination.ContractTerminationTestUtils.awaitTerminationCount; + +public class CanTerminateFromConsumerTest { + + @RegisterExtension + private static final CeE2eTestExtension E2E_TEST_EXTENSION = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); + + @DisabledOnGithub + @Test + @SneakyThrows + void test( + E2eTestScenario scenario, + @Consumer EdcClient consumerClient, + @Provider EdcClient providerClient + ) { + val assetId = scenario.createAsset(); + scenario.createContractDefinition(assetId); + val negotiation = scenario.negotiateAssetAndAwait(assetId); + + // act + val detail = "Some detail"; + val reason = "Some reason"; + consumerClient.uiApi().terminateContractAgreement(negotiation.getContractAgreementId(), ContractTerminationRequest.builder() + .detail(detail) + .reason(reason) + .build()); + + awaitTerminationCount(consumerClient, 1); + awaitTerminationCount(providerClient, 1); + + val consumerSideAgreements = consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); + val providerSideAgreements = providerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); + + // assert + assertTermination(consumerSideAgreements, detail, reason, SELF); + assertTermination(providerSideAgreements, detail, reason, COUNTERPARTY); + } + +} diff --git a/tests/src/test/java/de/sovity/edc/extension/contacttermination/CanTerminateFromProviderTest.java b/tests/src/test/java/de/sovity/edc/extension/contacttermination/CanTerminateFromProviderTest.java new file mode 100644 index 000000000..27abcfec6 --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/extension/contacttermination/CanTerminateFromProviderTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.contacttermination; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.client.gen.model.ContractAgreementPageQuery; +import de.sovity.edc.client.gen.model.ContractTerminationRequest; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenario; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; +import de.sovity.edc.extension.utils.junit.DisabledOnGithub; +import lombok.SneakyThrows; +import lombok.val; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static de.sovity.edc.client.gen.model.ContractTerminatedBy.COUNTERPARTY; +import static de.sovity.edc.client.gen.model.ContractTerminatedBy.SELF; +import static de.sovity.edc.extension.contacttermination.ContractTerminationTestUtils.assertTermination; +import static de.sovity.edc.extension.contacttermination.ContractTerminationTestUtils.awaitTerminationCount; + +public class CanTerminateFromProviderTest { + + @RegisterExtension + private static final CeE2eTestExtension E2E_TEST_EXTENSION = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); + + @DisabledOnGithub + @Test + @SneakyThrows + void test( + E2eTestScenario scenario, + @Consumer EdcClient consumerClient, + @Provider EdcClient providerClient + ) { + val assetId = scenario.createAsset(); + scenario.createContractDefinition(assetId); + val negotiation = scenario.negotiateAssetAndAwait(assetId); + + // act + val detail = "Some detail"; + val reason = "Some reason"; + + providerClient.uiApi().terminateContractAgreement( + negotiation.getContractAgreementId(), + ContractTerminationRequest.builder() + .detail(detail) + .reason(reason) + .build()); + + awaitTerminationCount(consumerClient, 1); + awaitTerminationCount(providerClient, 1); + + val consumerSideAgreements = consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); + val providerSideAgreements = providerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); + + // assert + assertTermination(consumerSideAgreements, detail, reason, COUNTERPARTY); + assertTermination(providerSideAgreements, detail, reason, SELF); + } + +} diff --git a/tests/src/test/java/de/sovity/edc/e2e/ContractTerminationTest.java b/tests/src/test/java/de/sovity/edc/extension/contacttermination/ContractTerminationTest.java similarity index 56% rename from tests/src/test/java/de/sovity/edc/e2e/ContractTerminationTest.java rename to tests/src/test/java/de/sovity/edc/extension/contacttermination/ContractTerminationTest.java index 084d98e1d..2d3c16f4f 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/ContractTerminationTest.java +++ b/tests/src/test/java/de/sovity/edc/extension/contacttermination/ContractTerminationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 sovity GmbH + * Copyright (c) 2024 sovity GmbH * * This program and the accompanying materials are made available under the * terms of the Apache License, Version 2.0 which is available at @@ -12,32 +12,25 @@ * */ -package de.sovity.edc.e2e; +package de.sovity.edc.extension.contacttermination; import de.sovity.edc.client.EdcClient; import de.sovity.edc.client.gen.ApiException; -import de.sovity.edc.client.gen.model.ContractAgreementPage; -import de.sovity.edc.client.gen.model.ContractAgreementPageQuery; -import de.sovity.edc.client.gen.model.ContractTerminatedBy; import de.sovity.edc.client.gen.model.ContractTerminationRequest; import de.sovity.edc.client.gen.model.InitiateTransferRequest; -import de.sovity.edc.client.gen.model.TransferHistoryEntry; -import de.sovity.edc.extension.contacttermination.ContractAgreementTerminationService; -import de.sovity.edc.extension.contacttermination.ContractTerminationEvent; -import de.sovity.edc.extension.contacttermination.ContractTerminationObserver; -import de.sovity.edc.extension.e2e.extension.Consumer; -import de.sovity.edc.extension.e2e.extension.E2eScenario; -import de.sovity.edc.extension.e2e.extension.E2eTestExtension; -import de.sovity.edc.extension.e2e.extension.Provider; +import de.sovity.edc.ext.db.jooq.Tables; +import de.sovity.edc.extension.db.directaccess.DslContextFactory; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenario; +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; import de.sovity.edc.extension.utils.junit.DisabledOnGithub; import de.sovity.edc.utils.jsonld.vocab.Prop; import jakarta.ws.rs.HttpMethod; import lombok.SneakyThrows; import lombok.val; -import org.awaitility.Awaitility; -import org.eclipse.edc.connector.contract.spi.ContractId; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcessStates; -import org.eclipse.edc.junit.extensions.EdcExtension; +import org.eclipse.edc.connector.controlplane.contract.spi.ContractOfferId; +import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcessStates; import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; @@ -48,144 +41,28 @@ import org.mockserver.model.HttpRequest; import org.mockserver.model.HttpResponse; -import java.time.OffsetDateTime; -import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; import java.util.stream.IntStream; -import static de.sovity.edc.client.gen.model.ContractTerminatedBy.COUNTERPARTY; -import static de.sovity.edc.client.gen.model.ContractTerminatedBy.SELF; -import static de.sovity.edc.client.gen.model.ContractTerminationStatus.ONGOING; -import static de.sovity.edc.client.gen.model.ContractTerminationStatus.TERMINATED; -import static de.sovity.edc.extension.e2e.extension.Helpers.defaultE2eTestExtension; -import static java.time.Duration.ofSeconds; -import static java.util.concurrent.TimeUnit.SECONDS; +import static de.sovity.edc.extension.contacttermination.ContractTerminationTestUtils.awaitTerminationCount; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.within; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.DynamicTest.dynamicTest; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; -public class ContractTerminationTest { +class ContractTerminationTest { @RegisterExtension - private static E2eTestExtension e2eTestExtension = defaultE2eTestExtension(); - - @Test - @DisabledOnGithub - void canGetAgreementPageForNonTerminatedContract( - E2eScenario scenario, - @Consumer EdcClient consumerClient, - @Provider EdcClient providerClient - ) { - val assets = IntStream.range(0, 3).mapToObj((it) -> scenario.createAsset()); - - val agreements = assets - .peek(scenario::createContractDefinition) - .map(scenario::negotiateAssetAndAwait) - .toList(); - - consumerClient.uiApi().terminateContractAgreement( - agreements.get(0).getContractAgreementId(), - ContractTerminationRequest.builder() - .detail("detail 0") - .reason("reason 0") - .build() - ); - - consumerClient.uiApi().terminateContractAgreement( - agreements.get(1).getContractAgreementId(), - ContractTerminationRequest.builder() - .detail("detail 1") - .reason("reason 1") - .build() - ); - - awaitTerminationCount(consumerClient, 2); - awaitTerminationCount(providerClient, 2); - - // act - // don't terminate the contract - val allAgreements = consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); - val terminatedAgreements = - consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().terminationStatus(TERMINATED).build()); - val ongoingAgreements = - consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().terminationStatus(ONGOING).build()); - - // assert - assertThat(allAgreements.getContractAgreements()).hasSize(3); - assertThat(terminatedAgreements.getContractAgreements()).hasSize(2); - assertThat(ongoingAgreements.getContractAgreements()).hasSize(1); - } - - @DisabledOnGithub - @Test - @SneakyThrows - void canGetAgreementPageForTerminatedContract( - E2eScenario scenario, - @Consumer EdcClient consumerClient, - @Provider EdcClient providerClient - ) { - val assetId = scenario.createAsset(); - scenario.createContractDefinition(assetId); - scenario.negotiateAssetAndAwait(assetId); - - val agreements = consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); - - // act - - val reason = "Reason"; - val details = "Details"; - consumerClient.uiApi().terminateContractAgreement( - agreements.getContractAgreements().get(0).getContractAgreementId(), - ContractTerminationRequest.builder().reason(reason).detail(details).build()); - - awaitTerminationCount(consumerClient, 1); - awaitTerminationCount(providerClient, 1); - - val agreementsAfterTermination = consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); - - // assert - assertTermination(agreementsAfterTermination, details, reason, SELF); - } - - @DisabledOnGithub - @Test - @SneakyThrows - void canTerminateFromConsumer( - E2eScenario scenario, - @Consumer EdcClient consumerClient, - @Provider EdcClient providerClient - ) { - val assetId = scenario.createAsset(); - scenario.createContractDefinition(assetId); - val negotiation = scenario.negotiateAssetAndAwait(assetId); - - // act - val detail = "Some detail"; - val reason = "Some reason"; - consumerClient.uiApi().terminateContractAgreement(negotiation.getContractAgreementId(), ContractTerminationRequest.builder() - .detail(detail) - .reason(reason) - .build()); - - awaitTerminationCount(consumerClient, 1); - awaitTerminationCount(providerClient, 1); - - val consumerSideAgreements = consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); - val providerSideAgreements = providerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); - - // assert - assertTermination(consumerSideAgreements, detail, reason, SELF); - assertTermination(providerSideAgreements, detail, reason, COUNTERPARTY); - } + private static final CeE2eTestExtension E2E_TEST_EXTENSION = CeE2eTestExtension.builder() + .additionalModule(":launchers:connectors:sovity-dev") + .build(); @DisabledOnGithub @Test void limitTheReasonSizeAt100Chars( - E2eScenario scenario, + E2eTestScenario scenario, @Consumer EdcClient consumerClient, @Provider EdcClient providerClient ) { @@ -226,7 +103,7 @@ void limitTheReasonSizeAt100Chars( @DisabledOnGithub @Test void limitTheDetailSizeAt1000Chars( - E2eScenario scenario, + E2eTestScenario scenario, @Consumer EdcClient consumerClient, @Provider EdcClient providerClient ) { @@ -270,7 +147,7 @@ void limitTheDetailSizeAt1000Chars( @DisabledOnGithub @TestFactory List theDetailsAreMandatory( - E2eScenario scenario, + E2eTestScenario scenario, @Consumer EdcClient consumerClient ) { val invalidDetails = List.of( @@ -305,42 +182,6 @@ List theDetailsAreMandatory( })).toList(); } - @DisabledOnGithub - @Test - @SneakyThrows - void canTerminateFromProvider( - E2eScenario scenario, - @Consumer EdcClient consumerClient, - @Provider EdcClient providerClient - ) { - val assetId = scenario.createAsset(); - scenario.createContractDefinition(assetId); - val negotiation = scenario.negotiateAssetAndAwait(assetId); - - // act - val detail = "Some detail"; - val reason = "Some reason"; - - providerClient.uiApi().terminateContractAgreement( - negotiation.getContractAgreementId(), - ContractTerminationRequest.builder() - .detail(detail) - .reason(reason) - .build()); - - awaitTerminationCount(consumerClient, 1); - awaitTerminationCount(providerClient, 1); - - val consumerSideAgreements = consumerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); - val providerSideAgreements = providerClient.uiApi().getContractAgreementPage(ContractAgreementPageQuery.builder().build()); - - // assert - - // assert - assertTermination(consumerSideAgreements, detail, reason, COUNTERPARTY); - assertTermination(providerSideAgreements, detail, reason, SELF); - } - @Test void doesntCrashWhenAgreementDoesntExist( @Consumer EdcClient consumerClient @@ -349,17 +190,19 @@ void doesntCrashWhenAgreementDoesntExist( assertThrows( ApiException.class, () -> consumerClient.uiApi().terminateContractAgreement( - ContractId.create("definition-1", "asset-1").toString(), + ContractOfferId.create("definition-1", "asset-1").toString(), ContractTerminationRequest.builder().detail("Some detail").reason("Some reason").build())); } @DisabledOnGithub @Test @SneakyThrows - void cantTransferDataAfterTerminated( - E2eScenario scenario, + void cantTransferDataAfterTerminatedOnProviderSideOnly( + E2eTestScenario scenario, ClientAndServer mockServer, + @Consumer DslContextFactory consumerDsl, @Consumer EdcClient consumerClient, + @Provider DslContextFactory providerDsl, @Provider EdcClient providerClient ) { val assetId = "asset-1"; @@ -375,6 +218,7 @@ void cantTransferDataAfterTerminated( val transferRequest = InitiateTransferRequest.builder() .contractAgreementId(negotiation.getContractAgreementId()) + .transferType("HttpData-PUSH") .dataSinkProperties( Map.of( Prop.Edc.BASE_URL, destinationUrl, @@ -410,6 +254,20 @@ void cantTransferDataAfterTerminated( awaitTerminationCount(consumerClient, 1); awaitTerminationCount(providerClient, 1); + val t = Tables.SOVITY_CONTRACT_TERMINATION; + + val terminatedOnProviderSide = providerDsl.transactionResult((ptrx) -> + ptrx.selectCount() + .from(t) + .where(t.CONTRACT_AGREEMENT_ID.eq(contractAgreementId)) + .execute()); + + assertThat(terminatedOnProviderSide).isEqualTo(1); + // pretend that the consumer didn't receive the termination message and let them try to get the data + consumerDsl.transactionResult((ctrx) -> ctrx.truncate(t).execute()); + val terminatedOnConsumerSide = consumerDsl.transactionResult((ctrx) -> ctrx.fetchCount(t)); + assertThat(terminatedOnConsumerSide).isEqualTo(0); + // act consumerClient.uiApi().initiateTransfer(transferRequest); // first transfer attempt @@ -423,7 +281,7 @@ void cantTransferDataAfterTerminated( @Test @DisabledOnGithub void canTerminateOnlyOnce( - E2eScenario scenario, + E2eTestScenario scenario, @Consumer EdcClient consumerClient, @Provider EdcClient providerClient ) { @@ -451,11 +309,11 @@ void canTerminateOnlyOnce( @Test @DisabledOnGithub void canListenToTerminationEvents( - E2eScenario scenario, + E2eTestScenario scenario, @Consumer EdcClient consumerClient, - @Consumer EdcExtension consumerExtension, + @Consumer ContractAgreementTerminationService consumerService, @Provider EdcClient providerClient, - @Provider EdcExtension providerExtension + @Provider ContractAgreementTerminationService providerService ) { // arrange val assetId = scenario.createAsset(); @@ -467,9 +325,6 @@ void canListenToTerminationEvents( val contractTerminationRequest = ContractTerminationRequest.builder().detail(detail).reason(reason).build(); val contractAgreementId = negotiation.getContractAgreementId(); - val consumerService = consumerExtension.getContext().getService(ContractAgreementTerminationService.class); - val providerService = providerExtension.getContext().getService(ContractAgreementTerminationService.class); - val consumerObserver = Mockito.spy(new ContractTerminationObserver() { }); val providerObserver = Mockito.spy(new ContractTerminationObserver() { @@ -520,58 +375,14 @@ void canListenToTerminationEvents( assertThat(providerService.getContractTerminationObservable().getListeners()).hasSize(0); } - private static void assertTerminationEvent(ArgumentCaptor argument, String contractAgreementId, - ContractTerminationRequest contractTerminationRequest) { + private static void assertTerminationEvent( + ArgumentCaptor argument, + String contractAgreementId, + ContractTerminationRequest contractTerminationRequest + ) { assertThat(argument.getValue().contractAgreementId()).isEqualTo(contractAgreementId); assertThat(argument.getValue().detail()).isEqualTo(contractTerminationRequest.getDetail()); assertThat(argument.getValue().reason()).isEqualTo(contractTerminationRequest.getReason()); assertThat(argument.getValue().timestamp()).isNotNull(); } - - private static void assertTermination( - ContractAgreementPage consumerSideAgreements, - String detail, - String reason, - ContractTerminatedBy terminatedBy - ) { - val contractAgreements = consumerSideAgreements.getContractAgreements(); - assertThat(contractAgreements).hasSize(1); - assertThat(contractAgreements.get(0).getTerminationStatus()).isEqualTo(TERMINATED); - - val consumerInformation = contractAgreements.get(0).getTerminationInformation(); - - assertThat(consumerInformation).isNotNull(); - - val now = OffsetDateTime.now(); - assertThat(consumerInformation.getTerminatedAt()).isCloseTo(now, within(1, ChronoUnit.MINUTES)); - - assertThat(consumerInformation.getDetail()).isEqualTo(detail); - assertThat(consumerInformation.getReason()).isEqualTo(reason); - assertThat(consumerInformation.getTerminatedBy()).isEqualTo(terminatedBy); - } - - private TransferHistoryEntry awaitTransfer(EdcClient client, String transferProcessId) { - val historyEntry = Awaitility.await().atMost(10, SECONDS).until(() -> - client.uiApi() - .getTransferHistoryPage() - .getTransferEntries() - .stream() - .filter(it -> it.getTransferProcessId().equals(transferProcessId)) - .findFirst(), - first -> first.map(it -> it.getState().getCode().equals(TransferProcessStates.COMPLETED.code())) - .orElse(false)); - - return historyEntry.get(); - } - - private void awaitTerminationCount(EdcClient client, int count) { - Awaitility.await().atMost(ofSeconds(5)).until( - () -> client.uiApi() - .getContractAgreementPage(ContractAgreementPageQuery.builder().build()) - .getContractAgreements() - .stream() - .filter(it -> it.getTerminationStatus().equals(TERMINATED)) - .count() >= count - ); - } } diff --git a/tests/src/test/java/de/sovity/edc/extension/contacttermination/ContractTerminationTestUtils.java b/tests/src/test/java/de/sovity/edc/extension/contacttermination/ContractTerminationTestUtils.java new file mode 100644 index 000000000..77af4c21f --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/extension/contacttermination/ContractTerminationTestUtils.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.contacttermination; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.client.gen.model.ContractAgreementPage; +import de.sovity.edc.client.gen.model.ContractAgreementPageQuery; +import de.sovity.edc.client.gen.model.ContractTerminatedBy; +import lombok.experimental.UtilityClass; +import lombok.val; +import org.awaitility.Awaitility; + +import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; + +import static de.sovity.edc.client.gen.model.ContractTerminationStatus.TERMINATED; +import static java.time.Duration.ofSeconds; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.within; + +@UtilityClass +public class ContractTerminationTestUtils { + + public static void awaitTerminationCount(EdcClient client, int count) { + Awaitility.await().atMost(ofSeconds(5)).until( + () -> client.uiApi() + .getContractAgreementPage(ContractAgreementPageQuery.builder().build()) + .getContractAgreements() + .stream() + .filter(it -> it.getTerminationStatus().equals(TERMINATED)) + .count() >= count + ); + } + + public static void assertTermination( + ContractAgreementPage consumerSideAgreements, + String detail, + String reason, + ContractTerminatedBy terminatedBy + ) { + val contractAgreements = consumerSideAgreements.getContractAgreements(); + assertThat(contractAgreements).hasSize(1); + assertThat(contractAgreements.get(0).getTerminationStatus()).isEqualTo(TERMINATED); + + val consumerInformation = contractAgreements.get(0).getTerminationInformation(); + + assertThat(consumerInformation).isNotNull(); + + val now = OffsetDateTime.now(); + assertThat(consumerInformation.getTerminatedAt()).isCloseTo(now, within(1, ChronoUnit.MINUTES)); + + assertThat(consumerInformation.getDetail()).isEqualTo(detail); + assertThat(consumerInformation.getReason()).isEqualTo(reason); + assertThat(consumerInformation.getTerminatedBy()).isEqualTo(terminatedBy); + } + +} diff --git a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/DspCatalogService.java b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/DspCatalogService.java index 603bd2b27..231f708f2 100644 --- a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/DspCatalogService.java +++ b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/DspCatalogService.java @@ -20,7 +20,7 @@ import jakarta.json.JsonObject; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; -import org.eclipse.edc.connector.spi.catalog.CatalogService; +import org.eclipse.edc.connector.controlplane.services.spi.catalog.CatalogService; import org.eclipse.edc.spi.query.QuerySpec; import java.nio.charset.StandardCharsets; @@ -30,27 +30,27 @@ public class DspCatalogService { private final CatalogService catalogService; private final DspDataOfferBuilder dspDataOfferBuilder; - public DspCatalog fetchDataOffers(String endpoint) throws DspCatalogServiceException { - var catalogJson = fetchDcatResponse(endpoint, QuerySpec.max()); + public DspCatalog fetchDataOffers(String participantId, String endpoint) throws DspCatalogServiceException { + var catalogJson = fetchDcatResponse(participantId, endpoint, QuerySpec.max()); return dspDataOfferBuilder.buildDataOffers(endpoint, catalogJson); } - public DspCatalog fetchDataOffersWithFilters(String endpoint, QuerySpec querySpec) { - var catalogJson = fetchDcatResponse(endpoint, querySpec); + public DspCatalog fetchDataOffersWithFilters(String participantId, String endpoint, QuerySpec querySpec) { + var catalogJson = fetchDcatResponse(participantId, endpoint, querySpec); return dspDataOfferBuilder.buildDataOffers(endpoint, catalogJson); } - private JsonObject fetchDcatResponse(String connectorEndpoint, QuerySpec querySpec) { - var raw = fetchDcatRaw(connectorEndpoint, querySpec); + private JsonObject fetchDcatResponse(String participantId, String connectorEndpoint, QuerySpec querySpec) { + var raw = fetchDcatRaw(participantId, connectorEndpoint, querySpec); var string = new String(raw, StandardCharsets.UTF_8); return JsonUtils.parseJsonObj(string); } @SneakyThrows - private byte[] fetchDcatRaw(String connectorEndpoint, QuerySpec querySpec) { + private byte[] fetchDcatRaw(String participantId, String connectorEndpoint, QuerySpec querySpec) { return catalogService - .requestCatalog(connectorEndpoint, "dataspace-protocol-http", querySpec) - .get() - .orElseThrow(DspCatalogServiceException::ofFailure); + .requestCatalog(participantId, connectorEndpoint, "dataspace-protocol-http", querySpec) + .get() + .orElseThrow(DspCatalogServiceException::ofFailure); } } diff --git a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/mapper/DspDataOfferBuilder.java b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/mapper/DspDataOfferBuilder.java index cf6444b84..acfccf743 100644 --- a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/mapper/DspDataOfferBuilder.java +++ b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/mapper/DspDataOfferBuilder.java @@ -33,12 +33,13 @@ public class DspDataOfferBuilder { public DspCatalog buildDataOffers(String endpoint, JsonObject json) { json = jsonLd.expand(json).orElseThrow(DspCatalogServiceException::ofFailure); - String participantId = JsonLdUtils.string(json, Prop.Edc.PARTICIPANT_ID); + var participantId = JsonLdUtils.string(json, Prop.Edc.PARTICIPANT_ID); + var dataOffers = JsonLdUtils.listOfObjects(json, Prop.Dcat.DATASET); return new DspCatalog( endpoint, participantId, - JsonLdUtils.listOfObjects(json, Prop.Dcat.DATASET).stream() + dataOffers.stream() .map(this::buildDataOffer) .toList() ); @@ -49,15 +50,14 @@ private DspDataOffer buildDataOffer(JsonObject dataset) { .map(this::buildContractOffer) .toList(); - var distributions = JsonLdUtils.listOfObjects(dataset, Prop.Dcat.DISTRIBUTION_AS_USED_BY_CORE_EDC); + var distributions = JsonLdUtils.listOfObjects(dataset, Prop.Dcat.DISTRIBUTION_WILL_BE_OVERWRITTEN_BY_CATALOG); var assetProperties = Json.createObjectBuilder(dataset) .remove(Prop.TYPE) .remove(Prop.Odrl.HAS_POLICY) - .remove(Prop.Dcat.DISTRIBUTION_AS_USED_BY_CORE_EDC) + .remove(Prop.Dcat.DISTRIBUTION_WILL_BE_OVERWRITTEN_BY_CATALOG) .build(); - return new DspDataOffer( assetProperties, contractOffers, diff --git a/utils/catalog-parser/src/test/java/de/sovity/edc/utils/catalog/DspCatalogServiceTest.java b/utils/catalog-parser/src/test/java/de/sovity/edc/utils/catalog/DspCatalogServiceTest.java index 88fa35cb2..0b184e0dd 100644 --- a/utils/catalog-parser/src/test/java/de/sovity/edc/utils/catalog/DspCatalogServiceTest.java +++ b/utils/catalog-parser/src/test/java/de/sovity/edc/utils/catalog/DspCatalogServiceTest.java @@ -19,7 +19,7 @@ import de.sovity.edc.utils.jsonld.vocab.Prop; import lombok.SneakyThrows; import org.apache.commons.io.IOUtils; -import org.eclipse.edc.connector.spi.catalog.CatalogService; +import org.eclipse.edc.connector.controlplane.services.spi.catalog.CatalogService; import org.eclipse.edc.jsonld.TitaniumJsonLd; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.query.QuerySpec; @@ -38,13 +38,20 @@ class DspCatalogServiceTest { String endpoint = "http://localhost:11003/api/v1/dsp"; + String participantId = "someParticipantId"; private DspCatalogService newDspCatalogService(String resultJsonFilename) { var catalogJson = readFile(resultJsonFilename); var catalogService = mock(CatalogService.class); var result = CompletableFuture.completedFuture(StatusResult.success(catalogJson.getBytes(StandardCharsets.UTF_8))); - when(catalogService.requestCatalog(eq(endpoint), eq("dataspace-protocol-http"), eq(QuerySpec.max()))).thenReturn(result); + when(catalogService.requestCatalog( + eq(participantId), + eq(endpoint), + eq("dataspace-protocol-http"), + eq(QuerySpec.max())) + ).thenReturn(result); + var monitor = mock(Monitor.class); var dataOfferBuilder = new DspDataOfferBuilder(new TitaniumJsonLd(monitor)); @@ -57,7 +64,7 @@ void testCatalogMapping() { var dspCatalogService = newDspCatalogService("catalogResponse.json"); // act - var actual = dspCatalogService.fetchDataOffers(endpoint); + var actual = dspCatalogService.fetchDataOffers(participantId, endpoint); // assert var offers = actual.getDataOffers(); @@ -66,7 +73,7 @@ void testCatalogMapping() { assertThat(actual.getEndpoint()).isEqualTo(endpoint); assertThat(actual.getParticipantId()).isEqualTo("provider"); assertThat(JsonLdUtils.id(offer.getAssetPropertiesJsonLd())) - .isEqualTo("test-1.0"); + .isEqualTo("test-1.0"); assertThat(offer.getAssetPropertiesJsonLd().get(Prop.TYPE)).isNull(); assertThat(JsonLdUtils.string(offer.getAssetPropertiesJsonLd(), Prop.Dcat.VERSION)).isEqualTo("1.0"); diff --git a/utils/catalog-parser/src/test/resources/de/sovity/edc/utils/catalog/catalogResponse.json b/utils/catalog-parser/src/test/resources/de/sovity/edc/utils/catalog/catalogResponse.json index d069f7302..75ed999fa 100644 --- a/utils/catalog-parser/src/test/resources/de/sovity/edc/utils/catalog/catalogResponse.json +++ b/utils/catalog-parser/src/test/resources/de/sovity/edc/utils/catalog/catalogResponse.json @@ -40,7 +40,7 @@ "@context": { "dct": "https://purl.org/dc/terms/", "edc": "https://w3id.org/edc/v0.0.1/ns/", - "dcat": "https://www.w3.org/ns/dcat/", + "dcat": "http://www.w3.org/ns/dcat#", "odrl": "http://www.w3.org/ns/odrl/2/", "dspace": "https://w3id.org/dspace/v0.8/" } diff --git a/utils/json-and-jsonld-utils/src/main/java/de/sovity/edc/utils/jsonld/vocab/Prop.java b/utils/json-and-jsonld-utils/src/main/java/de/sovity/edc/utils/jsonld/vocab/Prop.java index 4a057ddd2..56596deaa 100644 --- a/utils/json-and-jsonld-utils/src/main/java/de/sovity/edc/utils/jsonld/vocab/Prop.java +++ b/utils/json-and-jsonld-utils/src/main/java/de/sovity/edc/utils/jsonld/vocab/Prop.java @@ -36,36 +36,40 @@ public class Prop { public class Edc { public final String CTX = "https://w3id.org/edc/v0.0.1/ns/"; public final String CTX_ALIAS = "edc"; + public final String TYPE_ASSET = CTX + "Asset"; public final String TYPE_DATA_ADDRESS = CTX + "DataAddress"; - public final String ID = CTX + "id"; - public final String PARTICIPANT_ID = CTX + "participantId"; - public final String PROPERTIES = CTX + "properties"; - public final String PRIVATE_PROPERTIES = CTX + "privateProperties"; + + public final String ASSET_ID = CTX + "assetId"; + public final String AUTH_CODE = CTX + "authCode"; + public final String AUTH_KEY = CTX + "authKey"; + public final String BASE_URL = CTX + "baseUrl"; + public final String BODY = CTX + "body"; + public final String CONNECTOR_ADDRESS = CTX + "connectorAddress"; + public final String CONNECTOR_ID = CTX + "connectorId"; + public final String CONTENT_TYPE = CTX + "contentType"; + public final String CONTRACT_ID = CTX + "contractId"; + public final String COUNTER_PARTY_ADDRESS = CTX + "counterPartyAddress"; public final String DATA_ADDRESS = CTX + "dataAddress"; - public final String TYPE = CTX + "type"; public final String DATA_ADDRESS_TYPE_HTTP_DATA = "HttpData"; public final String DATA_ADDRESS_TYPE_HTTP_PROXY = "HttpProxy"; - public final String BASE_URL = CTX + "baseUrl"; + public final String DATA_DESTINATION = CTX + "dataDestination"; + public final String ID = CTX + "id"; + public final String MEDIA_TYPE = CTX + "mediaType"; public final String METHOD = CTX + "method"; - public final String CONTENT_TYPE = CTX + "contentType"; - public final String QUERY_PARAMS = CTX + "queryParams"; - public final String AUTH_KEY = CTX + "authKey"; - public final String AUTH_CODE = CTX + "authCode"; - public final String SECRET_NAME = CTX + "secretName"; + public final String PARTICIPANT_ID = CTX + "participantId"; + public final String PATH = CTX + "path"; + public final String PRIVATE_PROPERTIES = CTX + "privateProperties"; + public final String PROPERTIES = CTX + "properties"; + public final String PROXY_BODY = CTX + "proxyBody"; public final String PROXY_METHOD = CTX + "proxyMethod"; public final String PROXY_PATH = CTX + "proxyPath"; public final String PROXY_QUERY_PARAMS = CTX + "proxyQueryParams"; - public final String PROXY_BODY = CTX + "proxyBody"; - - // Transfer Request Related - public static String TYPE_TRANSFER_REQUEST = CTX + "TransferRequest"; - public final String CONNECTOR_ADDRESS = CTX + "connectorAddress"; - public final String CONTRACT_ID = CTX + "contractId"; - public final String CONNECTOR_ID = CTX + "connectorId"; - public final String ASSET_ID = CTX + "assetId"; - public final String DATA_DESTINATION = CTX + "dataDestination"; + public final String QUERY_PARAMS = CTX + "queryParams"; public final String RECEIVER_HTTP_ENDPOINT = CTX + "receiverHttpEndpoint"; + public final String SECRET_NAME = CTX + "secretName"; + public final String TYPE = CTX + "type"; + public final String TYPE_TRANSFER_REQUEST = CTX + "TransferRequest"; } /** @@ -76,16 +80,14 @@ public class Dcat { /** * Context as specified in https://www.w3.org/TR/vocab-dcat-3/#normative-namespaces */ + // TODO: get a sample from the catalog in v0.7 and validate that this is the correct URI and update `catalogResponse.json` public final String CTX = "http://www.w3.org/ns/dcat#"; + public final String DATASET = CTX + "dataset"; /** - * Context as used in the Core EDC, or atleast how its output from a DCAT request + * TODO Explain what happen and link code */ - public final String CTX_WRONG_BUT_USED_BY_CORE_EDC = "https://www.w3.org/ns/dcat/"; - - public final String DATASET = CTX_WRONG_BUT_USED_BY_CORE_EDC + "dataset"; - public final String DISTRIBUTION = CTX + "distribution"; - public final String DISTRIBUTION_AS_USED_BY_CORE_EDC = CTX_WRONG_BUT_USED_BY_CORE_EDC + "distribution"; + public final String DISTRIBUTION_WILL_BE_OVERWRITTEN_BY_CATALOG = CTX + "distribution"; public final String VERSION = CTX + "version"; public final String KEYWORDS = CTX + "keyword"; public final String LANDING_PAGE = CTX + "landingPage"; @@ -145,6 +147,7 @@ public class SovityDcatExt { public final String DATA_SOURCE_AVAILABILITY_ON_REQUEST = "ON_REQUEST"; public final String CONTACT_EMAIL = CTX + "contactEmail"; public final String CONTACT_PREFERRED_EMAIL_SUBJECT = CTX + "contactPreferredEmailSubject"; + public final String DISTRIBUTION = CTX + "distribution"; @UtilityClass public class HttpDatasourceHints { @@ -230,4 +233,10 @@ public class Rdfs { public final String LITERAL = CTX + "Literal"; public final String LABEL = CTX + "label"; } + + /* + * TODO: add EDC jsonld keys in here instead of the EDC keys + * + * EDC_NAMESPACE + "method" -> Prop.Edc.METHOD + */ } diff --git a/utils/test-utils/build.gradle.kts b/utils/test-utils/build.gradle.kts index 79b41f7fb..38e171b43 100644 --- a/utils/test-utils/build.gradle.kts +++ b/utils/test-utils/build.gradle.kts @@ -7,8 +7,10 @@ dependencies { annotationProcessor(libs.lombok) compileOnly(libs.lombok) - api(libs.junit.api) - implementation(libs.apache.commonsLang) + api(libs.apache.commonsLang) + api(libs.edc.contractSpi) + api(libs.edc.jsonLdSpi) + api(libs.edc.jsonLdLib) api(libs.edc.junit) api(libs.awaitility.java) @@ -17,9 +19,14 @@ dependencies { api(project(":extensions:wrapper:clients:java-client")) api(project(":utils:json-and-jsonld-utils")) + + api(libs.junit.api) + implementation(project(":utils:versions")) + implementation(libs.edc.controlPlaneSpi) implementation(libs.edc.jsonLd) implementation(libs.assertj.core) + implementation(libs.mockito.core) implementation(libs.jooq.jooq) implementation(libs.mockserver.netty) implementation(libs.testcontainers.testcontainers) diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/ConnectorRemote.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/ConnectorRemote.java deleted file mode 100644 index f74d4b15c..000000000 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/ConnectorRemote.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - init - * - */ - -package de.sovity.edc.extension.e2e.connector; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.sovity.edc.extension.e2e.connector.config.ConnectorRemoteConfig; -import io.restassured.http.Header; -import io.restassured.specification.RequestSpecification; -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonObject; -import jakarta.json.JsonValue; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import org.eclipse.edc.connector.contract.spi.ContractId; -import org.eclipse.edc.jsonld.TitaniumJsonLd; -import org.eclipse.edc.jsonld.spi.JsonLd; -import org.eclipse.edc.jsonld.util.JacksonJsonLd; -import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.monitor.ConsoleMonitor; -import org.eclipse.edc.spi.result.Failure; - -import java.time.Duration; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicReference; - -import static io.restassured.RestAssured.given; -import static io.restassured.http.ContentType.JSON; -import static jakarta.json.Json.createObjectBuilder; -import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; -import static org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationStates.FINALIZED; -import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; -import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; -import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; -import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_DATASET_ATTRIBUTE; -import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_POLICY_ATTRIBUTE; -import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; -import static org.eclipse.edc.spi.CoreConstants.EDC_PREFIX; - -@SuppressWarnings("java:S5960") -@RequiredArgsConstructor -public class ConnectorRemote { - - @Getter - private final ConnectorRemoteConfig config; - - private final ObjectMapper objectMapper = JacksonJsonLd.createObjectMapper(); - public final Duration timeout = Duration.ofSeconds(60); - private final JsonLd jsonLd = new TitaniumJsonLd(new ConsoleMonitor()); - - public void createAsset(String assetId, Map dataAddressProperties) { - var requestBody = createObjectBuilder() - .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) - .add("asset", createObjectBuilder() - .add(ID, assetId) - .add("properties", createObjectBuilder() - .add("description", "description"))) - .add("dataAddress", createObjectBuilder(dataAddressProperties)) - .build(); - - prepareManagementApiCall() - .contentType(JSON) - .body(requestBody) - .when() - .post("/v2/assets") - .then() - .statusCode(200) - .contentType(JSON); - } - - public String createPolicy(JsonObject policyJsonObject) { - var requestBody = createObjectBuilder() - .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) - .add(TYPE, EDC_NAMESPACE + "PolicyDefinition") - .add(EDC_NAMESPACE + "policy", policyJsonObject) - .build(); - - return prepareManagementApiCall() - .contentType(JSON) - .body(requestBody) - .when() - .post("/v2/policydefinitions") - .then() - .statusCode(200) - .contentType(JSON) - .extract().jsonPath().getString(ID); - } - - public void createContractDefinition( - String assetId, - String contractDefinitionId, - String accessPolicyId, - String contractPolicyId) { - var requestBody = createObjectBuilder() - .add(ID, contractDefinitionId) - .add(TYPE, EDC_NAMESPACE + "ContractDefinition") - .add(EDC_NAMESPACE + "accessPolicyId", accessPolicyId) - .add(EDC_NAMESPACE + "contractPolicyId", contractPolicyId) - .add(EDC_NAMESPACE + "assetsSelector", Json.createArrayBuilder() - .add(createObjectBuilder() - .add(TYPE, "CriterionDto") - .add(EDC_NAMESPACE + "operandLeft", EDC_NAMESPACE + "id") - .add(EDC_NAMESPACE + "operator", "=") - .add(EDC_NAMESPACE + "operandRight", assetId) - .build()) - .build()) - .build(); - - prepareManagementApiCall() - .contentType(JSON) - .body(requestBody) - .when() - .post("/v2/contractdefinitions") - .then() - .statusCode(200) - .contentType(JSON); - } - - public JsonArray getCatalogDatasets(String providerProtocolApiUrl) { - var datasetReference = new AtomicReference(); - var requestBody = createObjectBuilder() - .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) - .add(TYPE, EDC_NAMESPACE + "CatalogRequest") - .add(EDC_NAMESPACE + "counterPartyAddress", providerProtocolApiUrl) - .add(EDC_NAMESPACE + "protocol", "dataspace-protocol-http") - .build(); - - await().atMost(timeout).untilAsserted(() -> { - var response = prepareManagementApiCall() - .contentType(JSON) - .when() - .body(requestBody) - .post("/v2/catalog/request") - .then() - .statusCode(200) - .extract().body().asString(); - - var responseBody = objectMapper.readValue(response, JsonObject.class); - - var catalog = jsonLd.expand(responseBody).orElseThrow(this::throwFailure); - - var datasets = catalog.getJsonArray(DCAT_DATASET_ATTRIBUTE); - assertThat(datasets).isNotEmpty(); - - datasetReference.set(datasets); - }); - - return datasetReference.get(); - } - - public JsonObject getDatasetForAsset(String assetId, String providerProtocolApiUrl) { - var datasets = getCatalogDatasets(providerProtocolApiUrl); - return datasets.stream() - .map(JsonValue::asJsonObject) - .filter(it -> assetId.equals(getDatasetContractId(it).assetIdPart())) - .findFirst() - .orElseThrow(() -> new EdcException("No dataset for asset %s in the catalog".formatted(assetId))); - } - - public String negotiateContract( - String providerParticipantId, - String providerProtocolApiUrl, - String offerId, - String assetId, - JsonObject policy) { - var requestBody = createObjectBuilder() - .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) - .add(TYPE, EDC_NAMESPACE + "ContractRequest") - .add(EDC_NAMESPACE + "consumerId", config.getParticipantId()) - .add(EDC_NAMESPACE + "providerId", providerParticipantId) - .add(EDC_NAMESPACE + "connectorAddress", providerProtocolApiUrl) - .add(EDC_NAMESPACE + "protocol", "dataspace-protocol-http") - .add(EDC_NAMESPACE + "offer", createObjectBuilder() - .add(EDC_NAMESPACE + "offerId", offerId) - .add(EDC_NAMESPACE + "assetId", assetId) - .add(EDC_NAMESPACE + "policy", jsonLd.compact(policy).orElseThrow(this::throwFailure)) - ) - .build(); - - var negotiationId = prepareManagementApiCall() - .contentType(JSON) - .body(requestBody) - .when() - .post("/v2/contractnegotiations") - .then() - .statusCode(200) - .extract().body().jsonPath().getString(ID); - - await().atMost(timeout).untilAsserted(() -> { - var state = getContractNegotiationState(negotiationId); - assertThat(state).isEqualTo(FINALIZED.name()); - }); - - return getContractAgreementId(negotiationId); - } - - public String getContractAgreementId(String negotiationId) { - var contractAgreementId = new AtomicReference(); - - await().atMost(timeout).untilAsserted(() -> { - var agreementId = getContractNegotiationField(negotiationId); - assertThat(agreementId).isNotNull().isInstanceOf(String.class); - - contractAgreementId.set(agreementId); - }); - - var id = contractAgreementId.get(); - assertThat(id).isNotEmpty(); - return id; - } - - private String getContractNegotiationField(String negotiationId) { - return prepareManagementApiCall() - .contentType(JSON) - .when() - .get("/v2/contractnegotiations/{id}", negotiationId) - .then() - .statusCode(200) - .extract().body().jsonPath() - .getString("'edc:contractAgreementId'"); - } - - public String getContractNegotiationState(String id) { - return prepareManagementApiCall() - .contentType(JSON) - .when() - .get("/v2/contractnegotiations/{id}/state", id) - .then() - .statusCode(200) - .extract().body().jsonPath().getString("'edc:state'"); - } - - public String getParticipantId() { - return config.getParticipantId(); - } - - public String initiateTransfer( - String contractAgreementId, - String assetId, - String providerProtocolApiUrl, - JsonObject destination) { - var requestBody = createObjectBuilder() - .add(TYPE, EDC_NAMESPACE + "TransferRequest") - .add(EDC_NAMESPACE + "protocol", "dataspace-protocol-http") - .add(EDC_NAMESPACE + "connectorAddress", providerProtocolApiUrl) - .add(EDC_NAMESPACE + "connectorId", config.getParticipantId()) - .add(EDC_NAMESPACE + "assetId", assetId) - .add(EDC_NAMESPACE + "dataDestination", destination) - .add(EDC_NAMESPACE + "contractId", contractAgreementId) - .add(EDC_NAMESPACE + "privateProperties", Json.createObjectBuilder().build()) - .add(EDC_NAMESPACE + "managedResources", false) - .build(); - - return prepareManagementApiCall() - .contentType(JSON) - .body(requestBody) - .when() - .post("/v2/transferprocesses") - .then() - .statusCode(200) - .extract().body().jsonPath().getString(ID); - } - - public String consumeOffer( - String providerId, - String providerProtocolApiUrl, - String assetId, - JsonObject destination) { - var dataset = getDatasetForAsset(assetId, providerProtocolApiUrl); - var contractId = getDatasetContractId(dataset); - var policy = dataset.getJsonArray(ODRL_POLICY_ATTRIBUTE).get(0).asJsonObject(); - - var contractAgreementId = negotiateContract( - providerId, - providerProtocolApiUrl, - contractId.toString(), - contractId.assetIdPart(), - policy); - - var transferProcessId = initiateTransfer( - contractAgreementId, - assetId, - providerProtocolApiUrl, - destination); - - assertThat(transferProcessId).isNotNull(); - return transferProcessId; - } - - public String getTransferProcessState(String id) { - return prepareManagementApiCall() - .contentType(JSON) - .when() - .get("/v2/transferprocesses/{id}/state", id) - .then() - .statusCode(200) - .extract().body().jsonPath().getString("'edc:state'"); - } - - public void createDataOffer( - String assetId, - String targetUrl - ) { - Map dataSource = Map.of( - EDC_NAMESPACE + "type", "HttpData", - EDC_NAMESPACE + "baseUrl", targetUrl, - EDC_NAMESPACE + "proxyQueryParams", "true" - ); - - var policy = createObjectBuilder() - .add(TYPE, "use") - .build(); - - var contractDefinitionId = UUID.randomUUID().toString(); - createAsset(assetId, dataSource); - var noConstraintPolicyId = createPolicy(policy); - createContractDefinition( - assetId, - contractDefinitionId, - noConstraintPolicyId, - noConstraintPolicyId); - } - - public RequestSpecification prepareManagementApiCall() { - var apiUrl = config.getManagementApiUrl(); - var request = given().baseUri(apiUrl); - - var header = config.getManagementApiAuthHeaderFactory().get(); - if (header != null) { - request = request.header(new Header(header.getLeft(), header.getRight())); - } - - return request; - } - - - public ContractId getDatasetContractId(JsonObject dataset) { - var id = dataset.getJsonArray(ODRL_POLICY_ATTRIBUTE).get(0).asJsonObject().getString(ID); - return ContractId.parseId(id).orElseThrow(this::throwFailure); - } - - private RuntimeException throwFailure(Failure failure) { - return new IllegalStateException(failure.getFailureDetail()); - } -} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorBootConfig.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorBootConfig.java new file mode 100644 index 000000000..3aef71ee7 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorBootConfig.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + * + */ + +package de.sovity.edc.extension.e2e.connector.config; + +import de.sovity.edc.utils.config.model.ConfigProp; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Singular; + +import java.util.HashMap; +import java.util.Map; + + +/** + * Config before EDC has been started. + *

+ * This does not include all config properties, as the EDC will do defaulting on startup. + */ +@Getter +@Builder(toBuilder = true) +@AllArgsConstructor +public class ConnectorBootConfig { + @Singular("property") + private Map properties; + + @Singular("property") + private Map additionalRawProperties; + + public Map asMap() { + var merged = new HashMap(); + properties.forEach((prop, value) -> merged.put(prop.getProperty(), value)); + merged.putAll(additionalRawProperties); + return merged; + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorConfig.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorConfig.java deleted file mode 100644 index 25d1dd7fa..000000000 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorConfig.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - init - * - */ - -package de.sovity.edc.extension.e2e.connector.config; - -import de.sovity.edc.utils.config.ConfigProps; -import de.sovity.edc.utils.config.ConfigUtils; -import de.sovity.edc.utils.config.model.ConfigProp; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; -import org.apache.commons.lang3.tuple.Pair; - -import java.util.Map; -import java.util.function.Supplier; - - -@Builder -@AllArgsConstructor -public class ConnectorConfig { - /** - * Connector Properties after applying defaults from {@link ConfigProps} - */ - @Getter - @Setter - private Map properties; - - private Supplier> managementApiAuthHeaderFactory; - - public Supplier> getManagementApiAuthHeaderFactory() { - if (managementApiAuthHeaderFactory == null) { - return () -> Pair.of("X-Api-Key", ConfigUtils.getManagementApiKey(properties)); - } - return managementApiAuthHeaderFactory; - } - - public ConnectorConfig setProperty(ConfigProp property, String value) { - properties.put(property.getProperty(), value); - return this; - } - - public ConnectorConfig setProperty(String property, String value) { - properties.put(property, value); - return this; - } - - public String getDefaultApiUrl() { - return ConfigUtils.getDefaultApiUrl(properties); - } - - public String getManagementApiUrl() { - return ConfigUtils.getManagementApiUrl(properties); - } - - public String getManagementApiKey() { - return ConfigUtils.getManagementApiKey(properties); - } - - public String getProtocolApiUrl() { - return ConfigUtils.getProtocolApiUrl(properties); - } - - public String getPublicApiUrl() { - return ConfigUtils.getPublicApiUrl(properties); - } - - public String getParticipantId() { - return ConfigProps.EDC_PARTICIPANT_ID.getRaw(properties); - } -} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorConfigFactory.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorConfigFactory.java deleted file mode 100644 index 827157bb6..000000000 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorConfigFactory.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - init - * - */ - -package de.sovity.edc.extension.e2e.connector.config; - -import de.sovity.edc.extension.e2e.db.TestDatabase; -import de.sovity.edc.utils.config.ConfigProps; -import de.sovity.edc.utils.config.ConfigService; -import de.sovity.edc.utils.config.model.ConfigProp; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import lombok.val; - -import java.io.IOException; -import java.net.ServerSocket; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; -import java.util.UUID; - -import static org.eclipse.edc.junit.testfixtures.TestUtils.MAX_TCP_PORT; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class ConnectorConfigFactory { - - private static final Random RANDOM = new Random(); - - public static ConnectorConfig forTestDatabase( - String participantId, - TestDatabase testDatabase - ) { - return forTestDatabase(participantId, testDatabase, Map.of()); - } - - public static ConnectorConfig forTestDatabase( - String participantId, - TestDatabase testDatabase, - Map overrides - ) { - val firstPort = getFreePortRange(5); - - // The initialization of the Map is split into several statements - // due to the parameter limit of Map.of(...) - var propertiesInput = new HashMap<>(Map.of( - ConfigProps.MY_EDC_NETWORK_TYPE, ConfigProps.NetworkType.UNIT_TEST, - ConfigProps.MY_EDC_FIRST_PORT, String.valueOf(firstPort), - ConfigProps.EDC_API_AUTH_KEY, "api-key-%s".formatted(UUID.randomUUID().toString()), - ConfigProps.MY_EDC_C2C_IAM_TYPE, "mock-iam", - ConfigProps.MY_EDC_PARTICIPANT_ID, participantId - )); - - propertiesInput.putAll(Map.of( - ConfigProps.MY_EDC_JDBC_URL, testDatabase.getJdbcCredentials().jdbcUrl(), - ConfigProps.MY_EDC_JDBC_USER, testDatabase.getJdbcCredentials().jdbcUser(), - ConfigProps.MY_EDC_JDBC_PASSWORD, testDatabase.getJdbcCredentials().jdbcPassword(), - ConfigProps.EDC_FLYWAY_CLEAN_ENABLE, "true", - ConfigProps.EDC_FLYWAY_CLEAN, "true" - )); - - propertiesInput.putAll(Map.of( - ConfigProps.MY_EDC_TITLE, "Connector Title %s".formatted(participantId), - ConfigProps.MY_EDC_DESCRIPTION, "Connector Description %s".formatted(participantId), - ConfigProps.MY_EDC_CURATOR_URL, "http://curator.%s".formatted(participantId), - ConfigProps.MY_EDC_CURATOR_NAME, "Curator Name %s".formatted(participantId), - ConfigProps.MY_EDC_MAINTAINER_URL, "http://maintainer.%s".formatted(participantId), - ConfigProps.MY_EDC_MAINTAINER_NAME, "Maintainer Name %s".formatted(participantId) - )); - - propertiesInput.putAll(overrides); - - var properties = ConfigService.applyDefaults(propertiesInput, ConfigProps.ALL_CE_PROPS); - - return ConnectorConfig.builder() - .properties(properties) - .build(); - } - - public static synchronized int getFreePortRange(int size) { - // pick a random in a reasonable range - int firstPort = RANDOM.nextInt(10_000, 50_000); - - int currentPort = firstPort; - do { - if (canUsePort(currentPort)) { - currentPort++; - } else { - firstPort = currentPort++; - } - } while (currentPort <= firstPort + size); - - return firstPort; - } - - private static boolean canUsePort(int port) { - - if (port <= 0 || port >= MAX_TCP_PORT) { - throw new IllegalArgumentException("Lower bound must be > 0 and < " + MAX_TCP_PORT + " and be < upperBound"); - } - - try (ServerSocket serverSocket = new ServerSocket(port)) { - serverSocket.setReuseAddress(true); - return true; - } catch (IOException e) { - return false; - } - } -} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/DatasourceConfigUtils.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/DatasourceConfigUtils.java deleted file mode 100644 index 47b822453..000000000 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/DatasourceConfigUtils.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - init - * - */ - -package de.sovity.edc.extension.e2e.connector.config; - -import de.sovity.edc.extension.e2e.db.JdbcCredentials; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class DatasourceConfigUtils { - private static final List DATASOURCE_NAMES = List.of( - "default", - "asset", - "contractdefinition", - "contractnegotiation", - "policy", - "transferprocess", - "dataplaneinstance" - ); - - public static Map configureDatasources(JdbcCredentials credentials) { - var properties = new HashMap(); - properties.put("edc.flyway.clean.enable", "true"); - properties.put("edc.flyway.clean", "true"); - DATASOURCE_NAMES.forEach(name -> { - properties.put("edc.datasource.%s.name".formatted(name), name); - properties.put("edc.datasource.%s.url".formatted(name), credentials.jdbcUrl()); - properties.put("edc.datasource.%s.user".formatted(name), credentials.jdbcUser()); - properties.put("edc.datasource.%s.password".formatted(name), credentials.jdbcPassword()); - }); - return properties; - } - -} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/PortUtils.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/PortUtils.java new file mode 100644 index 000000000..dbc7e233d --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/PortUtils.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + * + */ + +package de.sovity.edc.extension.e2e.connector.config; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.io.IOException; +import java.net.ServerSocket; +import java.util.Random; + +import static org.eclipse.edc.util.io.Ports.MAX_TCP_PORT; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class PortUtils { + + private static final Random RANDOM = new Random(); + + public static synchronized int getFreePortRange(int size) { + // pick a random in a reasonable range + int firstPort = RANDOM.nextInt(10_000, 50_000); + + int currentPort = firstPort; + do { + if (canUsePort(currentPort)) { + currentPort++; + } else { + firstPort = currentPort++; + } + } while (currentPort <= firstPort + size); + + return firstPort; + } + + private static boolean canUsePort(int port) { + + if (port <= 0 || port >= MAX_TCP_PORT) { + throw new IllegalArgumentException("Lower bound must be > 0 and < " + MAX_TCP_PORT + " and be < upperBound"); + } + + try (ServerSocket serverSocket = new ServerSocket(port)) { + serverSocket.setReuseAddress(true); + return true; + } catch (IOException e) { + return false; + } + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eScenario.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/api_wrapper/E2eTestScenario.java similarity index 85% rename from utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eScenario.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/api_wrapper/E2eTestScenario.java index 24e4335e6..d4541ee03 100644 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eScenario.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/api_wrapper/E2eTestScenario.java @@ -12,7 +12,7 @@ * */ -package de.sovity.edc.extension.e2e.extension; +package de.sovity.edc.extension.e2e.connector.remotes.api_wrapper; import de.sovity.edc.client.EdcClient; import de.sovity.edc.client.gen.model.ContractDefinitionRequest; @@ -38,52 +38,44 @@ import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.client.gen.model.UiPolicyLiteral; import de.sovity.edc.client.gen.model.UiPolicyLiteralType; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; import de.sovity.edc.utils.jsonld.vocab.Prop; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NonNull; import lombok.val; import org.awaitility.Awaitility; -import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; import org.jetbrains.annotations.NotNull; import org.mockserver.integration.ClientAndServer; import org.mockserver.model.HttpRequest; import org.mockserver.model.HttpResponse; -import java.time.Duration; import java.time.OffsetDateTime; import java.util.List; +import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; import static de.sovity.edc.client.gen.model.TransferProcessSimplifiedState.RUNNING; -import static java.time.Duration.ofSeconds; import static org.assertj.core.api.Assertions.assertThat; -public class E2eScenario { - private final ConnectorConfig consumerConfig; - private final ConnectorConfig providerConfig; - private final ClientAndServer mockServer; - private final Duration timeout = ofSeconds(10); - - private EdcClient consumerClient; - private EdcClient providerClient; +@Builder +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class E2eTestScenario { + @NonNull + private final E2eTestScenarioConfig config; - public E2eScenario(ConnectorConfig consumerConfig, ConnectorConfig providerConfig, ClientAndServer mockServer) { - this.consumerConfig = consumerConfig; - this.providerConfig = providerConfig; - this.mockServer = mockServer; + @NonNull + private final EdcClient consumerClient; - consumerClient = EdcClient.builder() - .managementApiUrl(consumerConfig.getManagementApiUrl()) - .managementApiKey(consumerConfig.getManagementApiKey()) - .build(); + @NonNull + private final EdcClient providerClient; - providerClient = EdcClient.builder() - .managementApiUrl(providerConfig.getManagementApiUrl()) - .managementApiKey(providerConfig.getManagementApiKey()) - .build(); - } + @NonNull + private final ClientAndServer mockServer; - private final AtomicInteger assetCounter = new AtomicInteger(0); + private final Random random = new Random(); public String createAsset() { val dummyDataSource = UiDataSource.builder() @@ -97,7 +89,7 @@ public String createAsset() { } private @NotNull String nextAssetId() { - return "asset-" + assetCounter.getAndIncrement(); + return "asset-" + random.nextInt(); } public String createAsset(String id, UiDataSourceHttpData uiDataSourceHttpData) { @@ -171,8 +163,9 @@ public IdResponseDto createContractDefinition(String policyId, String assetId) { } public UiContractNegotiation negotiateAssetAndAwait(String assetId) { - val connectorEndpoint = providerConfig.getProtocolApiUrl(); - val offers = consumerClient.uiApi().getCatalogPageDataOffers(connectorEndpoint); + val connectorEndpoint = config.getProviderProtocolApiUrl(); + val participantId = config.getProviderParticipantId(); + val offers = consumerClient.uiApi().getCatalogPageDataOffers(participantId, connectorEndpoint); val offersContainingContract = offers.stream() .filter(offer -> offer.getAsset().getAssetId().equals(assetId)) @@ -183,8 +176,8 @@ public UiContractNegotiation negotiateAssetAndAwait(String assetId) { val firstContractOffer = offersContainingContract.get(0).getContractOffers().get(0); val dataOffer = offersContainingContract.get(0); var negotiationRequest = ContractNegotiationRequest.builder() + .counterPartyId(dataOffer.getParticipantId()) .counterPartyAddress(dataOffer.getEndpoint()) - .counterPartyParticipantId(dataOffer.getParticipantId()) .assetId(dataOffer.getAsset().getAssetId()) .contractOfferId(firstContractOffer.getContractOfferId()) .policyJsonLd(firstContractOffer.getPolicy().getPolicyJsonLd()) @@ -192,7 +185,7 @@ public UiContractNegotiation negotiateAssetAndAwait(String assetId) { val negotiation = consumerClient.uiApi().initiateContractNegotiation(negotiationRequest); - val neg = Awaitility.await().atMost(timeout).until( + val neg = Awaitility.await().atMost(config.getTimeout()).until( () -> consumerClient.uiApi().getContractNegotiation(negotiation.getContractNegotiationId()), it -> it.getState().getSimplifiedState() != ContractNegotiationSimplifiedState.IN_PROGRESS ); @@ -252,7 +245,7 @@ public String transferAndAwait(InitiateCustomTransferRequest transferRequest) { } public void awaitTransferCompletion(String transferId) { - Awaitility.await().atMost(timeout).until( + Awaitility.await().atMost(config.getTimeout()).until( () -> consumerClient.uiApi() .getTransferHistoryPage() .getTransferEntries() diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/api_wrapper/E2eTestScenarioConfig.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/api_wrapper/E2eTestScenarioConfig.java new file mode 100644 index 000000000..24b2c4191 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/api_wrapper/E2eTestScenarioConfig.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + * + */ + +package de.sovity.edc.extension.e2e.connector.remotes.api_wrapper; + +import de.sovity.edc.utils.config.ConfigUtils; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NonNull; +import org.eclipse.edc.spi.system.configuration.Config; + +import java.time.Duration; + +import static java.time.Duration.ofSeconds; + + +@Getter +@Builder +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class E2eTestScenarioConfig { + @NonNull + private final String providerParticipantId; + + @NonNull + private final String providerProtocolApiUrl; + + @Builder.Default + private final Duration timeout = ofSeconds(10); + + public static E2eTestScenarioConfig forProviderConfig(Config providerConfig) { + return builder() + .providerParticipantId(ConfigUtils.getParticipantId(providerConfig)) + .providerProtocolApiUrl(ConfigUtils.getProtocolApiUrl(providerConfig)) + .build(); + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/MockedAsset.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/api_wrapper/MockedAsset.java similarity index 91% rename from utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/MockedAsset.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/api_wrapper/MockedAsset.java index 45609e48f..f84fa35b1 100644 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/MockedAsset.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/api_wrapper/MockedAsset.java @@ -12,7 +12,7 @@ * */ -package de.sovity.edc.extension.e2e.extension; +package de.sovity.edc.extension.e2e.connector.remotes.api_wrapper; import java.util.concurrent.atomic.AtomicInteger; diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/DataTransferTestUtil.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/management_api/DataTransferTestUtil.java similarity index 94% rename from utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/DataTransferTestUtil.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/management_api/DataTransferTestUtil.java index 320b6a05e..b5f7ab6d2 100644 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/DataTransferTestUtil.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/management_api/DataTransferTestUtil.java @@ -12,7 +12,7 @@ * */ -package de.sovity.edc.extension.e2e.connector; +package de.sovity.edc.extension.e2e.connector.remotes.management_api; import jakarta.json.JsonObject; import lombok.AccessLevel; @@ -27,7 +27,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; -import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; +import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE; @SuppressWarnings("java:S5960") @NoArgsConstructor(access = AccessLevel.PRIVATE) diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/management_api/ManagementApiConnectorRemote.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/management_api/ManagementApiConnectorRemote.java new file mode 100644 index 000000000..6017f6382 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/management_api/ManagementApiConnectorRemote.java @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + * + */ + +package de.sovity.edc.extension.e2e.connector.remotes.management_api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.http.Header; +import io.restassured.specification.RequestSpecification; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.eclipse.edc.connector.controlplane.contract.spi.ContractOfferId; +import org.eclipse.edc.jsonld.TitaniumJsonLd; +import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.jsonld.util.JacksonJsonLd; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.monitor.ConsoleMonitor; +import org.eclipse.edc.spi.result.Failure; + +import java.time.Duration; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; + +import static io.restassured.RestAssured.given; +import static io.restassured.http.ContentType.JSON; +import static jakarta.json.Json.createObjectBuilder; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; +import static org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiationStates.FINALIZED; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VOCAB; +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_DATASET_ATTRIBUTE; +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_POLICY_ATTRIBUTE; +import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE; +import static org.eclipse.edc.spi.constants.CoreConstants.EDC_PREFIX; + +@SuppressWarnings("java:S5960") +@RequiredArgsConstructor +public class ManagementApiConnectorRemote { + + @Getter + private final ManagementApiConnectorRemoteConfig config; + + private final ObjectMapper objectMapper = JacksonJsonLd.createObjectMapper(); + public final Duration timeout = Duration.ofSeconds(60); + private final JsonLd jsonLd = new TitaniumJsonLd(new ConsoleMonitor()); + + public void createAsset(String assetId, Map dataAddressProperties) { + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add("@type", Json.createValue("https://w3id.org/edc/v0.0.1/ns/Asset")) + .add("@id", Json.createValue(assetId)) + .add("properties", createObjectBuilder() + .add("description", "description")) + .add("dataAddress", createObjectBuilder(dataAddressProperties)) + .build(); + + prepareManagementApiCall() + .contentType(JSON) + .body(requestBody) + .when() + .post("/v3/assets") + .then() + .statusCode(200) + .contentType(JSON); + } + + public String createPolicy(JsonObject policyJsonObject) { + var requestBody = + createObjectBuilder() + .add(CONTEXT, createObjectBuilder() + .add("edc", EDC_NAMESPACE) + .build()) + .add(TYPE, "edc:PolicyDefinition") + .add("policy", policyJsonObject) + .build(); + + return prepareManagementApiCall() + .contentType(JSON) + .body(requestBody) + .when() + .post("/v3/policydefinitions") + .then() + .statusCode(200) + .contentType(JSON) + .extract().jsonPath().getString(ID); + } + + public void createContractDefinition( + String assetId, + String contractDefinitionId, + String accessPolicyId, + String contractPolicyId + ) { + var requestBody = createObjectBuilder() + .add(ID, contractDefinitionId) + .add(TYPE, EDC_NAMESPACE + "ContractDefinition") + .add(EDC_NAMESPACE + "accessPolicyId", accessPolicyId) + .add(EDC_NAMESPACE + "contractPolicyId", contractPolicyId) + .add(EDC_NAMESPACE + "assetsSelector", Json.createArrayBuilder() + .add(createObjectBuilder() + .add(TYPE, "CriterionDto") + .add(EDC_NAMESPACE + "operandLeft", EDC_NAMESPACE + "id") + .add(EDC_NAMESPACE + "operator", "=") + .add(EDC_NAMESPACE + "operandRight", assetId) + .build()) + .build()) + .build(); + + prepareManagementApiCall() + .contentType(JSON) + .body(requestBody) + .when() + .post("/v3/contractdefinitions") + .then() + .statusCode(200) + .contentType(JSON); + } + + public JsonArray getCatalogDatasets(String providerProtocolApiUrl) { + var datasetReference = new AtomicReference(); + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add(TYPE, EDC_NAMESPACE + "CatalogRequest") + .add(EDC_NAMESPACE + "counterPartyAddress", providerProtocolApiUrl) + .add(EDC_NAMESPACE + "protocol", "dataspace-protocol-http") + .build(); + + await().atMost(timeout).untilAsserted(() -> { + var response = prepareManagementApiCall() + .contentType(JSON) + .when() + .body(requestBody) + .post("/v3/catalog/request") + .then() + .statusCode(200) + .extract().body().asString(); + + var responseBody = objectMapper.readValue(response, JsonObject.class); + + var catalog = jsonLd.expand(responseBody).orElseThrow(this::throwFailure); + + var datasets = catalog.getJsonArray(DCAT_DATASET_ATTRIBUTE); + assertThat(datasets).isNotEmpty(); + + datasetReference.set(datasets); + }); + + return datasetReference.get(); + } + + public JsonObject getDatasetForAsset(String assetId, String providerProtocolApiUrl) { + var datasets = getCatalogDatasets(providerProtocolApiUrl); + return datasets.stream() + .map(JsonValue::asJsonObject) + .filter(it -> assetId.equals(getDatasetContractId(it).assetIdPart())) + .findFirst() + .orElseThrow(() -> new EdcException("No dataset for asset %s in the catalog".formatted(assetId))); + } + + public String negotiateContract( + String providerParticipantId, + String providerProtocolApiUrl, + String offerId, + String assetId, + JsonObject policy + ) { + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add(TYPE, "ContractRequest") + .add("counterPartyAddress", providerProtocolApiUrl) + .add("providerId", providerParticipantId) + .add("policy", policy) + .add("protocol", "dataspace-protocol-http") + .build(); + + var negotiationId = prepareManagementApiCall() + .contentType(JSON) + .body(requestBody) + .when() + .post("/v3/contractnegotiations") + .then() + .statusCode(200) + .extract().body().jsonPath().getString(ID); + + await().atMost(timeout).untilAsserted(() -> { + var state = getContractNegotiationState(negotiationId); + assertThat(state).isEqualTo(FINALIZED.name()); + }); + + return getContractAgreementId(negotiationId); + } + + public String getContractAgreementId(String negotiationId) { + var contractAgreementId = new AtomicReference(); + + await().atMost(timeout).untilAsserted(() -> { + var agreementId = getContractNegotiationField(negotiationId); + assertThat(agreementId).isNotNull().isInstanceOf(String.class); + + contractAgreementId.set(agreementId); + }); + + var id = contractAgreementId.get(); + assertThat(id).isNotEmpty(); + return id; + } + + private String getContractNegotiationField(String negotiationId) { + return prepareManagementApiCall() + .contentType(JSON) + .when() + .get("/v3/contractnegotiations/{id}", negotiationId) + .then() + .statusCode(200) + .extract().body().jsonPath() + .getString("contractAgreementId"); + } + + public String getContractNegotiationState(String id) { + return prepareManagementApiCall() + .contentType(JSON) + .when() + .get("/v3/contractnegotiations/{id}/state", id) + .then() + .statusCode(200) + .extract().body().jsonPath().getString("state"); + } + + public String getParticipantId() { + return config.getParticipantId(); + } + + public String initiateTransfer( + String contractAgreementId, + String assetId, + String providerProtocolApiUrl, + JsonObject destination + ) { + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder() + .add(VOCAB, EDC_NAMESPACE)) + .add(TYPE, "TransferRequest") + .add("contractId", contractAgreementId) + .add("counterPartyAddress", providerProtocolApiUrl) + .add("protocol", "dataspace-protocol-http") + .add("transferType", "HttpData-PUSH") + .add("assetId", assetId) + .add("dataDestination", destination) + .add("contractId", contractAgreementId) + .add("privateProperties", createObjectBuilder().build()) + .build(); + + return prepareManagementApiCall() + .contentType(JSON) + .body(requestBody) + .when() + .post("/v3/transferprocesses") + .then() + .statusCode(200) + .extract().body().jsonPath().getString(ID); + } + + public String consumeOffer( + String providerId, + String providerProtocolApiUrl, + String assetId, + JsonObject destination + ) { + var dataset = getDatasetForAsset(assetId, providerProtocolApiUrl); + var contractId = getDatasetContractId(dataset); + var policy = dataset.getJsonArray(ODRL_POLICY_ATTRIBUTE).get(0).asJsonObject(); + + val editedPolicy = Json.createObjectBuilder() + .add(CONTEXT, "http://www.w3.org/ns/odrl.jsonld") + .add(TYPE, "odrl:Offer") + .add(ID, policy.get(ID)) + .add("assigner", providerId) + .add("permission", policy.get("http://www.w3.org/ns/odrl/2/permission")) + .add("prohibition", policy.get("http://www.w3.org/ns/odrl/2/prohibition")) + .add("obligation", policy.get("http://www.w3.org/ns/odrl/2/obligation")) + .add("target", assetId) + .build(); + + var contractAgreementId = negotiateContract( + providerId, + providerProtocolApiUrl, + contractId.toString(), + contractId.assetIdPart(), + editedPolicy); + + var transferProcessId = initiateTransfer( + contractAgreementId, + assetId, + providerProtocolApiUrl, + destination); + + assertThat(transferProcessId).isNotNull(); + return transferProcessId; + } + + public void createDataOffer( + String assetId, + String targetUrl + ) { + Map dataSource = Map.of( + EDC_NAMESPACE + "type", "HttpData", + EDC_NAMESPACE + "baseUrl", targetUrl, + EDC_NAMESPACE + "proxyQueryParams", "true" + ); + + var policy = createObjectBuilder() + .add(CONTEXT, "http://www.w3.org/ns/odrl.jsonld") + .add(TYPE, "Set") + .build(); + + var contractDefinitionId = UUID.randomUUID().toString(); + createAsset(assetId, dataSource); + var noConstraintPolicyId = createPolicy(policy); + createContractDefinition( + assetId, + contractDefinitionId, + noConstraintPolicyId, + noConstraintPolicyId); + } + + public RequestSpecification prepareManagementApiCall() { + var apiUrl = config.getManagementApiUrl(); + var request = given().baseUri(apiUrl); + + var header = config.getManagementApiAuthHeaderFactory().get(); + if (header != null) { + request = request.header(new Header(header.getLeft(), header.getRight())); + } + + return request; + } + + public ContractOfferId getDatasetContractId(JsonObject dataset) { + var id = dataset.getJsonArray(ODRL_POLICY_ATTRIBUTE).get(0).asJsonObject().getString(ID); + return ContractOfferId.parseId(id).orElseThrow(this::throwFailure); + } + + private RuntimeException throwFailure(Failure failure) { + return new IllegalStateException(failure.getFailureDetail()); + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorRemoteConfig.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/management_api/ManagementApiConnectorRemoteConfig.java similarity index 54% rename from utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorRemoteConfig.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/management_api/ManagementApiConnectorRemoteConfig.java index a2d0acc50..f5ea98f40 100644 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorRemoteConfig.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/management_api/ManagementApiConnectorRemoteConfig.java @@ -12,14 +12,16 @@ * */ -package de.sovity.edc.extension.e2e.connector.config; +package de.sovity.edc.extension.e2e.connector.remotes.management_api; +import de.sovity.edc.utils.config.ConfigUtils; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NonNull; import org.apache.commons.lang3.tuple.Pair; +import org.eclipse.edc.spi.system.configuration.Config; import org.jetbrains.annotations.Nullable; import java.util.function.Supplier; @@ -28,7 +30,7 @@ @Getter @Builder @AllArgsConstructor(access = AccessLevel.PRIVATE) -public class ConnectorRemoteConfig { +public class ManagementApiConnectorRemoteConfig { @NonNull private final String participantId; @@ -47,14 +49,18 @@ public class ConnectorRemoteConfig { @NonNull private final String publicApiUrl; - public static ConnectorRemoteConfig fromConnectorConfig(ConnectorConfig connectorConfig) { + public static ManagementApiConnectorRemoteConfig forConnector( + Config config, + Supplier> managementApiAuthHeaderFactory + ) { + var configAfterEdcBoot = config.getEntries(); return builder() - .participantId(connectorConfig.getParticipantId()) - .managementApiUrl(connectorConfig.getManagementApiUrl()) - .managementApiAuthHeaderFactory(connectorConfig.getManagementApiAuthHeaderFactory()) - .protocolApiUrl(connectorConfig.getProtocolApiUrl()) - .publicApiUrl(connectorConfig.getPublicApiUrl()) - .defaultApiUrl(connectorConfig.getDefaultApiUrl()) + .participantId(ConfigUtils.getParticipantId(configAfterEdcBoot)) + .managementApiUrl(ConfigUtils.getManagementApiUrl(configAfterEdcBoot)) + .managementApiAuthHeaderFactory(managementApiAuthHeaderFactory) + .protocolApiUrl(ConfigUtils.getProtocolApiUrl(configAfterEdcBoot)) + .publicApiUrl(ConfigUtils.getPublicApiUrl(configAfterEdcBoot)) + .defaultApiUrl(ConfigUtils.getDefaultApiUrl(configAfterEdcBoot)) .build(); } } diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/MockDataAddressRemote.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/test_backend_controller/TestBackendRemote.java similarity index 78% rename from utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/MockDataAddressRemote.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/test_backend_controller/TestBackendRemote.java index 248fffd3f..1f1e5195f 100644 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/MockDataAddressRemote.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/remotes/test_backend_controller/TestBackendRemote.java @@ -12,18 +12,18 @@ * */ -package de.sovity.edc.extension.e2e.connector; +package de.sovity.edc.extension.e2e.connector.remotes.test_backend_controller; import jakarta.json.JsonObject; import lombok.RequiredArgsConstructor; import java.util.Map; -import static de.sovity.edc.extension.e2e.connector.DataTransferTestUtil.buildDataAddressJsonLd; -import static de.sovity.edc.extension.e2e.connector.DataTransferTestUtil.buildDataAddressProperties; +import static de.sovity.edc.extension.e2e.connector.remotes.management_api.DataTransferTestUtil.buildDataAddressJsonLd; +import static de.sovity.edc.extension.e2e.connector.remotes.management_api.DataTransferTestUtil.buildDataAddressProperties; @RequiredArgsConstructor -public class MockDataAddressRemote { +public class TestBackendRemote { private final String defaultApiUrl; public String getDataSinkUrl() { diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionDeferred.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionDeferred.java deleted file mode 100644 index 91096b7b8..000000000 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionDeferred.java +++ /dev/null @@ -1,36 +0,0 @@ -package de.sovity.edc.extension.e2e.db; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.experimental.Delegate; -import org.junit.jupiter.api.extension.AfterTestExecutionCallback; -import org.junit.jupiter.api.extension.BeforeAllCallback; -import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ParameterResolver; - -import java.util.Map; -import java.util.function.Supplier; - -@RequiredArgsConstructor -public class EdcRuntimeExtensionDeferred - implements BeforeAllCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver { - - private final String moduleName; - private final String logPrefix; - - private final Supplier> propertyFactory; - - @Delegate(types = { - BeforeTestExecutionCallback.class, - AfterTestExecutionCallback.class, - ParameterResolver.class - }) - @Getter - private EdcRuntimeExtensionFixed edcRuntimeExtensionFixed = null; - - @Override - public void beforeAll(ExtensionContext extensionContext) throws Exception { - edcRuntimeExtensionFixed = new EdcRuntimeExtensionFixed(moduleName, logPrefix, propertyFactory.get()); - } -} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionFixed.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionFixed.java deleted file mode 100644 index 495ba4a81..000000000 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionFixed.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2022 Microsoft Corporation - * - * 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: - * Microsoft Corporation - initial API and implementation - * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - improvements - * - */ - -package de.sovity.edc.extension.e2e.db; - -import org.eclipse.edc.junit.extensions.EdcExtension; -import org.eclipse.edc.junit.testfixtures.TestUtils; -import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.monitor.ConsoleMonitor; -import org.eclipse.edc.spi.monitor.Monitor; -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.extension.AfterTestExecutionCallback; -import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; -import org.junit.jupiter.api.extension.ExtensionContext; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Arrays; -import java.util.Locale; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.CountDownLatch; -import java.util.stream.Stream; - -import static java.lang.String.format; -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.eclipse.edc.boot.system.ExtensionLoader.loadMonitor; - -/** - * A JUnit extension for running an embedded EDC runtime as part of a test fixture. A custom gradle task printClasspath - * is used to determine the runtime classpath of the module to run. The runtime obtains a classpath determined by the - * Gradle build. - *

- * This extension attaches an EDC runtime to the {@link BeforeTestExecutionCallback} and - * {@link AfterTestExecutionCallback} lifecycle hooks. Parameter injection of runtime services is supported. - */ -public class EdcRuntimeExtensionFixed extends EdcExtension { - - private static final Monitor MONITOR = loadMonitor(); - - private final String moduleName; - private final String logPrefix; - private final Map properties; - private Thread runtimeThread; - - public EdcRuntimeExtensionFixed(String moduleName, String logPrefix, Map properties) { - this.moduleName = moduleName; - this.logPrefix = logPrefix; - this.properties = Map.copyOf(properties); - } - - @Override - public void beforeTestExecution(ExtensionContext extensionContext) throws Exception { - // Find the project root directory, moving up the directory tree - var root = TestUtils.findBuildRoot(); - - // Run a Gradle custom task to determine the runtime classpath of the module to run - String[] command = { - new File(root, TestUtils.GRADLE_WRAPPER).getCanonicalPath(), - "-q", - moduleName + ":printClasspath" - }; - Process exec = Runtime.getRuntime().exec(command); - var classpathString = new String(exec.getInputStream().readAllBytes()); - var errorOutput = new String(exec.getErrorStream().readAllBytes()); - if (exec.waitFor() != 0) { - throw new EdcException(format("Failed to run gradle command: [%s]. Output: %s %s", - String.join(" ", command), classpathString, errorOutput)); - } - - // Replace subproject JAR entries with subproject build directories in classpath. - // This ensures modified classes are picked up without needing to rebuild dependent JARs. - - var splitRegex = ":|\\s"; - if (System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("windows")) { - splitRegex = ";|\\s"; - } - - var classPathEntries = Arrays.stream(classpathString.split(splitRegex)) - .filter(s -> !s.isBlank()) - .flatMap(p -> resolveClassPathEntry(root, p)) - .toArray(URL[]::new); - - // Create a ClassLoader that only has the target module class path, and is not - // parented with the current ClassLoader. - var classLoader = URLClassLoader.newInstance(classPathEntries, ClassLoader.getSystemClassLoader()); - - // Temporarily inject system properties. - var savedProperties = (Properties) System.getProperties().clone(); - properties.forEach(System::setProperty); - - var latch = new CountDownLatch(1); - - runtimeThread = new Thread(() -> { - try { - - // Make the ClassLoader available to the ServiceLoader. - // This ensures the target module's extensions are discovered and loaded at runtime boot. - Thread.currentThread().setContextClassLoader(classLoader); - - // Boot EDC runtime. - super.beforeTestExecution(extensionContext); - - latch.countDown(); - } catch (Exception e) { - throw new EdcException(e); - } - }); - - MONITOR.info("Starting module " + moduleName); - // Start thread and wait for EDC to start up. - runtimeThread.start(); - - if (!latch.await(20, SECONDS)) { - throw new EdcException("Failed to start EDC runtime"); - } - - MONITOR.info("Module " + moduleName + " started"); - // Restore system properties. - System.setProperties(savedProperties); - } - - @Override - public void afterTestExecution(ExtensionContext context) throws Exception { - if (runtimeThread != null) { - runtimeThread.join(); - } - super.afterTestExecution(context); - } - - @Override - protected @NotNull Monitor createMonitor() { - // disable logs when "quiet" log level is set - if (System.getProperty("org.gradle.logging.level") != null) { - return new Monitor() { - }; - } else { - return new ConsoleMonitor(logPrefix, ConsoleMonitor.Level.DEBUG); - } - } - - /** - * Replace Gradle subproject JAR entries with subproject build directories in classpath. This ensures modified - * classes are picked up without needing to rebuild dependent JARs. - * - * @param root project root directory. - * @param classPathEntry class path entry to resolve. - * @return resolved class path entries for the input argument. - */ - private Stream resolveClassPathEntry(File root, String classPathEntry) { - try { - File f = new File(classPathEntry).getCanonicalFile(); - - // If class path entry is not a JAR under the root (i.e. a sub-project), do not transform it - boolean isUnderRoot = f.getCanonicalPath().startsWith(root.getCanonicalPath() + File.separator); - if (!classPathEntry.toLowerCase(Locale.ROOT).endsWith(".jar") || !isUnderRoot) { - var sanitizedClassPathEntry = classPathEntry.replace("build/resources/main", "src/main/resources"); - return Stream.of(new File(sanitizedClassPathEntry).toURI().toURL()); - } - - // Replace JAR entry with the resolved classes and resources folder - var buildDir = f.getParentFile().getParentFile(); - return Stream.of( - new File(buildDir, "/classes/java/main").toURI().toURL(), - new File(buildDir, "../src/main/resources").toURI().toURL() - ); - } catch (IOException e) { - throw new EdcException(e); - } - } -} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionWithTestDatabase.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionWithTestDatabase.java deleted file mode 100644 index eab4e8eea..000000000 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionWithTestDatabase.java +++ /dev/null @@ -1,82 +0,0 @@ -package de.sovity.edc.extension.e2e.db; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.experimental.Delegate; -import lombok.val; -import org.eclipse.edc.junit.extensions.EdcExtension; -import org.jooq.DSLContext; -import org.jooq.impl.DSL; -import org.junit.jupiter.api.extension.AfterAllCallback; -import org.junit.jupiter.api.extension.AfterTestExecutionCallback; -import org.junit.jupiter.api.extension.BeforeAllCallback; -import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.api.extension.ParameterResolutionException; -import org.junit.jupiter.api.extension.ParameterResolver; - -import java.util.Map; -import java.util.function.Function; - -@RequiredArgsConstructor -public class EdcRuntimeExtensionWithTestDatabase - implements BeforeAllCallback, AfterAllCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver { - - private final String moduleName; - private final String logPrefix; - - @Getter - @Delegate(types = {AfterAllCallback.class}) - private final TestDatabase testDatabase = new TestDatabaseViaTestcontainers(); - - private final Function> propertyFactory; - - @Delegate(types = { - BeforeTestExecutionCallback.class, - AfterTestExecutionCallback.class - }) - @Getter - private EdcRuntimeExtensionFixed edcRuntimeExtension = null; - - @Override - public void beforeAll(ExtensionContext extensionContext) throws Exception { - testDatabase.beforeAll(extensionContext); - edcRuntimeExtension = new EdcRuntimeExtensionFixed(moduleName, logPrefix, propertyFactory.apply(testDatabase)); - } - - @Override - public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) - throws ParameterResolutionException { - - val type = parameterContext.getParameter().getType(); - - if (DSLContext.class.equals(type)) { - return true; - } else if (EdcExtension.class.equals(type)) { - return true; - } - - return edcRuntimeExtension.supportsParameter(parameterContext, extensionContext); - } - - @Override - public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) - throws ParameterResolutionException { - - val type = parameterContext.getParameter().getType(); - - if (DSLContext.class.equals(type)) { - return getDslContext().dsl(); - } else if (EdcExtension.class.equals(type)) { - return edcRuntimeExtension; - } else { - return edcRuntimeExtension.resolveParameter(parameterContext, extensionContext); - } - } - - private synchronized DSLContext getDslContext() { - val credentials = testDatabase.getJdbcCredentials(); - return DSL.using(credentials.jdbcUrl(), credentials.jdbcUser(), credentials.jdbcPassword()); - } -} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/CeE2eTestExtensionConfigFactory.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/CeE2eTestExtensionConfigFactory.java deleted file mode 100644 index e096e2895..000000000 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/CeE2eTestExtensionConfigFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.extension.e2e.extension; - -import lombok.experimental.UtilityClass; - -@UtilityClass -public class CeE2eTestExtensionConfigFactory { - - public static E2eTestExtensionConfig defaultBuilder() { - return E2eTestExtensionConfig.builder().moduleName(":launchers:connectors:sovity-dev").build(); - } - - public static E2eTestExtensionConfig withModule(String module) { - return defaultBuilder().toBuilder().moduleName(module).build(); - } -} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eTestExtension.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eTestExtension.java deleted file mode 100644 index e33abddaa..000000000 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eTestExtension.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.extension.e2e.extension; - -import de.sovity.edc.client.EdcClient; -import de.sovity.edc.extension.e2e.connector.ConnectorRemote; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; -import de.sovity.edc.extension.utils.Lazy; -import lombok.val; -import org.junit.jupiter.api.extension.AfterAllCallback; -import org.junit.jupiter.api.extension.AfterTestExecutionCallback; -import org.junit.jupiter.api.extension.BeforeAllCallback; -import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ParameterContext; -import org.junit.jupiter.api.extension.ParameterResolutionException; -import org.junit.jupiter.api.extension.ParameterResolver; -import org.mockserver.integration.ClientAndServer; - -import java.util.List; -import java.util.stream.Stream; - -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorRemoteConfig.fromConnectorConfig; -import static org.eclipse.edc.junit.testfixtures.TestUtils.getFreePort; -import static org.mockserver.stop.Stop.stopQuietly; - -public class E2eTestExtension - implements BeforeAllCallback, AfterAllCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver { - - private E2eTestExtensionConfig config; - - private ConnectorConfig consumerConfig; - private final EdcRuntimeExtensionWithTestDatabase consumerExtension; - - private ConnectorConfig providerConfig; - private final EdcRuntimeExtensionWithTestDatabase providerExtension; - - private final List> partySupportedTypes = - List.of(ConnectorConfig.class, EdcClient.class, ConnectorRemote.class, ClientAndServer.class); - private final List> supportedTypes = Stream.concat(partySupportedTypes.stream(), Stream.of(E2eScenario.class)).toList(); - - private Lazy clientAndServer; - - public E2eTestExtension(String moduleName) { - this(E2eTestExtensionConfig.builder().moduleName(moduleName).build()); - } - - public E2eTestExtension( - E2eTestExtensionConfig config - ) { - this.config = config; - - consumerExtension = new EdcRuntimeExtensionWithTestDatabase( - config.getModuleName(), - config.getConsumerParticipantId(), - testDatabase -> { - consumerConfig = forTestDatabase(config.getConsumerParticipantId(), testDatabase); - - config.getConfigCustomizer().accept(consumerConfig); - config.getConsumerConfigCustomizer().accept(consumerConfig); - return consumerConfig.getProperties(); - } - ); - - providerExtension = new EdcRuntimeExtensionWithTestDatabase( - config.getModuleName(), - config.getProviderParticipantId(), - testDatabase -> { - providerConfig = forTestDatabase(config.getProviderParticipantId(), testDatabase); - - config.getConfigCustomizer().accept(providerConfig); - config.getProviderConfigCustomizer().accept(providerConfig); - return providerConfig.getProperties(); - } - ); - } - - @Override - public void beforeAll(ExtensionContext context) throws Exception { - consumerExtension.beforeAll(context); - providerExtension.beforeAll(context); - } - - @Override - public void beforeTestExecution(ExtensionContext context) throws Exception { - clientAndServer = new Lazy<>(() -> ClientAndServer.startClientAndServer(getFreePort())); - consumerExtension.beforeTestExecution(context); - providerExtension.beforeTestExecution(context); - } - - @Override - public void afterTestExecution(ExtensionContext context) throws Exception { - if (clientAndServer.isInitialized()) { - stopQuietly(clientAndServer.get()); - } - consumerExtension.afterTestExecution(context); - providerExtension.afterTestExecution(context); - } - - @Override - public void afterAll(ExtensionContext context) throws Exception { - consumerExtension.afterAll(context); - providerExtension.afterAll(context); - } - - @Override - public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) - throws ParameterResolutionException { - - val isProvider = isProvider(parameterContext); - val isConsumer = isConsumer(parameterContext); - - if (isProvider && isConsumer) { - throw new ParameterResolutionException("Either @Provider or @Consumer may be used."); - } - - val type = parameterContext.getParameter().getType(); - - if (isConsumer) { - return partySupportedTypes.contains(type) || consumerExtension.supportsParameter(parameterContext, extensionContext); - } - - if (isProvider) { - return partySupportedTypes.contains(type) || providerExtension.supportsParameter(parameterContext, extensionContext); - } - - if (supportedTypes.contains(type)) { - return true; - } - - return consumerExtension.supportsParameter(parameterContext, extensionContext) || - providerExtension.supportsParameter(parameterContext, extensionContext); - } - - @Override - public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) - throws ParameterResolutionException { - - val isConsumer = isConsumer(parameterContext); - val isProvider = isProvider(parameterContext); - - val type = parameterContext.getParameter().getType(); - - if (isConsumer) { - if (EdcClient.class.equals(type)) { - return newEdcClient(consumerConfig); - } else if (ConnectorConfig.class.equals(type)) { - return consumerConfig; - } else if (ConnectorRemote.class.equals(type)) { - return new ConnectorRemote(fromConnectorConfig(consumerConfig)); - } else { - return consumerExtension.resolveParameter(parameterContext, extensionContext); - } - } - - if (isProvider) { - if (EdcClient.class.equals(type)) { - return newEdcClient(providerConfig); - } else if (ConnectorConfig.class.equals(type)) { - return providerConfig; - } else if (ConnectorRemote.class.equals(type)) { - return new ConnectorRemote(fromConnectorConfig(providerConfig)); - } else { - return providerExtension.resolveParameter(parameterContext, extensionContext); - } - } - - if (E2eScenario.class.equals(type)) { - return new E2eScenario(consumerConfig, providerConfig, clientAndServer.get()); - } else if (ClientAndServer.class.equals(type)) { - return clientAndServer.get(); - } - - throw new IllegalArgumentException( - "The parameters must be annotated by the EDC side: @Provider or @Consumer or be one of the supported classes."); - } - - private static boolean isProvider(ParameterContext parameterContext) { - return parameterContext.getParameter().getDeclaredAnnotation(Provider.class) != null; - } - - private static boolean isConsumer(ParameterContext parameterContext) { - return parameterContext.getParameter().getDeclaredAnnotation(Consumer.class) != null; - } - - private EdcClient newEdcClient(ConnectorConfig consumerConfig) { - return EdcClient.builder() - .managementApiUrl(consumerConfig.getManagementApiUrl()) - .managementApiKey(consumerConfig.getManagementApiKey()) - .build(); - } -} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eTestExtensionConfig.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eTestExtensionConfig.java deleted file mode 100644 index 9cac7681d..000000000 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eTestExtensionConfig.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.extension.e2e.extension; - -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import lombok.Builder; -import lombok.Getter; - -import java.util.function.Consumer; - -@Builder(toBuilder = true) -@Getter -public class E2eTestExtensionConfig { - - private String moduleName; - - @Builder.Default - private String consumerParticipantId = "consumer"; - - @Builder.Default - private String providerParticipantId = "provider"; - - @Builder.Default - private Consumer configCustomizer = it -> { - }; - - @Builder.Default - private Consumer consumerConfigCustomizer = it -> { - }; - - @Builder.Default - private Consumer providerConfigCustomizer = it -> { - }; -} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/Helpers.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/Helpers.java deleted file mode 100644 index 4fa3ae399..000000000 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/Helpers.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2024 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.extension.e2e.extension; - -import lombok.experimental.UtilityClass; - -import static de.sovity.edc.extension.e2e.extension.CeE2eTestExtensionConfigFactory.withModule; - -@UtilityClass -public class Helpers { - public static E2eTestExtension defaultE2eTestExtension() { - return new E2eTestExtension(withModule(":launchers:connectors:sovity-dev")); - } -} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/CeE2eTestExtension.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/CeE2eTestExtension.java new file mode 100644 index 000000000..f75c33f2e --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/CeE2eTestExtension.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.e2e.junit; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.extension.e2e.connector.config.ConnectorBootConfig.ConnectorBootConfigBuilder; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenario; +import de.sovity.edc.extension.e2e.connector.remotes.api_wrapper.E2eTestScenarioConfig; +import de.sovity.edc.extension.e2e.connector.remotes.test_backend_controller.TestBackendRemote; +import de.sovity.edc.extension.e2e.junit.utils.InstancesForEachConnector; +import de.sovity.edc.extension.e2e.junit.utils.InstancesForJunitTest; +import de.sovity.edc.utils.config.ConfigUtils; +import lombok.Builder; +import lombok.Singular; +import lombok.experimental.Delegate; +import org.eclipse.edc.spi.system.configuration.Config; +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.AfterTestExecutionCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.mockserver.integration.ClientAndServer; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; + +import static org.eclipse.edc.util.io.Ports.getFreePort; +import static org.mockserver.stop.Stop.stopQuietly; + +@Builder +public class CeE2eTestExtension + implements BeforeAllCallback, AfterAllCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver { + + @Singular("additionalModule") + private List additionalModules; + + @Builder.Default + private boolean skipDb = false; + + @Builder.Default + private Consumer configCustomizer = it -> { + }; + + @Builder.Default + private Consumer consumerConfigCustomizer = it -> { + }; + + @Builder.Default + private Consumer providerConfigCustomizer = it -> { + }; + + @Builder.Default + private List cleanupHooks = new ArrayList<>(); + + private final InstancesForEachConnector instancesForEachConnector = new InstancesForEachConnector<>( + Arrays.asList(CeE2eTestSide.values()), + (parameterContext, extensionContext) -> CeE2eTestSide.fromParameterContextOrNull(parameterContext) + ); + + @Delegate(types = ParameterResolver.class) + private final InstancesForJunitTest instances = new InstancesForJunitTest(); + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + instances.put(instancesForEachConnector); + instances.addParameterResolver(instancesForEachConnector); + + for (CeE2eTestSide side : CeE2eTestSide.values()) { + var extension = CeIntegrationTestExtension.builder() + .participantId(side.getParticipantId()) + .additionalModules(additionalModules) + .configOverrides(config -> { + configCustomizer.accept(config); + if (side == CeE2eTestSide.CONSUMER) { + consumerConfigCustomizer.accept(config); + } else { + providerConfigCustomizer.accept(config); + } + }) + .skipDb(skipDb) + .build(); + + // Register DbRuntimePerClassExtension + instancesForEachConnector.forSide(side).put(extension); + instancesForEachConnector.forSide(side).addParameterResolver(extension); + + // Start EDC + extension.beforeAll(context); + } + + // Register TestBackendRemote + instances.putLazy(TestBackendRemote.class, this::buildTestBackendRemote); + } + + @Override + public void beforeTestExecution(ExtensionContext context) { + // Register ClientAndServer + instances.putLazy( + ClientAndServer.class, + () -> ClientAndServer.startClientAndServer(getFreePort()) + ); + + // Register ConnectorRemoteClient + instances.putLazy(E2eTestScenario.class, this::buildE2eTestScenario); + } + + @Override + public void afterTestExecution(ExtensionContext context) { + if (instances.isLazyInitialized(ClientAndServer.class)) { + stopQuietly(instances.get(ClientAndServer.class)); + } + } + + @Override + public void afterAll(ExtensionContext context) throws Exception { + // for loop explicitly used because of checked exceptions + for (var extension : instancesForEachConnector.all(CeIntegrationTestExtension.class)) { + extension.afterAll(context); + } + } + + private E2eTestScenario buildE2eTestScenario() { + return E2eTestScenario.builder() + .consumerClient(instancesForEachConnector.forSide(CeE2eTestSide.CONSUMER).get(EdcClient.class)) + .providerClient(instancesForEachConnector.forSide(CeE2eTestSide.PROVIDER).get(EdcClient.class)) + .mockServer(instances.get(ClientAndServer.class)) + .config(E2eTestScenarioConfig.forProviderConfig(getConfig(CeE2eTestSide.PROVIDER))) + .build(); + } + + private TestBackendRemote buildTestBackendRemote() { + var defaultApiUrl = ConfigUtils.getDefaultApiUrl(getConfig(CeE2eTestSide.PROVIDER)); + return new TestBackendRemote(defaultApiUrl); + } + + private Config getConfig(CeE2eTestSide ceE2eTestSide) { + return instancesForEachConnector.forSide(ceE2eTestSide).get(Config.class); + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/CeE2eTestSide.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/CeE2eTestSide.java new file mode 100644 index 000000000..76cd7aed0 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/CeE2eTestSide.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.e2e.junit; + +import de.sovity.edc.extension.e2e.junit.utils.Consumer; +import de.sovity.edc.extension.e2e.junit.utils.Provider; +import lombok.val; +import org.jetbrains.annotations.Nullable; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; + +public enum CeE2eTestSide { + CONSUMER, + PROVIDER; + + public String getParticipantId() { + return name().toLowerCase(); + } + + + @Nullable + public static CeE2eTestSide fromParameterContextOrNull(ParameterContext parameterContext) { + val isProvider = parameterContext.getParameter().getDeclaredAnnotation(Provider.class) != null; + val isConsumer = parameterContext.getParameter().getDeclaredAnnotation(Consumer.class) != null; + + if (isProvider && isConsumer) { + throw new ParameterResolutionException("Either @Provider or @Consumer may be used."); + } + if (isConsumer) { + return CeE2eTestSide.CONSUMER; + } + if (isProvider) { + return CeE2eTestSide.PROVIDER; + } + return null; + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/CeIntegrationTestExtension.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/CeIntegrationTestExtension.java new file mode 100644 index 000000000..516a836a0 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/CeIntegrationTestExtension.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.e2e.junit; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.extension.e2e.connector.config.ConnectorBootConfig.ConnectorBootConfigBuilder; +import de.sovity.edc.extension.e2e.connector.remotes.management_api.ManagementApiConnectorRemote; +import de.sovity.edc.extension.e2e.db.JdbcCredentials; +import de.sovity.edc.extension.e2e.db.TestDatabase; +import de.sovity.edc.extension.e2e.junit.edc.EmbeddedRuntimeFixed; +import de.sovity.edc.extension.e2e.junit.edc.RuntimeExtensionFixed; +import de.sovity.edc.extension.e2e.junit.edc.RuntimePerClassExtensionFixed; +import de.sovity.edc.extension.e2e.junit.utils.InstancesForJunitTest; +import de.sovity.edc.utils.config.CeConfigProps; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Singular; +import lombok.experimental.Delegate; +import org.jetbrains.annotations.Nullable; +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterResolver; + +import java.util.List; +import java.util.function.Consumer; + +/** + * Starts one DB and one EDC + */ +@Builder +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +public class CeIntegrationTestExtension + implements BeforeAllCallback, AfterAllCallback, AfterEachCallback, ParameterResolver { + + @Getter + @Builder.Default + private final String participantId = "connector"; + + @Singular("additionalModule") + private final List additionalModules; + + @Builder.Default + private final boolean skipDb = false; + + @Builder.Default + private final Consumer beforeEdcStartup = runtime -> { + }; + + @Nullable + private final Consumer configOverrides; + + @Delegate(types = ParameterResolver.class) + private final InstancesForJunitTest instances = new InstancesForJunitTest(); + + @Override + public void beforeAll(ExtensionContext extensionContext) throws Exception { + // Start DB + if (!skipDb) { + var dbExtension = TestDatabaseExtension.builder().build(); + instances.put(dbExtension); + instances.addParameterResolver(dbExtension); + dbExtension.beforeAll(extensionContext); + } + + // Start Connector + var bootConfig = CeIntegrationTestUtils.defaultConfig( + participantId, + getTestDatabaseOrMock(), + configOverrides + ); + var runtime = new EmbeddedRuntimeFixed( + participantId, + bootConfig, + CeConfigProps.ALL_CE_PROPS, + additionalModules.toArray(String[]::new) + ); + instances.put(runtime); + + var connectorExtension = new RuntimePerClassExtensionFixed(runtime); + beforeEdcStartup.accept(connectorExtension); + connectorExtension.beforeAll(extensionContext); + + instances.put(connectorExtension); + instances.addParameterResolver(connectorExtension); + + // Configure Clients and Utilities + var config = runtime.getContext().getConfig(); + instances.put(config); + instances.putLazy(EdcClient.class, () -> CeIntegrationTestUtils.getEdcClient(config)); + instances.putLazy(ManagementApiConnectorRemote.class, () -> CeIntegrationTestUtils.getManagementApiConnectorRemote(config)); + + instances.put(new Janitor()); + } + + @Override + public void afterAll(ExtensionContext extensionContext) throws Exception { + try { + instances.get(RuntimePerClassExtensionFixed.class).afterAll(extensionContext); + } finally { + if (!skipDb) { + instances.get(TestDatabaseExtension.class).afterAll(extensionContext); + } + } + } + + private TestDatabase getTestDatabaseOrMock() { + if (!skipDb) { + return instances.get(TestDatabaseExtension.class).getTestDatabase(); + } + return () -> new JdbcCredentials("no-test-db", "no-test-db", "no-test-db"); + } + + @Override + public void afterEach(ExtensionContext extensionContext) throws Exception { + instances.get(Janitor.class).clear(); + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/CeIntegrationTestUtils.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/CeIntegrationTestUtils.java new file mode 100644 index 000000000..9b00a1694 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/CeIntegrationTestUtils.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.e2e.junit; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.extension.e2e.connector.config.ConnectorBootConfig; +import de.sovity.edc.extension.e2e.connector.config.ConnectorBootConfig.ConnectorBootConfigBuilder; +import de.sovity.edc.extension.e2e.connector.config.PortUtils; +import de.sovity.edc.extension.e2e.connector.remotes.management_api.ManagementApiConnectorRemote; +import de.sovity.edc.extension.e2e.connector.remotes.management_api.ManagementApiConnectorRemoteConfig; +import de.sovity.edc.extension.e2e.db.TestDatabase; +import de.sovity.edc.utils.config.CeConfigProps; +import de.sovity.edc.utils.config.ConfigUtils; +import lombok.experimental.UtilityClass; +import lombok.val; +import org.apache.commons.lang3.tuple.Pair; +import org.eclipse.edc.spi.system.configuration.Config; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; +import java.util.function.Consumer; + +@UtilityClass +public final class CeIntegrationTestUtils { + + public static ConnectorBootConfig defaultConfig( + String participantId, + @Nullable + TestDatabase testDatabase, + @Nullable + Consumer overrides + ) { + val firstPort = PortUtils.getFreePortRange(5); + val apiKey = "api-key-%s".formatted(UUID.randomUUID().toString()); + + val configBuilder = ConnectorBootConfig.builder() + // Network + .property(CeConfigProps.MY_EDC_NETWORK_TYPE, CeConfigProps.CeEnvironment.UNIT_TEST) + .property(CeConfigProps.MY_EDC_FIRST_PORT, String.valueOf(firstPort)) + + // API Auth + .property(CeConfigProps.EDC_API_AUTH_KEY, apiKey) + + // C2C Auth + .property(CeConfigProps.MY_EDC_C2C_IAM_TYPE, CeConfigProps.CeC2cIamType.MOCK_IAM) + .property(CeConfigProps.MY_EDC_PARTICIPANT_ID, participantId) + + // DB + .property(CeConfigProps.MY_EDC_JDBC_URL, testDatabase.getJdbcCredentials().jdbcUrl()) + .property(CeConfigProps.MY_EDC_JDBC_USER, testDatabase.getJdbcCredentials().jdbcUser()) + .property(CeConfigProps.MY_EDC_JDBC_PASSWORD, testDatabase.getJdbcCredentials().jdbcPassword()) + .property(CeConfigProps.EDC_FLYWAY_CLEAN_ENABLE, "true") + .property(CeConfigProps.EDC_FLYWAY_CLEAN, "true") + + // Metadata + .property(CeConfigProps.MY_EDC_TITLE, "Connector Title %s".formatted(participantId)) + .property(CeConfigProps.MY_EDC_DESCRIPTION, "Connector Description %s".formatted(participantId)) + .property(CeConfigProps.MY_EDC_CURATOR_URL, "http://curator.%s".formatted(participantId)) + .property(CeConfigProps.MY_EDC_CURATOR_NAME, "Curator Name %s".formatted(participantId)) + .property(CeConfigProps.MY_EDC_MAINTAINER_URL, "http://maintainer.%s".formatted(participantId)) + .property(CeConfigProps.MY_EDC_MAINTAINER_NAME, "Maintainer Name %s".formatted(participantId)); + if (overrides != null) { + overrides.accept(configBuilder); + } + return configBuilder.build(); + } + + public static EdcClient getEdcClient(Config config) { + return EdcClient.builder() + .managementApiUrl(ConfigUtils.getManagementApiUrl(config.getEntries())) + .managementApiKey(ConfigUtils.getManagementApiKey(config.getEntries())) + .customConfigurer(it -> it + .setConnectTimeout(0) + .setReadTimeout(0) + .setWriteTimeout(0) + ) + .build(); + } + + public static ManagementApiConnectorRemote getManagementApiConnectorRemote(Config config) { + var connectorRemoteConfig = ManagementApiConnectorRemoteConfig.forConnector(config, () -> Pair.of( + "X-Api-Key", + ConfigUtils.getManagementApiKey(config.getEntries()) + )); + return new ManagementApiConnectorRemote(connectorRemoteConfig); + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/Janitor.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/Janitor.java new file mode 100644 index 000000000..42ddec877 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/Janitor.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.e2e.junit; + +import de.sovity.edc.client.EdcClient; +import lombok.val; +import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Automatically cleans up the allocated resources when the API or service is used via its wrappers. + */ +public class Janitor { + + private final List hooks = new ArrayList<>(); + + public void clear() { + Collections.reverse(hooks); + for (val hook : hooks) { + try { + hook.run(); + } catch (Exception e) { + // swallow. This may happen if an element is deleted twice for instance + e.printStackTrace(); + } + } + hooks.clear(); + } + + public void afterEach(Runnable runnable) { + hooks.add(runnable); + } + + public JanitorApiWrapper withClient(EdcClient client) { + return new JanitorApiWrapper(this, client); + } + + public JanitorServiceWrapper withAssetService(AssetService assetService) { + return new JanitorServiceWrapper(this, assetService); + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/JanitorApiWrapper.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/JanitorApiWrapper.java new file mode 100644 index 000000000..5aa4c7322 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/JanitorApiWrapper.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.e2e.junit; + +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.client.gen.model.ContractDefinitionRequest; +import de.sovity.edc.client.gen.model.IdResponseDto; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; +import de.sovity.edc.client.gen.model.UiAssetCreateRequest; +import lombok.RequiredArgsConstructor; +import lombok.val; + +@RequiredArgsConstructor +public class JanitorApiWrapper { + + private final Janitor janitor; + private final EdcClient client; + + public IdResponseDto createAsset(UiAssetCreateRequest uiAssetCreateRequest) { + val result = client.uiApi().createAsset(uiAssetCreateRequest); + janitor.afterEach(() -> client.uiApi().deleteAsset(result.getId())); + return result; + } + + public IdResponseDto createPolicyDefinitionV2(PolicyDefinitionCreateDto policyDefinition) { + val result = client.uiApi().createPolicyDefinitionV2(policyDefinition); + janitor.afterEach(() -> client.uiApi().deletePolicyDefinition(result.getId())); + return result; + } + + public IdResponseDto createContractDefinition(ContractDefinitionRequest contractDefinitionRequest) { + val result = client.uiApi().createContractDefinition(contractDefinitionRequest); + janitor.afterEach(() -> client.uiApi().deleteContractDefinition(result.getId())); + return result; + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/JanitorServiceWrapper.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/JanitorServiceWrapper.java new file mode 100644 index 000000000..b0fb5addd --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/JanitorServiceWrapper.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.e2e.junit; + +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.eclipse.edc.connector.controlplane.asset.spi.domain.Asset; +import org.eclipse.edc.connector.controlplane.services.spi.asset.AssetService; +import org.eclipse.edc.spi.result.ServiceResult; + +@RequiredArgsConstructor +public class JanitorServiceWrapper { + + private final Janitor janitor; + private final AssetService service; + + public ServiceResult create(Asset asset) { + val result = service.create(asset); + janitor.afterEach(() -> service.delete(asset.getId())); + return result; + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/TestDatabaseExtension.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/TestDatabaseExtension.java new file mode 100644 index 000000000..ecc76f9c0 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/TestDatabaseExtension.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.e2e.junit; + +import de.sovity.edc.extension.e2e.db.TestDatabase; +import de.sovity.edc.extension.e2e.db.TestDatabaseViaTestcontainers; +import de.sovity.edc.extension.e2e.junit.utils.InstancesForJunitTest; +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Delegate; +import lombok.val; +import org.jooq.DSLContext; +import org.jooq.impl.DSL; +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterResolver; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * Starts one DB and one EDC + */ +@Builder +@RequiredArgsConstructor +public final class TestDatabaseExtension + implements BeforeAllCallback, AfterAllCallback, ParameterResolver { + + @Delegate(types = ParameterResolver.class) + private final InstancesForJunitTest instances = new InstancesForJunitTest(); + + @Getter + private final TestDatabase testDatabase = new TestDatabaseViaTestcontainers(); + + @Override + public void beforeAll(ExtensionContext extensionContext) throws Exception { + System.out.println("Starting Test DB"); + testDatabase.beforeAll(extensionContext); + System.out.printf("Test DB Started with %s%n", testDatabase.getJdbcCredentials()); + instances.put(testDatabase); + instances.putLazy(DSLContext.class, () -> { + val credentials = testDatabase.getJdbcCredentials(); + return DSL.using(credentials.jdbcUrl(), credentials.jdbcUser(), credentials.jdbcPassword()); + }); + instances.putLazy(Connection.class, () -> { + val credentials = testDatabase.getJdbcCredentials(); + try { + return DriverManager.getConnection(credentials.jdbcUrl(), credentials.jdbcUser(), credentials.jdbcPassword()); + } catch (SQLException e) { + throw new RuntimeException(e); + } + }); + } + + @Override + public void afterAll(ExtensionContext extensionContext) throws Exception { + System.out.println("Shutting down Test DB"); + testDatabase.afterAll(extensionContext); + System.out.println("Test DB shut down"); + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/EmbeddedRuntimeFixed.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/EmbeddedRuntimeFixed.java new file mode 100644 index 000000000..87277159b --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/EmbeddedRuntimeFixed.java @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2024 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 de.sovity.edc.extension.e2e.junit.edc; + +import de.sovity.edc.extension.e2e.connector.config.ConnectorBootConfig; +import de.sovity.edc.utils.config.SovityEdcRuntime; +import de.sovity.edc.utils.config.model.ConfigProp; +import org.apache.commons.lang3.Validate; +import org.eclipse.edc.junit.extensions.EmbeddedRuntime; +import org.eclipse.edc.junit.extensions.TestServiceExtensionContext; +import org.eclipse.edc.junit.testfixtures.TestUtils; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.monitor.ConsoleMonitor; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.SystemExtension; +import org.eclipse.edc.spi.system.configuration.Config; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; + +import static java.lang.String.format; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.eclipse.edc.boot.system.ExtensionLoader.loadMonitor; + +/** + * Starts one EDC + *

+ * Modified {@link EmbeddedRuntime}. All changes to the file are marked with "Begin of modified code" / "End of modified code" blocks. + */ +public class EmbeddedRuntimeFixed extends SovityEdcRuntime { + + private static final Monitor MONITOR = loadMonitor(); + + private final String name; + private final Map properties; + private final String[] additionalModules; + private final LinkedHashMap, Object> serviceMocks = new LinkedHashMap<>(); + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); + private final MultiSourceServiceLocator serviceLocator; + + /* Begin of modified code: Custom Constructors */ + + public EmbeddedRuntimeFixed( + String name, + ConnectorBootConfig connectorBootConfig, + List allConfigProps, + String... additionalModules + ) { + this( + new MultiSourceServiceLocator(), + name, + connectorBootConfig, + allConfigProps, + additionalModules + ); + } + + private EmbeddedRuntimeFixed( + MultiSourceServiceLocator serviceLocator, + String name, + ConnectorBootConfig connectorBootConfig, + List allConfigProps, + String... additionalModules + ) { + super(serviceLocator, allConfigProps); + this.serviceLocator = serviceLocator; + this.name = name; + this.additionalModules = additionalModules; + this.properties = connectorBootConfig.asMap(); + } + + /* End of modified code: Custom Constructors */ + + @Override + public void boot(boolean addShutdownHook) { + try { + /* Begin of Modified Code: Handle empty additionalModules */ + Validate.notEmpty(additionalModules, "additionalModules must not be empty, as the current classpath is excluded"); + /* End of Modified Code: Handle empty additionalModules */ + + // Find the project root directory, moving up the directory tree + var root = TestUtils.findBuildRoot(); + + // Run a Gradle custom task to determine the runtime classpath of the module to run + var printClasspath = Arrays.stream(additionalModules).map(it -> it + ":printClasspath"); + var commandStream = Stream.of(new File(root, TestUtils.GRADLE_WRAPPER).getCanonicalPath(), "-q"); + var command = Stream.concat(commandStream, printClasspath).toArray(String[]::new); + + var exec = Runtime.getRuntime().exec(command); + var classpathString = new String(exec.getInputStream().readAllBytes()); + var errorOutput = new String(exec.getErrorStream().readAllBytes()); + if (exec.waitFor() != 0) { + throw new EdcException(format("Failed to run gradle command: [%s]. Output: %s %s", + String.join(" ", command), classpathString, errorOutput)); + } + + /* Begin of modified code: Fix issue under Windows */ + + var splitRegex = ":|\\s"; + if (System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("windows")) { + splitRegex = ";|\\s"; + } + + // Replace subproject JAR entries with subproject build directories in classpath. + // This ensures modified classes are picked up without needing to rebuild dependent JARs. + var classPathEntries = Arrays.stream(classpathString.split(splitRegex)) + .filter(s -> !s.isBlank()) + .flatMap(p -> resolveClassPathEntry(root, p)) + .toArray(URL[]::new); + + /* End of modified code: Fix issue under Windows */ + + // Create a ClassLoader that only has the target module class path, and is not + // parented with the current ClassLoader. + var classLoader = URLClassLoader.newInstance(classPathEntries); + + // Temporarily inject system properties. + var savedProperties = (Properties) System.getProperties().clone(); + properties.forEach(System::setProperty); + + var runtimeException = new AtomicReference(); + var latch = new CountDownLatch(1); + + MONITOR.info("Starting runtime %s with additional modules: [%s]".formatted(name, String.join(",", additionalModules))); + + executorService.execute(() -> { + try { + Thread.currentThread().setContextClassLoader(classLoader); + + super.boot(false); + + latch.countDown(); + } catch (Exception e) { + runtimeException.set(e); + throw new EdcException(e); + } + }); + + if (!latch.await(20, SECONDS)) { + throw new EdcException("Failed to start EDC runtime", runtimeException.get()); + } + + MONITOR.info("Runtime %s started".formatted(name)); + // Restore system properties. + System.setProperties(savedProperties); + } catch (Exception e) { + throw new EdcException(e); + } + + } + + @Override + public void shutdown() { + serviceLocator.clearSystemExtensions(); + super.shutdown(); + } + + @Override + protected @NotNull ServiceExtensionContext createContext(Monitor monitor, Config config) { + return new TestServiceExtensionContext(monitor, config, serviceMocks); + } + + @Override + protected @NotNull Monitor createMonitor() { + // disable logs when "quiet" log level is set + if (System.getProperty("org.gradle.logging.level") != null) { + return new Monitor() { + }; + } else { + return new ConsoleMonitor(name, ConsoleMonitor.Level.DEBUG, true); + } + } + + public EmbeddedRuntimeFixed registerSystemExtension(Class type, SystemExtension extension) { + serviceLocator.registerSystemExtension(type, extension); + return this; + } + + public EmbeddedRuntimeFixed registerServiceMock(Class type, T mock) { + serviceMocks.put(type, mock); + return this; + } + + public T getService(Class clazz) { + return context.getService(clazz); + } + + public ServiceExtensionContext getContext() { + return context; + } + + /** + * Replace Gradle subproject JAR entries with subproject build directories in classpath. This ensures modified + * classes are picked up without needing to rebuild dependent JARs. + * + * @param root project root directory. + * @param classPathEntry class path entry to resolve. + * @return resolved class path entries for the input argument. + */ + private Stream resolveClassPathEntry(File root, String classPathEntry) { + try { + var f = new File(classPathEntry).getCanonicalFile(); + + // If class path entry is not a JAR under the root (i.e. a sub-project), do not transform it + var isUnderRoot = f.getCanonicalPath().startsWith(root.getCanonicalPath() + File.separator); + if (!classPathEntry.toLowerCase(Locale.ROOT).endsWith(".jar") || !isUnderRoot) { + var sanitizedClassPathEntry = classPathEntry.replace("build/resources/main", "src/main/resources"); + return Stream.of(new File(sanitizedClassPathEntry).toURI().toURL()); + } + + // Replace JAR entry with the resolved classes and resources folder + var buildDir = f.getParentFile().getParentFile(); + return Stream.of( + new File(buildDir, "/classes/java/main").toURI().toURL(), + new File(buildDir, "../src/main/resources").toURI().toURL() + ); + } catch (IOException e) { + throw new EdcException(e); + } + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/MultiSourceServiceLocator.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/MultiSourceServiceLocator.java new file mode 100644 index 000000000..3a5345408 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/MultiSourceServiceLocator.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 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 de.sovity.edc.extension.e2e.junit.edc; + +import org.eclipse.edc.boot.system.ServiceLocator; +import org.eclipse.edc.boot.system.ServiceLocatorImpl; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.system.SystemExtension; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +import static org.eclipse.edc.util.types.Cast.cast; + +/** + * Copied from Eclipse EDC due to class visibility + */ +class MultiSourceServiceLocator implements ServiceLocator { + private final ServiceLocator delegate = new ServiceLocatorImpl(); + private final LinkedHashMap, List> systemExtensions; + + MultiSourceServiceLocator() { + systemExtensions = new LinkedHashMap<>(); + } + + @Override + public List loadImplementors(Class type, boolean required) { + List extensions = cast(systemExtensions.getOrDefault(type, new ArrayList<>())); + extensions.addAll(delegate.loadImplementors(type, required)); + return extensions; + } + + /** + * This implementation will override singleton implementions found by the delegate. + */ + @Override + public T loadSingletonImplementor(Class type, boolean required) { + var extensions = systemExtensions.get(type); + if (extensions == null || extensions.isEmpty()) { + return delegate.loadSingletonImplementor(type, required); + } else if (extensions.size() > 1) { + throw new EdcException("Multiple extensions were registered for type: " + type.getName()); + } + return type.cast(extensions.get(0)); + } + + public void registerSystemExtension(Class type, SystemExtension extension) { + systemExtensions.computeIfAbsent(type, k -> new ArrayList<>()).add(extension); + } + + public void clearSystemExtensions() { + systemExtensions.clear(); + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/RuntimeExtensionFixed.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/RuntimeExtensionFixed.java new file mode 100644 index 000000000..0d11c7606 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/RuntimeExtensionFixed.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024 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 de.sovity.edc.extension.e2e.junit.edc; + +import lombok.Getter; +import org.eclipse.edc.spi.system.ConfigurationExtension; +import org.eclipse.edc.spi.system.SystemExtension; +import org.eclipse.edc.spi.system.configuration.ConfigFactory; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; + +import java.util.Map; + +import static org.eclipse.edc.util.types.Cast.cast; + +/** + * Starts one EDC + *

+ * Modified {@link org.eclipse.edc.junit.extensions.RuntimeExtension} + * that uses {@link EmbeddedRuntimeFixed} instead of {@link org.eclipse.edc.junit.extensions.EmbeddedRuntime}. + */ +public abstract class RuntimeExtensionFixed implements ParameterResolver { + @Getter + protected final EmbeddedRuntimeFixed runtime; + + protected RuntimeExtensionFixed(EmbeddedRuntimeFixed runtime) { + this.runtime = runtime; + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + var type = parameterContext.getParameter().getParameterizedType(); + if (type.equals(RuntimeExtensionFixed.class)) { + return true; + } else if (type.equals(EmbeddedRuntimeFixed.class)) { + return true; + } else if (type instanceof Class) { + return runtime.getContext().hasService(cast(type)); + } + return false; + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + var type = parameterContext.getParameter().getParameterizedType(); + if (type.equals(RuntimeExtensionFixed.class)) { + return this; + } else if (type.equals(EmbeddedRuntimeFixed.class)) { + return runtime; + } else if (type instanceof Class) { + return runtime.getContext().getService(cast(type)); + } + return null; + } + + /** + * Registers a mock service with the runtime. Note that the mock will overwrite any service already registered with the context. + * This is intentional. A warning will be logged to STDOUT if the mock actually replaces an existing service. + * + * @param mock the service mock + */ + public RuntimeExtensionFixed registerServiceMock(Class type, T mock) { + runtime.registerServiceMock(type, mock); + return this; + } + + /** + * Registers a service extension with the runtime. + */ + public RuntimeExtensionFixed registerSystemExtension(Class type, SystemExtension extension) { + runtime.registerSystemExtension(type, extension); + return this; + } + + public RuntimeExtensionFixed setConfiguration(Map configuration) { + registerSystemExtension(ConfigurationExtension.class, (ConfigurationExtension) () -> ConfigFactory.fromMap(configuration)); + return this; + } + + public T getService(Class clazz) { + return runtime.getService(clazz); + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/RuntimePerClassExtensionFixed.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/RuntimePerClassExtensionFixed.java new file mode 100644 index 000000000..39d70f26c --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/RuntimePerClassExtensionFixed.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 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 de.sovity.edc.extension.e2e.junit.edc; + +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +/** + * Starts one EDC that boots/shutdowns for each test method + *

+ * Modified {@link org.eclipse.edc.junit.extensions.RuntimePerClassExtension} + * that uses {@link EmbeddedRuntimeFixed} instead of {@link org.eclipse.edc.junit.extensions.EmbeddedRuntime}. + */ +public class RuntimePerClassExtensionFixed extends RuntimeExtensionFixed implements BeforeAllCallback, AfterAllCallback { + + public RuntimePerClassExtensionFixed(EmbeddedRuntimeFixed runtime) { + super(runtime); + } + + @Override + public void beforeAll(ExtensionContext extensionContext) { + runtime.boot(false); + } + + @Override + public void afterAll(ExtensionContext extensionContext) { + runtime.shutdown(); + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/RuntimePerMethodExtensionFixed.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/RuntimePerMethodExtensionFixed.java new file mode 100644 index 000000000..1f81d0e15 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/edc/RuntimePerMethodExtensionFixed.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 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 de.sovity.edc.extension.e2e.junit.edc; + +import org.junit.jupiter.api.extension.AfterTestExecutionCallback; +import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + + +/** + * Starts one EDC that boots/shutdowns once per test class + *

+ * Modified {@link org.eclipse.edc.junit.extensions.RuntimePerMethodExtension} + * that uses {@link EmbeddedRuntimeFixed} instead of {@link org.eclipse.edc.junit.extensions.EmbeddedRuntime}. + */ +public class RuntimePerMethodExtensionFixed extends RuntimeExtensionFixed + implements BeforeTestExecutionCallback, AfterTestExecutionCallback { + + public RuntimePerMethodExtensionFixed(EmbeddedRuntimeFixed runtime) { + super(runtime); + } + + @Override + public void beforeTestExecution(ExtensionContext extensionContext) { + runtime.boot(false); + } + + @Override + public void afterTestExecution(ExtensionContext extensionContext) { + runtime.shutdown(); + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/Consumer.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/utils/Consumer.java similarity index 67% rename from utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/Consumer.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/utils/Consumer.java index cbd622765..a36cd2fe3 100644 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/Consumer.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/utils/Consumer.java @@ -12,13 +12,15 @@ * */ -package de.sovity.edc.extension.e2e.extension; +package de.sovity.edc.extension.e2e.junit.utils; + +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * In test code, in conjunction with {@link E2eTestExtension}, specifies that the injected instance must come from the Consumer EDC + * In test code, in conjunction with {@link CeE2eTestExtension}, specifies that the injected instance must come from the Consumer EDC */ @Retention(RetentionPolicy.RUNTIME) public @interface Consumer { diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/utils/InstancesForEachConnector.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/utils/InstancesForEachConnector.java new file mode 100644 index 000000000..fb3617538 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/utils/InstancesForEachConnector.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.e2e.junit.utils; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; + +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; + +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toMap; + +/** + * A fancy {@link Map} of {@code S} and {@link InstancesForJunitTest}. + * + * @param Connector Side enum, rather than just a string + */ +public class InstancesForEachConnector implements ParameterResolver { + private final List sides; + private final BiFunction getSideOrNull; + private final Map instances; + + public InstancesForEachConnector( + List sides, + BiFunction getSideOrNull + ) { + this.sides = sides; + this.getSideOrNull = getSideOrNull; + this.instances = sides.stream().collect(toMap( + identity(), + unused -> new InstancesForJunitTest()) + ); + } + + + public List all(Class clazz) { + return sides.stream().map(side -> forSide(side).get(clazz)).toList(); + } + + public InstancesForJunitTest forSide(S side) { + var instancesOfSide = instances.get(side); + if (instancesOfSide == null) { + throw new IllegalArgumentException("No instances for side %s found".formatted(side)); + } + return instancesOfSide; + } + + @Override + public boolean supportsParameter( + ParameterContext parameterContext, + ExtensionContext extensionContext + ) throws ParameterResolutionException { + var side = getSideOrNull.apply(parameterContext, extensionContext); + if (side == null) { + return false; + } + + return forSide(side).supportsParameter(parameterContext, extensionContext); + } + + @Override + public Object resolveParameter( + ParameterContext parameterContext, + ExtensionContext extensionContext + ) throws ParameterResolutionException { + var side = getSideOrNull.apply(parameterContext, extensionContext); + if (side == null) { + throw new ParameterResolutionException("No side found for parameter %s".formatted(parameterContext.getParameter())); + } + + return forSide(side).resolveParameter(parameterContext, extensionContext); + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/utils/InstancesForJunitTest.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/utils/InstancesForJunitTest.java new file mode 100644 index 000000000..e6ca5fe3f --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/utils/InstancesForJunitTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2024 sovity GmbH + * + * 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: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.extension.e2e.junit.utils; + +import de.sovity.edc.extension.utils.Lazy; +import lombok.val; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; + +import java.lang.reflect.Parameter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class InstancesForJunitTest implements ParameterResolver { + private final Map, LazyOrValue> instances = new HashMap<>(); + private final List childResolvers = new ArrayList<>(); + + public void addParameterResolver(ParameterResolver resolver) { + childResolvers.add(resolver); + } + + public void put(Object object) { + instances.put(object.getClass(), LazyOrValue.ofValue(object)); + } + + public void putLazy(Class clazz, Supplier factory) { + instances.put(clazz, LazyOrValue.ofLazy(new Lazy<>(factory))); + } + + public boolean has(Class clazz) { + return supportsParameter(dummyParameterContext(clazz), null); + } + + @SuppressWarnings("unchecked") + public T get(Class clazz) { + return (T) resolveParameter(dummyParameterContext(clazz), null); + } + + public boolean isLazyInitialized(Class clazz) { + var lazy = instances.entrySet() + .stream() + .filter(isSubclassOfEntry(clazz)) + .findFirst() + .map(Map.Entry::getValue) + .filter(it -> it.lazy() != null) + .map(LazyOrValue::lazy) + .orElseThrow(() -> new IllegalArgumentException("No lazy object of type %s".formatted(clazz))); + return lazy.isInitialized(); + } + + @Override + public boolean supportsParameter( + ParameterContext parameterContext, + ExtensionContext extensionContext + ) throws ParameterResolutionException { + val clazz = parameterContext.getParameter().getType(); + + return instances.entrySet().stream().anyMatch(isSubclassOfEntry(clazz)) || + childResolvers.stream().anyMatch(r -> r.supportsParameter(parameterContext, extensionContext)); + } + + @Override + public Object resolveParameter( + ParameterContext parameterContext, + ExtensionContext extensionContext + ) throws ParameterResolutionException { + val clazz = parameterContext.getParameter().getType(); + return instances.entrySet() + .stream() + .filter(isSubclassOfEntry(clazz)) + .findFirst() + .map(entry -> entry.getValue().get()) + .orElseGet(() -> childResolvers.stream() + .filter(r -> r.supportsParameter(parameterContext, extensionContext)) + .findFirst() + .orElseThrow(() -> new ParameterResolutionException( + "No resolver found for type %s in list of resolvers and instances".formatted(clazz)) + ) + .resolveParameter(parameterContext, extensionContext)); + } + + @NotNull + private Predicate, LazyOrValue>> isSubclassOfEntry(Class clazz) { + return it -> clazz.isAssignableFrom(it.getKey()); + } + + + private record LazyOrValue(Object value, Lazy lazy) { + public static LazyOrValue ofValue(Object value) { + return new LazyOrValue(value, null); + } + + public static LazyOrValue ofLazy(Lazy lazy) { + return new LazyOrValue(null, lazy); + } + + public Object get() { + if (value != null) { + return value; + } + return lazy.get(); + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private ParameterContext dummyParameterContext(Class type) { + // While the ParameterContext API supports resolving all kinds of + // templated Array types etc, we only care about supporting resolving + // classes by java.lang.class + var parameter = mock(Parameter.class); + when(parameter.getType()).thenReturn((Class) type); + when(parameter.getParameterizedType()).thenReturn(type); + + var parameterContext = mock(ParameterContext.class); + when(parameterContext.getParameter()).thenReturn(parameter); + return parameterContext; + } +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/Provider.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/utils/Provider.java similarity index 67% rename from utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/Provider.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/utils/Provider.java index e3cff34b2..524b987af 100644 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/Provider.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/junit/utils/Provider.java @@ -12,13 +12,15 @@ * */ -package de.sovity.edc.extension.e2e.extension; +package de.sovity.edc.extension.e2e.junit.utils; + +import de.sovity.edc.extension.e2e.junit.CeE2eTestExtension; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * In test code, in conjunction with {@link E2eTestExtension}, specifies that the injected instance must come from the Provider EDC + * In test code, in conjunction with {@link CeE2eTestExtension}, specifies that the injected instance must come from the Provider EDC */ @Retention(RetentionPolicy.RUNTIME) public @interface Provider { diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/utils/junit/DisabledOnGithub.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/utils/junit/DisabledOnGithub.java index f0382d096..3cb1b240b 100644 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/utils/junit/DisabledOnGithub.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/utils/junit/DisabledOnGithub.java @@ -26,7 +26,7 @@ */ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) -@Tag("not-on-github") +@Tag("exclude-on-github") public @interface DisabledOnGithub { }