diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c677656c..244b9dc34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ please see [changelog_updates.md](docs/dev/changelog_updates.md). #### Minor Changes +- Both providers and consumers can now terminate their contracts. + #### Patch Changes ### Deployment Migration Notes @@ -548,7 +550,7 @@ https://github.com/sovity/edc-ui/releases/tag/v2.0.0 - New modules with common UI models and mappers for the Connector UI and Broker UI: `:extensions:wrapper:wrapper-common-api` and `:extensions:wrapper:wrapper-common-mappers`. - New module with centralized Vocab and utilities for dealing with EDC / DCAT JSON-LD: `:utils:json-and-jsonld-utils` - New module with utilities for parsing DCAT Catalog responses for use in the UI API Wrapper and the Broker Server: `:utils:catalog-parser` -- New modules with utilities for E2E Testing Connectors: `:utils:test-connector-remote` and `:extensions:test-backend-controller` +- New modules with utilities for E2E Testing Connectors: `:utils:test-utils` and `:extensions:test-backend-controller` #### Patch Changes diff --git a/README.md b/README.md index 7acfb1783..09d3d64ba 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,32 @@ Our contribution guideline can be found in [CONTRIBUTING.md](CONTRIBUTING.md).

(back to top)

+## Development + +### Developer Documentation + +- Local Development Guide (further below) +- [IntelliJ](docs/dev/intellij/intelliJ.md) +- [Changelog Updates](docs/dev/changelog_updates.md) + +

(back to top)

+ +### Requirements + +- Docker Environment +- JDK 17 +- GitHub Maven Registry Access + +To access the GitHub Maven Registry you need to provide the following properties, e.g. by providing +a `~/.gradle/gradle.properties`. + +```properties +gpr.user={your github username} +gpr.key={your github pat with packages.read} +``` + +

(back to top)

+ ## License diff --git a/docs/api/sovity-edc-api-wrapper.yaml b/docs/api/sovity-edc-api-wrapper.yaml index 13d5135d1..851967da8 100644 --- a/docs/api/sovity-edc-api-wrapper.yaml +++ b/docs/api/sovity-edc-api-wrapper.yaml @@ -255,8 +255,9 @@ paths: description: Collect filtered data for the Contract Agreement Page operationId: getContractAgreementPage requestBody: + description: "If null, returns all the contract agreements." content: - '*/*': + application/json: schema: $ref: '#/components/schemas/ContractAgreementPageQuery' responses: @@ -524,11 +525,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: @@ -736,7 +737,6 @@ components: UiDataSourceHttpDataMethod: type: string description: Supported HTTP Methods by UiDataSource - default: GET enum: - GET - POST @@ -744,6 +744,7 @@ components: - PATCH - DELETE - OPTIONS + default: GET UiDataSourceOnRequest: required: - contactEmail @@ -1788,14 +1789,18 @@ components: - reason type: object properties: - reason: - title: Termination reason - type: string - description: A short reason why this contract was terminated detail: title: Termination detail + maxLength: 1000 + minLength: 0 type: string description: A user explanation to detail why the contract was terminated. + reason: + title: Termination reason + maxLength: 100 + minLength: 0 + type: string + description: A short reason why this contract was terminated description: Data for terminating a Contract Agreement AtomicConstraintDto: required: diff --git a/docs/dev/intellij/intelliJ.md b/docs/dev/intellij/intelliJ.md new file mode 100644 index 000000000..0f30676ec --- /dev/null +++ b/docs/dev/intellij/intelliJ.md @@ -0,0 +1,53 @@ +# IntelliJ + +## Checkstyle + +Checkstyle errors are by default not shown in IntelliJ. + +There is an [IntelliJ Plugin](https://plugins.jetbrains.com/plugin/1065-checkstyle-idea) to see Checkstyle errors as errors in your IDE. + +### License Headers with IntelliJ + +While it's close to impossible to write a regex to validate all the possible copyright messages, the one currently configured in [checkstyle-config.xml](../checkstyle/checkstyle-config.xml) matches almost all the files in this project. + +Failing to use this template will make it progressively harder to fix the checkstyle errors as the copyright warnings will accumulate and dilute those errors, wasting precious brain time. + +IntelliJ has a feature to help maintain consistent copyright headers in + +`Settings > Editor > Copyright > Copyright profiles`. + +The copyright below passes the checkstyle when put in a Java multiline comment. + +``` +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 + +``` + +Which once inserted at the top of a file will look like + +```java +/* + * 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 foo.bar; +``` diff --git a/extensions/catalog-crawler/catalog-crawler-e2e-test/build.gradle.kts b/extensions/catalog-crawler/catalog-crawler-e2e-test/build.gradle.kts index 6cc40c67d..9f3492139 100644 --- a/extensions/catalog-crawler/catalog-crawler-e2e-test/build.gradle.kts +++ b/extensions/catalog-crawler/catalog-crawler-e2e-test/build.gradle.kts @@ -10,7 +10,7 @@ dependencies { testCompileOnly(libs.lombok) testImplementation(project(":utils:versions")) - testImplementation(project(":utils:test-connector-remote")) + testImplementation(project(":utils:test-utils")) testImplementation(project(":utils:json-and-jsonld-utils")) testImplementation(project(":extensions:catalog-crawler:catalog-crawler-db")) testImplementation(project(":extensions:wrapper:clients:java-client")) @@ -18,7 +18,6 @@ dependencies { testImplementation(libs.assertj.core) testImplementation(libs.mockito.core) - testImplementation(libs.mockito.inline) testImplementation(libs.edc.junit) testImplementation(libs.restAssured.restAssured) testImplementation(libs.testcontainers.testcontainers) diff --git a/extensions/catalog-crawler/catalog-crawler-e2e-test/src/test/java/de/sovity/edc/ext/catalog/crawler/CrawlerE2eTest.java b/extensions/catalog-crawler/catalog-crawler-e2e-test/src/test/java/de/sovity/edc/ext/catalog/crawler/CrawlerE2eTest.java index 3fedd0961..db8a7631e 100644 --- a/extensions/catalog-crawler/catalog-crawler-e2e-test/src/test/java/de/sovity/edc/ext/catalog/crawler/CrawlerE2eTest.java +++ b/extensions/catalog-crawler/catalog-crawler-e2e-test/src/test/java/de/sovity/edc/ext/catalog/crawler/CrawlerE2eTest.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.catalog.crawler; diff --git a/extensions/catalog-crawler/catalog-crawler/build.gradle.kts b/extensions/catalog-crawler/catalog-crawler/build.gradle.kts index b63b7004f..7c2b46f7e 100644 --- a/extensions/catalog-crawler/catalog-crawler/build.gradle.kts +++ b/extensions/catalog-crawler/catalog-crawler/build.gradle.kts @@ -21,10 +21,9 @@ dependencies { testAnnotationProcessor(libs.lombok) testCompileOnly(libs.lombok) - testImplementation(project(":utils:test-connector-remote")) + testImplementation(project(":utils:test-utils")) testImplementation(libs.assertj.core) testImplementation(libs.mockito.core) - testImplementation(libs.mockito.inline) testImplementation(libs.restAssured.restAssured) testImplementation(libs.testcontainers.testcontainers) testImplementation(libs.flyway.core) diff --git a/extensions/contract-termination/README.md b/extensions/contract-termination/README.md new file mode 100644 index 000000000..e9dbda30f --- /dev/null +++ b/extensions/contract-termination/README.md @@ -0,0 +1,39 @@ + +
+
+ + Logo + + +

EDC-Connector Extension:
Contract Termination

+ +

+ Report Bug + ยท + Request Feature +

+
+ + +## About this Extension + +Using our [`sovity-messenger`](../sovity-messenger) extension, both providers and consumers can now terminate contracts in a transparent way. Contract termination information is persisted in its own table on both sides and terminated contracts will be prevented from being transferable. + +## Why does this extension exist? + +Contracts termination is not natively supported by the Data Space Protocol (DSP) or in the Eclipse EDC. Customer Feedback and real-world Dataspace projects have proven for there to be many reasons for a party to want to terminate a contract. We want to enable contract termination in a transparent way for all participating parties, the provider, the consumer, and if necessary, the authority via the Logging House. + +## Details + +When a User clicks "Terminate contract" on a contract agreement, a request is sent to the EDC to mark the contract agreement as terminated, followed by a notification and registration of that same termination on the counterpart's side. + +The termination is saved in the EDC's database. +Any transfer started from this contract agreement will be rejected. + +## License + +Apache License 2.0 - see [LICENSE](../../LICENSE) + +## Contact + +sovity GmbH - contact@sovity.de diff --git a/extensions/contract-termination/build.gradle.kts b/extensions/contract-termination/build.gradle.kts new file mode 100644 index 000000000..61c1ad4ec --- /dev/null +++ b/extensions/contract-termination/build.gradle.kts @@ -0,0 +1,61 @@ + +plugins { + `java-library` + `maven-publish` +} + +dependencies { + annotationProcessor(libs.lombok) + compileOnly(libs.lombok) + + implementation(project(":utils:jooq-database-access")) + implementation(project(":extensions:database-direct-access")) + implementation(project(":extensions:sovity-messenger")) + + implementation(libs.edc.coreSpi) + implementation(libs.edc.transferSpi) + implementation(libs.edc.dspNegotiationTransform) + + 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.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/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 new file mode 100644 index 000000000..a16096979 --- /dev/null +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractAgreementTerminationDetails.java @@ -0,0 +1,47 @@ +/* + * 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.ext.db.jooq.enums.ContractTerminatedBy; +import lombok.Builder; +import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; + +import java.time.OffsetDateTime; + +@Builder(toBuilder = true) +public record ContractAgreementTerminationDetails( + String contractAgreementId, + String counterpartyId, + String counterpartyAddress, + ContractNegotiation.Type type, + String providerAgentId, + String consumerAgentId, + String reason, + String detail, + OffsetDateTime terminatedAt, + ContractTerminatedBy terminatedBy +) { + public boolean isTerminated() { + return terminatedAt != null; + } + + boolean thisEdcIsTheConsumer() { + return type.equals(ContractNegotiation.Type.CONSUMER); + } + + boolean thisEdcIsTheProvider() { + return type.equals(ContractNegotiation.Type.PROVIDER); + } +} 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 new file mode 100644 index 000000000..36a151b5b --- /dev/null +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractAgreementTerminationService.java @@ -0,0 +1,104 @@ +/* + * 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.extension.contacttermination.query.ContractAgreementTerminationDetailsQuery; +import de.sovity.edc.extension.contacttermination.query.TerminateContractQuery; +import de.sovity.edc.extension.messenger.SovityMessenger; +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.monitor.Monitor; +import org.jetbrains.annotations.Nullable; +import org.jooq.DSLContext; + +import java.time.OffsetDateTime; + +import static de.sovity.edc.ext.db.jooq.enums.ContractTerminatedBy.COUNTERPARTY; +import static de.sovity.edc.ext.db.jooq.enums.ContractTerminatedBy.SELF; + +@RequiredArgsConstructor +public class ContractAgreementTerminationService { + + private final SovityMessenger sovityMessenger; + private final ContractAgreementTerminationDetailsQuery contractAgreementTerminationDetailsQuery; + private final TerminateContractQuery terminateContractQuery; + private final Monitor monitor; + private final String thisParticipantId; + + /** + * This is to terminate an EDC's own contract. + * If the termination comes from an external system, use + * {@link #terminateCounterpartyAgreement(DSLContext, String, ContractTerminationParam)} + * to validate the counter-party's identity. + */ + public OffsetDateTime terminateAgreementOrThrow(DSLContext dsl, ContractTerminationParam termination) { + + val details = contractAgreementTerminationDetailsQuery.fetchAgreementDetailsOrThrow(dsl, termination.contractAgreementId()); + + if (details == null) { + throw new EdcException("Could not find the contract agreement with ID %s.".formatted(termination.contractAgreementId())); + } + + if (details.isTerminated()) { + return details.terminatedAt(); + } + + val terminatedAt = terminateContractQuery.terminateConsumerAgreementOrThrow(dsl, termination, SELF); + + notifyTerminationToProvider(details.counterpartyAddress(), termination); + + return terminatedAt; + } + + public OffsetDateTime terminateCounterpartyAgreement( + DSLContext dsl, + @Nullable String identity, + ContractTerminationParam termination + ) { + val details = contractAgreementTerminationDetailsQuery.fetchAgreementDetailsOrThrow(dsl, termination.contractAgreementId()); + + if (details == null) { + val message = "Could not find the contract agreement with ID %s.".formatted(termination.contractAgreementId()); + throw new EdcException(message); + } + + boolean thisEdcIsConsumerAndSenderIsProvider = details.thisEdcIsTheConsumer() && details.providerAgentId().equals(identity); + boolean thisEdcIsProviderAndSenderIsConsumer = details.thisEdcIsTheProvider() && details.consumerAgentId().equals(identity); + + if (!(thisEdcIsConsumerAndSenderIsProvider || thisEdcIsProviderAndSenderIsConsumer)) { + monitor.severe( + "The EDC %s attempted to terminate a contract that it was not related to!".formatted(details.consumerAgentId())); + throw new EdcException("The requester's identity %s is neither the consumer nor the provider".formatted(identity)); + } + + if (details.isTerminated()) { + throw new EdcException("The contract is already terminated"); + } + + val agent = thisParticipantId.equals(details.counterpartyId()) ? SELF : COUNTERPARTY; + + return terminateContractQuery.terminateConsumerAgreementOrThrow(dsl, termination, agent); + } + + public void notifyTerminationToProvider(String counterPartyAddress, ContractTerminationParam termination) { + sovityMessenger.send( + counterPartyAddress, + new ContractTerminationMessage( + termination.contractAgreementId(), + termination.detail(), + termination.reason())); + } +} 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 new file mode 100644 index 000000000..cad805be9 --- /dev/null +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractTerminationExtension.java @@ -0,0 +1,114 @@ +/* + * 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.extension.contacttermination.query.ContractAgreementIsTerminatedQuery; +import de.sovity.edc.extension.contacttermination.query.ContractAgreementTerminationDetailsQuery; +import de.sovity.edc.extension.contacttermination.query.TerminateContractQuery; +import de.sovity.edc.extension.db.directaccess.DslContextFactory; +import de.sovity.edc.extension.messenger.SovityMessenger; +import de.sovity.edc.extension.messenger.SovityMessengerRegistry; +import lombok.val; +import org.eclipse.edc.connector.transfer.spi.observe.TransferProcessObservable; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.runtime.metamodel.annotation.Provides; +import org.eclipse.edc.runtime.metamodel.annotation.Setting; +import org.eclipse.edc.spi.agent.ParticipantAgentService; +import org.eclipse.edc.spi.iam.IdentityService; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; + + +@Provides(ContractAgreementTerminationService.class) +public class ContractTerminationExtension implements ServiceExtension { + + @Setting(required = true) + private static final String EDC_PARTICIPANT_ID = "edc.participant.id"; + + @Inject + private DslContextFactory dslContextFactory; + + @Inject + private IdentityService identityService; + + @Inject + private Monitor monitor; + + @Inject + private SovityMessenger sovityMessenger; + + @Inject + private SovityMessengerRegistry messengerRegistry; + + @Inject + private TransferProcessObservable observable; + + @Inject + private ParticipantAgentService participantAgentService; + + @Override + public void initialize(ServiceExtensionContext context) { + + val terminationService = setupTerminationService(context); + setupMessenger(terminationService); + setupTransferPrevention(); + } + + private ContractAgreementTerminationService setupTerminationService(ServiceExtensionContext context) { + + val config = context.getConfig(); + val contractAgreementTerminationDetailsQuery = new ContractAgreementTerminationDetailsQuery(); + val terminateContractQuery = new TerminateContractQuery(); + + val terminationService = new ContractAgreementTerminationService( + sovityMessenger, + contractAgreementTerminationDetailsQuery, + terminateContractQuery, + monitor, + config.getString(EDC_PARTICIPANT_ID) + ); + + context.registerService(ContractAgreementTerminationService.class, terminationService); + + return terminationService; + } + + private void setupMessenger(ContractAgreementTerminationService terminationService) { + messengerRegistry.register( + ContractTerminationMessage.class, + (claims, termination) -> + dslContextFactory.transactionResult(dsl -> + terminationService.terminateCounterpartyAgreement( + dsl, + participantAgentService.createFor(claims).getIdentity(), + buildTerminationRequest(termination)))); + } + + private static ContractTerminationParam buildTerminationRequest(ContractTerminationMessage message) { + return new ContractTerminationParam( + message.getContractAgreementId(), + message.getDetail(), + message.getReason() + ); + } + + private void setupTransferPrevention() { + observable.registerListener( + new TransferProcessBlocker( + dslContextFactory, + new ContractAgreementIsTerminatedQuery())); + } +} diff --git a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractTerminationMessage.java b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractTerminationMessage.java new file mode 100644 index 000000000..dbf3c4da7 --- /dev/null +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractTerminationMessage.java @@ -0,0 +1,43 @@ +/* + * 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 com.fasterxml.jackson.annotation.JsonProperty; +import de.sovity.edc.extension.messenger.SovityMessage; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Builder +@AllArgsConstructor +@Getter +@NoArgsConstructor +public class ContractTerminationMessage implements SovityMessage { + + @JsonProperty("contractAgreementId") + private String contractAgreementId; + + @JsonProperty("detail") + private String detail; + + @JsonProperty("reason") + private String reason; + + @Override + public String getType() { + return "io.sovity.message.contract.terminate"; + } +} diff --git a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractTerminationParam.java b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractTerminationParam.java new file mode 100644 index 000000000..995830d66 --- /dev/null +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/ContractTerminationParam.java @@ -0,0 +1,25 @@ +/* + * 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 lombok.Builder; + +@Builder +public record ContractTerminationParam( + String contractAgreementId, + String detail, + String reason +) { +} 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 new file mode 100644 index 000000000..256b8f179 --- /dev/null +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/TransferProcessBlocker.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.extension.contacttermination; + +import de.sovity.edc.extension.contacttermination.query.ContractAgreementIsTerminatedQuery; +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; + +@RequiredArgsConstructor +public class TransferProcessBlocker implements TransferProcessListener { + + private final DslContextFactory dslContextFactory; + private final ContractAgreementIsTerminatedQuery contractAgreementIsTerminated; + + @Override + public void preRequesting(TransferProcess process) { + val terminated = dslContextFactory.transactionResult(dsl -> + contractAgreementIsTerminated.isTerminated(dsl, process.getContractId())); + + if (terminated) { + val message = "Interrupted: the contract agreement %s is terminated.".formatted(process.getContractId()); + throw new IllegalStateException(message); + } + } +} diff --git a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementIsTerminatedQuery.java b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementIsTerminatedQuery.java new file mode 100644 index 000000000..05b31ba3c --- /dev/null +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementIsTerminatedQuery.java @@ -0,0 +1,33 @@ +/* + * 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.query; + +import de.sovity.edc.ext.db.jooq.Tables; +import lombok.val; +import org.jooq.DSLContext; + +public class ContractAgreementIsTerminatedQuery { + + public boolean isTerminated(DSLContext dsl, String contractAgreementId) { + + val t = Tables.SOVITY_CONTRACT_TERMINATION; + + return dsl.fetchExists( + dsl.select() + .from(t) + .where(t.CONTRACT_AGREEMENT_ID.eq(contractAgreementId)) + ); + } +} 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 new file mode 100644 index 000000000..46454d025 --- /dev/null +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementTerminationDetailsQuery.java @@ -0,0 +1,53 @@ +/* + * 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.query; + +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.jooq.DSLContext; + +import static de.sovity.edc.ext.db.jooq.Tables.EDC_CONTRACT_AGREEMENT; +import static de.sovity.edc.ext.db.jooq.Tables.EDC_CONTRACT_NEGOTIATION; +import static de.sovity.edc.ext.db.jooq.Tables.SOVITY_CONTRACT_TERMINATION; + +@RequiredArgsConstructor +public class ContractAgreementTerminationDetailsQuery { + + public ContractAgreementTerminationDetails fetchAgreementDetailsOrThrow(DSLContext dsl, String agreementId) { + val n = EDC_CONTRACT_NEGOTIATION; + val a = EDC_CONTRACT_AGREEMENT; + val t = SOVITY_CONTRACT_TERMINATION; + + return dsl.transactionResult(trx -> + trx.dsl().select( + n.AGREEMENT_ID, + n.COUNTERPARTY_ID, + n.COUNTERPARTY_ADDRESS, + n.TYPE.convertFrom(ContractNegotiation.Type::valueOf), + a.PROVIDER_AGENT_ID, + a.CONSUMER_AGENT_ID, + t.REASON, + t.DETAIL, + t.TERMINATED_AT, + t.TERMINATED_BY) + .from( + n.join(a).on(n.AGREEMENT_ID.eq(a.AGR_ID)) + .leftJoin(SOVITY_CONTRACT_TERMINATION).on(n.AGREEMENT_ID.eq(t.CONTRACT_AGREEMENT_ID))) + .where(a.AGR_ID.eq(agreementId)) + .fetchOneInto(ContractAgreementTerminationDetails.class)); + } +} diff --git a/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/query/TerminateContractQuery.java b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/query/TerminateContractQuery.java new file mode 100644 index 000000000..f404eb92c --- /dev/null +++ b/extensions/contract-termination/src/main/java/de/sovity/edc/extension/contacttermination/query/TerminateContractQuery.java @@ -0,0 +1,50 @@ +/* + * 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.query; + +import de.sovity.edc.ext.db.jooq.enums.ContractTerminatedBy; +import de.sovity.edc.extension.contacttermination.ContractTerminationParam; +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.jooq.DSLContext; + +import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; + +import static de.sovity.edc.ext.db.jooq.Tables.SOVITY_CONTRACT_TERMINATION; + +@RequiredArgsConstructor +public class TerminateContractQuery { + + public OffsetDateTime terminateConsumerAgreementOrThrow( + DSLContext dsl, + ContractTerminationParam termination, + ContractTerminatedBy terminatedBy) { + + val tooAccurate = OffsetDateTime.now(); + val now = tooAccurate.truncatedTo(ChronoUnit.MICROS); + + val newTermination = dsl.newRecord(SOVITY_CONTRACT_TERMINATION); + newTermination.setContractAgreementId(termination.contractAgreementId()); + newTermination.setDetail(termination.detail()); + newTermination.setReason(termination.reason()); + newTermination.setTerminatedBy(terminatedBy); + newTermination.setTerminatedAt(now); + + newTermination.insert(); + + return now; + } +} diff --git a/extensions/contract-termination/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/contract-termination/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 000000000..61b77a354 --- /dev/null +++ b/extensions/contract-termination/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1,14 @@ +# +# 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 +# + +de.sovity.edc.extension.contacttermination.ContractTerminationExtension diff --git a/extensions/contract-termination/src/test/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementTerminationDetailsQueryTest.java b/extensions/contract-termination/src/test/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementTerminationDetailsQueryTest.java new file mode 100644 index 000000000..a13d156c9 --- /dev/null +++ b/extensions/contract-termination/src/test/java/de/sovity/edc/extension/contacttermination/query/ContractAgreementTerminationDetailsQueryTest.java @@ -0,0 +1,124 @@ +/* + * 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.query; + +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.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 lombok.val; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation.Type.CONSUMER; + + +@ExtendWith(E2eTestExtension.class) +class ContractAgreementTerminationDetailsQueryTest { + + @Test + void fetchAgreementDetailsOrThrow_whenAgreementIsPresent_shouldReturnTheAgreementDetails( + E2eScenario scenario, + @Consumer DslContextFactory dslContextFactory, + @Provider ConnectorConfig providerConfig + ) { + // arrange + + val assetId = scenario.createAsset(); + scenario.createContractDefinition(assetId); + val negotiations = scenario.negotiateAssetAndAwait(assetId); + + dslContextFactory.rollbackTransaction(dsl -> { + val query = new ContractAgreementTerminationDetailsQuery(); + + // act + val agreementId = negotiations.getContractAgreementId(); + val details = query.fetchAgreementDetailsOrThrow(dsl, agreementId); + + // assert + assertThat(details).isEqualTo(ContractAgreementTerminationDetails.builder() + .contractAgreementId(agreementId) + .counterpartyId("provider") + .counterpartyAddress(providerConfig.getProtocolEndpoint().getUri().toString()) + .type(CONSUMER) + .providerAgentId("provider") + .consumerAgentId("consumer") + .reason(null) + .detail(null) + .terminatedAt(null) + .terminatedBy(null) + .build()); + } + ); + } + + @Test + void fetchAgreementDetailsOrThrow_whenAgreementIsMissing_shouldReturnEmptyOptional(@Consumer DslContextFactory dslContextFactory) { + // arrange + + dslContextFactory.rollbackTransaction(dsl -> { + val query = new ContractAgreementTerminationDetailsQuery(); + + // act + val details = query.fetchAgreementDetailsOrThrow(dsl, "agreement:doesnt:exist"); + + // assert + assertThat(details).isNull(); + } + ); + } + + @Test + void fetchAgreementDetailsOrThrow_whenTerminationAlreadyExists_shouldReturnOptionalWithTerminationData( + E2eScenario scenario, + @Consumer DslContextFactory dslContextFactory, + @Provider ConnectorConfig providerConfig + ) { + // arrange + + val assetId = scenario.createAsset(); + scenario.createContractDefinition(assetId); + val negotiations = scenario.negotiateAssetAndAwait(assetId); + val terminationRequest = new ContractTerminationRequest("Terminated because of good reasons", "User Termination"); + val termination = scenario.terminateContractAgreementAndAwait(CONSUMER, negotiations.getContractAgreementId(), terminationRequest); + + dslContextFactory.rollbackTransaction(dsl -> { + val query = new ContractAgreementTerminationDetailsQuery(); + + // act + val agreementId = negotiations.getContractAgreementId(); + val details = query.fetchAgreementDetailsOrThrow(dsl, agreementId); + + // assert + assertThat(details.contractAgreementId()).isEqualTo(agreementId); + assertThat(details.counterpartyId()).isEqualTo("provider"); + assertThat(details.counterpartyAddress()).isEqualTo(providerConfig.getProtocolEndpoint().getUri().toString()); + assertThat(details.type()).isEqualTo(CONSUMER); + assertThat(details.providerAgentId()).isEqualTo("provider"); + assertThat(details.consumerAgentId()).isEqualTo("consumer"); + assertThat(details.reason()).isEqualTo("User Termination"); + assertThat(details.detail()).isEqualTo("Terminated because of good reasons"); + assertThat(details.terminatedAt()).isEqualTo(termination.getLastUpdatedDate()); + assertThat(details.terminatedBy()).isEqualTo(ContractTerminatedBy.SELF); + } + ); + } +} 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 new file mode 100644 index 000000000..c4e5dc825 --- /dev/null +++ b/extensions/contract-termination/src/test/java/de/sovity/edc/extension/contacttermination/query/TerminateContractQueryTest.java @@ -0,0 +1,83 @@ +/* + * 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.query; + +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 lombok.val; +import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.time.OffsetDateTime; + +import static de.sovity.edc.ext.db.jooq.enums.ContractTerminatedBy.COUNTERPARTY; +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(E2eTestExtension.class) +class TerminateContractQueryTest { + + @Test + void terminateConsumerAgreementOrThrow_shouldInsertRowInTerminationTable( + E2eScenario scenario, + @Consumer DslContextFactory dslContextFactory, + @Provider ConnectorConfig providerConfig + ) { + val assetId = scenario.createAsset(); + scenario.createContractDefinition(assetId); + val negotiation = scenario.negotiateAssetAndAwait(assetId); + + dslContextFactory.rollbackTransaction(trx -> { + + // arrange + val query = new TerminateContractQuery(); + val agreementId = negotiation.getContractAgreementId(); + + val details = new ContractTerminationParam( + agreementId, + "Some detail", + "Some reason" + ); + val now = OffsetDateTime.now(); + + // act + val terminatedAt = query.terminateConsumerAgreementOrThrow(trx.dsl(), details, COUNTERPARTY); + + // assert + assertThat(terminatedAt).isNotNull(); + + val detailsQuery = new ContractAgreementTerminationDetailsQuery(); + val detailsAfterTermination = detailsQuery.fetchAgreementDetailsOrThrow(trx.dsl(), agreementId); + + assertThat(detailsAfterTermination.contractAgreementId()).isEqualTo(agreementId); + assertThat(detailsAfterTermination.counterpartyId()).isEqualTo("provider"); + assertThat(detailsAfterTermination.counterpartyAddress()) + .isEqualTo(providerConfig.getProtocolEndpoint().getUri().toString()); + assertThat(detailsAfterTermination.type()).isEqualTo(ContractNegotiation.Type.CONSUMER); + assertThat(detailsAfterTermination.providerAgentId()).isEqualTo("provider"); + assertThat(detailsAfterTermination.consumerAgentId()).isEqualTo("consumer"); + assertThat(detailsAfterTermination.reason()).isEqualTo("Some reason"); + assertThat(detailsAfterTermination.detail()).isEqualTo("Some detail"); + assertThat(detailsAfterTermination.terminatedAt()).isBetween(now, now.plusSeconds(1)); + assertThat(detailsAfterTermination.terminatedBy()).isEqualTo(COUNTERPARTY); + } + ); + } +} diff --git a/extensions/database-direct-access/build.gradle.kts b/extensions/database-direct-access/build.gradle.kts new file mode 100644 index 000000000..3aecfb4d1 --- /dev/null +++ b/extensions/database-direct-access/build.gradle.kts @@ -0,0 +1,25 @@ + +plugins { + `java-library` + `maven-publish` +} + +dependencies { + annotationProcessor(libs.lombok) + compileOnly(libs.lombok) + + implementation(libs.edc.coreSpi) + + implementation(libs.jooq.jooq) + implementation(libs.hikari) +} + +group = libs.versions.sovityEdcExtensionGroup.get() + +publishing { + publications { + create(project.name) { + from(components["java"]) + } + } +} 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 new file mode 100644 index 000000000..a69d4eba8 --- /dev/null +++ b/extensions/database-direct-access/src/main/java/de/sovity/edc/extension/db/directaccess/DatabaseDirectAccessExtension.java @@ -0,0 +1,88 @@ +/* + * 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.db.directaccess; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import lombok.val; +import org.eclipse.edc.runtime.metamodel.annotation.Provides; +import org.eclipse.edc.runtime.metamodel.annotation.Setting; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; + +@Provides(DslContextFactory.class) +public class DatabaseDirectAccessExtension implements ServiceExtension { + public static final String NAME = "DirectDatabaseAccess"; + + /** + * The JDBC URL. + */ + @Setting(required = true) + public static final String EDC_DATASOURCE_DEFAULT_URL = "edc.datasource.default.url"; + + /** + * The JDBC user. + */ + @Setting(required = true) + public static final String EDC_DATASOURCE_JDBC_USER = "edc.datasource.default.user"; + + /** + * The JDBC password. + */ + @Setting(required = true) + public static final String EDC_DATASOURCE_JDBC_PASSWORD = "edc.datasource.default.password"; + + /** + * Sets the connection pool size to use during the flyway migration. + */ + @Setting(defaultValue = "3") + public static final String EDC_SERVER_DB_CONNECTION_POOL_SIZE = "edc.server.db.connection.pool.size"; + + /** + * Sets the connection timeout for the datasource in milliseconds. + */ + @Setting(defaultValue = "5000") + public static final String EDC_SERVER_DB_CONNECTION_TIMEOUT_IN_MS = "edc.server.db.connection.timeout.in.ms"; + + + @Override + public String name() { + return NAME; + } + + @Override + public void initialize(ServiceExtensionContext context) { + initializeDirectDatabaseAccess(context); + } + + private void initializeDirectDatabaseAccess(ServiceExtensionContext context) { + + val hikariConfig = new HikariConfig(); + val config = context.getConfig(); + hikariConfig.setJdbcUrl(config.getString(EDC_DATASOURCE_DEFAULT_URL)); + hikariConfig.setUsername(config.getString(EDC_DATASOURCE_JDBC_USER)); + hikariConfig.setPassword(config.getString(EDC_DATASOURCE_JDBC_PASSWORD)); + hikariConfig.setMinimumIdle(1); + hikariConfig.setMaximumPoolSize(config.getInteger(EDC_SERVER_DB_CONNECTION_POOL_SIZE)); + hikariConfig.setIdleTimeout(30000); + hikariConfig.setPoolName("direct-database-access"); + hikariConfig.setMaxLifetime(50000); + hikariConfig.setConnectionTimeout(config.getInteger(EDC_SERVER_DB_CONNECTION_TIMEOUT_IN_MS)); + + val dda = new DslContextFactory(new HikariDataSource(hikariConfig)); + + context.registerService(DslContextFactory.class, dda); + } +} diff --git a/extensions/database-direct-access/src/main/java/de/sovity/edc/extension/db/directaccess/DslContextFactory.java b/extensions/database-direct-access/src/main/java/de/sovity/edc/extension/db/directaccess/DslContextFactory.java new file mode 100644 index 000000000..dbca8cca0 --- /dev/null +++ b/extensions/database-direct-access/src/main/java/de/sovity/edc/extension/db/directaccess/DslContextFactory.java @@ -0,0 +1,58 @@ +/* + * 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.db.directaccess; + +import lombok.RequiredArgsConstructor; +import org.eclipse.edc.runtime.metamodel.annotation.ExtensionPoint; +import org.jooq.DSLContext; +import org.jooq.SQLDialect; +import org.jooq.impl.DSL; + +import java.util.function.Consumer; +import java.util.function.Function; +import javax.sql.DataSource; + +@ExtensionPoint +@RequiredArgsConstructor +public class DslContextFactory { + + private final DataSource dataSource; + + private DSLContext newDslContext() { + return DSL.using(dataSource, SQLDialect.POSTGRES); + } + + public void transaction(Consumer consumer) { + newDslContext().transaction((trx) -> consumer.accept(trx.dsl())); + } + + /** + * For test purposes: a transaction that never succeeds + */ + public void rollbackTransaction(Consumer consumer) { + try { + newDslContext().transaction((trx) -> { + consumer.accept(trx.dsl()); + throw new RollbackException(); + }); + } catch (RollbackException e) { + // swallowed. Expected. + } + } + + public T transactionResult(Function f) { + return newDslContext().transactionResult((trx) -> f.apply(trx.dsl())); + } +} diff --git a/extensions/database-direct-access/src/main/java/de/sovity/edc/extension/db/directaccess/RollbackException.java b/extensions/database-direct-access/src/main/java/de/sovity/edc/extension/db/directaccess/RollbackException.java new file mode 100644 index 000000000..2a75236aa --- /dev/null +++ b/extensions/database-direct-access/src/main/java/de/sovity/edc/extension/db/directaccess/RollbackException.java @@ -0,0 +1,21 @@ +/* + * 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.db.directaccess; + +public class RollbackException extends RuntimeException { + public RollbackException() { + super("Rolled back."); + } +} diff --git a/extensions/database-direct-access/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/database-direct-access/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 000000000..2241735a9 --- /dev/null +++ b/extensions/database-direct-access/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1 @@ +de.sovity.edc.extension.db.directaccess.DatabaseDirectAccessExtension 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 new file mode 100644 index 000000000..24c8c3d88 --- /dev/null +++ b/extensions/postgres-flyway/src/main/resources/db/migration/V10__add_contract_termination.sql @@ -0,0 +1,25 @@ +-- +-- 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/sovity-edc-extensions-package/build.gradle.kts b/extensions/sovity-edc-extensions-package/build.gradle.kts index 10a522670..dc4edc6d1 100644 --- a/extensions/sovity-edc-extensions-package/build.gradle.kts +++ b/extensions/sovity-edc-extensions-package/build.gradle.kts @@ -11,6 +11,7 @@ dependencies { api(project(":extensions:policy-always-true")) // API Extensions + api(project(":extensions:contract-termination")) api(project(":extensions:edc-ui-config")) api(project(":extensions:last-commit-info")) api(project(":extensions:wrapper:wrapper")) diff --git a/extensions/sovity-messenger/build.gradle.kts b/extensions/sovity-messenger/build.gradle.kts index 815865804..cd9c7655d 100644 --- a/extensions/sovity-messenger/build.gradle.kts +++ b/extensions/sovity-messenger/build.gradle.kts @@ -22,7 +22,6 @@ dependencies { testCompileOnly(libs.lombok) - testImplementation(project(":utils:test-connector-remote")) testImplementation(project(":utils:test-utils")) testImplementation(libs.edc.junit) @@ -48,8 +47,8 @@ dependencies { testImplementation(libs.junit.api) testImplementation(libs.jsonAssert) testImplementation(libs.mockito.core) - testImplementation(libs.mockito.inline) testImplementation(libs.mockserver.netty) + testImplementation(libs.postgres) testImplementation(libs.restAssured.restAssured) testImplementation(libs.testcontainers.testcontainers) testImplementation(libs.testcontainers.junitJupiter) diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessage.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessage.java index 04d07f0a1..1c049f0d6 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessage.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessage.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger; 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 82dbfe54d..38791ddfa 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 @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger; @@ -23,6 +24,7 @@ import lombok.val; import org.eclipse.edc.spi.EdcException; import org.eclipse.edc.spi.message.RemoteMessageDispatcherRegistry; +import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.response.StatusResult; import org.jetbrains.annotations.NotNull; @@ -42,6 +44,8 @@ public class SovityMessenger { private final ObjectMapper serializer; + private final Monitor monitor; + /** * Sends a message to the counterparty address and returns a future result. * @@ -94,6 +98,7 @@ private Function header.getString(SovityMessengerStatus.HANDLER_EXCEPTION.getCode(), "No outgoing body."), payload); } else { + monitor.info(header.getString("message", "No message in the response header.")); throw new SovityMessengerException(header.getString("message")); } } catch (JsonProcessingException e) { diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessengerException.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessengerException.java index 2de888e30..dd3b9290b 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessengerException.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessengerException.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger; 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 5a01dc7c0..545529043 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 @@ -9,11 +9,13 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import de.sovity.edc.extension.messenger.controller.SovityMessageController; import de.sovity.edc.extension.messenger.impl.JsonObjectFromSovityMessageRequest; import de.sovity.edc.extension.messenger.impl.JsonObjectFromSovityMessageResponse; @@ -27,6 +29,7 @@ import org.eclipse.edc.protocol.dsp.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; @@ -68,6 +71,9 @@ public class SovityMessengerExtension implements ServiceExtension { @Inject private WebService webService; + @Inject + private ParticipantAgentService participantAgentService; + @Override public String name() { return NAME; @@ -76,6 +82,7 @@ public String name() { @Override public void initialize(ServiceExtensionContext context) { val objectMapper = new ObjectMapperFactory().createObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); val handlers = new SovityMessengerRegistry(); setupSovityMessengerEmitter(context, objectMapper); setupSovityMessengerReceiver(context, objectMapper, handlers); @@ -89,7 +96,7 @@ private void setupSovityMessengerEmitter(ServiceExtensionContext context, Object typeTransformerRegistry.register(new JsonObjectFromSovityMessageRequest()); - val sovityMessenger = new SovityMessenger(registry, objectMapper); + val sovityMessenger = new SovityMessenger(registry, objectMapper, monitor); context.registerService(SovityMessenger.class, sovityMessenger); } @@ -100,6 +107,7 @@ private void setupSovityMessengerReceiver(ServiceExtensionContext context, Objec typeTransformerRegistry, monitor, objectMapper, + participantAgentService, handlers); webService.registerResource(dspApiConfiguration.getContextAlias(), receiver); diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessengerRegistry.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessengerRegistry.java index 933dc6a1f..317c0a392 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessengerRegistry.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/SovityMessengerRegistry.java @@ -9,17 +9,20 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger; -import de.sovity.edc.extension.messenger.impl.Handler; +import de.sovity.edc.extension.messenger.impl.HandlerBox; import lombok.SneakyThrows; import lombok.val; +import org.eclipse.edc.spi.iam.ClaimToken; -import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; @@ -28,7 +31,7 @@ */ public class SovityMessengerRegistry { - private final Map> handlers = new HashMap<>(); + private final Map> handlers = new HashMap<>(); /** * Register a handler to process a sovity message. @@ -41,7 +44,25 @@ public class SovityMessengerRegistry { @SneakyThrows public void register(Class incomingMessage, Function handler) { val type = getTypeViaIntrospection(incomingMessage); - register(incomingMessage, type, handler); + registerIfNotExists(incomingMessage, type, (claims, in) -> handler.apply(in)); + } + + @SneakyThrows + public void register(Class incomingMessage, BiFunction handler) { + val type = getTypeViaIntrospection(incomingMessage); + registerIfNotExists(incomingMessage, type, handler); + } + + /** + * Use this constructor only if your message can't have a default constructor. Otherwise, prefer using + * {@link #register(Class, Function)} for type safety. + */ + public void register(Class clazz, String type, Function handler) { + registerIfNotExists(clazz, type, (BiFunction) (claimToken, in) -> handler.apply(in)); + } + + public void register(Class clazz, String type, BiFunction handler) { + registerIfNotExists(clazz, type, handler); } /** @@ -53,19 +74,19 @@ public void register(Class incomingMessage, @SneakyThrows public void registerSignal(Class incomingSignal, Consumer handler) { val type = getTypeViaIntrospection(incomingSignal); - registerSignal(incomingSignal, type, handler); + registerIfNotExists(incomingSignal, type, (claims, in) -> { + handler.accept(in); + return null; + }); } - /** - * Use this constructor only if your message can't have a default constructor. Otherwise, prefer using - * {@link #register(Class, Function)} for type safety. - */ - public void register(Class clazz, String type, Function handler) { - if (handlers.containsKey(type)) { - throw new IllegalStateException("A handler is already registered for " + type); - } - - handlers.put(type, new Handler<>(clazz, handler)); + @SneakyThrows + public void registerSignal(Class incomingSignal, BiConsumer handler) { + val type = getTypeViaIntrospection(incomingSignal); + registerIfNotExists(incomingSignal, type, (claims, in) -> { + handler.accept(claims, in); + return null; + }); } /** @@ -73,11 +94,18 @@ public void register(Class clazz, String typ * {@link #registerSignal(Class, Consumer)} for type safety. */ public void registerSignal(Class clazz, String type, Consumer handler) { + registerIfNotExists(clazz, type, (claims, in) -> { + handler.accept(in); + return null; + }); + } + + public void registerSignal(Class clazz, String type, BiConsumer handler) { if (handlers.containsKey(type)) { throw new IllegalStateException("A handler is already registered for " + type); } - register(clazz, type, in -> { - handler.accept(in); + registerIfNotExists(clazz, type, (claims, in) -> { + handler.accept(claims, in); return null; }); } @@ -89,14 +117,23 @@ public void registerSignal(Class clazz, String ty * @return The function to process this message type. */ @SuppressWarnings("unchecked") - public Handler getHandler(String type) { - return (Handler) handlers.get(type); + public HandlerBox getHandler(String type) { + return (HandlerBox) handlers.get(type); } - private static String getTypeViaIntrospection(Class incomingMessage) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { + @SneakyThrows + private static String getTypeViaIntrospection(Class incomingMessage) { val defaultConstructor = incomingMessage.getConstructor(); defaultConstructor.setAccessible(true); val type = defaultConstructor.newInstance().getType(); return type; } + + private void registerIfNotExists(Class clazz, String type, BiFunction handler) { + if (handlers.containsKey(type)) { + throw new IllegalStateException("A handler is already registered for " + type); + } + + handlers.put(type, new HandlerBox<>(clazz, handler)); + } } 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 5acc77c21..1981039aa 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 @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.controller; @@ -17,7 +18,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import de.sovity.edc.extension.messenger.SovityMessage; import de.sovity.edc.extension.messenger.SovityMessengerRegistry; -import de.sovity.edc.extension.messenger.impl.Handler; +import de.sovity.edc.extension.messenger.impl.HandlerBox; import de.sovity.edc.extension.messenger.impl.SovityMessageRequest; import de.sovity.edc.extension.messenger.impl.SovityMessageResponse; import de.sovity.edc.extension.messenger.impl.SovityMessengerStatus; @@ -36,6 +37,7 @@ import lombok.val; import org.eclipse.edc.protocol.dsp.api.configuration.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; @@ -61,6 +63,7 @@ public class SovityMessageController { private final TypeTransformerRegistry typeTransformerRegistry; private final Monitor monitor; private final ObjectMapper mapper; + private final ParticipantAgentService participant; @Getter private final SovityMessengerRegistry handlers; @@ -78,6 +81,8 @@ public Response post( ).build(); } + val claims = validation.getContent(); + val handler = getHandler(request); if (handler == null) { val errorAnswer = buildErrorNoHandlerHeader(request); @@ -87,7 +92,7 @@ public Response post( } try { - val response = processMessage(request, handler); + val response = processMessage(request, handler, claims); return typeTransformerRegistry.transform(response, JsonObject.class) .map(it -> Response.ok().type(MediaType.APPLICATION_JSON).entity(it).build()) @@ -108,10 +113,10 @@ public Response post( } } - private SovityMessageResponse processMessage(SovityMessageRequest compacted, Handler handler) 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(parsed); + val result = handler.handler().apply(claims, parsed); val resultBody = mapper.writeValueAsString(result); val response = new SovityMessageResponse( @@ -165,7 +170,7 @@ private SovityMessageResponse buildErrorHandlerExceptionHeader(SovityMessageRequ return new SovityMessageResponse(headerStr, ""); } - private Handler getHandler(SovityMessageRequest request) { + private HandlerBox getHandler(SovityMessageRequest request) { final var messageType = getMessageType(request); return handlers.getHandler(messageType); } diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/Handler.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/HandlerBox.java similarity index 69% rename from extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/Handler.java rename to extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/HandlerBox.java index 4e7ef993b..7112a803b 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/Handler.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/HandlerBox.java @@ -9,11 +9,14 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.impl; -import java.util.function.Function; +import org.eclipse.edc.spi.iam.ClaimToken; + +import java.util.function.BiFunction; -public record Handler(Class clazz, Function handler) { +public record HandlerBox(Class clazz, BiFunction handler) { } 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 baf15f102..1a3f36c78 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 @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.impl; diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/JsonObjectFromSovityMessageResponse.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/JsonObjectFromSovityMessageResponse.java index 9ae6a42e8..b8c747c24 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/JsonObjectFromSovityMessageResponse.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/JsonObjectFromSovityMessageResponse.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.impl; 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/MessageEmitter.java index 1ba6bfb46..c6350f7b3 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/MessageEmitter.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.impl; 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 index c997b9e4b..ff53f5dde 100644 --- 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 @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.impl; diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/ObjectMapperFactory.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/ObjectMapperFactory.java index 4c794e5ba..f158e9ca8 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/ObjectMapperFactory.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/ObjectMapperFactory.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.impl; 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 4a057b76f..b5d330437 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 @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.impl; diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageResponse.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageResponse.java index e6c79d291..c966f187c 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageResponse.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessageResponse.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.impl; diff --git a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessengerStatus.java b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessengerStatus.java index 516c16dce..799a9ab44 100644 --- a/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessengerStatus.java +++ b/extensions/sovity-messenger/src/main/java/de/sovity/edc/extension/messenger/impl/SovityMessengerStatus.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.impl; 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 dce553b83..898c9645f 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 @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/controller/Answer.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/controller/Answer.java index e21839a13..0b4d1281c 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/controller/Answer.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/controller/Answer.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.controller; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/controller/Payload.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/controller/Payload.java index 6d791d5bf..2d3cc5c90 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/controller/Payload.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/controller/Payload.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.controller; 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 c297e442a..35dd978f0 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 @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.controller; @@ -23,6 +24,8 @@ 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; @@ -32,9 +35,12 @@ import java.net.MalformedURLException; import java.net.URL; +import java.util.Map; import java.util.function.Function; +import static java.util.Collections.emptyMap; import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.spi.agent.ParticipantAgentService.DEFAULT_IDENTITY_CLAIM_KEY; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; @@ -48,9 +54,15 @@ class SovityMessageControllerTest { private ObjectMapper objectMapper = omf.createObjectMapper(); private IdentityService identityService = mock(IdentityService.class); private SovityMessengerRegistry handlers = new SovityMessengerRegistry(); + private ParticipantAgentService participantAgentService = mock(ParticipantAgentService.class); @BeforeEach public void beforeEach() { + reset( + participantAgentService, + identityService + ); + transformers = new TypeTransformerRegistryImpl(); transformers.register(new JsonObjectFromSovityMessageRequest()); transformers.register(new JsonObjectFromSovityMessageResponse()); @@ -62,7 +74,6 @@ public void beforeEach() { handlers = new SovityMessengerRegistry(); - reset(identityService); when(identityService.verifyJwtToken(any(), any())).thenReturn(Result.success(ClaimToken.Builder.newInstance().build())); } @@ -78,6 +89,7 @@ void canAnswerRequest() throws JsonProcessingException, MalformedURLException { transformers, monitor, objectMapper, + participantAgentService, handlers ); @@ -106,7 +118,14 @@ void post_whenNonAuthorized_shouldReturnHttp401() throws MalformedURLException, val identityService = mock(IdentityService.class); when(identityService.verifyJwtToken(any(), any())).thenReturn(Result.failure("Invalid token")); - val controller = new SovityMessageController(identityService, "http://example.com/callback", transformers, monitor, objectMapper, handlers); + val controller = new SovityMessageController( + identityService, + "http://example.com/callback", + transformers, + monitor, + objectMapper, + participantAgentService, + handlers); val message = new SovityMessageRequest( new URL("https://example.com/api"), @@ -122,4 +141,40 @@ void post_whenNonAuthorized_shouldReturnHttp401() throws MalformedURLException, } } + @Test + void canIdentifyTheEmittingEdc() throws JsonProcessingException, MalformedURLException { + // arrange + when(participantAgentService.createFor(any())) + .thenReturn(new ParticipantAgent(Map.of(DEFAULT_IDENTITY_CLAIM_KEY, "theRealEdc"), emptyMap())); + + val handlers = new SovityMessengerRegistry(); + + val controller = new SovityMessageController( + identityService, + "http://example.com/callback", + transformers, + monitor, + objectMapper, + participantAgentService, + handlers + ); + + Function handler = payload -> new Answer(String.valueOf(payload.getInteger())); + handlers.register(Payload.class, "foo", handler); + + val message = new SovityMessageRequest( + new URL("https://example.com/api"), + """ + { "type" : "foo" } + """, + objectMapper.writeValueAsString(new Payload(1))); + + // act + + try (val response = controller.post("", message)) { + // assert + assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode()); + } + + } } diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/SovityMessengerDemo.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/SovityMessengerDemo.java index 1052df2b9..a7b67d458 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/SovityMessengerDemo.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/SovityMessengerDemo.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.demo; @@ -17,10 +18,13 @@ import de.sovity.edc.extension.messenger.SovityMessengerRegistry; import de.sovity.edc.extension.messenger.demo.message.Addition; import de.sovity.edc.extension.messenger.demo.message.Answer; +import de.sovity.edc.extension.messenger.demo.message.Counterparty; import de.sovity.edc.extension.messenger.demo.message.Failing; import de.sovity.edc.extension.messenger.demo.message.Signal; import de.sovity.edc.extension.messenger.demo.message.Sqrt; +import lombok.val; import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.agent.ParticipantAgentService; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; @@ -29,6 +33,9 @@ public class SovityMessengerDemo implements ServiceExtension { + @Inject + private ParticipantAgentService participantAgentService; + public static final String NAME = "sovityMessengerDemo"; @Override @@ -62,6 +69,12 @@ public void initialize(ServiceExtensionContext context) { throw new RuntimeException("Failed!"); }); + + registry.register(Counterparty.class, (claims, counterparty) -> { + val agent = participantAgentService.createFor(claims); + return new Answer(); + }); + /* * In the counterpart connector, messages can be sent with the code below. * Check out the de.sovity.edc.extension.sovitymessenger.demo.SovityMessengerDemoTest#demo() 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 afc357de9..9a4c57992 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 @@ -9,78 +9,40 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.demo; 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.db.EdcRuntimeExtensionWithTestDatabase; import de.sovity.edc.extension.messenger.SovityMessenger; import de.sovity.edc.extension.messenger.SovityMessengerException; import de.sovity.edc.extension.messenger.demo.message.Addition; import de.sovity.edc.extension.messenger.demo.message.Answer; +import de.sovity.edc.extension.messenger.demo.message.Counterparty; import de.sovity.edc.extension.messenger.demo.message.Failing; import de.sovity.edc.extension.messenger.demo.message.Signal; 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 lombok.SneakyThrows; import lombok.val; -import org.eclipse.edc.junit.extensions.EdcExtension; -import org.eclipse.edc.spi.iam.TokenDecorator; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; +import static java.util.concurrent.TimeUnit.SECONDS; class SovityMessengerDemoTest { - // Setup, you may skip this part - - 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(); - @RegisterExtension - static final TestDatabase RECEIVER_DATABASE = new TestDatabaseViaTestcontainers(); - - private ConnectorConfig providerConfig; - private ConnectorConfig consumerConfig; - - private String receiverAddress; - - // still setup, skip - - @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); - - receiverAddress = "http://localhost:" + consumerConfig.getProtocolEndpoint().port() + consumerConfig.getProtocolEndpoint().path(); - } - - /** - * Actual usage of the Sovity Messenger. - */ @DisabledOnGithub @Test - void demo() throws ExecutionException, InterruptedException, TimeoutException { + @SneakyThrows + void demo() { /* * Get a reference to the SovityMessenger. This is equivalent to * @@ -90,21 +52,23 @@ void demo() throws ExecutionException, InterruptedException, TimeoutException { * * This messenger is already configured to accept messages in de.sovity.edc.extension.messenger.demo.SovityMessengerDemo#initialize */ - val messenger = emitterEdcContext.getContext().getService(SovityMessenger.class); + val messenger = emitterExtension.getEdcRuntimeExtension().getContext().getService(SovityMessenger.class); System.out.println("START MARKER"); // 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()); try { // Wait for the answers - added.get(2, TimeUnit.SECONDS).onSuccess(it -> System.out.println(it.getAnswer())); - rooted.get(2, TimeUnit.SECONDS).onSuccess(it -> System.out.println(it.getAnswer())); - unregistered.get(2, TimeUnit.SECONDS); + added.get(2, SECONDS).onSuccess(it -> System.out.println(it.getAnswer())); + rooted.get(2, SECONDS).onSuccess(it -> System.out.println(it.getAnswer())); + withClaims.get(2, SECONDS); + unregistered.get(2, SECONDS); } catch (ExecutionException e) { /* * When a problem happens, a SovityMessengerException is thrown and encapsulated in an ExecutionException. @@ -115,8 +79,8 @@ void demo() throws ExecutionException, InterruptedException, TimeoutException { 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")); - failing1.get(2, TimeUnit.SECONDS); - failing2.get(2, TimeUnit.SECONDS); + failing1.get(2, SECONDS); + failing2.get(2, SECONDS); } catch (ExecutionException e) { val cause = e.getCause(); if (cause instanceof SovityMessengerException messengerException) { @@ -130,4 +94,33 @@ void demo() throws ExecutionException, InterruptedException, TimeoutException { 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.getProtocolEndpoint().getUri().toString(); + } } diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Addition.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Addition.java index 370a5c7bf..3160cfa72 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Addition.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Addition.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.demo.message; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Answer.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Answer.java index 8c79d1487..ac9bb2cc6 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Answer.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Answer.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.demo.message; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Counterparty.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Counterparty.java new file mode 100644 index 000000000..e2076eb28 --- /dev/null +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Counterparty.java @@ -0,0 +1,24 @@ +/* + * 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.demo.message; + +import de.sovity.edc.extension.messenger.SovityMessage; + +public class Counterparty implements SovityMessage { + @Override + public String getType() { + return "counterparty"; + } +} diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Failing.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Failing.java index 17dfa78be..533555b26 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Failing.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Failing.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.demo.message; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Multiplication.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Multiplication.java index f82c27dc3..fc142fa84 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Multiplication.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Multiplication.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.demo.message; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Signal.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Signal.java index 5cf54edff..5189ccf5b 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Signal.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Signal.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.demo.message; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Sqrt.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Sqrt.java index b2011d507..147b1abad 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Sqrt.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/Sqrt.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.demo.message; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/UnregisteredMessage.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/UnregisteredMessage.java index 5f1be9879..c7c3c5c02 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/UnregisteredMessage.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/demo/message/UnregisteredMessage.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.demo.message; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/Addition.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/Addition.java index a5f270e70..97fb90c57 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/Addition.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/Addition.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.dto; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/Answer.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/Answer.java index 29d3fa236..5bcc85af4 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/Answer.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/Answer.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.dto; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/Multiplication.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/Multiplication.java index e25689bb6..d3511bd4a 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/Multiplication.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/Multiplication.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.dto; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/UnsupportedMessage.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/UnsupportedMessage.java index 9ccad0e52..377a6a30b 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/UnsupportedMessage.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/dto/UnsupportedMessage.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.dto; 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 c8df906ee..89cb3308c 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 @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.echo; 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/MessageEmitterTest.java index 8369c7595..1d27a3f88 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/MessageEmitterTest.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.impl; diff --git a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/SovityMessengerRegistryImplTest.java b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/SovityMessengerRegistryImplTest.java index b2c44cd72..de996408b 100644 --- a/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/SovityMessengerRegistryImplTest.java +++ b/extensions/sovity-messenger/src/test/java/de/sovity/edc/extension/messenger/impl/SovityMessengerRegistryImplTest.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.impl; @@ -20,6 +21,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.val; +import org.eclipse.edc.spi.iam.ClaimToken; import org.junit.jupiter.api.Test; import java.util.function.Function; @@ -54,7 +56,7 @@ void canRegisterAndRetrieveHandler() { val back = handlers.getHandler("itoa"); // assert - assertThat(back.handler().apply(new MyInt(1))).isEqualTo("1"); + assertThat(back.handler().apply(ClaimToken.Builder.newInstance().build(), new MyInt(1))).isEqualTo("1"); } @Test 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 6c2334d85..272d9e642 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 @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.extension.messenger.impl; @@ -18,6 +19,7 @@ import de.sovity.edc.extension.messenger.dto.UnsupportedMessage; import lombok.val; import org.eclipse.edc.spi.message.RemoteMessageDispatcherRegistry; +import org.eclipse.edc.spi.monitor.ConsoleMonitor; import org.eclipse.edc.spi.response.StatusResult; import org.junit.jupiter.api.Test; @@ -50,7 +52,7 @@ void send_whenNoHandler_shouldThrowSovityMessengerException() throws MalformedUR null))); when(registry.dispatch(any(), any())).thenReturn(future); - val messenger = new SovityMessenger(registry, new ObjectMapperFactory().createObjectMapper()); + val messenger = new SovityMessenger(registry, new ObjectMapperFactory().createObjectMapper(), new ConsoleMonitor()); val answer = messenger.send(Answer.class, "https://example.com/api/dsp", new UnsupportedMessage()); // act diff --git a/extensions/test-backend-controller/src/main/java/de/sovity/edc/extension/testbackendcontroller/TestBackendController.java b/extensions/test-backend-controller/src/main/java/de/sovity/edc/extension/testbackendcontroller/TestBackendController.java index 3f7777cd0..8f1ea1676 100644 --- a/extensions/test-backend-controller/src/main/java/de/sovity/edc/extension/testbackendcontroller/TestBackendController.java +++ b/extensions/test-backend-controller/src/main/java/de/sovity/edc/extension/testbackendcontroller/TestBackendController.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.testbackendcontroller; diff --git a/extensions/test-backend-controller/src/main/java/de/sovity/edc/extension/testbackendcontroller/TestBackendExtension.java b/extensions/test-backend-controller/src/main/java/de/sovity/edc/extension/testbackendcontroller/TestBackendExtension.java index 4d5943187..d582486d9 100644 --- a/extensions/test-backend-controller/src/main/java/de/sovity/edc/extension/testbackendcontroller/TestBackendExtension.java +++ b/extensions/test-backend-controller/src/main/java/de/sovity/edc/extension/testbackendcontroller/TestBackendExtension.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.testbackendcontroller; diff --git a/extensions/wrapper/clients/java-client-example/src/test/java/de/sovity/edc/client/examples/GreetingResourceTest.java b/extensions/wrapper/clients/java-client-example/src/test/java/de/sovity/edc/client/examples/GreetingResourceTest.java index 4617344e5..7159c7a98 100644 --- a/extensions/wrapper/clients/java-client-example/src/test/java/de/sovity/edc/client/examples/GreetingResourceTest.java +++ b/extensions/wrapper/clients/java-client-example/src/test/java/de/sovity/edc/client/examples/GreetingResourceTest.java @@ -17,14 +17,11 @@ import de.sovity.edc.client.EdcClient; import de.sovity.edc.client.gen.api.UseCaseApi; import de.sovity.edc.client.gen.model.KpiResult; -import de.sovity.edc.client.gen.model.TransferProcessStatesDto; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.mockito.InjectMock; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.util.Map; - import static io.restassured.RestAssured.given; import static org.hamcrest.CoreMatchers.is; import static org.mockito.Mockito.mock; diff --git a/extensions/wrapper/wrapper-api/build.gradle.kts b/extensions/wrapper/wrapper-api/build.gradle.kts index 74003ce23..48644fa8b 100644 --- a/extensions/wrapper/wrapper-api/build.gradle.kts +++ b/extensions/wrapper/wrapper-api/build.gradle.kts @@ -15,14 +15,14 @@ dependencies { api(project(":extensions:wrapper:wrapper-common-mappers")) api(project(":extensions:wrapper:wrapper-ee-api")) - implementation(libs.jakarta.validationApi) + implementation(libs.apache.commonsLang) + implementation(libs.hibernate.validation) + implementation(libs.jakarta.el) implementation(libs.jakarta.rsApi) - implementation(libs.swagger.annotationsJakarta) - implementation(libs.swagger.jaxrs2Jakarta) implementation(libs.jakarta.servletApi) implementation(libs.jakarta.validationApi) - implementation(libs.jakarta.rsApi) - implementation(libs.apache.commonsLang) + implementation(libs.swagger.annotationsJakarta) + implementation(libs.swagger.jaxrs2Jakarta) } val openapiFileDir = "${project.buildDir}/swagger" 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 aa12367c2..9c28a1be2 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 @@ -34,7 +34,10 @@ import de.sovity.edc.ext.wrapper.api.ui.model.UiContractNegotiation; import de.sovity.edc.ext.wrapper.api.ui.model.UiDataOffer; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -144,9 +147,13 @@ interface UiResource { @POST @Path("pages/contract-agreement-page") + @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @Operation(description = "Collect filtered data for the Contract Agreement Page") - ContractAgreementPage getContractAgreementPage(@Nullable ContractAgreementPageQuery contractAgreementPageQuery); + ContractAgreementPage getContractAgreementPage( + @RequestBody(description = "If null, returns all the contract agreements.") + @Nullable ContractAgreementPageQuery contractAgreementPageQuery + ); @POST @Path("pages/contract-agreement-page/transfers") diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementPageQuery.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementPageQuery.java index c4803a142..f836e5399 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementPageQuery.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementPageQuery.java @@ -9,10 +9,13 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.ext.wrapper.api.ui.model; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; @@ -21,6 +24,7 @@ @Data @AllArgsConstructor @NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) @Schema(description = "Filters for querying a Contract Contract Agreement Page") public class ContractAgreementPageQuery { @Schema( diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementTerminationInfo.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementTerminationInfo.java index 0f7cf243e..cd80f3f86 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementTerminationInfo.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementTerminationInfo.java @@ -9,17 +9,20 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.ext.wrapper.api.ui.model; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.time.OffsetDateTime; +@Builder @Data @AllArgsConstructor @NoArgsConstructor diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractTerminatedBy.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractTerminatedBy.java index f249a3869..9ec952739 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractTerminatedBy.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractTerminatedBy.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.ext.wrapper.api.ui.model; diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractTerminationRequest.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractTerminationRequest.java index 45a98dfcd..6f570e607 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractTerminationRequest.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractTerminationRequest.java @@ -9,11 +9,13 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.ext.wrapper.api.ui.model; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -27,16 +29,20 @@ @RequiredArgsConstructor @Schema(description = "Data for terminating a Contract Agreement") public class ContractTerminationRequest { - - @Schema( - title = "Termination reason", - description = "A short reason why this contract was terminated", - requiredMode = Schema.RequiredMode.REQUIRED) - String reason; + public static final int MAX_REASON_SIZE = 100; + public static final int MAX_DETAIL_SIZE = 1000; @Schema( title = "Termination detail", description = "A user explanation to detail why the contract was terminated.", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @Size(max = MAX_DETAIL_SIZE) String detail; + + @Schema( + title = "Termination reason", + description = "A short reason why this contract was terminated", + requiredMode = Schema.RequiredMode.REQUIRED) + @Size(max = MAX_REASON_SIZE) + String reason; } diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractTerminationStatus.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractTerminationStatus.java index 652c18364..68c641516 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractTerminationStatus.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractTerminationStatus.java @@ -9,6 +9,7 @@ * * Contributors: * sovity GmbH - initial API and implementation + * */ package de.sovity.edc.ext.wrapper.api.ui.model; 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 9dfa624a9..20289bfe9 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 @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.ui.model; diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResource.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResource.java index 218b337dd..51408dfce 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResource.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResource.java @@ -58,7 +58,7 @@ public interface UseCaseResource { @Produces(MediaType.APPLICATION_JSON) @Operation(description = "Fetch a connector's data offers") List queryCatalog( - @Valid @NotNull + @NotNull CatalogQuery catalogQuery ); diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AtomicConstraintDto.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AtomicConstraintDto.java index 560f93ce2..8419b712a 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AtomicConstraintDto.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AtomicConstraintDto.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.model; diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/OperatorDto.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/OperatorDto.java index 34ab6a955..0e31e0ff7 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/OperatorDto.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/OperatorDto.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.model; diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PermissionDto.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PermissionDto.java index 5c107ab29..a783f1348 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PermissionDto.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PermissionDto.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.model; diff --git a/extensions/wrapper/wrapper-common-mappers/build.gradle.kts b/extensions/wrapper/wrapper-common-mappers/build.gradle.kts index d468dadee..fe5a1bf79 100644 --- a/extensions/wrapper/wrapper-common-mappers/build.gradle.kts +++ b/extensions/wrapper/wrapper-common-mappers/build.gradle.kts @@ -27,7 +27,6 @@ dependencies { testImplementation(libs.junit.api) testImplementation(libs.junit.params) testImplementation(libs.mockito.core) - testImplementation(libs.mockito.inline) testImplementation(libs.mockito.junitJupiter) testRuntimeOnly(libs.junit.engine) } 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 78f4fcb4d..168dc5666 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 @@ -14,9 +14,9 @@ package de.sovity.edc.ext.wrapper.api.common.mappers; +import de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils.FailedMappingException; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.AtomicConstraintMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ConstraintExtractor; -import de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils.FailedMappingException; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.MappingErrors; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.PolicyValidator; import de.sovity.edc.ext.wrapper.api.common.model.Expression; diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetEditRequestMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetEditRequestMapper.java index 3ad1344e5..c65fe5243 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetEditRequestMapper.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/AssetEditRequestMapper.java @@ -14,10 +14,10 @@ package de.sovity.edc.ext.wrapper.api.common.mappers.asset; +import de.sovity.edc.ext.wrapper.api.common.model.DataSourceType; import de.sovity.edc.ext.wrapper.api.common.model.UiAssetCreateRequest; import de.sovity.edc.ext.wrapper.api.common.model.UiAssetEditRequest; import de.sovity.edc.ext.wrapper.api.common.model.UiDataSource; -import de.sovity.edc.ext.wrapper.api.common.model.DataSourceType; import lombok.NonNull; import lombok.RequiredArgsConstructor; 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 936ebaf1d..e8c7cd00b 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 @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.mappers.asset; 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 84050b94b..4ce35bc5c 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 @@ -8,15 +8,16 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.mappers.asset; import de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils.AssetJsonLdUtils; import de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils.ShortDescriptionBuilder; -import de.sovity.edc.ext.wrapper.api.common.model.UiAsset; import de.sovity.edc.ext.wrapper.api.common.model.DataSourceAvailability; +import de.sovity.edc.ext.wrapper.api.common.model.UiAsset; import de.sovity.edc.utils.JsonUtils; import de.sovity.edc.utils.jsonld.JsonLdUtils; import de.sovity.edc.utils.jsonld.vocab.Prop; diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/AssetJsonLdUtils.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/AssetJsonLdUtils.java index c0a018eba..d0ab38673 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/AssetJsonLdUtils.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/AssetJsonLdUtils.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils; diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/EdcPropertyUtils.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/EdcPropertyUtils.java index e7f198345..d305809d9 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/EdcPropertyUtils.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/EdcPropertyUtils.java @@ -8,18 +8,17 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils; -import lombok.RequiredArgsConstructor; import org.eclipse.edc.spi.types.domain.DataAddress; import java.util.HashMap; import java.util.Map; -@RequiredArgsConstructor public class EdcPropertyUtils { /** diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/FailedMappingException.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/FailedMappingException.java index f9063dc11..be429af06 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/FailedMappingException.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/FailedMappingException.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils; diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/JsonBuilderUtils.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/JsonBuilderUtils.java index a2158e37e..a182b75a0 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/JsonBuilderUtils.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/JsonBuilderUtils.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils; diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/ShortDescriptionBuilder.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/ShortDescriptionBuilder.java index 1f59e9960..a82c2ab1f 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/ShortDescriptionBuilder.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/ShortDescriptionBuilder.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils; diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapper.java index 47c75f218..7586a2081 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapper.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapper.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.mappers.policy; @@ -19,7 +20,6 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.eclipse.edc.policy.model.AtomicConstraint; -import org.eclipse.edc.policy.model.Constraint; import org.eclipse.edc.policy.model.LiteralExpression; import java.util.List; diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractor.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractor.java index 1ac5f3ca1..405d166dc 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractor.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractor.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.mappers.policy; diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/LiteralMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/LiteralMapper.java index 92f0194bc..f271cd773 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/LiteralMapper.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/LiteralMapper.java @@ -8,13 +8,13 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.mappers.policy; import com.fasterxml.jackson.databind.ObjectMapper; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.MappingErrors; import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyLiteral; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/MappingErrors.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/MappingErrors.java index ad58bde83..3dc6e4b65 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/MappingErrors.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/MappingErrors.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.mappers.policy; 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 7bdc44502..92b24cfad 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 @@ -8,12 +8,12 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.common.mappers.policy; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.MappingErrors; import lombok.RequiredArgsConstructor; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/EdcPropertyUtilsTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/EdcPropertyUtilsTest.java index 87f593789..8a6482870 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/EdcPropertyUtilsTest.java +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/EdcPropertyUtilsTest.java @@ -14,7 +14,6 @@ package de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils; -import de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils.EdcPropertyUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/ShortDescriptionBuilderTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/ShortDescriptionBuilderTest.java index 480b584f1..e1986bae0 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/ShortDescriptionBuilderTest.java +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/ShortDescriptionBuilderTest.java @@ -14,7 +14,6 @@ package de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractorTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractorTest.java index 4f7730469..0245b6bb0 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractorTest.java +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractorTest.java @@ -14,10 +14,6 @@ package de.sovity.edc.ext.wrapper.api.common.mappers.policy; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.AtomicConstraintMapper; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ConstraintExtractor; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.MappingErrors; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.PolicyValidator; import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyConstraint; import org.eclipse.edc.policy.model.AndConstraint; import org.eclipse.edc.policy.model.AtomicConstraint; diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/LiteralMapperTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/LiteralMapperTest.java index 3c4786117..052890d4a 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/LiteralMapperTest.java +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/LiteralMapperTest.java @@ -15,8 +15,6 @@ package de.sovity.edc.ext.wrapper.api.common.mappers.policy; import com.fasterxml.jackson.databind.ObjectMapper; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.LiteralMapper; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.MappingErrors; import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyLiteral; import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyLiteralType; import org.eclipse.edc.policy.model.Expression; diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/MappingErrorsTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/MappingErrorsTest.java index a217ffa88..f65d52a88 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/MappingErrorsTest.java +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/MappingErrorsTest.java @@ -14,7 +14,6 @@ package de.sovity.edc.ext.wrapper.api.common.mappers.policy; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.MappingErrors; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/OperatorMapperTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/OperatorMapperTest.java index 18635313f..0283d5ead 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/OperatorMapperTest.java +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/OperatorMapperTest.java @@ -14,7 +14,6 @@ package de.sovity.edc.ext.wrapper.api.common.mappers.policy; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.OperatorMapper; import de.sovity.edc.ext.wrapper.api.common.model.OperatorDto; import org.assertj.core.api.Assertions; import org.eclipse.edc.policy.model.Operator; 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 1e28f8ebf..2151874d6 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 @@ -28,8 +28,6 @@ package de.sovity.edc.ext.wrapper.api.common.mappers.policy; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.MappingErrors; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.PolicyValidator; import org.eclipse.edc.policy.model.Action; import org.eclipse.edc.policy.model.Constraint; import org.eclipse.edc.policy.model.Duty; diff --git a/extensions/wrapper/wrapper/build.gradle.kts b/extensions/wrapper/wrapper/build.gradle.kts index 55b88a8f2..2a080c73b 100644 --- a/extensions/wrapper/wrapper/build.gradle.kts +++ b/extensions/wrapper/wrapper/build.gradle.kts @@ -8,25 +8,37 @@ dependencies { annotationProcessor(libs.lombok) compileOnly(libs.lombok) - implementation(libs.edc.apiCore) - implementation(libs.edc.managementApiConfiguration) - implementation(libs.edc.dspHttpSpi) api(project(":extensions:wrapper:wrapper-api")) api(project(":extensions:wrapper:wrapper-common-mappers")) api(project(":utils:catalog-parser")) api(project(":utils:json-and-jsonld-utils")) + api(libs.edc.contractDefinitionApi) api(libs.edc.controlPlaneSpi) api(libs.edc.coreSpi) api(libs.edc.policyDefinitionApi) api(libs.edc.transferProcessApi) + + implementation(project(":extensions:contract-termination")) + implementation(project(":extensions:database-direct-access")) + implementation(project(":extensions:sovity-messenger")) + implementation(project(":utils:jooq-database-access")) + implementation(libs.apache.commonsLang) + implementation(libs.edc.apiCore) + implementation(libs.edc.managementApiConfiguration) + implementation(libs.edc.dspHttpSpi) + implementation(libs.jooq.jooq) + implementation(libs.hibernate.validation) + implementation(libs.hikari) + implementation(libs.jakarta.el) testAnnotationProcessor(libs.lombok) testCompileOnly(libs.lombok) testImplementation(project(":extensions:wrapper:clients:java-client")) testImplementation(project(":extensions:policy-always-true")) + testImplementation(project(":extensions:postgres-flyway")) testImplementation(project(":utils:test-utils")) testImplementation(libs.edc.controlPlaneCore) testImplementation(libs.edc.dsp) @@ -44,10 +56,13 @@ dependencies { // Updated jetty versions for e.g. CVE-2023-26048 testImplementation(libs.bundles.jetty.cve2023) - testImplementation(libs.edc.jsonLd) + testImplementation(libs.edc.controlPlaneSql) + testImplementation(libs.edc.contractNegotiationStoreSql) testImplementation(libs.edc.dspHttpSpi) testImplementation(libs.edc.dspApiConfiguration) testImplementation(libs.edc.dataPlaneSelectorCore) + testImplementation(libs.edc.jsonLd) + testImplementation(libs.edc.transferProcessStoreSql) testImplementation(libs.jsonUnit.assertj) testImplementation(libs.restAssured.restAssured) 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 82c993a55..8f2b29210 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 @@ -17,6 +17,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import de.sovity.edc.extension.contacttermination.ContractAgreementTerminationService; +import de.sovity.edc.extension.db.directaccess.DslContextFactory; +import de.sovity.edc.extension.messenger.SovityMessenger; 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; @@ -42,7 +45,9 @@ public class WrapperExtension implements ServiceExtension { + public static final String EXTENSION_NAME = "WrapperExtension"; + @Inject private AssetIndex assetIndex; @Inject @@ -52,18 +57,24 @@ public class WrapperExtension implements ServiceExtension { @Inject private ContractAgreementService contractAgreementService; @Inject + private ContractAgreementTerminationService contractAgreementTerminationService; + @Inject private ContractDefinitionStore contractDefinitionStore; @Inject private ContractNegotiationService contractNegotiationService; @Inject private ContractNegotiationStore contractNegotiationStore; @Inject + private DslContextFactory dslContextFactory; + @Inject private ManagementApiConfiguration dataManagementApiConfiguration; @Inject private PolicyDefinitionStore policyDefinitionStore; @Inject private PolicyEngine policyEngine; @Inject + private SovityMessenger sovityMessenger; + @Inject private TransferProcessService transferProcessService; @Inject private TransferProcessStore transferProcessStore; @@ -91,30 +102,33 @@ public void initialize(ServiceExtensionContext context) { fixObjectMapperDateSerialization(objectMapper); var wrapperExtensionContext = WrapperExtensionContextBuilder.buildContext( - assetIndex, - assetService, - catalogService, - context.getConfig(), - contractAgreementService, - contractDefinitionService, - contractDefinitionStore, - contractNegotiationService, - contractNegotiationStore, - jsonLd, - context.getMonitor(), - objectMapper, - policyDefinitionService, - policyDefinitionStore, - policyEngine, - transferProcessService, - transferProcessStore, - typeTransformerRegistry + assetIndex, + assetService, + catalogService, + context.getConfig(), + contractAgreementService, + contractAgreementTerminationService, + contractDefinitionService, + contractDefinitionStore, + contractNegotiationService, + contractNegotiationStore, + dslContextFactory, + jsonLd, + context.getMonitor(), + objectMapper, + policyDefinitionService, + policyDefinitionStore, + policyEngine, + sovityMessenger, + transferProcessService, + transferProcessStore, + typeTransformerRegistry ); wrapperExtensionContext.selfDescriptionService().validateSelfDescriptionConfig(); wrapperExtensionContext.jaxRsResources().forEach(resource -> - webService.registerResource(dataManagementApiConfiguration.getContextAlias(), resource)); + webService.registerResource(dataManagementApiConfiguration.getContextAlias(), 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 36074d5ed..5a1d41324 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 @@ -38,6 +38,7 @@ import de.sovity.edc.ext.wrapper.api.ui.pages.catalog.CatalogApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.catalog.UiDataOfferBuilder; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.ContractAgreementPageApiService; +import de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.ContractAgreementTerminationApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.ContractAgreementTransferApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.services.ContractAgreementDataFetcher; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.services.ContractAgreementPageCardBuilder; @@ -71,6 +72,11 @@ import de.sovity.edc.ext.wrapper.api.usecase.pages.catalog.UseCaseCatalogApiService; import de.sovity.edc.ext.wrapper.api.usecase.services.KpiApiService; import de.sovity.edc.ext.wrapper.api.usecase.services.SupportedPolicyApiService; +import de.sovity.edc.extension.contacttermination.ContractAgreementTerminationService; +import de.sovity.edc.extension.contacttermination.query.ContractAgreementTerminationDetailsQuery; +import de.sovity.edc.extension.contacttermination.query.TerminateContractQuery; +import de.sovity.edc.extension.db.directaccess.DslContextFactory; +import de.sovity.edc.extension.messenger.SovityMessenger; import de.sovity.edc.utils.catalog.DspCatalogService; import de.sovity.edc.utils.catalog.mapper.DspDataOfferBuilder; import lombok.NoArgsConstructor; @@ -109,24 +115,27 @@ public class WrapperExtensionContextBuilder { public static WrapperExtensionContext buildContext( - AssetIndex assetIndex, - AssetService assetService, - CatalogService catalogService, - Config config, - ContractAgreementService contractAgreementService, - ContractDefinitionService contractDefinitionService, - ContractDefinitionStore contractDefinitionStore, - ContractNegotiationService contractNegotiationService, - ContractNegotiationStore contractNegotiationStore, - JsonLd jsonLd, - Monitor monitor, - ObjectMapper objectMapper, - PolicyDefinitionService policyDefinitionService, - PolicyDefinitionStore policyDefinitionStore, - PolicyEngine policyEngine, - TransferProcessService transferProcessService, - TransferProcessStore transferProcessStore, - TypeTransformerRegistry typeTransformerRegistry + AssetIndex assetIndex, + AssetService assetService, + CatalogService catalogService, + Config config, + ContractAgreementService contractAgreementService, + ContractAgreementTerminationService contractAgreementTerminationService, + ContractDefinitionService contractDefinitionService, + ContractDefinitionStore contractDefinitionStore, + ContractNegotiationService contractNegotiationService, + ContractNegotiationStore contractNegotiationStore, + DslContextFactory dslContextFactory, + JsonLd jsonLd, + Monitor monitor, + ObjectMapper objectMapper, + PolicyDefinitionService policyDefinitionService, + PolicyDefinitionStore policyDefinitionStore, + PolicyEngine policyEngine, + SovityMessenger sovityMessenger, + TransferProcessService transferProcessService, + TransferProcessStore transferProcessStore, + TypeTransformerRegistry typeTransformerRegistry ) { // UI API var operatorMapper = new OperatorMapper(); @@ -138,188 +147,193 @@ public static WrapperExtensionContext buildContext( var policyValidator = new PolicyValidator(); var constraintExtractor = new ConstraintExtractor(policyValidator, atomicConstraintMapper); var policyMapper = new PolicyMapper( - constraintExtractor, - atomicConstraintMapper, - typeTransformerRegistry); + constraintExtractor, + atomicConstraintMapper, + typeTransformerRegistry); var edcPropertyUtils = new EdcPropertyUtils(); var selfDescriptionService = new SelfDescriptionService(config, monitor); var ownConnectorEndpointService = new OwnConnectorEndpointServiceImpl(selfDescriptionService); var assetMapper = newAssetMapper(typeTransformerRegistry, jsonLd, ownConnectorEndpointService); var transferProcessStateService = new TransferProcessStateService(); var contractNegotiationUtils = new ContractNegotiationUtils( - contractNegotiationService, - selfDescriptionService + contractNegotiationService, + selfDescriptionService ); var contractAgreementPageCardBuilder = new ContractAgreementPageCardBuilder( - policyMapper, - transferProcessStateService, - assetMapper, - contractNegotiationUtils + policyMapper, + transferProcessStateService, + assetMapper, + contractNegotiationUtils ); var contractAgreementDataFetcher = new ContractAgreementDataFetcher( - contractAgreementService, - contractNegotiationStore, - transferProcessService, - assetIndex + contractAgreementService, + contractNegotiationStore, + transferProcessService, + assetIndex ); var contractAgreementApiService = new ContractAgreementPageApiService( - contractAgreementDataFetcher, - contractAgreementPageCardBuilder + contractAgreementDataFetcher, + contractAgreementPageCardBuilder ); var contactDefinitionBuilder = new ContractDefinitionBuilder(criterionMapper); var contractDefinitionApiService = new ContractDefinitionApiService( - contractDefinitionService, - criterionMapper, - contactDefinitionBuilder); + contractDefinitionService, + criterionMapper, + contactDefinitionBuilder); var transferHistoryPageApiService = new TransferHistoryPageApiService( - assetService, - contractAgreementService, - contractNegotiationStore, - transferProcessService, - transferProcessStateService + assetService, + contractAgreementService, + contractNegotiationStore, + transferProcessService, + transferProcessStateService ); var transferHistoryPageAssetFetcherService = new TransferHistoryPageAssetFetcherService( - assetService, - transferProcessService, - assetMapper, - contractNegotiationStore, - contractNegotiationUtils + assetService, + transferProcessService, + assetMapper, + contractNegotiationStore, + contractNegotiationUtils ); var contractAgreementUtils = new ContractAgreementUtils(contractAgreementService); var parameterizationCompatibilityUtils = new ParameterizationCompatibilityUtils(); var assetIdValidator = new AssetIdValidator(); var assetApiService = new AssetApiService( - assetService, - assetMapper, - assetIdValidator, - selfDescriptionService + assetService, + assetMapper, + assetIdValidator, + selfDescriptionService ); var transferRequestBuilder = new TransferRequestBuilder( - contractAgreementUtils, - contractNegotiationUtils, - edcPropertyUtils, - typeTransformerRegistry, - parameterizationCompatibilityUtils + contractAgreementUtils, + contractNegotiationUtils, + edcPropertyUtils, + typeTransformerRegistry, + parameterizationCompatibilityUtils ); var contractAgreementTransferApiService = new ContractAgreementTransferApiService( - transferRequestBuilder, - transferProcessService + transferRequestBuilder, + transferProcessService ); + var agreementDetailsQuery = new ContractAgreementTerminationDetailsQuery(); + var terminateContractQuery = new TerminateContractQuery(); + var contractAgreementTerminationApiService = new ContractAgreementTerminationApiService(contractAgreementTerminationService); var policyDefinitionApiService = new PolicyDefinitionApiService( - policyDefinitionService, - policyMapper + policyDefinitionService, + policyMapper ); var dataOfferBuilder = new DspDataOfferBuilder(jsonLd); var uiDataOfferBuilder = new UiDataOfferBuilder(assetMapper, policyMapper); var dspCatalogService = new DspCatalogService(catalogService, dataOfferBuilder); var catalogApiService = new CatalogApiService( - uiDataOfferBuilder, - dspCatalogService + uiDataOfferBuilder, + dspCatalogService ); var contractOfferMapper = new ContractOfferMapper(policyMapper); var contractNegotiationBuilder = new ContractNegotiationBuilder(contractOfferMapper); var contractNegotiationStateService = new ContractNegotiationStateService(); var contractNegotiationApiService = new ContractNegotiationApiService( - contractNegotiationService, - contractNegotiationBuilder, - contractNegotiationStateService + contractNegotiationService, + contractNegotiationBuilder, + contractNegotiationStateService ); var miwConfigBuilder = new MiwConfigService(config); var dapsConfigBuilder = new DapsConfigService(config); var dashboardDataFetcher = new DashboardDataFetcher( - contractNegotiationStore, - transferProcessService, - assetIndex, - policyDefinitionService, - contractDefinitionService + contractNegotiationStore, + transferProcessService, + assetIndex, + policyDefinitionService, + contractDefinitionService ); var dashboardApiService = new DashboardPageApiService( - dashboardDataFetcher, - transferProcessStateService, - dapsConfigBuilder, - miwConfigBuilder, - selfDescriptionService + dashboardDataFetcher, + transferProcessStateService, + dapsConfigBuilder, + miwConfigBuilder, + selfDescriptionService ); var uiResource = new UiResourceImpl( - contractAgreementApiService, - contractAgreementTransferApiService, - transferHistoryPageApiService, - transferHistoryPageAssetFetcherService, - assetApiService, - policyDefinitionApiService, - catalogApiService, - contractDefinitionApiService, - contractNegotiationApiService, - dashboardApiService + contractAgreementApiService, + contractAgreementTransferApiService, + contractAgreementTerminationApiService, + transferHistoryPageApiService, + transferHistoryPageAssetFetcherService, + assetApiService, + policyDefinitionApiService, + catalogApiService, + contractDefinitionApiService, + contractNegotiationApiService, + dashboardApiService, + dslContextFactory ); // Use Case API var filterExpressionOperatorMapper = new FilterExpressionOperatorMapper(); var filterExpressionLiteralMapper = new FilterExpressionLiteralMapper(); var filterExpressionMapper = new FilterExpressionMapper( - filterExpressionOperatorMapper, - filterExpressionLiteralMapper + filterExpressionOperatorMapper, + filterExpressionLiteralMapper ); var kpiApiService = new KpiApiService( - assetIndex, - policyDefinitionStore, - contractDefinitionStore, - transferProcessStore, - contractAgreementService, - transferProcessStateService + assetIndex, + policyDefinitionStore, + contractDefinitionStore, + transferProcessStore, + contractAgreementService, + transferProcessStateService ); var supportedPolicyApiService = new SupportedPolicyApiService(policyEngine); var useCaseCatalogApiService = new UseCaseCatalogApiService( - uiDataOfferBuilder, - dspCatalogService, - filterExpressionMapper + uiDataOfferBuilder, + dspCatalogService, + filterExpressionMapper ); var useCaseResource = new UseCaseResourceImpl( - kpiApiService, - supportedPolicyApiService, - useCaseCatalogApiService, - policyDefinitionApiService + kpiApiService, + supportedPolicyApiService, + useCaseCatalogApiService, + policyDefinitionApiService ); // Collect all JAX-RS resources return new WrapperExtensionContext(List.of( - uiResource, - useCaseResource + uiResource, + useCaseResource ), selfDescriptionService); } @NotNull private static AssetMapper newAssetMapper( - TypeTransformerRegistry typeTransformerRegistry, - JsonLd jsonLd, - OwnConnectorEndpointService ownConnectorEndpointService + TypeTransformerRegistry typeTransformerRegistry, + JsonLd jsonLd, + OwnConnectorEndpointService ownConnectorEndpointService ) { var edcPropertyUtils = new EdcPropertyUtils(); var assetJsonLdUtils = new AssetJsonLdUtils(); var assetEditRequestMapper = new AssetEditRequestMapper(); var shortDescriptionBuilder = new ShortDescriptionBuilder(); var assetJsonLdParser = new AssetJsonLdParser( - assetJsonLdUtils, - shortDescriptionBuilder, - ownConnectorEndpointService + assetJsonLdUtils, + shortDescriptionBuilder, + ownConnectorEndpointService ); var httpHeaderMapper = new HttpHeaderMapper(); var httpDataSourceMapper = new HttpDataSourceMapper(httpHeaderMapper); var dataSourceMapper = new DataSourceMapper( - edcPropertyUtils, - httpDataSourceMapper + edcPropertyUtils, + httpDataSourceMapper ); var assetJsonLdBuilder = new AssetJsonLdBuilder( - dataSourceMapper, - assetJsonLdParser, - assetEditRequestMapper + dataSourceMapper, + assetJsonLdParser, + assetEditRequestMapper ); return new AssetMapper( - typeTransformerRegistry, - assetJsonLdBuilder, - assetJsonLdParser, - jsonLd + typeTransformerRegistry, + assetJsonLdBuilder, + assetJsonLdParser, + jsonLd ); } } 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 872c4a651..158d8f559 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 @@ -21,10 +21,10 @@ import de.sovity.edc.ext.wrapper.api.ui.model.AssetPage; import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementPage; import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementPageQuery; -import de.sovity.edc.ext.wrapper.api.ui.model.ContractTerminationRequest; import de.sovity.edc.ext.wrapper.api.ui.model.ContractDefinitionPage; import de.sovity.edc.ext.wrapper.api.ui.model.ContractDefinitionRequest; import de.sovity.edc.ext.wrapper.api.ui.model.ContractNegotiationRequest; +import de.sovity.edc.ext.wrapper.api.ui.model.ContractTerminationRequest; import de.sovity.edc.ext.wrapper.api.ui.model.DashboardPage; import de.sovity.edc.ext.wrapper.api.ui.model.IdResponseDto; import de.sovity.edc.ext.wrapper.api.ui.model.InitiateCustomTransferRequest; @@ -36,6 +36,7 @@ import de.sovity.edc.ext.wrapper.api.ui.pages.asset.AssetApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.catalog.CatalogApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.ContractAgreementPageApiService; +import de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.ContractAgreementTerminationApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.ContractAgreementTransferApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_definitions.ContractDefinitionApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_negotiations.ContractNegotiationApiService; @@ -43,17 +44,25 @@ import de.sovity.edc.ext.wrapper.api.ui.pages.policy.PolicyDefinitionApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferHistoryPageApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferHistoryPageAssetFetcherService; +import de.sovity.edc.extension.db.directaccess.DslContextFactory; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validation; +import jakarta.validation.ValidatorFactory; import lombok.RequiredArgsConstructor; +import lombok.val; import org.jetbrains.annotations.Nullable; import java.util.List; +import static de.sovity.edc.ext.wrapper.utils.ValidatorUtils.validate; + @SuppressWarnings("java:S6539") // This class is so large so the generated API Clients can have one UiApi @RequiredArgsConstructor public class UiResourceImpl implements UiResource { private final ContractAgreementPageApiService contractAgreementApiService; private final ContractAgreementTransferApiService contractAgreementTransferApiService; + private final ContractAgreementTerminationApiService contractAgreementTerminationApiService; private final TransferHistoryPageApiService transferHistoryPageApiService; private final TransferHistoryPageAssetFetcherService transferHistoryPageAssetFetcherService; private final AssetApiService assetApiService; @@ -62,6 +71,7 @@ public class UiResourceImpl implements UiResource { private final ContractDefinitionApiService contractDefinitionApiService; private final ContractNegotiationApiService contractNegotiationApiService; private final DashboardPageApiService dashboardPageApiService; + private final DslContextFactory dslContextFactory; @Override public DashboardPage getDashboardPage() { @@ -135,10 +145,10 @@ public UiContractNegotiation getContractNegotiation(String contractNegotiationId @Override public ContractAgreementPage getContractAgreementPage(@Nullable ContractAgreementPageQuery contractAgreementPageQuery) { - return contractAgreementApiService.contractAgreementPage(); + return dslContextFactory.transactionResult(dsl -> + contractAgreementApiService.contractAgreementPage(dsl, contractAgreementPageQuery)); } - @Override public IdResponseDto initiateTransfer(InitiateTransferRequest request) { return contractAgreementTransferApiService.initiateTransfer(request); @@ -150,8 +160,13 @@ public IdResponseDto initiateCustomTransfer(InitiateCustomTransferRequest reques } @Override - public IdResponseDto terminateContractAgreement(String contractAgreementId, ContractTerminationRequest contractTerminationRequest) { - return null; + public IdResponseDto terminateContractAgreement( + String contractAgreementId, + ContractTerminationRequest contractTerminationRequest + ) { + validate(contractTerminationRequest); + return dslContextFactory.transactionResult(dsl -> + contractAgreementTerminationApiService.terminate(dsl, contractAgreementId, contractTerminationRequest)); } @Override diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/ContractAgreementPageApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/ContractAgreementPageApiService.java index 8487f8eab..60a597b8b 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/ContractAgreementPageApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/ContractAgreementPageApiService.java @@ -16,10 +16,13 @@ import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementCard; import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementPage; +import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementPageQuery; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.services.ContractAgreementDataFetcher; import de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.services.ContractAgreementPageCardBuilder; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jooq.DSLContext; import java.util.Comparator; @@ -29,15 +32,25 @@ public class ContractAgreementPageApiService { private final ContractAgreementPageCardBuilder contractAgreementPageCardBuilder; @NotNull - public ContractAgreementPage contractAgreementPage() { - var agreements = contractAgreementDataFetcher.getContractAgreements(); + public ContractAgreementPage contractAgreementPage(DSLContext dsl, @Nullable ContractAgreementPageQuery contractAgreementPageQuery) { + var agreements = contractAgreementDataFetcher.getContractAgreements(dsl); var cards = agreements.stream() - .map(agreement -> contractAgreementPageCardBuilder.buildContractAgreementCard( - agreement.agreement(), agreement.negotiation(), agreement.asset(), agreement.transfers())) - .sorted(Comparator.comparing(ContractAgreementCard::getContractSigningDate).reversed()) - .toList(); + .map(agreement -> contractAgreementPageCardBuilder.buildContractAgreementCard( + agreement.agreement(), + agreement.negotiation(), + agreement.asset(), + agreement.transfers(), + agreement.termination())) + .sorted(Comparator.comparing(ContractAgreementCard::getContractSigningDate).reversed()); - return new ContractAgreementPage(cards); + if (contractAgreementPageQuery == null || contractAgreementPageQuery.getTerminationStatus() == null) { + return new ContractAgreementPage(cards.toList()); + } else { + var filtered = cards.filter(card -> + card.getTerminationStatus().equals(contractAgreementPageQuery.getTerminationStatus())) + .toList(); + return new ContractAgreementPage(filtered); + } } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/ContractAgreementTerminationApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/ContractAgreementTerminationApiService.java new file mode 100644 index 000000000..0c4ac4a7f --- /dev/null +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreements/ContractAgreementTerminationApiService.java @@ -0,0 +1,53 @@ +/* + * 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_agreements; + +import de.sovity.edc.ext.wrapper.api.ui.model.ContractTerminationRequest; +import de.sovity.edc.ext.wrapper.api.ui.model.IdResponseDto; +import de.sovity.edc.extension.contacttermination.ContractAgreementTerminationService; +import de.sovity.edc.extension.contacttermination.ContractTerminationParam; +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.eclipse.edc.spi.EdcException; +import org.jooq.DSLContext; + +@RequiredArgsConstructor +public class ContractAgreementTerminationApiService { + + private final ContractAgreementTerminationService contractAgreementTerminationService; + + public IdResponseDto terminate( + DSLContext dsl, + String contractAgreementId, + ContractTerminationRequest contractTerminationRequest) { + + try { + val terminatedAt = contractAgreementTerminationService.terminateAgreementOrThrow( + dsl, + new ContractTerminationParam( + contractAgreementId, + contractTerminationRequest.getDetail(), + contractTerminationRequest.getReason())); + + return IdResponseDto.builder() + .id(contractAgreementId) + .lastUpdatedDate(terminatedAt) + .build(); + + } catch (RuntimeException e) { + throw new EdcException("Failed to terminate the agreement %s".formatted(contractAgreementId) + " : " + e.getMessage(), e); + } + } +} 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 77f26eefa..6e3411762 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 @@ -14,12 +14,14 @@ 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 java.util.List; +import java.util.Map; /** @@ -34,7 +36,8 @@ public record ContractAgreementData( ContractAgreement agreement, ContractNegotiation negotiation, Asset asset, - List transfers + List transfers, + SovityContractTerminationRecord termination ) { } 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 4e9b19e15..a0f45c062 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 @@ -14,6 +14,7 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.services; +import de.sovity.edc.ext.db.jooq.tables.records.SovityContractTerminationRecord; import de.sovity.edc.ext.wrapper.api.ServiceException; import de.sovity.edc.ext.wrapper.utils.MapUtils; import lombok.RequiredArgsConstructor; @@ -27,11 +28,15 @@ 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; import java.util.List; import java.util.Map; +import static de.sovity.edc.ext.db.jooq.Tables.SOVITY_CONTRACT_TERMINATION; +import static java.util.function.Function.identity; import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toMap; @RequiredArgsConstructor public class ContractAgreementDataFetcher { @@ -46,26 +51,46 @@ public class ContractAgreementDataFetcher { * @return {@link ContractAgreementData}s */ @NotNull - public List getContractAgreements() { + public List getContractAgreements(DSLContext dsl) { var agreements = getAllContractAgreements(); var assets = MapUtils.associateBy(getAllAssets(), Asset::getId); var negotiations = getAllContractNegotiations().stream() - .filter(it -> it.getContractAgreement() != null) - .collect(groupingBy(it -> it.getContractAgreement().getId())); + .filter(it -> it.getContractAgreement() != null) + .collect(groupingBy(it -> it.getContractAgreement().getId())); var transfers = getAllTransferProcesses().stream() - .collect(groupingBy(it -> it.getDataRequest().getContractId())); + .collect(groupingBy(it -> it.getDataRequest().getContractId())); + + var terminations = fetchTerminations(dsl, agreements); // A ContractAgreement has multiple ContractNegotiations when doing a loopback consumption return agreements.stream() - .flatMap(agreement -> negotiations.getOrDefault(agreement.getId(), List.of()).stream() - .map(negotiation -> { - var asset = getAsset(agreement, negotiation, assets); - var contractTransfers = transfers.getOrDefault(agreement.getId(), List.of()); - return new ContractAgreementData(agreement, negotiation, asset, contractTransfers); - })) - .toList(); + .flatMap(agreement -> negotiations.getOrDefault(agreement.getId(), List.of()) + .stream() + .map(negotiation -> { + var asset = getAsset(agreement, negotiation, assets); + var contractTransfers = transfers.getOrDefault(agreement.getId(), List.of()); + return new ContractAgreementData(agreement, negotiation, asset, contractTransfers, terminations.get(agreement.getId())); + })) + .toList(); + } + + private @NotNull Map fetchTerminations(DSLContext dsl, List agreements) { + + var agreementIds = agreements.stream().map(ContractAgreement::getId).toList(); + + var t = SOVITY_CONTRACT_TERMINATION; + + var terminations = dsl.select() + .from(t) + .where(t.CONTRACT_AGREEMENT_ID.in(agreementIds)) + .fetch() + .into(t) + .stream() + .collect(toMap(SovityContractTerminationRecord::getContractAgreementId, identity())); + + return terminations; } private Asset getAsset(ContractAgreement agreement, ContractNegotiation negotiation, Map assets) { 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 f7a7c2644..7e35f1a3d 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 @@ -14,14 +14,16 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.contract_agreements.services; +import de.sovity.edc.ext.db.jooq.tables.records.SovityContractTerminationRecord; import de.sovity.edc.ext.wrapper.api.common.mappers.AssetMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.PolicyMapper; import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementCard; import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementDirection; -import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementTransferProcess; import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementTerminationInfo; -import de.sovity.edc.ext.wrapper.api.ui.model.ContractTerminationStatus; +import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementTransferProcess; +import de.sovity.edc.ext.wrapper.api.ui.model.ContractTerminatedBy; import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferProcessStateService; +import jakarta.validation.constraints.Null; import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; @@ -32,7 +34,10 @@ import java.util.Comparator; import java.util.List; +import java.util.Map; +import static de.sovity.edc.ext.wrapper.api.ui.model.ContractTerminationStatus.ONGOING; +import static de.sovity.edc.ext.wrapper.api.ui.model.ContractTerminationStatus.TERMINATED; import static de.sovity.edc.ext.wrapper.utils.EdcDateUtils.utcMillisToOffsetDateTime; import static de.sovity.edc.ext.wrapper.utils.EdcDateUtils.utcSecondsToOffsetDateTime; @@ -45,11 +50,13 @@ public class ContractAgreementPageCardBuilder { @NotNull public ContractAgreementCard buildContractAgreementCard( - @NonNull ContractAgreement agreement, - @NonNull ContractNegotiation negotiation, - @NonNull Asset asset, - @NonNull List transferProcesses + @NonNull ContractAgreement agreement, + @NonNull ContractNegotiation negotiation, + @NonNull Asset asset, + @NonNull List transferProcesses, + SovityContractTerminationRecord termination ) { + var assetParticipantId = contractNegotiationUtils.getProviderParticipantId(negotiation); var assetConnectorEndpoint = contractNegotiationUtils.getProviderConnectorEndpoint(negotiation); @@ -63,32 +70,51 @@ public ContractAgreementCard buildContractAgreementCard( card.setAsset(assetMapper.buildUiAsset(asset, assetConnectorEndpoint, assetParticipantId)); card.setContractPolicy(policyMapper.buildUiPolicy(agreement.getPolicy())); card.setTransferProcesses(buildTransferProcesses(transferProcesses)); - card.setTerminationStatus(ContractTerminationStatus.ONGOING); - card.setTerminationInformation(null); + + addTermination(termination, card); + return card; } + private static void addTermination(SovityContractTerminationRecord termination, ContractAgreementCard card) { + if (termination != null) { + card.setTerminationStatus(TERMINATED); + card.setTerminationInformation(ContractAgreementTerminationInfo.builder() + .detail(termination.getDetail()) + .reason(termination.getReason()) + .terminatedAt(termination.getTerminatedAt()) + .terminatedBy(switch (termination.getTerminatedBy()) { + case SELF -> ContractTerminatedBy.SELF; + case COUNTERPARTY -> ContractTerminatedBy.COUNTERPARTY; + }) + .build()); + } else { + card.setTerminationStatus(ONGOING); + card.setTerminationInformation(null); + } + } + @NotNull private List buildTransferProcesses( - @NonNull List transferProcessEntities + @NonNull List transferProcessEntities ) { return transferProcessEntities.stream() - .map(this::buildContractAgreementTransfer) - .sorted(Comparator.comparing(ContractAgreementTransferProcess::getLastUpdatedDate) - .reversed()) - .toList(); + .map(this::buildContractAgreementTransfer) + .sorted(Comparator.comparing(ContractAgreementTransferProcess::getLastUpdatedDate) + .reversed()) + .toList(); } @NotNull - private ContractAgreementTransferProcess buildContractAgreementTransfer( - TransferProcess transferProcessEntity) { + private ContractAgreementTransferProcess buildContractAgreementTransfer(TransferProcess transferProcessEntity) { + var transferProcess = new ContractAgreementTransferProcess(); + transferProcess.setTransferProcessId(transferProcessEntity.getId()); - transferProcess.setLastUpdatedDate( - utcMillisToOffsetDateTime(transferProcessEntity.getUpdatedAt())); - transferProcess.setState(transferProcessStateService.buildTransferProcessState( - transferProcessEntity.getState())); + transferProcess.setLastUpdatedDate(utcMillisToOffsetDateTime(transferProcessEntity.getUpdatedAt())); + transferProcess.setState(transferProcessStateService.buildTransferProcessState(transferProcessEntity.getState())); transferProcess.setErrorMessage(transferProcessEntity.getErrorDetail()); + return transferProcess; } } 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 e63b10170..0ce0b737e 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 @@ -17,10 +17,10 @@ import de.sovity.edc.ext.wrapper.api.ServiceException; import de.sovity.edc.ext.wrapper.api.common.mappers.PolicyMapper; -import de.sovity.edc.ext.wrapper.api.usecase.model.PolicyCreateRequest; import de.sovity.edc.ext.wrapper.api.common.model.PolicyDefinitionCreateRequest; import de.sovity.edc.ext.wrapper.api.common.model.PolicyDefinitionDto; import de.sovity.edc.ext.wrapper.api.ui.model.IdResponseDto; +import de.sovity.edc.ext.wrapper.api.usecase.model.PolicyCreateRequest; import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.eclipse.edc.connector.policy.spi.PolicyDefinition; 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 a00d3552c..f3a295e4d 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 @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResourceImpl.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResourceImpl.java index c743faa64..076c0db12 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResourceImpl.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResourceImpl.java @@ -14,12 +14,12 @@ package de.sovity.edc.ext.wrapper.api.usecase; -import de.sovity.edc.ext.wrapper.api.usecase.model.PolicyCreateRequest; import de.sovity.edc.ext.wrapper.api.ui.model.IdResponseDto; import de.sovity.edc.ext.wrapper.api.ui.model.UiDataOffer; import de.sovity.edc.ext.wrapper.api.ui.pages.policy.PolicyDefinitionApiService; import de.sovity.edc.ext.wrapper.api.usecase.model.CatalogQuery; import de.sovity.edc.ext.wrapper.api.usecase.model.KpiResult; +import de.sovity.edc.ext.wrapper.api.usecase.model.PolicyCreateRequest; import de.sovity.edc.ext.wrapper.api.usecase.pages.catalog.UseCaseCatalogApiService; import de.sovity.edc.ext.wrapper.api.usecase.services.KpiApiService; import de.sovity.edc.ext.wrapper.api.usecase.services.SupportedPolicyApiService; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/utils/ValidatorUtils.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/utils/ValidatorUtils.java new file mode 100644 index 000000000..c7b292f21 --- /dev/null +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/utils/ValidatorUtils.java @@ -0,0 +1,33 @@ +/* + * 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.utils; + +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validation; +import jakarta.validation.ValidatorFactory; +import jakarta.ws.rs.BadRequestException; +import lombok.val; + +public class ValidatorUtils { + private static final ValidatorFactory FACTORY = Validation.buildDefaultValidatorFactory(); + + public static void validate(Object object) { + val validator = FACTORY.getValidator(); + val constraintViolations = validator.validate(object); + if (!constraintViolations.isEmpty()) { + throw new BadRequestException(new ConstraintViolationException("Failed to validate", constraintViolations)); + } + } +} diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/TestUtils.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/TestUtils.java deleted file mode 100644 index 12054c816..000000000 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/TestUtils.java +++ /dev/null @@ -1,85 +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; - -import de.sovity.edc.client.EdcClient; -import org.eclipse.edc.junit.extensions.EdcExtension; -import org.eclipse.edc.spi.protocol.ProtocolWebhook; - -import java.util.HashMap; -import java.util.Map; - -public class TestUtils { - private static final int MANAGEMENT_PORT = 34002; - private static final int PROTOCOL_PORT = 34003; - private static final int WEB_PORT = 34001; - private static final String MANAGEMENT_PATH = "/api/management"; - private static final String PROTOCOL_PATH = "/api/dsp"; - public static final String MANAGEMENT_API_KEY = "123456"; - public static final String MANAGEMENT_ENDPOINT = "http://localhost:" + MANAGEMENT_PORT + MANAGEMENT_PATH; - - - public static final String PROTOCOL_HOST = "http://localhost:" + PROTOCOL_PORT; - public static final String PROTOCOL_ENDPOINT = PROTOCOL_HOST + PROTOCOL_PATH; - - public static Map createConfiguration( - Map additionalConfigProperties - ) { - Map config = new HashMap<>(); - config.put("web.http.port", String.valueOf(WEB_PORT)); - config.put("web.http.path", "/api"); - config.put("web.http.management.port", String.valueOf(MANAGEMENT_PORT)); - config.put("web.http.management.path", MANAGEMENT_PATH); - config.put("web.http.protocol.port", String.valueOf(PROTOCOL_PORT)); - config.put("web.http.protocol.path", PROTOCOL_PATH); - config.put("edc.api.auth.key", MANAGEMENT_API_KEY); - config.put("edc.dsp.callback.address", PROTOCOL_ENDPOINT); - config.put("edc.oauth.provider.audience", "idsc:IDS_CONNECTORS_ALL"); - - config.put("edc.participant.id", "my-edc-participant-id"); - config.put("my.edc.participant.id", "my-edc-participant-id"); - config.put("my.edc.title", "My Connector"); - config.put("my.edc.description", "My Connector Description"); - config.put("my.edc.curator.url", "https://connector.my-org"); - config.put("my.edc.curator.name", "My Org"); - config.put("my.edc.maintainer.url", "https://maintainer-org"); - config.put("my.edc.maintainer.name", "Maintainer Org"); - - config.put("edc.oauth.token.url", "https://token-url.daps"); - config.put("edc.oauth.provider.jwks.url", "https://jwks-url.daps"); - config.put("tx.ssi.miw.authority.id", "my-authority-id"); - config.put("tx.ssi.miw.url", "https://miw"); - config.put("tx.ssi.oauth.token.url", "https://token.miw"); - config.putAll(additionalConfigProperties); - return config; - } - - public static void setupExtension(EdcExtension extension) { - System.out.println("Hello World from TestUtils#setupExtension!"); - setupExtension(extension, Map.of()); - } - - public static void setupExtension(EdcExtension extension, Map configProperties) { - extension.registerServiceMock(ProtocolWebhook.class, () -> PROTOCOL_ENDPOINT); - extension.setConfiguration(createConfiguration(configProperties)); - } - - public static EdcClient edcClient() { - return EdcClient.builder() - .managementApiUrl(TestUtils.MANAGEMENT_ENDPOINT) - .managementApiKey(TestUtils.MANAGEMENT_API_KEY) - .build(); - } -} diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/asset/AssetApiServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/asset/AssetApiServiceTest.java index 08922d047..f11cee68b 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/asset/AssetApiServiceTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/asset/AssetApiServiceTest.java @@ -21,20 +21,20 @@ import de.sovity.edc.client.gen.model.UiAssetEditRequest; import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; -import de.sovity.edc.ext.wrapper.TestUtils; 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.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.junit.extensions.EdcExtension; 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.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; import java.text.SimpleDateFormat; import java.time.LocalDate; @@ -42,32 +42,47 @@ 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 -@ExtendWith(EdcExtension.class) public class AssetApiServiceTest { + private static EdcClient client; + + @RegisterExtension + static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( + ":launchers:connectors:sovity-dev", + "edc", + testDatabase -> { + val config = forTestDatabase("MyEDC", testDatabase); + client = EdcClient.builder() + .managementApiUrl(config.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .build(); + return config.getProperties(); + } + ); + public static final String DATA_SINK = "http://my-data-sink/api/stuff"; - EdcClient client; EdcPropertyUtils edcPropertyUtils; @BeforeEach - void setUp(EdcExtension extension) { - TestUtils.setupExtension(extension); + void setup() { edcPropertyUtils = new EdcPropertyUtils(); - client = TestUtils.edcClient(); } @Test - void assetPage(AssetService assetStore) { + void assetPage() { + val assetService = providerExtension.getEdcRuntimeExtension().getContext().getService(AssetService.class); + // arrange var properties = Map.of( - Asset.PROPERTY_ID, "asset-1", - Prop.Dcat.LANDING_PAGE, "https://data-source.my-org/docs" + Asset.PROPERTY_ID, "asset-11", + Prop.Dcat.LANDING_PAGE, "https://data-source.my-org/docs" ); - createAsset(assetStore, "2023-06-01", properties); + createAsset(assetService, "2023-06-01", properties); // act var result = client.uiApi().getAssetPage(); @@ -81,23 +96,27 @@ void assetPage(AssetService assetStore) { } @Test - void assetPageSorting(AssetService assetService) { + void assetPageSorting() { + val assetService = providerExtension.getEdcRuntimeExtension().getContext().getService(AssetService.class); + // arrange - createAsset(assetService, "2023-06-01", Map.of(Asset.PROPERTY_ID, "asset-1")); - createAsset(assetService, "2023-06-03", Map.of(Asset.PROPERTY_ID, "asset-3")); - createAsset(assetService, "2023-06-02", Map.of(Asset.PROPERTY_ID, "asset-2")); + 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")); // act var result = client.uiApi().getAssetPage(); // assert assertThat(result.getAssets()) - .extracting(UiAsset::getAssetId) - .containsExactly("asset-3", "asset-2", "asset-1"); + .extracting(UiAsset::getAssetId) + .containsExactly("asset-23", "asset-22", "asset-21"); } @Test - void testAssetCreation(AssetService assetService) { + void testAssetCreation() { + val assetService = providerExtension.getEdcRuntimeExtension().getContext().getService(AssetService.class); + // arrange var dataSource = UiDataSource.builder() .type(DataSourceType.HTTP_DATA) @@ -111,65 +130,65 @@ void testAssetCreation(AssetService assetService) { .customProperties(Map.of("oauth2:tokenUrl", "https://token-url")) .build(); var uiAssetRequest = UiAssetCreateRequest.builder() - .id("asset-1") - .title("AssetTitle") - .description("AssetDescription") - .licenseUrl("https://license-url") - .version("1.0.0") - .language("en") - .mediaType("application/json") - .dataCategory("dataCategory") - .dataSubcategory("dataSubcategory") - .dataModel("dataModel") - .geoReferenceMethod("geoReferenceMethod") - .transportMode("transportMode") - .sovereignLegalName("my sovereign") - .geoLocation("40.0, 40.0") - .nutsLocations(Arrays.asList("DE", "DE929")) - .dataSampleUrls(Arrays.asList("https://sample-a", "https://sample-b")) - .referenceFileUrls(Arrays.asList("https://reference-a", "https://reference-b")) - .referenceFilesDescription("RF Description") - .conditionsForUse("Conditions for use") - .dataUpdateFrequency("every month") - .temporalCoverageFrom(LocalDate.of(2020, 1, 1)) - .temporalCoverageToInclusive(LocalDate.of(2020, 1, 8)) - .keywords(List.of("keyword1", "keyword2")) - .publisherHomepage("publisherHomepage") - .dataSource(dataSource) - .customJsonAsString("{\"test\":\"value\"}") - .customJsonLdAsString(""" - { - "https://string": "value", - "https://number": 3.14, - "https://array": [1,2,3], - "https://object": { "https://key": "value" }, - "https://booleans/are/not/supported/by/Eclipse/EDC": true, - "https://null/will/be/eliminated": null - } - """) - .privateCustomJsonAsString("{\"private test\":\"private value\"}") - .privateCustomJsonLdAsString(""" - { - "https://private/string": "value", - "https://private/number": 3.14, - "https://private/array": [1,2,3], - "https://private/object": { "https://key": "value" }, - "https://private/booleans/are/not/supported/by/Eclipse/EDC": true, - "https://private/null/will/be/eliminated": null - } - """) - .build(); + .id("asset-31") + .title("AssetTitle") + .description("AssetDescription") + .licenseUrl("https://license-url") + .version("1.0.0") + .language("en") + .mediaType("application/json") + .dataCategory("dataCategory") + .dataSubcategory("dataSubcategory") + .dataModel("dataModel") + .geoReferenceMethod("geoReferenceMethod") + .transportMode("transportMode") + .sovereignLegalName("my sovereign") + .geoLocation("40.0, 40.0") + .nutsLocations(Arrays.asList("DE", "DE929")) + .dataSampleUrls(Arrays.asList("https://sample-a", "https://sample-b")) + .referenceFileUrls(Arrays.asList("https://reference-a", "https://reference-b")) + .referenceFilesDescription("RF Description") + .conditionsForUse("Conditions for use") + .dataUpdateFrequency("every month") + .temporalCoverageFrom(LocalDate.of(2020, 1, 1)) + .temporalCoverageToInclusive(LocalDate.of(2020, 1, 8)) + .keywords(List.of("keyword1", "keyword2")) + .publisherHomepage("publisherHomepage") + .dataSource(dataSource) + .customJsonAsString(""" + { "test" : "value" } + """) + .customJsonLdAsString(""" + { + "https://string": "value", + "https://number": 3.14, + "https://array": [1,2,3], + "https://object": { "https://key": "value" } + } + """) + .privateCustomJsonAsString(""" + { "private test" : "private value" } + """) + .privateCustomJsonLdAsString(""" + { + "https://private/string": "value", + "https://private/number": 3.14, + "https://private/array": [1,2,3], + "https://private/object": { "https://key": "value" } + } + """) + .build(); // act var response = client.uiApi().createAsset(uiAssetRequest); // assert - assertThat(response.getId()).isEqualTo("asset-1"); + assertThat(response.getId()).isEqualTo("asset-31"); var assets = client.uiApi().getAssetPage().getAssets(); assertThat(assets).hasSize(1); var asset = assets.get(0); - assertThat(asset.getAssetId()).isEqualTo("asset-1"); + assertThat(asset.getAssetId()).isEqualTo("asset-31"); assertThat(asset.getTitle()).isEqualTo("AssetTitle"); assertThat(asset.getDescription()).isEqualTo("AssetDescription"); assertThat(asset.getVersion()).isEqualTo("1.0.0"); @@ -192,41 +211,43 @@ void testAssetCreation(AssetService assetService) { assertThat(asset.getTemporalCoverageToInclusive()).isEqualTo(LocalDate.of(2020, 1, 8)); assertThat(asset.getLicenseUrl()).isEqualTo("https://license-url"); assertThat(asset.getKeywords()).isEqualTo(List.of("keyword1", "keyword2")); - assertThat(asset.getCreatorOrganizationName()).isEqualTo("My Org"); + assertThat(asset.getCreatorOrganizationName()).isEqualTo("Curator Name MyEDC"); assertThat(asset.getPublisherHomepage()).isEqualTo("publisherHomepage"); assertThat(asset.getHttpDatasourceHintsProxyMethod()).isTrue(); assertThat(asset.getHttpDatasourceHintsProxyPath()).isTrue(); assertThat(asset.getHttpDatasourceHintsProxyQueryParams()).isTrue(); assertThat(asset.getHttpDatasourceHintsProxyBody()).isTrue(); assertThatJson(asset.getCustomJsonAsString()).isEqualTo(""" - { "test": "value" } - """); + { "test": "value" } + """); assertThatJson(asset.getCustomJsonLdAsString()).isEqualTo(""" - { - "https://string": "value", - "https://number": 3.14, - "https://array": [1.0, 2.0, 3.0], - "https://object": { "https://key": "value" } - } - """); + { + "https://string": "value", + "https://number": 3.14, + "https://array": [1.0, 2.0, 3.0], + "https://object": { "https://key": "value" } + } + """); assertThatJson(asset.getPrivateCustomJsonAsString()).isEqualTo(""" - { "private test": "private value" } - """); + { "private test": "private value" } + """); assertThatJson(asset.getPrivateCustomJsonLdAsString()).isEqualTo(""" - { - "https://private/string": "value", - "https://private/number": 3.14, - "https://private/array": [1.0, 2.0, 3.0], - "https://private/object": { "https://key": "value" } - } - """); + { + "https://private/string": "value", + "https://private/number": 3.14, + "https://private/array": [1.0, 2.0, 3.0], + "https://private/object": { "https://key": "value" } + } + """); var assetWithDataAddress = assetService.query(QuerySpec.max()).orElseThrow(FailedMappingException::ofFailure).toList().get(0); assertThat(assetWithDataAddress.getDataAddress().getProperties()).containsEntry("oauth2:tokenUrl", "https://token-url"); } @Test - void testeditAsset(AssetService assetService) { + void testeditAsset() { + val assetService = providerExtension.getEdcRuntimeExtension().getContext().getService(AssetService.class); + // arrange var dataSource = UiDataSource.builder() .type(DataSourceType.HTTP_DATA) @@ -240,41 +261,41 @@ void testeditAsset(AssetService assetService) { .customProperties(Map.of("oauth2:tokenUrl", "https://token-url")) .build(); var createRequest = UiAssetCreateRequest.builder() - .id("asset-1") - .title("AssetTitle") - .description("AssetDescription") - .licenseUrl("https://license-url") - .version("1.0.0") - .language("en") - .mediaType("application/json") - .dataCategory("dataCategory") - .dataSubcategory("dataSubcategory") - .dataModel("dataModel") - .geoReferenceMethod("geoReferenceMethod") - .transportMode("transportMode") - .sovereignLegalName("my sovereign") - .geoLocation("40.0, 40.0") - .nutsLocations(Arrays.asList("DE", "DE929")) - .dataSampleUrls(Arrays.asList("https://sample-a", "https://sample-b")) - .referenceFileUrls(Arrays.asList("https://reference-a", "https://reference-b")) - .referenceFilesDescription("RF Description") - .conditionsForUse("Conditions for use") - .dataUpdateFrequency("every month") - .temporalCoverageFrom(LocalDate.of(2020, 1, 1)) - .temporalCoverageToInclusive(LocalDate.of(2020, 1, 8)) - .keywords(List.of("keyword1", "keyword2")) - .publisherHomepage("publisherHomepage") - .dataSource(dataSource) - .customJsonAsString(""" - { "test": "value" } - """) - .customJsonLdAsString(""" - { - "https://to-change": "value1", - "https://for-deletion": "value2" - } - """) - .build(); + .id("asset-41") + .title("AssetTitle") + .description("AssetDescription") + .licenseUrl("https://license-url") + .version("1.0.0") + .language("en") + .mediaType("application/json") + .dataCategory("dataCategory") + .dataSubcategory("dataSubcategory") + .dataModel("dataModel") + .geoReferenceMethod("geoReferenceMethod") + .transportMode("transportMode") + .sovereignLegalName("my sovereign") + .geoLocation("40.0, 40.0") + .nutsLocations(Arrays.asList("DE", "DE929")) + .dataSampleUrls(Arrays.asList("https://sample-a", "https://sample-b")) + .referenceFileUrls(Arrays.asList("https://reference-a", "https://reference-b")) + .referenceFilesDescription("RF Description") + .conditionsForUse("Conditions for use") + .dataUpdateFrequency("every month") + .temporalCoverageFrom(LocalDate.of(2020, 1, 1)) + .temporalCoverageToInclusive(LocalDate.of(2020, 1, 8)) + .keywords(List.of("keyword1", "keyword2")) + .publisherHomepage("publisherHomepage") + .dataSource(dataSource) + .customJsonAsString(""" + { "test": "value" } + """) + .customJsonLdAsString(""" + { + "https://to-change": "value1", + "https://for-deletion": "value2" + } + """) + .build(); client.uiApi().createAsset(createRequest); var dataAddressBeforeEdit = assetService.query(QuerySpec.max()) @@ -283,50 +304,50 @@ void testeditAsset(AssetService assetService) { .getProperties(); var editRequest = UiAssetEditRequest.builder() - .title("AssetTitle 2") - .description("AssetDescription 2") - .licenseUrl("https://license-url/2") - .version("2.0.0") - .language("de") - .mediaType("application/json+utf8") - .dataCategory("dataCategory2") - .dataSubcategory("dataSubcategory2") - .dataModel("dataModel2") - .geoReferenceMethod("geoReferenceMethod2") - .sovereignLegalName("my sovereign2") - .geoLocation("50.0, 50.0") - .nutsLocations(Arrays.asList("NL", "NL929")) - .dataSampleUrls(Arrays.asList("https://sample-a2", "https://sample-b2")) - .referenceFileUrls(Arrays.asList("https://reference-a2", "https://reference-b2")) - .referenceFilesDescription("RF Description2") - .conditionsForUse("Conditions for use2") - .dataUpdateFrequency("every week") - .temporalCoverageFrom(LocalDate.of(2021, 1, 1)) - .temporalCoverageToInclusive(LocalDate.of(2021, 1, 8)) - .transportMode("transportMode2") - .keywords(List.of("keyword3")) - .publisherHomepage("publisherHomepage2") - .customJsonAsString(""" - { "edited": "new value" } - """) - .customJsonLdAsString(""" - { - "https://to-change": "new value LD", - "https://for-deletion": null - } - """) - .build(); + .title("AssetTitle 2") + .description("AssetDescription 2") + .licenseUrl("https://license-url/2") + .version("2.0.0") + .language("de") + .mediaType("application/json+utf8") + .dataCategory("dataCategory2") + .dataSubcategory("dataSubcategory2") + .dataModel("dataModel2") + .geoReferenceMethod("geoReferenceMethod2") + .sovereignLegalName("my sovereign2") + .geoLocation("50.0, 50.0") + .nutsLocations(Arrays.asList("NL", "NL929")) + .dataSampleUrls(Arrays.asList("https://sample-a2", "https://sample-b2")) + .referenceFileUrls(Arrays.asList("https://reference-a2", "https://reference-b2")) + .referenceFilesDescription("RF Description2") + .conditionsForUse("Conditions for use2") + .dataUpdateFrequency("every week") + .temporalCoverageFrom(LocalDate.of(2021, 1, 1)) + .temporalCoverageToInclusive(LocalDate.of(2021, 1, 8)) + .transportMode("transportMode2") + .keywords(List.of("keyword3")) + .publisherHomepage("publisherHomepage2") + .customJsonAsString(""" + { "edited": "new value" } + """) + .customJsonLdAsString(""" + { + "https://to-change": "new value LD", + "https://for-deletion": null + } + """) + .build(); // act - var response = client.uiApi().editAsset("asset-1", editRequest); + var response = client.uiApi().editAsset("asset-41", editRequest); // assert - assertThat(response.getId()).isEqualTo("asset-1"); + assertThat(response.getId()).isEqualTo("asset-41"); var assets = client.uiApi().getAssetPage().getAssets(); assertThat(assets).hasSize(1); var asset = assets.get(0); - assertThat(asset.getAssetId()).isEqualTo("asset-1"); + assertThat(asset.getAssetId()).isEqualTo("asset-41"); assertThat(asset.getTitle()).isEqualTo("AssetTitle 2"); assertThat(asset.getDescription()).isEqualTo("AssetDescription 2"); assertThat(asset.getVersion()).isEqualTo("2.0.0"); @@ -349,18 +370,18 @@ void testeditAsset(AssetService assetService) { assertThat(asset.getTemporalCoverageToInclusive()).isEqualTo(LocalDate.of(2021, 1, 8)); assertThat(asset.getLicenseUrl()).isEqualTo("https://license-url/2"); assertThat(asset.getKeywords()).isEqualTo(List.of("keyword3")); - assertThat(asset.getCreatorOrganizationName()).isEqualTo("My Org"); + assertThat(asset.getCreatorOrganizationName()).isEqualTo("Curator Name MyEDC"); assertThat(asset.getPublisherHomepage()).isEqualTo("publisherHomepage2"); assertThat(asset.getHttpDatasourceHintsProxyMethod()).isTrue(); assertThat(asset.getHttpDatasourceHintsProxyPath()).isTrue(); assertThat(asset.getHttpDatasourceHintsProxyQueryParams()).isTrue(); assertThat(asset.getHttpDatasourceHintsProxyBody()).isTrue(); assertThat(asset.getCustomJsonAsString()).isEqualTo(""" - { "edited": "new value" } - """); + { "edited": "new value" } + """); assertThatJson(asset.getCustomJsonLdAsString()).isEqualTo(""" - { "https://to-change": "new value LD" } - """); + { "https://to-change": "new value LD" } + """); var dataAddressAfterEdit = assetService.query(QuerySpec.max()) .orElseThrow(FailedMappingException::ofFailure).toList().get(0) @@ -379,15 +400,15 @@ void testAssetCreation_noProxying() { .build()) .build(); var uiAssetRequest = UiAssetCreateRequest.builder() - .id("asset-1") - .dataSource(dataSource) - .build(); + .id("asset-51") + .dataSource(dataSource) + .build(); // act var response = client.uiApi().createAsset(uiAssetRequest); // assert - assertThat(response.getId()).isEqualTo("asset-1"); + assertThat(response.getId()).isEqualTo("asset-51"); var assets = client.uiApi().getAssetPage().getAssets(); assertThat(assets).hasSize(1); var asset = assets.get(0); @@ -407,7 +428,7 @@ void testAssetCreation_differentDataAddressType() { )) .build(); var uiAssetRequest = UiAssetCreateRequest.builder() - .id("asset-1") + .id("asset-61") .dataSource(dataSource) .build(); @@ -415,7 +436,7 @@ void testAssetCreation_differentDataAddressType() { var response = client.uiApi().createAsset(uiAssetRequest); // assert - assertThat(response.getId()).isEqualTo("asset-1"); + assertThat(response.getId()).isEqualTo("asset-61"); var assets = client.uiApi().getAssetPage().getAssets(); assertThat(assets).hasSize(1); var asset = assets.get(0); @@ -426,35 +447,37 @@ void testAssetCreation_differentDataAddressType() { } @Test - void testDeleteAsset(AssetService assetService) { + void testDeleteAsset() { + val assetService = providerExtension.getEdcRuntimeExtension().getContext().getService(AssetService.class); + // arrange - createAsset(assetService, "2023-06-01", Map.of(Asset.PROPERTY_ID, "asset-1")); + createAsset(assetService, "2023-06-01", Map.of(Asset.PROPERTY_ID, "asset-71")); assertThat(assetService.query(QuerySpec.max()).getContent()).isNotEmpty(); // act - var response = client.uiApi().deleteAsset("asset-1"); + var response = client.uiApi().deleteAsset("asset-71"); // assert - assertThat(response.getId()).isEqualTo("asset-1"); + assertThat(response.getId()).isEqualTo("asset-71"); assertThat(assetService.query(QuerySpec.max()).getContent()).isEmpty(); } private void createAsset( - AssetService assetService, - String date, - Map properties + AssetService assetService, + String date, + Map properties ) { DataAddress dataAddress = DataAddress.Builder.newInstance() - .type("HttpData") - .property(Prop.Edc.BASE_URL, DATA_SINK) - .build(); + .type("HttpData") + .property(Prop.Edc.BASE_URL, DATA_SINK) + .build(); var asset = Asset.Builder.newInstance() - .id(properties.get(Asset.PROPERTY_ID)) - .properties(edcPropertyUtils.toMapOfObject(properties)) - .dataAddress(dataAddress) - .createdAt(dateFormatterToLong(date)) - .build(); + .id(properties.get(Asset.PROPERTY_ID)) + .properties(edcPropertyUtils.toMapOfObject(properties)) + .dataAddress(dataAddress) + .createdAt(dateFormatterToLong(date)) + .build(); assetService.create(asset); } diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiTest.java index a4a366355..fa71fe209 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiTest.java @@ -26,32 +26,41 @@ import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; -import de.sovity.edc.ext.wrapper.TestUtils; +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 lombok.SneakyThrows; import org.eclipse.edc.junit.annotations.ApiTest; -import org.eclipse.edc.junit.extensions.EdcExtension; -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 java.util.List; +import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static org.assertj.core.api.Assertions.assertThat; @ApiTest -@ExtendWith(EdcExtension.class) class CatalogApiTest { - private EdcClient client; - private final String dataOfferId = "my-data-offer-2023-11"; - + 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.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .build(); + return config.getProperties(); + } + ); - @BeforeEach - void setUp(EdcExtension extension) { - TestUtils.setupExtension(extension); - client = TestUtils.edcClient(); - } + private final String dataOfferId = "my-data-offer-2023-11"; /** * There used to be issues with the Prop.DISTRIBUTION field being occupied by core EDC. @@ -59,13 +68,14 @@ void setUp(EdcExtension extension) { */ @DisabledOnGithub @Test + @SneakyThrows void testDistributionKey() { // arrange createAsset(); createPolicy(); createContractDefinition(); // act - var catalogPageDataOffers = client.uiApi().getCatalogPageDataOffers(TestUtils.PROTOCOL_ENDPOINT); + var catalogPageDataOffers = client.uiApi().getCatalogPageDataOffers(config.getProtocolEndpoint().getUri().toString()); // assert assertThat(catalogPageDataOffers.size()).isEqualTo(1); diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java index 8aca8a06f..9b6536366 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java @@ -18,7 +18,9 @@ import de.sovity.edc.client.gen.model.ContractAgreementDirection; import de.sovity.edc.client.gen.model.OperatorDto; import de.sovity.edc.client.gen.model.TransferProcessSimplifiedState; -import de.sovity.edc.ext.wrapper.TestUtils; +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.utils.jsonld.vocab.Prop; import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; @@ -29,19 +31,18 @@ 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.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.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.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; import java.net.URI; import java.time.LocalDate; @@ -51,33 +52,45 @@ 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.ConnectorRemoteConfigFactory.fromConnectorConfig; import static org.assertj.core.api.Assertions.assertThat; @ApiTest -@ExtendWith(EdcExtension.class) 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.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .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(); - EdcClient client; LocalDate today = LocalDate.parse("2019-04-01"); ZonedDateTime todayAsZonedDateTime = today.atStartOfDay(ZoneId.systemDefault()); long todayEpochMillis = todayAsZonedDateTime.toInstant().toEpochMilli(); long todayEpochSeconds = todayAsZonedDateTime.toInstant().getEpochSecond(); - @BeforeEach - void setUp(EdcExtension extension) { - TestUtils.setupExtension(extension); - client = TestUtils.edcClient(); - } - @Test void testContractAgreementPage( - ContractNegotiationStore contractNegotiationStore, - TransferProcessStore transferProcessStore, - AssetIndex assetIndex - ) { + ContractNegotiationStore contractNegotiationStore, + TransferProcessStore transferProcessStore, + AssetIndex assetIndex) { // arrange assetIndex.create(asset(ASSET_ID)).orElseThrow(storeFailure -> new RuntimeException("Failed to create asset")); @@ -116,91 +129,92 @@ void testContractAgreementPage( private DataAddress dataAddress() { return DataAddress.Builder.newInstance() - .type("HttpData") - .properties(Map.of("baseUrl", "http://some-url")) - .build(); + .type("HttpData") + .properties(Map.of("baseUrl", "http://some-url")) + .build(); } 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") - .dataDestination(DataAddress.Builder.newInstance().type("HttpData").build()) - .build(); + .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) - .contentDataAddress(DataAddress.Builder.newInstance().type("HttpData").build()) - .errorDetail("my-error-message-" + transfer) - .build(); + .id("my-transfer-" + contract + "-" + transfer) + .state(code) + .type(TransferProcess.Type.PROVIDER) + .dataRequest(dataRequest) + .contentDataAddress(DataAddress.Builder.newInstance().type("HttpData").build()) + .errorDetail("my-error-message-" + transfer) + .build(); } private ContractNegotiation contractDefinition(int contract) { var agreement = ContractAgreement.Builder.newInstance() - .id("my-contract-agreement-" + contract) - .assetId(ASSET_ID) - .contractSigningDate(todayEpochSeconds) - .policy(alwaysTrue()) - .providerId(URI.create("http://other-connector").toString()) - .consumerId(URI.create("http://my-connector").toString()) - .build(); + .id("my-contract-agreement-" + contract) + .assetId(ASSET_ID) + .contractSigningDate(todayEpochSeconds) + .policy(alwaysTrue()) + .providerId(URI.create("http://other-connector").toString()) + .consumerId(URI.create("http://my-connector").toString()) + .build(); // Contract Negotiations can contain multiple Contract Offers (?) // Test this var irrelevantOffer = ContractOffer.Builder.newInstance() - .id("my-contract-offer-" + contract + "-irrelevant") - .assetId(asset(contract + "-irrelevant").getId()) - .policy(alwaysTrue()) - .build(); + .id("my-contract-offer-" + contract + "-irrelevant") + .assetId(asset(contract + "-irrelevant").getId()) + .policy(alwaysTrue()) + .build(); var offer = ContractOffer.Builder.newInstance() - .id("my-contract-offer-" + contract) - .assetId(ASSET_ID) - .policy(alwaysTrue()) - .build(); + .id("my-contract-offer-" + contract) + .assetId(ASSET_ID) + .policy(alwaysTrue()) + .build(); return ContractNegotiation.Builder.newInstance() - .correlationId("my-correlation-" + contract) - .contractAgreement(agreement) - .id("my-contract-negotiation-" + contract) - .counterPartyAddress("http://other-connector") - .counterPartyId("urn:connector:other-connector") - .protocol("ids") - .type(ContractNegotiation.Type.PROVIDER) - .contractOffers(List.of(irrelevantOffer, offer)) - .build(); + .correlationId("my-correlation-" + contract) + .contractAgreement(agreement) + .id("my-contract-negotiation-" + contract) + .counterPartyAddress("http://other-connector") + .counterPartyId("urn:connector:other-connector") + .protocol("ids") + .type(ContractNegotiation.Type.PROVIDER) + .contractOffers(List.of(irrelevantOffer, offer)) + .build(); } private Asset asset(String assetId) { return Asset.Builder.newInstance() - .id(assetId) - .property(Prop.Dcat.LANDING_PAGE, "X") - .createdAt(todayEpochMillis) - .dataAddress(dataAddress()) - .build(); + .id(assetId) + .property(Prop.Dcat.LANDING_PAGE, "X") + .createdAt(todayEpochMillis) + .dataAddress(dataAddress()) + .build(); } private Policy alwaysTrue() { var alwaysTrueConstraint = AtomicConstraint.Builder.newInstance() - .leftExpression(new LiteralExpression("ALWAYS_TRUE")) - .operator(Operator.EQ) - .rightExpression(new LiteralExpression("true")) - .build(); + .leftExpression(new LiteralExpression("ALWAYS_TRUE")) + .operator(Operator.EQ) + .rightExpression(new LiteralExpression("true")) + .build(); var alwaysTruePermission = Permission.Builder.newInstance() - .action(Action.Builder.newInstance().type("USE").build()) - .constraint(alwaysTrueConstraint) - .build(); + .action(Action.Builder.newInstance().type("USE").build()) + .constraint(alwaysTrueConstraint) + .build(); return Policy.Builder.newInstance() - .permission(alwaysTruePermission) - .build(); + .permission(alwaysTruePermission) + .build(); } private String todayPlusDays(int i) { 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 index 284b375ce..84ceac267 100644 --- 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 @@ -17,7 +17,8 @@ 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.ext.wrapper.TestUtils; +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; @@ -28,33 +29,40 @@ 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.junit.extensions.EdcExtension; import org.eclipse.edc.policy.model.Policy; import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; -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 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 -@ExtendWith(EdcExtension.class) 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"; - EdcClient client; - - @BeforeEach - void setUp(EdcExtension extension) { - TestUtils.setupExtension(extension); - client = TestUtils.edcClient(); - } + 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.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .build(); + return config.getProperties(); + } + ); @Test void startTransferProcessForAgreementId( @@ -110,6 +118,7 @@ void startCustomTransferProcessForAgreementId( .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, 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 index f2b8cc420..3f9e18eb4 100644 --- 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 @@ -7,36 +7,47 @@ 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.ext.wrapper.TestUtils; +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.junit.extensions.EdcExtension; import org.eclipse.edc.spi.query.Criterion; import org.eclipse.edc.spi.query.QuerySpec; -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 java.util.List; +import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static org.assertj.core.api.Assertions.assertThat; @ApiTest -@ExtendWith(EdcExtension.class) class ContractDefinitionPageApiServiceTest { - // arrange - private EdcClient client; + private static final String PARTICIPANT_ID = "my-edc-participant-id"; - @BeforeEach - void setUp(EdcExtension extension) { - TestUtils.setupExtension(extension); - client = TestUtils.edcClient(); - } + 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.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .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); @@ -62,7 +73,7 @@ void contractDefinitionPage(ContractDefinitionService contractDefinitionService) @Test void contractDefinitionPageSorting(ContractDefinitionService contractDefinitionService) { // arrange - var client = TestUtils.edcClient(); + createContractDefinition( contractDefinitionService, "contractDefinition-id-1", @@ -98,7 +109,7 @@ void contractDefinitionPageSorting(ContractDefinitionService contractDefinitionS @Test void testContractDefinitionCreation(ContractDefinitionService contractDefinitionService) { // arrange - var client = TestUtils.edcClient(); + var criterion = new UiCriterion( "exampleLeft1", UiCriterionOperator.EQ, @@ -133,7 +144,7 @@ void testContractDefinitionCreation(ContractDefinitionService contractDefinition @Test void testDeleteContractDefinition(ContractDefinitionService contractDefinitionService) { // arrange - var client = TestUtils.edcClient(); + 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); 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 index 543513525..2bd2af260 100644 --- 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 @@ -15,7 +15,8 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.dashboard; import de.sovity.edc.client.EdcClient; -import de.sovity.edc.ext.wrapper.TestUtils; +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.contract.spi.types.agreement.ContractAgreement; import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; @@ -35,7 +36,8 @@ 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.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.Mockito; import java.util.Collection; import java.util.List; @@ -43,6 +45,7 @@ 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; @@ -51,46 +54,72 @@ import static org.mockito.Mockito.when; @ApiTest -@ExtendWith(EdcExtension.class) class DashboardPageApiServiceTest { - EdcClient client; + 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("edc.oauth.token.url", "https://token-url.daps"); + config.setProperty("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.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .build(); + return config.getProperties(); + } + ); + AssetIndex assetIndex; PolicyDefinitionService policyDefinitionService; TransferProcessService transferProcessService; ContractNegotiationStore contractNegotiationStore; ContractDefinitionService contractDefinitionService; - private Random random; + + private final Random random = new Random(); @BeforeEach - void setUp(EdcExtension extension) { - assetIndex = mock(AssetIndex.class); - extension.registerServiceMock(AssetIndex.class, assetIndex); + void setUp(EdcExtension context) { - policyDefinitionService = mock(PolicyDefinitionService.class); - extension.registerServiceMock(PolicyDefinitionService.class, policyDefinitionService); + client = EdcClient.builder() + .managementApiUrl(config.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .build(); - transferProcessService = mock(TransferProcessService.class); - extension.registerServiceMock(TransferProcessService.class, transferProcessService); - contractNegotiationStore = mock(ContractNegotiationStore.class); - extension.registerServiceMock(ContractNegotiationStore.class, contractNegotiationStore); + assetIndex = mock(); + context.registerServiceMock(AssetIndex.class, assetIndex); - contractDefinitionService = mock(ContractDefinitionService.class); - extension.registerServiceMock(ContractDefinitionService.class, contractDefinitionService); + policyDefinitionService = mock(); + context.registerServiceMock(PolicyDefinitionService.class, policyDefinitionService); - TestUtils.setupExtension(extension); - client = TestUtils.edcClient(); - random = new Random(); - } + 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, this::mockAsset), - repeat(8, this::mockPolicyDefinition), - repeat(9, this::mockContractDefinition), + repeat(7, Mockito::mock), + repeat(8, Mockito::mock), + repeat(9, Mockito::mock), List.of( mockContractNegotiation(1, CONSUMER), mockContractNegotiation(2, PROVIDER), @@ -135,13 +164,14 @@ void testConnectorMetadata() { // assert assertThat(dashboardPage.getConnectorParticipantId()).isEqualTo("my-edc-participant-id"); - assertThat(dashboardPage.getConnectorDescription()).isEqualTo("My Connector Description"); - assertThat(dashboardPage.getConnectorTitle()).isEqualTo("My Connector"); - assertThat(dashboardPage.getConnectorEndpoint()).isEqualTo(TestUtils.PROTOCOL_ENDPOINT); - assertThat(dashboardPage.getConnectorCuratorName()).isEqualTo("My Org"); - assertThat(dashboardPage.getConnectorCuratorUrl()).isEqualTo("https://connector.my-org"); - assertThat(dashboardPage.getConnectorMaintainerName()).isEqualTo("Maintainer Org"); - assertThat(dashboardPage.getConnectorMaintainerUrl()).isEqualTo("https://maintainer-org"); + 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.getProtocolEndpoint().getUri().toString()); + 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"); @@ -154,15 +184,15 @@ void testConnectorMetadata() { } private Asset mockAsset() { - return mock(Asset.class); + return mock(); } private PolicyDefinition mockPolicyDefinition() { - return mock(PolicyDefinition.class); + return mock(); } private ContractDefinition mockContractDefinition() { - return mock(ContractDefinition.class); + return mock(); } private ContractNegotiation mockContractNegotiation(int contract, ContractNegotiation.Type type) { @@ -183,10 +213,10 @@ private ContractNegotiation mockContractNegotiationInProgress(ContractNegotiatio } private TransferProcess mockTransferProcess(int contractId, int state) { - DataRequest dataRequest = mock(DataRequest.class); + DataRequest dataRequest = mock(); when(dataRequest.getContractId()).thenReturn("ca-" + contractId); - TransferProcess transferProcess = mock(TransferProcess.class); + TransferProcess transferProcess = mock(); when(transferProcess.getId()).thenReturn(String.valueOf(random.nextInt())); when(transferProcess.getDataRequest()).thenReturn(dataRequest); when(transferProcess.getState()).thenReturn(state); diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java index 2156b609a..d80ac3cbd 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java @@ -23,41 +23,53 @@ import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; import de.sovity.edc.client.gen.model.UiPolicyLiteral; import de.sovity.edc.client.gen.model.UiPolicyLiteralType; -import de.sovity.edc.ext.wrapper.TestUtils; +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 lombok.SneakyThrows; +import lombok.val; 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.junit.extensions.EdcRuntimeExtension; import org.eclipse.edc.spi.entity.Entity; import org.eclipse.edc.spi.query.QuerySpec; -import org.junit.jupiter.api.BeforeEach; +import org.jooq.DSLContext; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; +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 -@ExtendWith(EdcExtension.class) class PolicyDefinitionApiServiceTest { - EdcClient client; + 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.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .build(); + return config.getProperties(); + } + ); UiPolicyConstraint constraint = UiPolicyConstraint.builder() - .left("a") - .operator(OperatorDto.EQ) - .right(UiPolicyLiteral.builder() - .type(UiPolicyLiteralType.STRING) - .value("b") - .build()) - .build(); - - @BeforeEach - void setUp(EdcExtension extension) { - TestUtils.setupExtension(extension); - client = TestUtils.edcClient(); - } + .left("a") + .operator(OperatorDto.EQ) + .right(UiPolicyLiteral.builder() + .type(UiPolicyLiteralType.STRING) + .value("b") + .build()) + .build(); @Test void getPolicyList() { @@ -71,8 +83,8 @@ void getPolicyList() { var policyDefinitions = response.getPolicies(); assertThat(policyDefinitions).hasSize(2); var policyDefinition = policyDefinitions.stream() - .filter(it -> it.getPolicyDefinitionId().equals("my-policy-def-1")) - .findFirst().get(); + .filter(it -> it.getPolicyDefinitionId().equals("my-policy-def-1")) + .findFirst().get(); assertThat(policyDefinition.getPolicyDefinitionId()).isEqualTo("my-policy-def-1"); assertThat(policyDefinition.getPolicy().getConstraints()).hasSize(1); @@ -81,23 +93,38 @@ void getPolicyList() { } @Test - void test_sorting(PolicyDefinitionService policyDefinitionService) { + void sortPoliciesFromNewestToOldest(DslContextFactory dslContextFactory) { // arrange - createPolicyDefinition(policyDefinitionService, "my-policy-def-2", 1628956802000L); - createPolicyDefinition(policyDefinitionService, "my-policy-def-0", 1628956800000L); - createPolicyDefinition(policyDefinitionService, "my-policy-def-1", 1628956801000L); + createPolicyDefinition("my-policy-def-0"); + createPolicyDefinition("my-policy-def-1"); + createPolicyDefinition("my-policy-def-2"); + + dslContextFactory.transaction(dsl -> + Map.of( + "my-policy-def-0", 1628956800000L, + "my-policy-def-1", 1628956801000L, + "my-policy-def-2", 1628956802000L + ).forEach((id, time) -> setPolicyDefCreatedAt(dsl, id, time))); // act var result = client.uiApi().getPolicyDefinitionPage(); // assert assertThat(result.getPolicies()) - .extracting(PolicyDefinitionDto::getPolicyDefinitionId) - .containsExactly( - "always-true", - "my-policy-def-2", - "my-policy-def-1", - "my-policy-def-0"); + .extracting(PolicyDefinitionDto::getPolicyDefinitionId) + .containsExactly( + "always-true", + "my-policy-def-2", + "my-policy-def-1", + "my-policy-def-0"); + } + + private static void setPolicyDefCreatedAt(DSLContext dsl, String id, Long time) { + val p = Tables.EDC_POLICYDEFINITIONS; + dsl.update(p) + .set(p.CREATED_AT, time) + .where(p.POLICY_ID.eq(id)) + .execute(); } @Test @@ -105,7 +132,7 @@ void test_delete(PolicyDefinitionService policyDefinitionService) { // arrange createPolicyDefinition("my-policy-def-1"); assertThat(policyDefinitionService.query(QuerySpec.max()).getContent().toList()) - .extracting(Entity::getId).contains("always-true", "my-policy-def-1"); + .extracting(Entity::getId).contains("always-true", "my-policy-def-1"); // act var response = client.uiApi().deletePolicyDefinition("my-policy-def-1"); @@ -113,7 +140,7 @@ void test_delete(PolicyDefinitionService policyDefinitionService) { // assert assertThat(response.getId()).isEqualTo("my-policy-def-1"); assertThat(policyDefinitionService.query(QuerySpec.max()).getContent()) - .extracting(Entity::getId).containsExactly("always-true"); + .extracting(Entity::getId).containsExactly("always-true"); } private void createPolicyDefinition(String policyDefinitionId) { @@ -122,18 +149,4 @@ private void createPolicyDefinition(String policyDefinitionId) { client.uiApi().createPolicyDefinition(policyDefinition); } - @SneakyThrows - private void createPolicyDefinition( - PolicyDefinitionService policyDefinitionService, - String policyDefinitionId, - long createdAt) { - createPolicyDefinition(policyDefinitionId); - var policyDefinition = policyDefinitionService.findById(policyDefinitionId); - - // Forcefully overwrite createdAt - var createdAtField = Entity.class.getDeclaredField("createdAt"); - createdAtField.setAccessible(true); - createdAtField.set(policyDefinition, createdAt); - policyDefinitionService.update(policyDefinition); - } } diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiServiceTest.java index 88b17cc8b..a0cf4346c 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiServiceTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageApiServiceTest.java @@ -16,32 +16,41 @@ import de.sovity.edc.client.EdcClient; import de.sovity.edc.client.gen.model.ContractAgreementDirection; -import de.sovity.edc.ext.wrapper.TestUtils; +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 org.eclipse.edc.junit.extensions.EdcExtension; -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 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 -@ExtendWith(EdcExtension.class) class TransferHistoryPageApiServiceTest { - EdcClient client; - @BeforeEach - void setUp(EdcExtension extension) { - TestUtils.setupExtension(extension); - client = TestUtils.edcClient(); - } + 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.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .build(); + return config.getProperties(); + } + ); @Test void transferHistoryTest( diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessAssetApiServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessAssetApiServiceTest.java index 65ba76323..f18f73f05 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessAssetApiServiceTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferProcessAssetApiServiceTest.java @@ -15,33 +15,41 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory; import de.sovity.edc.client.EdcClient; -import de.sovity.edc.ext.wrapper.TestUtils; +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 org.eclipse.edc.junit.extensions.EdcExtension; import org.eclipse.edc.spi.monitor.Monitor; -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 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 -@ExtendWith(EdcExtension.class) class TransferProcessAssetApiServiceTest { - EdcClient client = TestUtils.edcClient(); + private static ConnectorConfig config; + private static EdcClient client; - @BeforeEach - void setUp(EdcExtension extension) { - TestUtils.setupExtension(extension); - client = TestUtils.edcClient(); - } + @RegisterExtension + static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( + ":launchers:connectors:sovity-dev", + "provider", + testDatabase -> { + config = forTestDatabase("my-edc-participant-id", testDatabase); + client = EdcClient.builder() + .managementApiUrl(config.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .build(); + return config.getProperties(); + } + ); @Test void testProviderTransferProcess( 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 index 70864b626..66ab4ddbf 100644 --- 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 @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory; @@ -139,11 +140,13 @@ private static void createTransferProcess( ) 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() diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java index 4fc72cc3f..27c8cafcb 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java @@ -15,25 +15,34 @@ package de.sovity.edc.ext.wrapper.api.usecase; import de.sovity.edc.client.EdcClient; -import de.sovity.edc.ext.wrapper.TestUtils; +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.eclipse.edc.junit.extensions.EdcExtension; -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.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static org.assertj.core.api.Assertions.assertThat; @ApiTest -@ExtendWith(EdcExtension.class) class KpiApiTest { - EdcClient client; + 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.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .build(); + return config.getProperties(); + } + ); - @BeforeEach - void setUp(EdcExtension extension) { - TestUtils.setupExtension(extension); - client = TestUtils.edcClient(); - } @Test void getKpis() { // act diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/PolicyDefinitionApiServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/PolicyDefinitionApiServiceTest.java index e411e36a2..a6215b6ad 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/PolicyDefinitionApiServiceTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/PolicyDefinitionApiServiceTest.java @@ -7,15 +7,14 @@ import de.sovity.edc.client.gen.model.PermissionDto; import de.sovity.edc.client.gen.model.PolicyCreateRequest; import de.sovity.edc.client.gen.model.PolicyDefinitionDto; -import de.sovity.edc.ext.wrapper.TestUtils; +import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; +import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; import de.sovity.edc.utils.jsonld.vocab.Prop; import jakarta.json.Json; import jakarta.json.JsonObject; import org.eclipse.edc.junit.annotations.ApiTest; -import org.eclipse.edc.junit.extensions.EdcExtension; -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 java.io.StringReader; import java.util.List; @@ -24,21 +23,30 @@ import static de.sovity.edc.client.gen.model.ExpressionType.AND; import static de.sovity.edc.client.gen.model.ExpressionType.ATOMIC_CONSTRAINT; +import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @ApiTest -@ExtendWith(EdcExtension.class) public class PolicyDefinitionApiServiceTest { - private EdcClient client; - - @BeforeEach - void setUp(EdcExtension extension) { - TestUtils.setupExtension(extension); - client = TestUtils.edcClient(); - } + 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.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .build(); + return config.getProperties(); + } + ); @Test void createTraceXPolicy() { 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 index 73113dd92..094595f7f 100644 --- 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 @@ -15,32 +15,41 @@ package de.sovity.edc.ext.wrapper.api.usecase; import de.sovity.edc.client.EdcClient; -import de.sovity.edc.ext.wrapper.TestUtils; +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.eclipse.edc.junit.extensions.EdcExtension; -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.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static org.assertj.core.api.Assertions.assertThat; @ApiTest -@ExtendWith(EdcExtension.class) class SupportedPolicyApiTest { - EdcClient edcClient; - @BeforeEach - void setUp(EdcExtension extension) { - TestUtils.setupExtension(extension); - edcClient = TestUtils.edcClient(); - } + 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.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .build(); + return config.getProperties(); + } + ); @Test void supportedPolicies() { // act - var actual = edcClient.useCaseApi().getSupportedFunctions(); + var actual = client.useCaseApi().getSupportedFunctions(); // assert - assertThat(actual).containsExactly("ALWAYS_TRUE", "https://w3id.org/edc/v0.0.1/ns/inForceDate"); + 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 index fc92c506e..e8cefe982 100644 --- 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 @@ -31,35 +31,42 @@ import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; -import de.sovity.edc.ext.wrapper.TestUtils; +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.eclipse.edc.junit.extensions.EdcExtension; -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 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 -@ExtendWith(EdcExtension.class) class UseCaseApiWrapperTest { - private EdcClient client; - - private String assetId1 = "test-asset-1"; - private String assetId2 = "test-asset-2"; - private String policyId = "policy-1"; + 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.getManagementEndpoint().getUri().toString()) + .managementApiKey(config.getProperties().get("edc.api.auth.key")) + .build(); + return config.getProperties(); + } + ); - @BeforeEach - void setup(EdcExtension extension) { - TestUtils.setupExtension(extension); - client = TestUtils.edcClient(); - } + private static String assetId1 = "test-asset-1"; + private static String assetId2 = "test-asset-2"; + private static String policyId = "policy-1"; @Test @DisabledOnGithub @@ -120,7 +127,7 @@ void shouldFetchWithoutFilterButWithLimit() { private CatalogQuery criterion(String leftOperand, CatalogFilterExpressionOperator operator, String rightOperand) { return CatalogQuery.builder() - .connectorEndpoint(TestUtils.PROTOCOL_ENDPOINT) + .connectorEndpoint(config.getProtocolEndpoint().getUri().toString()) .filterExpressions( List.of( CatalogFilterExpression.builder() @@ -135,7 +142,7 @@ private CatalogQuery criterion(String leftOperand, CatalogFilterExpressionOperat private CatalogQuery criterion(String leftOperand, CatalogFilterExpressionOperator operator, List rightOperand) { return CatalogQuery.builder() - .connectorEndpoint(TestUtils.PROTOCOL_ENDPOINT) + .connectorEndpoint(config.getProtocolEndpoint().getUri().toString()) .filterExpressions( List.of( CatalogFilterExpression.builder() @@ -150,7 +157,7 @@ private CatalogQuery criterion(String leftOperand, CatalogFilterExpressionOperat private CatalogQuery criterion(Integer limit, Integer offset) { return CatalogQuery.builder() - .connectorEndpoint(TestUtils.PROTOCOL_ENDPOINT) + .connectorEndpoint(config.getProtocolEndpoint().getUri().toString()) .limit(limit) .offset(offset) .build(); @@ -176,7 +183,7 @@ private void setupAssets() { var dataSource = UiDataSource.builder() .type(DataSourceType.HTTP_DATA) .httpData(UiDataSourceHttpData.builder() - .baseUrl(TestUtils.PROTOCOL_ENDPOINT) + .baseUrl(config.getProtocolEndpoint().getUri().toString()) .build()) .build(); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 64584f996..f32a5d574 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # groups -edcGroup="org.eclipse.edc" +edcGroup = "org.eclipse.edc" sovityCatalogCrawlerGroup = "de.sovity.edc.catalog.crawler" sovityEdcExtensionGroup = "de.sovity.edc.ext" sovityEdcGroup = "de.sovity.edc" @@ -23,9 +23,11 @@ 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" jakartaAnnotation = "1.3.5" +jakartaEl = "4.0.2" jakartaJson = "2.0.1" jakartaRs = "3.1.0" jakartaServletApi = "5.0.0" @@ -43,7 +45,7 @@ jsonUnit = "3.2.7" junit = "5.10.0" loggingHouse = "0.2.10" lombok = "1.18.30" -mockito = "4.8.0" +mockito = "5.12.0" mockserver = "5.15.0" okhttp = "4.12.0" okio = "3.9.0" @@ -83,6 +85,7 @@ edc-boot = { module = "org.eclipse.edc:boot", 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-controlPlaneAggregateServices = { module = "org.eclipse.edc:control-plane-aggregate-services", version.ref = "edc" } edc-controlPlaneCore = { module = "org.eclipse.edc:control-plane-core", version.ref = "edc" } @@ -97,6 +100,7 @@ edc-dataPlaneSelectorCore = { module = "org.eclipse.edc:data-plane-selector-core 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-dspHttpCore = { module = "org.eclipse.edc:dsp-http-core", version.ref = "edc" } edc-http = { module = "org.eclipse.edc:http", version.ref = "edc" } @@ -112,10 +116,12 @@ 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-policySpi = { module = "org.eclipse.edc:policy-spi", version.ref = "edc" } edc-sqlCore = { module = "org.eclipse.edc:sql-core", 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-transferSpi = { module = "org.eclipse.edc:transfer-spi", version.ref = "edc" } edc-transformCore = { module = "org.eclipse.edc:transform-core", version.ref = "edc" } edc-transformSpi = { module = "org.eclipse.edc:transform-spi", version.ref = "edc" } @@ -133,9 +139,12 @@ gsonFire = { module = "io.gsonfire:gson-fire", version.ref = "gsonFire" } guava = { module = "com.google.guava:guava", version.ref = "guava" } +hibernate-validation = { module = "org.hibernate.validator:hibernate-validator", version.ref = "hibernateValidator" } + hikari = { module = "com.zaxxer:HikariCP", version.ref = "hikari" } 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" } diff --git a/settings.gradle.kts b/settings.gradle.kts index bb5b28436..78a0903b2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,6 +4,8 @@ include(":extensions:catalog-crawler:catalog-crawler") include(":extensions:catalog-crawler:catalog-crawler-db") include(":extensions:catalog-crawler:catalog-crawler-launcher-base") include(":extensions:catalog-crawler:catalog-crawler-e2e-test") +include(":extensions:contract-termination") +include(":extensions:database-direct-access") include(":extensions:edc-ui-config") include(":extensions:last-commit-info") include(":extensions:policy-always-true") @@ -38,6 +40,5 @@ include(":tests") include(":utils:catalog-parser") include(":utils:jooq-database-access") include(":utils:json-and-jsonld-utils") -include(":utils:test-connector-remote") include(":utils:test-utils") include(":utils:versions") diff --git a/tests/build.gradle.kts b/tests/build.gradle.kts index afd26a2d6..8b232a5f1 100644 --- a/tests/build.gradle.kts +++ b/tests/build.gradle.kts @@ -6,19 +6,25 @@ dependencies { api(project(":launchers:common:base")) api(project(":launchers:common:auth-mock")) + testAnnotationProcessor(libs.lombok) testCompileOnly(libs.lombok) - testImplementation(project(":utils:test-utils")) + testImplementation(project(":extensions:test-backend-controller")) - testImplementation(project(":utils:test-connector-remote")) testImplementation(project(":extensions:wrapper:clients:java-client")) + testImplementation(project(":utils:test-utils")) testImplementation(libs.jsonUnit.assertj) testImplementation(libs.mockito.core) testImplementation(libs.assertj.core) testImplementation(libs.junit.api) testImplementation(libs.junit.params) testImplementation(libs.mockserver.netty) + testImplementation(libs.restAssured.restAssured) testRuntimeOnly(libs.junit.engine) } +tasks.getByName("test") { + maxParallelForks = Runtime.getRuntime().availableProcessors() / 2 +} + group = libs.versions.sovityEdcGroup.get() 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 1c946456a..436be683b 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.e2e; @@ -82,24 +83,24 @@ class ApiWrapperDemoTest { @BeforeEach void setup() { // set up provider EDC + Client - var providerConfig = forTestDatabase(PROVIDER_PARTICIPANT_ID, 21000, PROVIDER_DATABASE); + var providerConfig = forTestDatabase(PROVIDER_PARTICIPANT_ID, PROVIDER_DATABASE); providerEdcContext.setConfiguration(providerConfig.getProperties()); providerConnector = new ConnectorRemote(fromConnectorConfig(providerConfig)); providerClient = EdcClient.builder() - .managementApiUrl(providerConfig.getManagementEndpoint().getUri().toString()) - .managementApiKey(providerConfig.getProperties().get("edc.api.auth.key")) - .build(); + .managementApiUrl(providerConfig.getManagementEndpoint().getUri().toString()) + .managementApiKey(providerConfig.getProperties().get("edc.api.auth.key")) + .build(); // set up consumer EDC + Client - var consumerConfig = forTestDatabase(CONSUMER_PARTICIPANT_ID, 23000, CONSUMER_DATABASE); + var consumerConfig = forTestDatabase(CONSUMER_PARTICIPANT_ID, CONSUMER_DATABASE); consumerEdcContext.setConfiguration(consumerConfig.getProperties()); consumerConnector = new ConnectorRemote(fromConnectorConfig(consumerConfig)); consumerClient = EdcClient.builder() - .managementApiUrl(consumerConfig.getManagementEndpoint().getUri().toString()) - .managementApiKey(consumerConfig.getProperties().get("edc.api.auth.key")) - .build(); + .managementApiUrl(consumerConfig.getManagementEndpoint().getUri().toString()) + .managementApiKey(consumerConfig.getProperties().get("edc.api.auth.key")) + .build(); // We use the provider EDC as data sink / data source (it has the test-backend-controller extension) dataAddress = new MockDataAddressRemote(providerConnector.getConfig().getDefaultEndpoint()); @@ -124,89 +125,89 @@ void provide_and_consume() { private void createAsset() { var dataSource = UiDataSource.builder() - .type(DataSourceType.HTTP_DATA) - .httpData(UiDataSourceHttpData.builder() - .baseUrl(dataAddress.getDataSourceUrl(dataOfferData)) - .build()) - .build(); + .type(DataSourceType.HTTP_DATA) + .httpData(UiDataSourceHttpData.builder() + .baseUrl(dataAddress.getDataSourceUrl(dataOfferData)) + .build()) + .build(); var asset = UiAssetCreateRequest.builder() - .id(dataOfferId) - .title("My Data Offer") - .description("Example Data Offer.") - .version("2023-11") - .language("EN") - .publisherHomepage("https://my-department.my-org.com/my-data-offer") - .licenseUrl("https://my-department.my-org.com/my-data-offer#license") - .dataSource(dataSource) - .build(); + .id(dataOfferId) + .title("My Data Offer") + .description("Example Data Offer.") + .version("2023-11") + .language("EN") + .publisherHomepage("https://my-department.my-org.com/my-data-offer") + .licenseUrl("https://my-department.my-org.com/my-data-offer#license") + .dataSource(dataSource) + .build(); providerClient.uiApi().createAsset(asset); } private void createPolicy() { var afterYesterday = UiPolicyConstraint.builder() - .left("POLICY_EVALUATION_TIME") - .operator(OperatorDto.GT) - .right(UiPolicyLiteral.builder() - .type(UiPolicyLiteralType.STRING) - .value(OffsetDateTime.now().minusDays(1).toString()) - .build()) - .build(); + .left("POLICY_EVALUATION_TIME") + .operator(OperatorDto.GT) + .right(UiPolicyLiteral.builder() + .type(UiPolicyLiteralType.STRING) + .value(OffsetDateTime.now().minusDays(1).toString()) + .build()) + .build(); var beforeTomorrow = UiPolicyConstraint.builder() - .left("POLICY_EVALUATION_TIME") - .operator(OperatorDto.LT) - .right(UiPolicyLiteral.builder() - .type(UiPolicyLiteralType.STRING) - .value(OffsetDateTime.now().plusDays(1).toString()) - .build()) - .build(); + .left("POLICY_EVALUATION_TIME") + .operator(OperatorDto.LT) + .right(UiPolicyLiteral.builder() + .type(UiPolicyLiteralType.STRING) + .value(OffsetDateTime.now().plusDays(1).toString()) + .build()) + .build(); var policyDefinition = PolicyDefinitionCreateRequest.builder() - .policyDefinitionId(dataOfferId) - .policy(UiPolicyCreateRequest.builder() - .constraints(List.of(afterYesterday, beforeTomorrow)) - .build()) - .build(); + .policyDefinitionId(dataOfferId) + .policy(UiPolicyCreateRequest.builder() + .constraints(List.of(afterYesterday, beforeTomorrow)) + .build()) + .build(); providerClient.uiApi().createPolicyDefinition(policyDefinition); } private void createContractDefinition() { var contractDefinition = ContractDefinitionRequest.builder() - .contractDefinitionId(dataOfferId) - .accessPolicyId(dataOfferId) - .contractPolicyId(dataOfferId) - .assetSelector(List.of(UiCriterion.builder() - .operandLeft(Prop.Edc.ID) - .operator(UiCriterionOperator.EQ) - .operandRight(UiCriterionLiteral.builder() - .type(UiCriterionLiteralType.VALUE) - .value(dataOfferId) - .build()) - .build())) - .build(); + .contractDefinitionId(dataOfferId) + .accessPolicyId(dataOfferId) + .contractPolicyId(dataOfferId) + .assetSelector(List.of(UiCriterion.builder() + .operandLeft(Prop.Edc.ID) + .operator(UiCriterionOperator.EQ) + .operandRight(UiCriterionLiteral.builder() + .type(UiCriterionLiteralType.VALUE) + .value(dataOfferId) + .build()) + .build())) + .build(); providerClient.uiApi().createContractDefinition(contractDefinition); } private UiContractNegotiation initiateNegotiation(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()) - .build(); + .counterPartyAddress(dataOffer.getEndpoint()) + .counterPartyParticipantId(dataOffer.getParticipantId()) + .assetId(dataOffer.getAsset().getAssetId()) + .contractOfferId(contractOffer.getContractOfferId()) + .policyJsonLd(contractOffer.getPolicy().getPolicyJsonLd()) + .build(); return consumerClient.uiApi().initiateContractNegotiation(negotiationRequest); } private UiContractNegotiation awaitNegotiationDone(String negotiationId) { var negotiation = Awaitility.await().atMost(consumerConnector.timeout).until( - () -> consumerClient.uiApi().getContractNegotiation(negotiationId), - it -> it.getState().getSimplifiedState() != ContractNegotiationSimplifiedState.IN_PROGRESS + () -> consumerClient.uiApi().getContractNegotiation(negotiationId), + it -> it.getState().getSimplifiedState() != ContractNegotiationSimplifiedState.IN_PROGRESS ); assertThat(negotiation.getState().getSimplifiedState()).isEqualTo(ContractNegotiationSimplifiedState.AGREED); @@ -216,9 +217,9 @@ private UiContractNegotiation awaitNegotiationDone(String negotiationId) { private void initiateTransfer(UiContractNegotiation negotiation) { var contractAgreementId = negotiation.getContractAgreementId(); var transferRequest = InitiateTransferRequest.builder() - .contractAgreementId(contractAgreementId) - .dataSinkProperties(dataAddress.getDataSinkProperties()) - .build(); + .contractAgreementId(contractAgreementId) + .dataSinkProperties(dataAddress.getDataSinkProperties()) + .build(); consumerClient.uiApi().initiateTransfer(transferRequest); } diff --git a/tests/src/test/java/de/sovity/edc/e2e/ContractTerminationTest.java b/tests/src/test/java/de/sovity/edc/e2e/ContractTerminationTest.java new file mode 100644 index 000000000..a73735d83 --- /dev/null +++ b/tests/src/test/java/de/sovity/edc/e2e/ContractTerminationTest.java @@ -0,0 +1,437 @@ +/* + * 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.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.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 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.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockserver.integration.ClientAndServer; +import org.mockserver.model.HttpRequest; +import org.mockserver.model.HttpResponse; + +import java.time.OffsetDateTime; +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 java.time.Duration.ofSeconds; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@ExtendWith(E2eTestExtension.class) +public class ContractTerminationTest { + + + @Test + 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); + } + + @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); + } + + @DisabledOnGithub + @Test + void limitTheReasonSizeAt100Chars( + 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 max = 100; + val maxSize = IntStream.range(0, max).mapToObj(it -> "M").reduce("", (acc, e) -> acc + e); + val tooLong = IntStream.range(0, max + 1).mapToObj(it -> "O").reduce("", (acc, e) -> acc + e); + + // assert when too big + + assertThrows( + ApiException.class, + () -> consumerClient.uiApi() + .terminateContractAgreement(negotiation.getContractAgreementId(), ContractTerminationRequest.builder() + .detail(detail) + .reason(tooLong) + .build()) + ); + + // assert when max size + + consumerClient.uiApi().terminateContractAgreement(negotiation.getContractAgreementId(), ContractTerminationRequest.builder() + .detail(detail) + .reason(maxSize) + .build()); + + awaitTerminationCount(consumerClient, 1); + awaitTerminationCount(providerClient, 1); + + // termination completed == success + } + + @Test + void limitTheDetailSizeAt1000Chars( + E2eScenario scenario, + @Consumer EdcClient consumerClient, + @Provider EdcClient providerClient) { + + val assetId = scenario.createAsset(); + scenario.createContractDefinition(assetId); + val negotiation = scenario.negotiateAssetAndAwait(assetId); + + // act + val reason = "Some reason"; + val max = 1000; + val maxSize = IntStream.range(0, max).mapToObj(it -> "M").reduce("", (acc, e) -> acc + e); + val tooLong = IntStream.range(0, max + 1).mapToObj(it -> "O").reduce("", (acc, e) -> acc + e); + + // assert when too big + + assertThrows( + ApiException.class, + () -> consumerClient.uiApi().terminateContractAgreement( + negotiation.getContractAgreementId(), + ContractTerminationRequest.builder() + .detail(tooLong) + .reason(reason) + .build()) + ); + + // assert when max size + + consumerClient.uiApi().terminateContractAgreement( + negotiation.getContractAgreementId(), + ContractTerminationRequest.builder() + .detail(maxSize) + .reason(reason) + .build()); + + awaitTerminationCount(consumerClient, 1); + awaitTerminationCount(providerClient, 1); + + // termination completed == success + } + + @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) { + // act + assertThrows( + ApiException.class, + () -> consumerClient.uiApi().terminateContractAgreement( + ContractId.create("definition-1", "asset-1").toString(), + ContractTerminationRequest.builder().detail("Some detail").reason("Some reason").build())); + } + + @DisabledOnGithub + @Test + @SneakyThrows + void cantTransferDataAfterTerminated( + E2eScenario scenario, + ClientAndServer mockServer, + @Consumer EdcClient consumerClient, + @Provider EdcClient providerClient) { + + val assetId = "asset-1"; + val mockedAsset = scenario.createAssetWithMockResource(assetId); + scenario.createContractDefinition(assetId); + scenario.negotiateAssetAndAwait(assetId); + + 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 negotiation = scenario.negotiateAssetAndAwait(assetId); + + val transferRequest = InitiateTransferRequest.builder() + .contractAgreementId(negotiation.getContractAgreementId()) + .dataSinkProperties( + Map.of( + EDC_NAMESPACE + "baseUrl", destinationUrl, + EDC_NAMESPACE + "method", HttpMethod.POST, + EDC_NAMESPACE + "type", "HttpData" + ) + ) + .build(); + + val transferId = scenario.transferAndAwait(transferRequest); + + val historyEntry = consumerClient.uiApi() + .getTransferHistoryPage() + .getTransferEntries() + .stream() + .filter(it -> it.getTransferProcessId().equals(transferId)) + .findFirst() + .get(); + + assertThat(historyEntry.getState().getCode()).isEqualTo(TransferProcessStates.COMPLETED.code()); + assertThat(mockedAsset.networkAccesses().get()).isGreaterThan(0); + + mockedAsset.networkAccesses().set(0); + + val detail = "Some detail"; + val reason = "Some reason"; + val contractTerminationRequest = ContractTerminationRequest.builder().detail(detail).reason(reason).build(); + val contractAgreementId = negotiation.getContractAgreementId(); + + // only testing the provider's cancellation as this is the party that is concerned by data access + providerClient.uiApi().terminateContractAgreement(contractAgreementId, contractTerminationRequest); + + awaitTerminationCount(consumerClient, 1); + awaitTerminationCount(providerClient, 1); + + // act + consumerClient.uiApi().initiateTransfer(transferRequest); + // first transfer attempt + Thread.sleep(10_000); + assertThat(mockedAsset.networkAccesses().get()).isEqualTo(0); + // second transfer attempt + Thread.sleep(10_000); + assertThat(mockedAsset.networkAccesses().get()).isEqualTo(0); + } + + @Test + void canTerminateOnlyOnce( + E2eScenario scenario, + @Consumer EdcClient consumerClient, + @Provider EdcClient providerClient) { + + val assetId = scenario.createAsset(); + scenario.createContractDefinition(assetId); + val negotiation = scenario.negotiateAssetAndAwait(assetId); + + val detail = "Some detail"; + val reason = "Some reason"; + val contractTerminationRequest = ContractTerminationRequest.builder().detail(detail).reason(reason).build(); + val contractAgreementId = negotiation.getContractAgreementId(); + val firstTermination = consumerClient.uiApi().terminateContractAgreement(contractAgreementId, contractTerminationRequest); + + awaitTerminationCount(consumerClient, 1); + awaitTerminationCount(providerClient, 1); + + // act + + val alreadyExists = consumerClient.uiApi().terminateContractAgreement(contractAgreementId, contractTerminationRequest); + + assertThat(alreadyExists.getLastUpdatedDate()).isEqualTo(firstTermination.getLastUpdatedDate()); + } + + 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()).isBetween(now.minusMinutes(1), now.plusMinutes(1)); + + 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/e2e/DataSourceParameterizationTest.java b/tests/src/test/java/de/sovity/edc/e2e/DataSourceParameterizationTest.java index c8c5f453f..9df67d5d7 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/DataSourceParameterizationTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/DataSourceParameterizationTest.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.e2e; @@ -34,8 +35,12 @@ import de.sovity.edc.client.gen.model.UiDataSourceHttpData; import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; import de.sovity.edc.extension.e2e.connector.ConnectorRemote; -import de.sovity.edc.extension.e2e.db.TestDatabase; -import de.sovity.edc.extension.e2e.db.TestDatabaseFactory; +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.utils.junit.DisabledOnGithub; import de.sovity.edc.utils.JsonUtils; import de.sovity.edc.utils.jsonld.vocab.Prop; import jakarta.json.Json; @@ -44,13 +49,12 @@ import lombok.val; import okhttp3.HttpUrl; import org.awaitility.Awaitility; -import org.eclipse.edc.junit.extensions.EdcExtension; import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockserver.integration.ClientAndServer; import org.mockserver.model.HttpRequest; import org.mockserver.model.HttpResponse; @@ -67,13 +71,12 @@ import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; import java.util.stream.Stream; import javax.annotation.Nullable; import static de.sovity.edc.client.gen.model.TransferProcessSimplifiedState.OK; -import static de.sovity.edc.client.gen.model.TransferProcessSimplifiedState.RUNNING; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorRemoteConfigFactory.fromConnectorConfig; +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; @@ -87,44 +90,24 @@ import static org.mockserver.model.HttpRequest.request; import static org.mockserver.stop.Stop.stopQuietly; +@ExtendWith(E2eTestExtension.class) class DataSourceParameterizationTest { - private static final String PROVIDER_PARTICIPANT_ID = "provider"; - private static final String CONSUMER_PARTICIPANT_ID = "consumer"; - - @RegisterExtension - static final EdcExtension PROVIDER_EDC_CONTEXT = new EdcExtension(); - @RegisterExtension - static final EdcExtension CONSUMER_EDC_CONTEXT = new EdcExtension(); - - @RegisterExtension - static final TestDatabase PROVIDER_DATABASE = TestDatabaseFactory.getTestDatabase(1); - @RegisterExtension - static final TestDatabase CONSUMER_DATABASE = TestDatabaseFactory.getTestDatabase(2); - - private ConnectorRemote providerConnector; - private ConnectorRemote consumerConnector; - - private EdcClient providerClient; - private EdcClient consumerClient; - private final int port = getFreePort(); private final String sourcePath = "/source/some/path/"; private final String destinationPath = "/destination/some/path/"; - private final String sourceUrl = "http://localhost:" + port + sourcePath; - private final String destinationUrl = "http://localhost:" + port + destinationPath; private ClientAndServer mockServer; private static final AtomicInteger DATA_OFFER_INDEX = new AtomicInteger(0); record TestCase( - String name, - String id, - String method, - @Nullable String body, - @Nullable String mediaType, - @Nullable String path, - Map> queryParams + String name, + String id, + String method, + @Nullable String body, + @Nullable String mediaType, + @Nullable String path, + Map> queryParams ) { @Override public String toString() { @@ -142,217 +125,236 @@ public void stopServer() { stopQuietly(mockServer); } - @BeforeEach - void setup() { - // set up provider EDC + Client - var providerConfig = forTestDatabase(PROVIDER_PARTICIPANT_ID, 21000, PROVIDER_DATABASE); - PROVIDER_EDC_CONTEXT.setConfiguration(providerConfig.getProperties()); - providerConnector = new ConnectorRemote(fromConnectorConfig(providerConfig)); - - providerClient = EdcClient.builder() - .managementApiUrl(providerConfig.getManagementEndpoint().getUri().toString()) - .managementApiKey(providerConfig.getProperties().get("edc.api.auth.key")) - .build(); - - // set up consumer EDC + Client - var consumerConfig = forTestDatabase(CONSUMER_PARTICIPANT_ID, 23000, CONSUMER_DATABASE); - CONSUMER_EDC_CONTEXT.setConfiguration(consumerConfig.getProperties()); - consumerConnector = new ConnectorRemote(fromConnectorConfig(consumerConfig)); - - consumerClient = EdcClient.builder() - .managementApiUrl(consumerConfig.getManagementEndpoint().getUri().toString()) - .managementApiKey(consumerConfig.getProperties().get("edc.api.auth.key")) - .build(); - } - @Test - void canUseTheWorkaroundInCustomTransferRequest() { + void canUseTheWorkaroundInCustomTransferRequest( + E2eScenario scenario, + @Consumer EdcClient consumerClient, + @Provider ConnectorConfig providerConfig, + @Provider EdcClient providerClient + ) { // arrange val testCase = new TestCase( - "", - "data-offer-" + DATA_OFFER_INDEX.getAndIncrement(), - HttpMethod.PATCH, - "[]", - "application/json", - "my-endpoint", - Map.of("filter", List.of("a", "b", "c")) + "", + "data-offer-" + DATA_OFFER_INDEX.getAndIncrement(), + HttpMethod.PATCH, + "[]", + "application/json", + "my-endpoint", + Map.of("filter", List.of("a", "b", "c")) ); val received = new AtomicBoolean(false); - prepareDataTransferBackends(testCase, () -> received.set(true)); - - createData(testCase); + withMockServer((mockServer, context) -> { + prepareDataTransferBackends(testCase, () -> received.set(true), mockServer); - // act - val dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(getProtocolEndpoint(providerConnector)); - val startNegotiation = initiateNegotiation(dataOffers.get(0), dataOffers.get(0).getContractOffers().get(0)); - val negotiation = awaitNegotiationDone(startNegotiation.getContractNegotiationId()); + createData(providerClient, testCase, context); - String standardBase = "https://w3id.org/edc/v0.0.1/ns/"; - String workaroundBase = "https://sovity.de/workaround/proxy/param/"; - var transferRequestJsonLd = Json.createObjectBuilder() + // act + val providerEndpoint = providerConfig.getProtocolEndpoint().getUri().toString(); + val dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerEndpoint); + val startNegotiation = initiateNegotiation(consumerClient, dataOffers.get(0), dataOffers.get(0).getContractOffers().get(0)); + val negotiation = awaitNegotiationDone(consumerClient, startNegotiation.getContractNegotiationId()); + + val standardBase = "https://w3id.org/edc/v0.0.1/ns/"; + val workaroundBase = "https://sovity.de/workaround/proxy/param/"; + var transferRequestJsonLd = Json.createObjectBuilder() .add( - Prop.Edc.DATA_DESTINATION, - Json.createObjectBuilder(Map.of( - standardBase + "type", "HttpData", - standardBase + "baseUrl", destinationUrl, - standardBase + "method", "PUT", - workaroundBase + "pathSegments", testCase.path, - workaroundBase + "method", testCase.method, - workaroundBase + "queryParams", "filter=a&filter=b&filter=c", - workaroundBase + "mediaType", testCase.mediaType, - workaroundBase + "body", testCase.body - )).build() + Prop.Edc.DATA_DESTINATION, + Json.createObjectBuilder(Map.of( + standardBase + "type", "HttpData", + standardBase + "baseUrl", context.destinationUrl, + standardBase + "method", "PUT", + workaroundBase + "pathSegments", testCase.path, + workaroundBase + "method", testCase.method, + workaroundBase + "queryParams", "filter=a&filter=b&filter=c", + workaroundBase + "mediaType", testCase.mediaType, + workaroundBase + "body", testCase.body + )).build() ) .add(Prop.Edc.CTX + "transferType", Json.createObjectBuilder() - .add(Prop.Edc.CTX + "contentType", "application/octet-stream") - .add(Prop.Edc.CTX + "isFinite", true) + .add(Prop.Edc.CTX + "contentType", "application/octet-stream") + .add(Prop.Edc.CTX + "isFinite", true) ) .add(Prop.Edc.CTX + "protocol", HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) .add(Prop.Edc.CTX + "managedResources", false) .build(); - var transferRequest = InitiateCustomTransferRequest.builder() + var transferRequest = InitiateCustomTransferRequest.builder() .contractAgreementId(negotiation.getContractAgreementId()) .transferProcessRequestJsonLd(JsonUtils.toJson(transferRequestJsonLd)) .build(); - val transferId = consumerClient.uiApi().initiateCustomTransfer(transferRequest).getId(); + val transferId = scenario.transferAndAwait(transferRequest); + + // assert + val actual = consumerClient.uiApi().getTransferHistoryPage().getTransferEntries().get(0); + assertThat(actual.getAssetId()).isEqualTo(testCase.id); + assertThat(actual.getTransferProcessId()).isEqualTo(transferId); + assertThat(actual.getState().getSimplifiedState()).isEqualTo(OK); + + assertThat(received.get()).isTrue(); + }); + } + + private record Context( + int port, + String sourceUrl, + String destinationUrl + ) { + } - awaitTransferCompletion(transferId); + private void withMockServer(BiConsumer consumer) { + int port = getFreePort(); + val mockServer = ClientAndServer.startClientAndServer(port); - // assert - TransferHistoryEntry actual = consumerClient.uiApi().getTransferHistoryPage().getTransferEntries().get(0); - assertThat(actual.getAssetId()).isEqualTo(testCase.id); - assertThat(actual.getTransferProcessId()).isEqualTo(transferId); - assertThat(actual.getState().getSimplifiedState()).isEqualTo(OK); + val sourceUrl = "http://localhost:" + port + sourcePath; + val destinationUrl = "http://localhost:" + port + destinationPath; - assertThat(received.get()).isTrue(); + consumer.accept(mockServer, new Context(port, sourceUrl, destinationUrl)); + stopQuietly(mockServer); } - private void createData(TestCase testCase) { - createPolicy(testCase); - createAssetWithParameterizedMethod(testCase); - createContractDefinition(testCase); + private void createData(EdcClient providerClient, TestCase testCase, Context context) { + createPolicy(providerClient, testCase); + createAssetWithParameterizedMethod(providerClient, testCase, context); + createContractDefinition(providerClient, testCase); } @Test - void sendWithEdcManagementApi() { + void sendWithEdcManagementApi( + E2eScenario scenario, + @Consumer ConnectorRemote consumerConnector, + @Consumer EdcClient consumerClient, + @Provider ConnectorConfig providerConfig, + @Provider EdcClient providerClient + ) { // arrange val testCase = new TestCase( - "", - "data-offer-" + DATA_OFFER_INDEX.getAndIncrement(), - HttpMethod.PATCH, - "[]", - "application/json", - "my-endpoint", - Map.of("filter", List.of("a", "b", "c")) + "", + "data-offer-" + DATA_OFFER_INDEX.getAndIncrement(), + HttpMethod.PATCH, + "[]", + "application/json", + "my-endpoint", + Map.of("filter", List.of("a", "b", "c")) ); val received = new AtomicBoolean(false); - prepareDataTransferBackends(testCase, () -> received.set(true)); - - createData(testCase); + withMockServer((mockServer, context) -> { + prepareDataTransferBackends(testCase, () -> received.set(true), mockServer); - // act - val dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(getProtocolEndpoint(providerConnector)); - val startNegotiation = initiateNegotiation(dataOffers.get(0), dataOffers.get(0).getContractOffers().get(0)); - val negotiation = awaitNegotiationDone(startNegotiation.getContractNegotiationId()); + createData(providerClient, testCase, context); - String workaroundBase = "https://sovity.de/workaround/proxy/param/"; - String standardBase = "https://w3id.org/edc/v0.0.1/ns/"; - val transferId = consumerConnector.initiateTransfer( + // act + val providerEndpoint = providerConfig.getProtocolEndpoint().getUri().toString(); + val dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerEndpoint); + val startNegotiation = initiateNegotiation(consumerClient, dataOffers.get(0), dataOffers.get(0).getContractOffers().get(0)); + val negotiation = awaitNegotiationDone(consumerClient, startNegotiation.getContractNegotiationId()); + + String workaroundBase = "https://sovity.de/workaround/proxy/param/"; + String standardBase = "https://w3id.org/edc/v0.0.1/ns/"; + val transferId = consumerConnector.initiateTransfer( negotiation.getContractAgreementId(), testCase.id, - URI.create("http://localhost:21003/api/dsp"), + URI.create(providerEndpoint), Json.createObjectBuilder(Map.of( - standardBase + "type", "HttpData", - standardBase + "baseUrl", destinationUrl, - standardBase + "method", "PUT", - workaroundBase + "pathSegments", testCase.path, - workaroundBase + "method", testCase.method, - workaroundBase + "queryParams", "filter=a&filter=b&filter=c", - workaroundBase + "mediaType", testCase.mediaType, - workaroundBase + "body", testCase.body + standardBase + "type", "HttpData", + standardBase + "baseUrl", context.destinationUrl, + standardBase + "method", "PUT", + workaroundBase + "pathSegments", testCase.path, + workaroundBase + "method", testCase.method, + workaroundBase + "queryParams", "filter=a&filter=b&filter=c", + workaroundBase + "mediaType", testCase.mediaType, + workaroundBase + "body", testCase.body )).build() - ); + ); - awaitTransferCompletion(transferId); + scenario.awaitTransferCompletion(transferId); - // assert - TransferHistoryEntry actual = consumerClient.uiApi().getTransferHistoryPage().getTransferEntries().get(0); - assertThat(actual.getAssetId()).isEqualTo(testCase.id); - assertThat(actual.getTransferProcessId()).isEqualTo(transferId); - assertThat(actual.getState().getSimplifiedState()).isEqualTo(OK); + // assert + TransferHistoryEntry actual = consumerClient.uiApi().getTransferHistoryPage().getTransferEntries().get(0); + assertThat(actual.getAssetId()).isEqualTo(testCase.id); + assertThat(actual.getTransferProcessId()).isEqualTo(transferId); + assertThat(actual.getState().getSimplifiedState()).isEqualTo(OK); - assertThat(received.get()).isTrue(); + assertThat(received.get()).isTrue(); + }); } + @DisabledOnGithub @Test - void canTransferParameterizedAsset() { - source().forEach(testCase -> { + void canTransferParameterizedAsset( + E2eScenario scenario, + @Consumer EdcClient consumerClient, + @Provider ConnectorConfig providerConfig, + @Provider EdcClient providerClient) { + + source().parallel().forEach(testCase -> { // arrange val received = new AtomicBoolean(false); - prepareDataTransferBackends(testCase, () -> received.set(true)); + withMockServer((mockServer, context) -> { + prepareDataTransferBackends(testCase, () -> received.set(true), mockServer); - createData(testCase); + createData(providerClient, testCase, context); - // act - val dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(getProtocolEndpoint(providerConnector)); - val dataOffer = dataOffers.stream().filter(it -> it.getAsset().getAssetId().equals(testCase.id)).findFirst().get(); - val negotiationInit = initiateNegotiation(dataOffer, dataOffer.getContractOffers().get(0)); - val negotiation = awaitNegotiationDone(negotiationInit.getContractNegotiationId()); - val transferId = initiateTransferWithParameters(negotiation, testCase); + // act + val connectorEndpoint = providerConfig.getProtocolEndpoint().getUri().toString(); + val dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(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()); + val transferId = initiateTransferWithParameters(consumerClient, negotiation, testCase, context); - awaitTransferCompletion(transferId); + scenario.awaitTransferCompletion(transferId); - // assert - TransferHistoryEntry actual = consumerClient.uiApi() + // assert + TransferHistoryEntry actual = consumerClient.uiApi() .getTransferHistoryPage() .getTransferEntries() .stream() .filter(it -> it.getAssetId().equals(testCase.id)) .findFirst() .get(); - assertThat(actual.getAssetId()).isEqualTo(testCase.id); - assertThat(actual.getTransferProcessId()).isEqualTo(transferId); - assertThat(actual.getState().getSimplifiedState()).isEqualTo(OK); + assertThat(actual.getAssetId()).isEqualTo(testCase.id); + assertThat(actual.getTransferProcessId()).isEqualTo(transferId); + assertThat(actual.getState().getSimplifiedState()).isEqualTo(OK); - assertThat(received.get()).isTrue(); + assertThat(received.get()).isTrue(); + }); }); } private Stream source() { val httpMethods = List.of( - HttpMethod.POST, - // HttpMethod.HEAD, - HttpMethod.GET, - HttpMethod.DELETE, - HttpMethod.PUT, - HttpMethod.PATCH, - HttpMethod.OPTIONS + HttpMethod.POST, + // HttpMethod.HEAD, + HttpMethod.GET, + HttpMethod.DELETE, + HttpMethod.PUT, + HttpMethod.PATCH, + HttpMethod.OPTIONS ); val paths = Arrays.asList(null, "different/path/segment"); val queryParameters = List.of( - Map.>of(), - Map.of( - "limit", List.of("10"), - "filter", List.of("a", "b", "c") - ) + Map.>of(), + Map.of( + "limit", List.of("10"), + "filter", List.of("a", "b", "c") + ) ); return httpMethods.stream().flatMap(method -> - getBodyOptionsFor(method).stream().flatMap(body -> - paths.stream().flatMap(usePath -> - queryParameters.stream().map(params -> - new TestCase( - method + " body:" + body + " path:" + usePath + " params=" + params, - "data-offer-" + DATA_OFFER_INDEX.getAndIncrement(), - method, - body, - body == null ? null : "application/json", - usePath, - params - ))) - )); + getBodyOptionsFor(method).stream().flatMap(body -> + paths.stream().flatMap(usePath -> + queryParameters.stream().map(params -> + new TestCase( + method + " body:" + body + " path:" + usePath + " params=" + params, + "data-offer-" + DATA_OFFER_INDEX.getAndIncrement(), + method, + body, + body == null ? null : "application/json", + usePath, + params + ))) + )); } @NotNull @@ -370,9 +372,9 @@ private static List getBodyOptionsFor(String method) { return useBodyChoices; } - private void prepareDataTransferBackends(TestCase testCase, Runnable onRequestReceived) { + private void prepareDataTransferBackends(TestCase testCase, Runnable onRequestReceived, ClientAndServer mockServer) { String payload = generateRandomPayload(); - mockServer.reset(); + val requestDefinition = request(sourcePath).withMethod(testCase.method); if (testCase.body != null) { @@ -390,23 +392,23 @@ private void prepareDataTransferBackends(TestCase testCase, Runnable onRequestRe mockServer.when(requestDefinition, once()) - .respond((it) -> new HttpResponse() - .withStatusCode(HttpStatusCode.OK_200.code()) - .withBody(payload, StandardCharsets.UTF_8)); + .respond((it) -> new HttpResponse() + .withStatusCode(HttpStatusCode.OK_200.code()) + .withBody(payload, StandardCharsets.UTF_8)); mockServer.when(request(destinationPath).withMethod(HttpMethod.PUT)) - .respond((HttpRequest httpRequest) -> { - if (new String(httpRequest.getBodyAsRawBytes()).equals(payload)) { - onRequestReceived.run(); - } - return new HttpResponse().withStatusCode(200); - }); + .respond((HttpRequest httpRequest) -> { + if (new String(httpRequest.getBodyAsRawBytes()).equals(payload)) { + onRequestReceived.run(); + } + return new HttpResponse().withStatusCode(200); + }); mockServer.when(request("/.*")) - .respond((HttpRequest httpRequest) -> { - fail("Unexpected network call"); - return new HttpResponse().withStatusCode(HttpStatusCode.GONE_410.code()); - }); + .respond((HttpRequest httpRequest) -> { + fail("Unexpected network call"); + return new HttpResponse().withStatusCode(HttpStatusCode.GONE_410.code()); + }); } private static String generateRandomPayload() { @@ -415,9 +417,9 @@ private static String generateRandomPayload() { return Base64.getEncoder().encodeToString(data); } - private String createAssetWithParameterizedMethod(TestCase testCase) { + private String createAssetWithParameterizedMethod(EdcClient providerClient, TestCase testCase, Context context) { var httpData = new UiDataSourceHttpData(); - httpData.setBaseUrl(sourceUrl); + httpData.setBaseUrl(context.sourceUrl); if (testCase.path != null) { httpData.setEnablePathParameterization(true); } @@ -437,59 +439,59 @@ private String createAssetWithParameterizedMethod(TestCase testCase) { .build(); var asset = UiAssetCreateRequest.builder() - .id(testCase.id) - .title("My Data Offer") - .dataSource(dataSource) - .build(); + .id(testCase.id) + .title("My Data Offer") + .dataSource(dataSource) + .build(); return providerClient.uiApi().createAsset(asset).getId(); } - private void createPolicy(TestCase testCase) { + private void createPolicy(EdcClient providerClient, TestCase testCase) { var policyDefinition = PolicyDefinitionCreateRequest.builder() - .policyDefinitionId(testCase.id) - .policy(UiPolicyCreateRequest.builder() - .constraints(List.of()) - .build()) - .build(); + .policyDefinitionId(testCase.id) + .policy(UiPolicyCreateRequest.builder() + .constraints(List.of()) + .build()) + .build(); providerClient.uiApi().createPolicyDefinition(policyDefinition); } - private String createContractDefinition(TestCase testCase) { + private String createContractDefinition(EdcClient providerClient, TestCase testCase) { var contractDefinition = ContractDefinitionRequest.builder() - .contractDefinitionId(testCase.id) - .accessPolicyId(testCase.id) - .contractPolicyId(testCase.id) - .assetSelector(List.of(UiCriterion.builder() - .operandLeft(Prop.Edc.ID) - .operator(UiCriterionOperator.EQ) - .operandRight(UiCriterionLiteral.builder() - .type(UiCriterionLiteralType.VALUE) - .value(testCase.id) - .build()) - .build())) - .build(); + .contractDefinitionId(testCase.id) + .accessPolicyId(testCase.id) + .contractPolicyId(testCase.id) + .assetSelector(List.of(UiCriterion.builder() + .operandLeft(Prop.Edc.ID) + .operator(UiCriterionOperator.EQ) + .operandRight(UiCriterionLiteral.builder() + .type(UiCriterionLiteralType.VALUE) + .value(testCase.id) + .build()) + .build())) + .build(); return providerClient.uiApi().createContractDefinition(contractDefinition).getId(); } - private UiContractNegotiation initiateNegotiation(UiDataOffer dataOffer, UiContractOffer contractOffer) { + 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()) - .build(); + .counterPartyAddress(dataOffer.getEndpoint()) + .counterPartyParticipantId(dataOffer.getParticipantId()) + .assetId(dataOffer.getAsset().getAssetId()) + .contractOfferId(contractOffer.getContractOfferId()) + .policyJsonLd(contractOffer.getPolicy().getPolicyJsonLd()) + .build(); return consumerClient.uiApi().initiateContractNegotiation(negotiationRequest); } - private UiContractNegotiation awaitNegotiationDone(String negotiationId) { - var negotiation = Awaitility.await().atMost(consumerConnector.timeout).until( - () -> consumerClient.uiApi().getContractNegotiation(negotiationId), - it -> it.getState().getSimplifiedState() != ContractNegotiationSimplifiedState.IN_PROGRESS + private UiContractNegotiation awaitNegotiationDone(EdcClient consumerClient, String negotiationId) { + var negotiation = Awaitility.await().atMost(ofSeconds(10)).until( + () -> consumerClient.uiApi().getContractNegotiation(negotiationId), + it -> it.getState().getSimplifiedState() != ContractNegotiationSimplifiedState.IN_PROGRESS ); assertThat(negotiation.getState().getSimplifiedState()).isEqualTo(ContractNegotiationSimplifiedState.AGREED); @@ -497,15 +499,18 @@ private UiContractNegotiation awaitNegotiationDone(String negotiationId) { } private String initiateTransferWithParameters( - UiContractNegotiation negotiation, - TestCase testCase) { + EdcClient consumerClient, + UiContractNegotiation negotiation, + TestCase testCase, + Context context) { + String rootKey = "https://w3id.org/edc/v0.0.1/ns/"; val transferProcessProperties = new HashMap(); var contractAgreementId = negotiation.getContractAgreementId(); Map dataSinkProperties = new HashMap<>(); - dataSinkProperties.put(EDC_NAMESPACE + "baseUrl", destinationUrl); + 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); @@ -523,8 +528,8 @@ private String initiateTransferWithParameters( if (!testCase.queryParams.isEmpty()) { HttpUrl.Builder builder = new HttpUrl.Builder() - .scheme("http") - .host("example.com"); + .scheme("http") + .host("example.com"); for (val multiValueParam : testCase.queryParams.entrySet()) { for (val singleValue : multiValueParam.getValue()) { @@ -538,28 +543,11 @@ private String initiateTransferWithParameters( } var transferRequest = InitiateTransferRequest.builder() - .contractAgreementId(contractAgreementId) - .dataSinkProperties(dataSinkProperties) - .transferProcessProperties(transferProcessProperties) - .build(); + .contractAgreementId(contractAgreementId) + .dataSinkProperties(dataSinkProperties) + .transferProcessProperties(transferProcessProperties) + .build(); return consumerClient.uiApi().initiateTransfer(transferRequest).getId(); } - private String getProtocolEndpoint(ConnectorRemote connector) { - return connector.getConfig().getProtocolEndpoint().getUri().toString(); - } - - private void awaitTransferCompletion(String transferId) { - Awaitility.await().atMost(consumerConnector.timeout).until( - () -> consumerClient.uiApi() - .getTransferHistoryPage() - .getTransferEntries() - .stream() - .filter(it -> it.getTransferProcessId().equals(transferId)) - .findFirst() - .map(it -> it.getState().getSimplifiedState()), - it -> it.orElse(RUNNING) != RUNNING - ); - } - } 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 3a47e95e6..76b641959 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/DataSourceQueryParamsTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/DataSourceQueryParamsTest.java @@ -8,97 +8,42 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.e2e; import de.sovity.edc.client.EdcClient; -import de.sovity.edc.client.gen.model.ContractDefinitionRequest; -import de.sovity.edc.client.gen.model.ContractNegotiationRequest; -import de.sovity.edc.client.gen.model.ContractNegotiationSimplifiedState; -import de.sovity.edc.client.gen.model.DataSourceType; import de.sovity.edc.client.gen.model.InitiateTransferRequest; -import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest; -import de.sovity.edc.client.gen.model.UiAssetCreateRequest; import de.sovity.edc.client.gen.model.UiContractNegotiation; -import de.sovity.edc.client.gen.model.UiContractOffer; -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.UiDataOffer; -import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; -import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; -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.TestDatabaseFactory; +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.utils.junit.DisabledOnGithub; -import de.sovity.edc.utils.jsonld.vocab.Prop; -import org.awaitility.Awaitility; -import org.eclipse.edc.junit.extensions.EdcExtension; +import lombok.val; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.extension.ExtendWith; import java.util.HashMap; -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.ConnectorRemoteConfigFactory.fromConnectorConfig; -import static org.assertj.core.api.Assertions.assertThat; +@ExtendWith(E2eTestExtension.class) class DataSourceQueryParamsTest { - 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 = TestDatabaseFactory.getTestDatabase(1); - @RegisterExtension - static final TestDatabase CONSUMER_DATABASE = TestDatabaseFactory.getTestDatabase(2); - - private ConnectorRemote providerConnector; - private ConnectorRemote consumerConnector; - - private EdcClient providerClient; - private EdcClient consumerClient; private MockDataAddressRemote dataAddress; private final String encodedParam = "a=%25"; // Unencoded param "a=%" - private final String dataOfferId = "my-data-offer-2023-11"; @BeforeEach - void setup() { - // set up provider EDC + Client - var providerConfig = forTestDatabase(PROVIDER_PARTICIPANT_ID, 21000, PROVIDER_DATABASE); - providerEdcContext.setConfiguration(providerConfig.getProperties()); - providerConnector = new ConnectorRemote(fromConnectorConfig(providerConfig)); - - providerClient = EdcClient.builder() - .managementApiUrl(providerConfig.getManagementEndpoint().getUri().toString()) - .managementApiKey(providerConfig.getProperties().get("edc.api.auth.key")) - .build(); - - // set up consumer EDC + Client - var consumerConfig = forTestDatabase(CONSUMER_PARTICIPANT_ID, 23000, CONSUMER_DATABASE); - consumerEdcContext.setConfiguration(consumerConfig.getProperties()); - consumerConnector = new ConnectorRemote(fromConnectorConfig(consumerConfig)); - - consumerClient = EdcClient.builder() - .managementApiUrl(consumerConfig.getManagementEndpoint().getUri().toString()) - .managementApiKey(consumerConfig.getProperties().get("edc.api.auth.key")) - .build(); - + void setup(@Provider ConnectorConfig providerConfig) { // We use the provider EDC as data sink / data source (it has the test-backend-controller extension) - dataAddress = new MockDataAddressRemote(providerConnector.getConfig().getDefaultEndpoint()); + dataAddress = new MockDataAddressRemote(providerConfig.getDefaultEndpoint()); } @Test @@ -119,101 +64,32 @@ void testDirectQuerying() { */ @DisabledOnGithub @Test - void testQueryParamsDoubleEncoded() { + void testQueryParamsDoubleEncoded(E2eScenario scenario, @Consumer EdcClient consumerClient) { + // arrange - createPolicy(); - createAsset(); - createContractDefinition(); + val assetId = "asset-1"; + scenario.createAsset( + assetId, + UiDataSourceHttpData.builder() + .baseUrl(dataAddress.getDataSourceQueryParamsUrl()) + .queryString(encodedParam) + .build()); + scenario.createContractDefinition(assetId); // act - var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(getProtocolEndpoint(providerConnector)); - var negotiation = initiateNegotiation(dataOffers.get(0), dataOffers.get(0).getContractOffers().get(0)); - negotiation = awaitNegotiationDone(negotiation.getContractNegotiationId()); - initiateTransfer(negotiation); + val negotiation = scenario.negotiateAssetAndAwait(assetId); + initiateTransfer(consumerClient, negotiation); // assert validateDataTransferred(dataAddress.getDataSinkSpyUrl(), encodedParam); } - private void createAsset() { - var dataSource = UiDataSource.builder() - .type(DataSourceType.HTTP_DATA) - .httpData(UiDataSourceHttpData.builder() - .baseUrl(dataAddress.getDataSourceQueryParamsUrl()) - .queryString(encodedParam) - .build()) - .build(); - - var asset = UiAssetCreateRequest.builder() - .id(dataOfferId) - .title("My Data Offer") - .dataSource(dataSource) - .build(); - - providerClient.uiApi().createAsset(asset); - } - - private void createPolicy() { - var policyDefinition = PolicyDefinitionCreateRequest.builder() - .policyDefinitionId(dataOfferId) - .policy(UiPolicyCreateRequest.builder() - .constraints(List.of()) - .build()) - .build(); - - providerClient.uiApi().createPolicyDefinition(policyDefinition); - } - - private void createContractDefinition() { - var contractDefinition = ContractDefinitionRequest.builder() - .contractDefinitionId(dataOfferId) - .accessPolicyId(dataOfferId) - .contractPolicyId(dataOfferId) - .assetSelector(List.of(UiCriterion.builder() - .operandLeft(Prop.Edc.ID) - .operator(UiCriterionOperator.EQ) - .operandRight(UiCriterionLiteral.builder() - .type(UiCriterionLiteralType.VALUE) - .value(dataOfferId) - .build()) - .build())) - .build(); - - providerClient.uiApi().createContractDefinition(contractDefinition); - } - - private UiContractNegotiation initiateNegotiation(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()) - .build(); - - return consumerClient.uiApi().initiateContractNegotiation(negotiationRequest); - } - - private UiContractNegotiation awaitNegotiationDone(String negotiationId) { - var negotiation = Awaitility.await().atMost(consumerConnector.timeout).until( - () -> consumerClient.uiApi().getContractNegotiation(negotiationId), - it -> it.getState().getSimplifiedState() != ContractNegotiationSimplifiedState.IN_PROGRESS - ); - - assertThat(negotiation.getState().getSimplifiedState()).isEqualTo(ContractNegotiationSimplifiedState.AGREED); - return negotiation; - } - - private void initiateTransfer(UiContractNegotiation negotiation) { + private void initiateTransfer(EdcClient consumerClient, UiContractNegotiation negotiation) { var contractAgreementId = negotiation.getContractAgreementId(); var transferRequest = InitiateTransferRequest.builder() - .contractAgreementId(contractAgreementId) - .dataSinkProperties(dataAddress.getDataSinkProperties()) - .build(); + .contractAgreementId(contractAgreementId) + .dataSinkProperties(dataAddress.getDataSinkProperties()) + .build(); consumerClient.uiApi().initiateTransfer(transferRequest); } - - private String getProtocolEndpoint(ConnectorRemote connector) { - return connector.getConfig().getProtocolEndpoint().getUri().toString(); - } } 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 169ef34c1..08876aaa0 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/ManagementApiTransferTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/ManagementApiTransferTest.java @@ -8,72 +8,49 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ 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.db.TestDatabase; -import de.sovity.edc.extension.e2e.db.TestDatabaseViaTestcontainers; -import org.eclipse.edc.junit.extensions.EdcExtension; +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 org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.extension.ExtendWith; import java.util.UUID; 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.ConnectorRemoteConfigFactory.fromConnectorConfig; +@ExtendWith(E2eTestExtension.class) class ManagementApiTransferTest { - private static final String PROVIDER_PARTICIPANT_ID = "provider"; - private static final String CONSUMER_PARTICIPANT_ID = "consumer"; - private static final String TEST_BACKEND_TEST_DATA = UUID.randomUUID().toString(); - - @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 MockDataAddressRemote dataAddress; + private static final String TEST_BACKEND_TEST_DATA = UUID.randomUUID().toString(); @BeforeEach - void setup() { - var providerConfig = forTestDatabase(PROVIDER_PARTICIPANT_ID, 21000, PROVIDER_DATABASE); - providerEdcContext.setConfiguration(providerConfig.getProperties()); - providerConnector = new ConnectorRemote(fromConnectorConfig(providerConfig)); - - var consumerConfig = forTestDatabase(CONSUMER_PARTICIPANT_ID, 23000, CONSUMER_DATABASE); - consumerEdcContext.setConfiguration(consumerConfig.getProperties()); - consumerConnector = new ConnectorRemote(fromConnectorConfig(consumerConfig)); - + 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().getDefaultEndpoint()); } @Test - void testDataTransfer() { + void testDataTransfer(@Consumer ConnectorRemote consumerConnector, @Provider ConnectorRemote providerConnector) { // arrange var assetId = UUID.randomUUID().toString(); providerConnector.createDataOffer(assetId, dataAddress.getDataSourceUrl(TEST_BACKEND_TEST_DATA)); // act consumerConnector.consumeOffer( - providerConnector.getParticipantId(), - providerConnector.getConfig().getProtocolEndpoint().getUri(), - assetId, - dataAddress.getDataSinkJsonLd()); + providerConnector.getParticipantId(), + providerConnector.getConfig().getProtocolEndpoint().getUri(), + assetId, + dataAddress.getDataSinkJsonLd()); // assert validateDataTransferred(dataAddress.getDataSinkSpyUrl(), TEST_BACKEND_TEST_DATA); diff --git a/tests/src/test/java/de/sovity/edc/e2e/Ms8ConnectorMigrationTest.java b/tests/src/test/java/de/sovity/edc/e2e/Ms8ConnectorMigrationTest.java deleted file mode 100644 index dd6d9e7e1..000000000 --- a/tests/src/test/java/de/sovity/edc/e2e/Ms8ConnectorMigrationTest.java +++ /dev/null @@ -1,231 +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.client.EdcClient; -import de.sovity.edc.client.gen.model.ContractAgreementDirection; -import de.sovity.edc.client.gen.model.TransferProcessSimplifiedState; -import de.sovity.edc.ext.wrapper.utils.EdcDateUtils; -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.utils.junit.DisabledOnGithub; -import org.assertj.core.api.SoftAssertions; -import org.assertj.core.data.TemporalUnitLessThanOffset; -import org.eclipse.edc.junit.extensions.EdcExtension; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import java.nio.file.Paths; -import java.time.OffsetDateTime; -import java.time.temporal.ChronoUnit; -import java.util.List; -import java.util.function.Predicate; - -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.ConnectorRemoteConfigFactory.fromConnectorConfig; -import static org.assertj.core.api.Assertions.assertThat; - - -/** - * Test data offers and contracts of an MS8 connector migrated to the current version. - */ -class Ms8ConnectorMigrationTest { - - private static final String PROVIDER_PARTICIPANT_ID = "example-provider"; - private static final String CONSUMER_PARTICIPANT_ID = "example-connector"; - - @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; - - @BeforeEach - void setup() { - var providerConfig = forTestDatabase(PROVIDER_PARTICIPANT_ID, 21000, PROVIDER_DATABASE); - providerConfig.setProperty("edc.flyway.additional.migration.locations", - "filesystem:%s".formatted(getAbsoluteTestResourcePath("db/additional-test-data/provider"))); - providerEdcContext.setConfiguration(providerConfig.getProperties()); - providerConnector = new ConnectorRemote(fromConnectorConfig(providerConfig)); - - providerClient = EdcClient.builder() - .managementApiUrl(providerConfig.getManagementEndpoint().getUri().toString()) - .managementApiKey(providerConfig.getProperties().get("edc.api.auth.key")) - .build(); - - var consumerConfig = forTestDatabase(CONSUMER_PARTICIPANT_ID, 23000, CONSUMER_DATABASE); - consumerConfig.setProperty("edc.flyway.additional.migration.locations", - "filesystem:%s".formatted(getAbsoluteTestResourcePath("db/additional-test-data/consumer"))); - consumerEdcContext.setConfiguration(consumerConfig.getProperties()); - consumerConnector = new ConnectorRemote(fromConnectorConfig(consumerConfig)); - - consumerClient = EdcClient.builder() - .managementApiUrl(consumerConfig.getManagementEndpoint().getUri().toString()) - .managementApiKey(consumerConfig.getProperties().get("edc.api.auth.key")) - .build(); - - // We use the provider EDC as data sink / data source (it has the test-backend-controller extension) - dataAddress = new MockDataAddressRemote(providerConnector.getConfig().getDefaultEndpoint()); - } - - @DisabledOnGithub - @Test - void testMs8DataOffer_Properties() { - // arrange - var providerEndpoint = endpoint(providerConnector); - - // act - var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerEndpoint); - var asset = first(dataOffers, it -> it.getAsset().getAssetId().equals("first-asset-1.0")).getAsset(); - - // assert - SoftAssertions.assertSoftly(softly -> { - softly.assertThat(asset.getAssetId()).isEqualTo("first-asset-1.0"); - softly.assertThat(asset.getAssetJsonLd()).startsWith("{").endsWith("}"); - softly.assertThat(asset.getCreatorOrganizationName()).isEqualTo("Example GmbH"); - softly.assertThat(asset.getDataCategory()).isEqualTo("Traffic Information"); - softly.assertThat(asset.getDataModel()).isEqualTo("data-model"); - softly.assertThat(asset.getDataSubcategory()).isEqualTo("Accidents"); - softly.assertThat(asset.getDescription()).isEqualTo("My First Asset"); - softly.assertThat(asset.getGeoReferenceMethod()).isEqualTo("geo-ref"); - softly.assertThat(asset.getHttpDatasourceHintsProxyBody()).isFalse(); - softly.assertThat(asset.getHttpDatasourceHintsProxyMethod()).isFalse(); - softly.assertThat(asset.getHttpDatasourceHintsProxyPath()).isFalse(); - softly.assertThat(asset.getHttpDatasourceHintsProxyQueryParams()).isFalse(); - softly.assertThat(asset.getKeywords()).containsExactlyInAnyOrder("first", "asset"); - softly.assertThat(asset.getLandingPageUrl()).isEqualTo("https://endpoint-documentation"); - softly.assertThat(asset.getLanguage()).isEqualTo("https://w3id.org/idsa/code/EN"); - softly.assertThat(asset.getLicenseUrl()).isEqualTo("https://standard-license"); - softly.assertThat(asset.getMediaType()).isEqualTo("text/plain"); - softly.assertThat(asset.getTitle()).isEqualTo("First Asset"); - softly.assertThat(asset.getPublisherHomepage()).isEqualTo("https://publisher"); - softly.assertThat(asset.getTransportMode()).isEqualTo("Rail"); - softly.assertThat(asset.getVersion()).isEqualTo("1.0"); - }); - } - - @DisabledOnGithub - @Test - void testMs8ProvidingTransferProcess() { - // arrange - - // act - var providerTransfers = providerClient.uiApi().getTransferHistoryPage().getTransferEntries(); - assertThat(providerTransfers).hasSize(1); - var providerTransfer = providerTransfers.get(0); - - // assert - assertThat(providerTransfer.getAssetId()).isEqualTo("first-asset-1.0"); - assertThat(providerTransfer.getAssetName()).isEqualTo("First Asset"); - assertThat(providerTransfer.getContractAgreementId()).isEqualTo("Zmlyc3QtY2Q=:Zmlyc3QtYXNzZXQtMS4w:MjgzNTZkMTMtN2ZhYy00NTQwLTgwZjItMjI5NzJjOTc1ZWNi"); - assertThat(providerTransfer.getCounterPartyConnectorEndpoint()).isEqualTo(endpoint(consumerConnector)); - assertThat(providerTransfer.getCounterPartyParticipantId()).isEqualTo(consumerConnector.getParticipantId()); - assertIsEqualOffsetDateTime(providerTransfer.getCreatedDate(), EdcDateUtils.utcMillisToOffsetDateTime(1695208010855L)); - assertThat(providerTransfer.getDirection()).isEqualTo(ContractAgreementDirection.PROVIDING); - assertThat(providerTransfer.getErrorMessage()).isNull(); - assertIsEqualOffsetDateTime(providerTransfer.getLastUpdatedDate(), EdcDateUtils.utcMillisToOffsetDateTime(1695208010083L)); - assertThat(providerTransfer.getState().getSimplifiedState()).isEqualTo(TransferProcessSimplifiedState.OK); - assertThat(providerTransfer.getTransferProcessId()).isEqualTo("27075fc4-b18f-44e1-8bde-a9f62817dab2"); - } - - private void assertIsEqualOffsetDateTime(OffsetDateTime actual, OffsetDateTime expected) { - assertThat(actual).isCloseTo(expected, new TemporalUnitLessThanOffset(1, ChronoUnit.MINUTES)); - } - - @DisabledOnGithub - @Test - void testMs8ConsumingTransferProcess() { - // arrange - - // act - var consumerTransfers = consumerClient.uiApi().getTransferHistoryPage().getTransferEntries(); - assertThat(consumerTransfers).hasSize(1); - var consumerTransfer = consumerTransfers.get(0); - - // assert - assertThat(consumerTransfer.getAssetId()).isEqualTo("first-asset-1.0"); - assertThat(consumerTransfer.getAssetName()).isEqualTo("first-asset-1.0"); - assertThat(consumerTransfer.getContractAgreementId()).isEqualTo("Zmlyc3QtY2Q=:Zmlyc3QtYXNzZXQtMS4w:MjgzNTZkMTMtN2ZhYy00NTQwLTgwZjItMjI5NzJjOTc1ZWNi"); - assertThat(consumerTransfer.getCounterPartyConnectorEndpoint()).isEqualTo(endpoint(providerConnector)); - assertThat(consumerTransfer.getCounterPartyParticipantId()).isEqualTo(providerConnector.getParticipantId()); - assertIsEqualOffsetDateTime(consumerTransfer.getCreatedDate(), EdcDateUtils.utcMillisToOffsetDateTime(1695208008652L)); - assertThat(consumerTransfer.getDirection()).isEqualTo(ContractAgreementDirection.CONSUMING); - assertThat(consumerTransfer.getErrorMessage()).isNull(); - assertIsEqualOffsetDateTime(consumerTransfer.getLastUpdatedDate(), EdcDateUtils.utcMillisToOffsetDateTime(1695208011094L)); - assertThat(consumerTransfer.getState().getSimplifiedState()).isEqualTo(TransferProcessSimplifiedState.OK); - assertThat(consumerTransfer.getTransferProcessId()).isEqualTo("946aadd4-d4bf-47e9-8aea-c2279070e839"); - } - - @Test - void testMs8DataOffer_negotiateAndTransferNewContract() { - // arrange - var assetIds = providerConnector.getAssetIds(); - assertThat(assetIds).contains("second-asset"); - - // act - consumerConnector.consumeOffer( - providerConnector.getParticipantId(), - providerConnector.getConfig().getProtocolEndpoint().getUri(), - "second-asset", - dataAddress.getDataSinkJsonLd()); - - // assert - validateDataTransferred(dataAddress.getDataSinkSpyUrl(), "second-asset-data"); - } - - @Test - void testMs8Contract_transfer() { - // arrange - var assetIds = providerConnector.getAssetIds(); - assertThat(assetIds).contains("second-asset"); - - // act - var transferProcessId = consumerConnector.initiateTransfer( - "Zmlyc3QtY2Q=:Zmlyc3QtYXNzZXQtMS4w:MjgzNTZkMTMtN2ZhYy00NTQwLTgwZjItMjI5NzJjOTc1ZWNi", - "first-asset-1.0", - providerConnector.getConfig().getProtocolEndpoint().getUri(), - dataAddress.getDataSinkJsonLd() - ); - - // assert - assertThat(transferProcessId).isNotNull(); - validateDataTransferred(dataAddress.getDataSinkSpyUrl(), "first-asset-data"); - } - - private T first(List items, Predicate predicate) { - return items.stream().filter(predicate).findFirst().get(); - } - - private String endpoint(ConnectorRemote remote) { - return remote.getConfig().getProtocolEndpoint().getUri().toString(); - } - - public String getAbsoluteTestResourcePath(String path) { - return Paths.get("").resolve("src/test/resources").resolve(path).toAbsolutePath().toString(); - } -} 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 5cad0820f..f16aa4d7b 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/UiApiWrapperTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/UiApiWrapperTest.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.e2e; @@ -40,8 +41,10 @@ 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.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 de.sovity.edc.extension.utils.junit.DisabledOnGithub; import de.sovity.edc.utils.JsonUtils; import de.sovity.edc.utils.jsonld.vocab.Prop; @@ -49,7 +52,6 @@ import jakarta.json.JsonObject; import lombok.val; import org.awaitility.Awaitility; -import org.eclipse.edc.junit.extensions.EdcExtension; import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -65,8 +67,6 @@ 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.connector.config.ConnectorConfigFactory.forTestDatabase; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorRemoteConfigFactory.fromConnectorConfig; import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; @@ -78,49 +78,25 @@ class UiApiWrapperTest { 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 static E2eTestExtension e2eTestExtension = new E2eTestExtension(CONSUMER_PARTICIPANT_ID, PROVIDER_PARTICIPANT_ID); - private ConnectorRemote providerConnector; - private ConnectorRemote consumerConnector; - - private EdcClient providerClient; - private EdcClient consumerClient; private MockDataAddressRemote dataAddress; @BeforeEach - void setup() { - var providerConfig = forTestDatabase(PROVIDER_PARTICIPANT_ID, 21000, PROVIDER_DATABASE); - providerEdcContext.setConfiguration(providerConfig.getProperties()); - providerConnector = new ConnectorRemote(fromConnectorConfig(providerConfig)); - - providerClient = EdcClient.builder() - .managementApiUrl(providerConfig.getManagementEndpoint().getUri().toString()) - .managementApiKey(providerConfig.getProperties().get("edc.api.auth.key")) - .build(); - - var consumerConfig = forTestDatabase(CONSUMER_PARTICIPANT_ID, 23000, CONSUMER_DATABASE); - consumerEdcContext.setConfiguration(consumerConfig.getProperties()); - consumerConnector = new ConnectorRemote(fromConnectorConfig(consumerConfig)); - - consumerClient = EdcClient.builder() - .managementApiUrl(consumerConfig.getManagementEndpoint().getUri().toString()) - .managementApiKey(consumerConfig.getProperties().get("edc.api.auth.key")) - .build(); - + 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().getDefaultEndpoint()); } @DisabledOnGithub @Test - void provide_consume_assetMapping_policyMapping_agreements() { + void provide_consume_assetMapping_policyMapping_agreements( + @Consumer ConnectorConfig consumerConfig, + @Consumer ConnectorRemote consumerConnector, + @Consumer EdcClient consumerClient, + @Provider ConnectorConfig providerConfig, + @Provider EdcClient providerClient) { + // arrange var data = "expected data 123"; var yesterday = OffsetDateTime.now().minusDays(1); @@ -207,25 +183,26 @@ void provide_consume_assetMapping_policyMapping_agreements() { assertThat(assets).hasSize(1); var asset = assets.get(0); - var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(getProtocolEndpoint(providerConnector)); + var providerProtocolEndpoint = providerConfig.getProtocolEndpoint().getUri().toString(); + var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerProtocolEndpoint); assertThat(dataOffers).hasSize(1); var dataOffer = dataOffers.get(0); assertThat(dataOffer.getContractOffers()).hasSize(1); var contractOffer = dataOffer.getContractOffers().get(0); // act - var negotiation = negotiate(dataOffer, contractOffer); - initiateTransfer(negotiation); + var negotiation = negotiate(consumerClient, consumerConnector, dataOffer, contractOffer); + initiateTransfer(consumerClient, negotiation); var providerAgreements = providerClient.uiApi().getContractAgreementPage(null).getContractAgreements(); var consumerAgreements = consumerClient.uiApi().getContractAgreementPage(null).getContractAgreements(); // assert - assertThat(dataOffer.getEndpoint()).isEqualTo(getProtocolEndpoint(providerConnector)); + assertThat(dataOffer.getEndpoint()).isEqualTo(providerProtocolEndpoint); assertThat(dataOffer.getParticipantId()).isEqualTo(PROVIDER_PARTICIPANT_ID); assertThat(dataOffer.getAsset().getAssetId()).isEqualTo(assetId); assertThat(dataOffer.getAsset().getTitle()).isEqualTo("AssetName"); - assertThat(dataOffer.getAsset().getConnectorEndpoint()).isEqualTo(getProtocolEndpoint(providerConnector)); - assertThat(dataOffer.getAsset().getParticipantId()).isEqualTo(providerConnector.getParticipantId()); + assertThat(dataOffer.getAsset().getConnectorEndpoint()).isEqualTo(providerProtocolEndpoint); + assertThat(dataOffer.getAsset().getParticipantId()).isEqualTo(providerConfig.getProperties().get("edc.participant.id")); assertThat(dataOffer.getAsset().getKeywords()).isEqualTo(List.of("keyword1", "keyword2")); assertThat(dataOffer.getAsset().getDescription()).isEqualTo("AssetDescription"); assertThat(dataOffer.getAsset().getVersion()).isEqualTo("1.0.0"); @@ -266,8 +243,8 @@ void provide_consume_assetMapping_policyMapping_agreements() { // while the data offer on the consumer side won't contain private properties, the asset page on the provider side should assertThat(asset.getAssetId()).isEqualTo(assetId); assertThat(asset.getTitle()).isEqualTo("AssetName"); - assertThat(asset.getConnectorEndpoint()).isEqualTo(getProtocolEndpoint(providerConnector)); - assertThat(asset.getParticipantId()).isEqualTo(providerConnector.getParticipantId()); + assertThat(asset.getConnectorEndpoint()).isEqualTo(providerProtocolEndpoint); + assertThat(asset.getParticipantId()).isEqualTo(providerConfig.getProperties().get("edc.participant.id")); assertThatJson(asset.getCustomJsonAsString()).isEqualTo(""" { "test": "value" } @@ -294,7 +271,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("http://localhost:23003/api/dsp"); + assertThat(providerAgreement.getCounterPartyAddress()).isEqualTo(consumerConfig.getProtocolEndpoint().getUri().toString()); assertThat(providerAgreement.getCounterPartyId()).isEqualTo(CONSUMER_PARTICIPANT_ID); assertThat(providerAgreement.getAsset().getAssetId()).isEqualTo(assetId); @@ -329,11 +306,11 @@ void provide_consume_assetMapping_policyMapping_agreements() { validateDataTransferred(dataAddress.getDataSinkSpyUrl(), data); - validateTransferProcessesOk(); + validateTransferProcessesOk(consumerClient, providerClient); } @Test - void canOverrideTheWellKnowPropertiesUsingTheCustomProperties() { + void canOverrideTheWellKnowPropertiesUsingTheCustomProperties(@Provider EdcClient providerClient) { // arrange var dataSource = UiDataSource.builder() .type(DataSourceType.HTTP_DATA) @@ -379,11 +356,14 @@ void canOverrideTheWellKnowPropertiesUsingTheCustomProperties() { """); } - // TODO throw an error if the id is overridden - @DisabledOnGithub @Test - void customTransferRequest() { + void customTransferRequest( + @Consumer ConnectorRemote consumerConnector, + @Consumer EdcClient consumerClient, + @Provider ConnectorConfig providerConfig, + @Provider EdcClient providerClient) { + // arrange var data = "expected data 123"; @@ -414,14 +394,15 @@ void customTransferRequest() { .assetSelector(List.of()) .build()); - var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(getProtocolEndpoint(providerConnector)); + val providerProtocolEndpoint = providerConfig.getProtocolEndpoint().getUri().toString(); + var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerProtocolEndpoint); assertThat(dataOffers).hasSize(1); var dataOffer = dataOffers.get(0); assertThat(dataOffer.getContractOffers()).hasSize(1); var contractOffer = dataOffer.getContractOffers().get(0); // act - var negotiation = negotiate(dataOffer, contractOffer); + var negotiation = negotiate(consumerClient, consumerConnector, dataOffer, contractOffer); var transferRequestJsonLd = Json.createObjectBuilder() .add( Prop.Edc.DATA_DESTINATION, @@ -445,7 +426,12 @@ void customTransferRequest() { @DisabledOnGithub @Test - void editAssetOnLiveContract() { + void editAssetOnLiveContract( + @Consumer ConnectorRemote consumerConnector, + @Consumer EdcClient consumerClient, + @Provider ConnectorConfig providerConfig, + @Provider EdcClient providerClient) { + // arrange var data = "expected data 123"; @@ -500,12 +486,13 @@ void editAssetOnLiveContract() { .build())) .build()); - var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(getProtocolEndpoint(providerConnector)); + val providerProtocolEndpoint = providerConfig.getProtocolEndpoint().getUri().toString(); + var dataOffers = consumerClient.uiApi().getCatalogPageDataOffers(providerProtocolEndpoint); assertThat(dataOffers).hasSize(1); var dataOffer = dataOffers.get(0); assertThat(dataOffer.getContractOffers()).hasSize(1); var contractOffer = dataOffer.getContractOffers().get(0); - var negotiation = negotiate(dataOffer, contractOffer); + var negotiation = negotiate(consumerClient, consumerConnector, dataOffer, contractOffer); // act providerClient.uiApi().editAsset(assetId, UiAssetEditRequest.builder() @@ -537,10 +524,10 @@ void editAssetOnLiveContract() { } """) .build()); - initiateTransfer(negotiation); + initiateTransfer(consumerClient, negotiation); // assert - assertThat(consumerClient.uiApi().getCatalogPageDataOffers(getProtocolEndpoint(providerConnector)).get(0).getAsset().getTitle()).isEqualTo("Good Asset Title"); + assertThat(consumerClient.uiApi().getCatalogPageDataOffers(providerProtocolEndpoint).get(0).getAsset().getTitle()).isEqualTo("Good Asset Title"); val firstAsset = providerClient.uiApi().getContractAgreementPage(null).getContractAgreements().get(0).getAsset(); assertThat(firstAsset.getTitle()).isEqualTo("Good Asset Title"); assertThat(firstAsset.getCustomJsonAsString()).isEqualTo(""" @@ -566,11 +553,16 @@ void editAssetOnLiveContract() { } """); validateDataTransferred(dataAddress.getDataSinkSpyUrl(), data); - validateTransferProcessesOk(); + validateTransferProcessesOk(consumerClient, providerClient); assertThat(providerClient.uiApi().getTransferHistoryPage().getTransferEntries().get(0).getAssetName()).isEqualTo("Good Asset Title"); } - private UiContractNegotiation negotiate(UiDataOffer dataOffer, UiContractOffer contractOffer) { + private UiContractNegotiation negotiate( + EdcClient consumerClient, + ConnectorRemote consumerConnector, + UiDataOffer dataOffer, + UiContractOffer contractOffer) { + var negotiationRequest = ContractNegotiationRequest.builder() .counterPartyAddress(dataOffer.getEndpoint()) .counterPartyParticipantId(dataOffer.getParticipantId()) @@ -591,7 +583,7 @@ private UiContractNegotiation negotiate(UiDataOffer dataOffer, UiContractOffer c return negotiation; } - private void initiateTransfer(UiContractNegotiation negotiation) { + private void initiateTransfer(EdcClient consumerClient, UiContractNegotiation negotiation) { var contractAgreementId = negotiation.getContractAgreementId(); var transferRequest = InitiateTransferRequest.builder() .contractAgreementId(contractAgreementId) @@ -600,8 +592,8 @@ private void initiateTransfer(UiContractNegotiation negotiation) { consumerClient.uiApi().initiateTransfer(transferRequest); } - private void validateTransferProcessesOk() { - await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> { + private void validateTransferProcessesOk(EdcClient consumerClient, EdcClient providerClient) { + await().atMost(20, TimeUnit.SECONDS).untilAsserted(() -> { var providing = providerClient.uiApi().getTransferHistoryPage().getTransferEntries().get(0); var consuming = consumerClient.uiApi().getTransferHistoryPage().getTransferEntries().get(0); assertThat(providing.getState().getSimplifiedState()).isEqualTo(TransferProcessSimplifiedState.OK); @@ -614,8 +606,4 @@ private JsonObject getDatasinkPropertiesJsonObject() { var props = dataAddress.getDataSinkProperties(); return Json.createObjectBuilder((Map) (Map) props).build(); } - - private String getProtocolEndpoint(ConnectorRemote connector) { - return connector.getConfig().getProtocolEndpoint().getUri().toString(); - } } 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 a32f56217..2e8fa6630 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapperTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapperTest.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.e2e; @@ -36,82 +37,47 @@ 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.extension.Consumer; +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.jsonld.vocab.Prop; -import org.eclipse.edc.junit.extensions.EdcExtension; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.extension.ExtendWith; import java.time.OffsetDateTime; import java.util.List; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorRemoteConfigFactory.fromConnectorConfig; import static org.assertj.core.api.Assertions.assertThat; +@ExtendWith(E2eTestExtension.class) class UseCaseApiWrapperTest { - 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 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, 21000, PROVIDER_DATABASE); - providerEdcContext.setConfiguration(providerConfig.getProperties()); - providerConnector = new ConnectorRemote(fromConnectorConfig(providerConfig)); - - providerClient = EdcClient.builder() - .managementApiUrl(providerConfig.getManagementEndpoint().getUri().toString()) - .managementApiKey(providerConfig.getProperties().get("edc.api.auth.key")) - .build(); - - // set up consumer EDC + Client - var consumerConfig = forTestDatabase(CONSUMER_PARTICIPANT_ID, 23000, CONSUMER_DATABASE); - consumerEdcContext.setConfiguration(consumerConfig.getProperties()); - consumerConnector = new ConnectorRemote(fromConnectorConfig(consumerConfig)); - - consumerClient = EdcClient.builder() - .managementApiUrl(consumerConfig.getManagementEndpoint().getUri().toString()) - .managementApiKey(consumerConfig.getProperties().get("edc.api.auth.key")) - .build(); - + 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().getDefaultEndpoint()); } @DisabledOnGithub @Test - void catalog_filtering_by_like() { + void catalog_filtering_by_like( + @Consumer EdcClient consumerClient, + @Provider ConnectorRemote providerConnector, + @Provider EdcClient providerClient) { + // arrange - createPolicy(); - createAsset(); - createContractDefinition(); + createPolicy(providerClient); + createAsset(providerClient); + createContractDefinition(providerClient); - var query = criterion(Prop.Edc.ID, CatalogFilterExpressionOperator.LIKE, "%data-offer%"); + var query = criterion(providerConnector, Prop.Edc.ID, CatalogFilterExpressionOperator.LIKE, "%data-offer%"); // act var dataOffers = consumerClient.useCaseApi().queryCatalog(query); @@ -123,7 +89,12 @@ void catalog_filtering_by_like() { } - private CatalogQuery criterion(String leftOperand, CatalogFilterExpressionOperator operator, String rightOperand) { + private CatalogQuery criterion( + ConnectorRemote providerConnector, + String leftOperand, + CatalogFilterExpressionOperator operator, + String rightOperand) { + return CatalogQuery.builder() .connectorEndpoint(getProtocolEndpoint(providerConnector)) .filterExpressions( @@ -138,7 +109,7 @@ private CatalogQuery criterion(String leftOperand, CatalogFilterExpressionOperat .build(); } - private void createAsset() { + private void createAsset(EdcClient providerClient) { var dataSource = UiDataSource.builder() .type(DataSourceType.HTTP_DATA) .httpData(UiDataSourceHttpData.builder() @@ -160,7 +131,7 @@ private void createAsset() { providerClient.uiApi().createAsset(asset); } - private void createPolicy() { + private void createPolicy(EdcClient providerClient) { var afterYesterday = UiPolicyConstraint.builder() .left("POLICY_EVALUATION_TIME") .operator(OperatorDto.GT) @@ -189,7 +160,7 @@ private void createPolicy() { providerClient.uiApi().createPolicyDefinition(policyDefinition); } - private void createContractDefinition() { + private void createContractDefinition(EdcClient providerClient) { var contractDefinition = ContractDefinitionRequest.builder() .contractDefinitionId(dataOfferId) .accessPolicyId(dataOfferId) diff --git a/utils/catalog-parser/build.gradle.kts b/utils/catalog-parser/build.gradle.kts index daf3707ce..dee5ebaf0 100644 --- a/utils/catalog-parser/build.gradle.kts +++ b/utils/catalog-parser/build.gradle.kts @@ -23,7 +23,6 @@ dependencies { testCompileOnly(libs.lombok) testImplementation(project(":utils:test-utils")) testImplementation(libs.mockito.core) - testImplementation(libs.mockito.inline) testImplementation(libs.mockito.junitJupiter) testImplementation(libs.assertj.core) testImplementation(libs.junit.api) 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 e9559cf2a..603bd2b27 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 @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.utils.catalog; diff --git a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/DspCatalogServiceException.java b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/DspCatalogServiceException.java index 1d2a53dc0..7397afa15 100644 --- a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/DspCatalogServiceException.java +++ b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/DspCatalogServiceException.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.utils.catalog; diff --git a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/mapper/DspContractOfferUtils.java b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/mapper/DspContractOfferUtils.java deleted file mode 100644 index 53ad296ff..000000000 --- a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/mapper/DspContractOfferUtils.java +++ /dev/null @@ -1,78 +0,0 @@ -package de.sovity.edc.utils.catalog.mapper; - -import de.sovity.edc.utils.JsonUtils; -import de.sovity.edc.utils.jsonld.JsonLdUtils; -import de.sovity.edc.utils.jsonld.vocab.Prop; -import jakarta.json.Json; -import jakarta.json.JsonObject; -import lombok.val; -import org.eclipse.edc.connector.contract.spi.ContractId; -import org.jetbrains.annotations.NotNull; - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Base64; - -public class DspContractOfferUtils { - - /** - * /!\ Workaround - *

- * The Eclipse EDC uses a new random UUID for each policy that it returns and in turn a new contract ID. - * This Eclipse ID can't be used as such. - * As a workaround, we must introduce our own ID. - * For a first iteration, we will assume that the content of the policy remains the same (same content, same order) - * and hash it to use it as a key. - * - * @param contract The contract to compute an ID from - * @return A base64 string that can be used as an id for the {@code contract} - */ - public static String buildStableId(JsonObject contract) { - // NOTE: This doesn't enforce any property order and may cause trouble if the returned policy schema is not consistent. - // Use canonical form if needed later. - val noId = Json.createObjectBuilder(contract).remove(Prop.ID).build(); - val policyId = hash(noId); - - val currentId = ContractId.parseId(JsonLdUtils.string(contract, Prop.ID)) - .orElseThrow((failure) -> { - throw new RuntimeException("Failed to parse the contract id: " + failure.getFailureDetail()); - }); - - return currentId.definitionPart() + ":" + currentId.assetIdPart() + ":" + policyId; - } - - @NotNull - private static String hash(JsonObject noId) { - val policyJsonString = JsonUtils.toJson(noId); - val sha1 = sha1(policyJsonString); - // encoding with base16 to make the hash readable to humans (similarly to how the random UUID would have been readable) - val base16 = toBase16(sha1); - return toBase64(base16); - } - - @NotNull - private static String toBase64(String string) { - byte[] stringBytes = string.getBytes(StandardCharsets.UTF_8); - byte[] bytes = Base64.getEncoder().encode(stringBytes); - return new String(bytes); - } - - @NotNull - private static String toBase16(byte[] bytes) { - val sb = new StringBuilder(); - for (byte b : bytes) { - sb.append(Character.forDigit(b >> 4 & 0xf, 16)); - sb.append(Character.forDigit(b & 0xf, 16)); - } - return sb.toString(); - } - - private static byte[] sha1(String string) { - try { - return MessageDigest.getInstance("sha-1").digest(string.getBytes()); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - } -} 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 02c0ec338..cf6444b84 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 @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.utils.catalog.mapper; diff --git a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/model/DspCatalog.java b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/model/DspCatalog.java index e68bb07c5..0fdb5ef25 100644 --- a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/model/DspCatalog.java +++ b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/model/DspCatalog.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.utils.catalog.model; diff --git a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/model/DspContractOffer.java b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/model/DspContractOffer.java index a5150fc00..4ac17020e 100644 --- a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/model/DspContractOffer.java +++ b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/model/DspContractOffer.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.utils.catalog.model; diff --git a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/model/DspDataOffer.java b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/model/DspDataOffer.java index 278098e35..e18f661c1 100644 --- a/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/model/DspDataOffer.java +++ b/utils/catalog-parser/src/main/java/de/sovity/edc/utils/catalog/model/DspDataOffer.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.utils.catalog.model; diff --git a/utils/json-and-jsonld-utils/build.gradle.kts b/utils/json-and-jsonld-utils/build.gradle.kts index d2ef943f4..18ed02190 100644 --- a/utils/json-and-jsonld-utils/build.gradle.kts +++ b/utils/json-and-jsonld-utils/build.gradle.kts @@ -18,7 +18,6 @@ dependencies { testAnnotationProcessor(libs.lombok) testCompileOnly(libs.lombok) testImplementation(libs.mockito.core) - testImplementation(libs.mockito.inline) testImplementation(libs.mockito.junitJupiter) testImplementation(libs.assertj.core) testImplementation(libs.junit.api) diff --git a/utils/json-and-jsonld-utils/src/main/java/de/sovity/edc/utils/JsonUtils.java b/utils/json-and-jsonld-utils/src/main/java/de/sovity/edc/utils/JsonUtils.java index 1a91ae7cf..95c22d044 100644 --- a/utils/json-and-jsonld-utils/src/main/java/de/sovity/edc/utils/JsonUtils.java +++ b/utils/json-and-jsonld-utils/src/main/java/de/sovity/edc/utils/JsonUtils.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.utils; diff --git a/utils/json-and-jsonld-utils/src/main/java/de/sovity/edc/utils/jsonld/JsonLdUtils.java b/utils/json-and-jsonld-utils/src/main/java/de/sovity/edc/utils/jsonld/JsonLdUtils.java index ec44ecdad..f264949af 100644 --- a/utils/json-and-jsonld-utils/src/main/java/de/sovity/edc/utils/jsonld/JsonLdUtils.java +++ b/utils/json-and-jsonld-utils/src/main/java/de/sovity/edc/utils/jsonld/JsonLdUtils.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.utils.jsonld; 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 ea04f5e43..4a057ddd2 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 @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.utils.jsonld.vocab; diff --git a/utils/test-connector-remote/build.gradle.kts b/utils/test-connector-remote/build.gradle.kts deleted file mode 100644 index a3d3d6474..000000000 --- a/utils/test-connector-remote/build.gradle.kts +++ /dev/null @@ -1,35 +0,0 @@ - -plugins { - `java-library` -} - -dependencies { - annotationProcessor(libs.lombok) - compileOnly(libs.lombok) - - api(libs.junit.api) - implementation(libs.apache.commonsLang) - - api(libs.edc.junit) - api(libs.awaitility.java) - api(project(":utils:json-and-jsonld-utils")) - implementation(project(":utils:versions")) - implementation(libs.edc.sqlCore) - implementation(libs.edc.jsonLdSpi) - implementation(libs.edc.jsonLd) - implementation(libs.assertj.core) - implementation(libs.testcontainers.testcontainers) - implementation(libs.testcontainers.junitJupiter) - implementation(libs.testcontainers.postgresql) - implementation(libs.restAssured.restAssured) -} - -group = libs.versions.sovityEdcExtensionGroup.get() - -publishing { - publications { - create(project.name) { - from(components["java"]) - } - } -} diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionWithTestDatabase.java b/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionWithTestDatabase.java deleted file mode 100644 index af15b7822..000000000 --- a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionWithTestDatabase.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.sovity.edc.extension.e2e.db; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.experimental.Delegate; -import org.eclipse.edc.junit.extensions.EdcRuntimeExtension; -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 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, - ParameterResolver.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)); - } -} diff --git a/utils/test-connector-remote/README.md b/utils/test-utils/README.md similarity index 75% rename from utils/test-connector-remote/README.md rename to utils/test-utils/README.md index 903aa7a09..fa298552d 100644 --- a/utils/test-connector-remote/README.md +++ b/utils/test-utils/README.md @@ -16,7 +16,11 @@ ## About this Utility -Connector Remote for creating simple test data via the management API. +A toolset to ease testing. + +* Connector Remote for creating simple test data via the management API. +* E2eTestExtension to bootstrap end-to-end tests using the wrapper API. +* EdcRuntimeExtensionWithTestDatabase to test single connectors with a database. ## Why does this extension exist? diff --git a/utils/test-utils/build.gradle.kts b/utils/test-utils/build.gradle.kts index 5aae2ca05..e2d6e9038 100644 --- a/utils/test-utils/build.gradle.kts +++ b/utils/test-utils/build.gradle.kts @@ -4,7 +4,29 @@ plugins { } dependencies { + annotationProcessor(libs.lombok) + compileOnly(libs.lombok) + api(libs.junit.api) + implementation(libs.apache.commonsLang) + + api(libs.edc.junit) + api(libs.awaitility.java) + api(project(":extensions:wrapper:clients:java-client")) + api(project(":utils:json-and-jsonld-utils")) + + implementation(project(":extensions:policy-always-true")) + implementation(project(":utils:versions")) + implementation(libs.edc.jsonLdSpi) + implementation(libs.edc.jsonLd) + implementation(libs.edc.sqlCore) + implementation(libs.assertj.core) + implementation(libs.jooq.jooq) + implementation(libs.mockserver.netty) + implementation(libs.testcontainers.testcontainers) + implementation(libs.testcontainers.junitJupiter) + implementation(libs.testcontainers.postgresql) + implementation(libs.restAssured.restAssured) } group = libs.versions.sovityEdcExtensionGroup.get() diff --git a/utils/test-connector-remote/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 similarity index 95% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/ConnectorRemote.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/ConnectorRemote.java index e85911e77..ddc180bad 100644 --- a/utils/test-connector-remote/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 @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector; @@ -34,7 +35,6 @@ import java.net.URI; import java.time.Duration; -import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; @@ -56,8 +56,8 @@ @SuppressWarnings("java:S5960") @RequiredArgsConstructor public class ConnectorRemote { - @Getter + @Getter private final ConnectorRemoteConfig config; private final ObjectMapper objectMapper = JacksonJsonLd.createObjectMapper(); @@ -84,22 +84,6 @@ public void createAsset(String assetId, Map dataAddressPropertie .contentType(JSON); } - public List getAssetIds() { - var requestBody = createObjectBuilder() - .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) - .add(TYPE, EDC_NAMESPACE + "QuerySpec") - .build(); - return prepareManagementApiCall() - .contentType(JSON) - .body(requestBody) - .when() - .post("/v2/assets/request") - .then() - .statusCode(200) - .contentType(JSON) - .extract().jsonPath().getList("@id"); - } - public String createPolicy(JsonObject policyJsonObject) { var requestBody = createObjectBuilder() .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/DataTransferTestUtil.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/DataTransferTestUtil.java similarity index 98% rename from utils/test-connector-remote/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/DataTransferTestUtil.java index 88089a752..147debb37 100644 --- a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/DataTransferTestUtil.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/DataTransferTestUtil.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector; diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/MockDataAddressRemote.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/MockDataAddressRemote.java similarity index 98% rename from utils/test-connector-remote/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/MockDataAddressRemote.java index e67af343b..00e68aeb0 100644 --- a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/MockDataAddressRemote.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/MockDataAddressRemote.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector; diff --git a/utils/test-connector-remote/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 similarity index 97% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorConfig.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorConfig.java index ff34e619b..383ce8c93 100644 --- a/utils/test-connector-remote/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 @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector.config; diff --git a/utils/test-connector-remote/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 similarity index 75% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorConfigFactory.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorConfigFactory.java index a4e3d76a4..4608b9396 100644 --- a/utils/test-connector-remote/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 @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector.config; @@ -27,26 +28,12 @@ import static de.sovity.edc.extension.e2e.connector.config.DatasourceConfigUtils.configureDatasources; import static de.sovity.edc.extension.e2e.connector.config.api.EdcApiConfigFactory.configureApi; import static org.eclipse.edc.junit.testfixtures.TestUtils.MAX_TCP_PORT; -import static org.eclipse.edc.junit.testfixtures.TestUtils.getFreePort; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class ConnectorConfigFactory { private static final Random RANDOM = new Random(); - /** - * Creates the default configuration to start an EDC with the given test database. - * - * @deprecated Use {@link ConnectorConfigFactory#forTestDatabase(String, TestDatabase)} - * with automatic ports allocation to prevent port allocation conflicts. - */ - @Deprecated - public static ConnectorConfig forTestDatabase(String participantId, int firstPort, TestDatabase testDatabase) { - var config = basicEdcConfig(participantId, firstPort); - config.setProperties(configureDatasources(testDatabase.getJdbcCredentials())); - return config; - } - public static ConnectorConfig forTestDatabase(String participantId, TestDatabase testDatabase) { val firstPort = getFreePortRange(5); var config = basicEdcConfig(participantId, firstPort); @@ -56,16 +43,16 @@ public static ConnectorConfig forTestDatabase(String participantId, TestDatabase public static synchronized int getFreePortRange(int size) { // pick a random in a reasonable range - int firstPort = getFreePort(RANDOM.nextInt(10_000, 50_000)); + int firstPort = RANDOM.nextInt(10_000, 50_000); int currentPort = firstPort; do { - if (canUsePort(currentPort + 1)) { + if (canUsePort(currentPort)) { currentPort++; } else { - firstPort = getFreePort(currentPort++); + firstPort = currentPort++; } - } while (currentPort < firstPort + size); + } while (currentPort <= firstPort + size); return firstPort; } @@ -98,6 +85,8 @@ public static ConnectorConfig basicEdcConfig(String participantId, int firstPort properties.put("edc.last.commit.info", "test env commit message"); properties.put("edc.build.date", "2023-05-08T15:30:00Z"); + properties.put("edc.server.db.connection.timeout.in.ms", "5000"); + properties.put("my.edc.participant.id", participantId); properties.put("my.edc.title", "Connector Title %s".formatted(participantId)); properties.put("my.edc.description", "Connector Description %s".formatted(participantId)); @@ -106,6 +95,17 @@ public static ConnectorConfig basicEdcConfig(String participantId, int firstPort properties.put("my.edc.maintainer.url", "http://maintainer.%s".formatted(participantId)); properties.put("my.edc.maintainer.name", "Maintainer Name %s".formatted(participantId)); + properties.put("edc.server.db.connection.pool.size", "3"); + + properties.put("web.http.port", String.valueOf(apiConfig.getDefaultApiGroup().port())); + properties.put("web.http.path", String.valueOf(apiConfig.getDefaultApiGroup().path())); + properties.put("web.http.protocol.port", String.valueOf(apiConfig.getProtocolApiGroup().port())); + properties.put("web.http.protocol.path", String.valueOf(apiConfig.getProtocolApiGroup().path())); + properties.put("web.http.management.port", String.valueOf(apiConfig.getManagementApiGroup().port())); + properties.put("web.http.management.path", String.valueOf(apiConfig.getManagementApiGroup().path())); + properties.put("web.http.control.port", String.valueOf(apiConfig.getControlApiGroup().port())); + properties.put("web.http.control.path", String.valueOf(apiConfig.getControlApiGroup().path())); + return new ConnectorConfig( participantId, apiConfig.getDefaultApiGroup(), diff --git a/utils/test-connector-remote/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/config/ConnectorRemoteConfig.java similarity index 96% rename from utils/test-connector-remote/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/config/ConnectorRemoteConfig.java index 69dbcf302..8577b1d92 100644 --- a/utils/test-connector-remote/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/config/ConnectorRemoteConfig.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector.config; diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorRemoteConfigFactory.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorRemoteConfigFactory.java similarity index 99% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorRemoteConfigFactory.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorRemoteConfigFactory.java index 54f08c8fc..e3d9c4440 100644 --- a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorRemoteConfigFactory.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/ConnectorRemoteConfigFactory.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector.config; diff --git a/utils/test-connector-remote/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 similarity index 98% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/DatasourceConfigUtils.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/DatasourceConfigUtils.java index fd1df4057..47b822453 100644 --- a/utils/test-connector-remote/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 @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector.config; diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiConfig.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiConfig.java similarity index 97% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiConfig.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiConfig.java index d1cc4dd36..4aca4ef89 100644 --- a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiConfig.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiConfig.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector.config.api; diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiConfigFactory.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiConfigFactory.java similarity index 99% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiConfigFactory.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiConfigFactory.java index 603172ea4..5f5f26302 100644 --- a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiConfigFactory.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiConfigFactory.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector.config.api; diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiGroup.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiGroup.java similarity index 97% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiGroup.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiGroup.java index 3af481919..46bc7dcb6 100644 --- a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiGroup.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiGroup.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector.config.api; diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiGroupConfig.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiGroupConfig.java similarity index 96% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiGroupConfig.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiGroupConfig.java index 78c610da5..af579097e 100644 --- a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiGroupConfig.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/EdcApiGroupConfig.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector.config.api; diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/ApiKeyAuthProvider.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/ApiKeyAuthProvider.java similarity index 95% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/ApiKeyAuthProvider.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/ApiKeyAuthProvider.java index f747ed6e2..1b5919dfe 100644 --- a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/ApiKeyAuthProvider.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/ApiKeyAuthProvider.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector.config.api.auth; diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/AuthProvider.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/AuthProvider.java similarity index 93% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/AuthProvider.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/AuthProvider.java index 35474d8a9..a2e11a921 100644 --- a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/AuthProvider.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/AuthProvider.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector.config.api.auth; diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/NoneAuthProvider.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/NoneAuthProvider.java similarity index 95% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/NoneAuthProvider.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/NoneAuthProvider.java index 3181c9453..af59e7eb3 100644 --- a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/NoneAuthProvider.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/connector/config/api/auth/NoneAuthProvider.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.connector.config.api.auth; diff --git a/utils/test-connector-remote/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 similarity index 100% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionDeferred.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionDeferred.java diff --git a/utils/test-connector-remote/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 similarity index 100% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionFixed.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionFixed.java 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 new file mode 100644 index 000000000..868c3d89d --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/EdcRuntimeExtensionWithTestDatabase.java @@ -0,0 +1,69 @@ +package de.sovity.edc.extension.e2e.db; + +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.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 { + boolean isJooqDsl = parameterContext.getParameter().getType().equals(DSLContext.class); + return isJooqDsl || edcRuntimeExtension.supportsParameter(parameterContext, extensionContext); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + boolean isJooqDsl = parameterContext.getParameter().getType().equals(DSLContext.class); + if (isJooqDsl) { + return getDslContext().dsl(); + } 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-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/JdbcCredentials.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/JdbcCredentials.java similarity index 100% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/JdbcCredentials.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/JdbcCredentials.java diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabase.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabase.java similarity index 100% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabase.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabase.java diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabaseFactory.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabaseFactory.java similarity index 100% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabaseFactory.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabaseFactory.java diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaEnvVars.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaEnvVars.java similarity index 100% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaEnvVars.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaEnvVars.java diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaTestcontainers.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaTestcontainers.java similarity index 100% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaTestcontainers.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaTestcontainers.java diff --git a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/env/EnvUtil.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/env/EnvUtil.java similarity index 97% rename from utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/env/EnvUtil.java rename to utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/env/EnvUtil.java index 1b1c1bd69..9a2cc713a 100644 --- a/utils/test-connector-remote/src/main/java/de/sovity/edc/extension/e2e/env/EnvUtil.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/env/EnvUtil.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * sovity GmbH - init + * */ package de.sovity.edc.extension.e2e.env; 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/extension/Consumer.java new file mode 100644 index 000000000..cbd622765 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/Consumer.java @@ -0,0 +1,25 @@ +/* + * 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 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 + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface Consumer { +} 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/extension/E2eScenario.java new file mode 100644 index 000000000..a4bc6317d --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eScenario.java @@ -0,0 +1,275 @@ +/* + * 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.client.gen.model.ContractDefinitionRequest; +import de.sovity.edc.client.gen.model.ContractNegotiationRequest; +import de.sovity.edc.client.gen.model.ContractNegotiationSimplifiedState; +import de.sovity.edc.client.gen.model.ContractTerminationRequest; +import de.sovity.edc.client.gen.model.DataSourceType; +import de.sovity.edc.client.gen.model.IdResponseDto; +import de.sovity.edc.client.gen.model.InitiateCustomTransferRequest; +import de.sovity.edc.client.gen.model.InitiateTransferRequest; +import de.sovity.edc.client.gen.model.OperatorDto; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.client.gen.model.UiAssetCreateRequest; +import de.sovity.edc.client.gen.model.UiContractNegotiation; +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.UiPolicyConstraint; +import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; +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.val; +import org.awaitility.Awaitility; +import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +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.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import static de.sovity.edc.client.gen.model.TransferProcessSimplifiedState.RUNNING; +import static de.sovity.edc.extension.policy.AlwaysTruePolicyConstants.POLICY_DEFINITION_ID; +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; + + public E2eScenario(ConnectorConfig consumerConfig, ConnectorConfig providerConfig, ClientAndServer mockServer) { + this.consumerConfig = consumerConfig; + this.providerConfig = providerConfig; + this.mockServer = mockServer; + + consumerClient = EdcClient.builder() + .managementApiUrl(consumerConfig.getManagementEndpoint().getUri().toString()) + .managementApiKey(consumerConfig.getProperties().get("edc.api.auth.key")) + .build(); + + providerClient = EdcClient.builder() + .managementApiUrl(providerConfig.getManagementEndpoint().getUri().toString()) + .managementApiKey(providerConfig.getProperties().get("edc.api.auth.key")) + .build(); + } + + private final String alwaysTruePolicyId = POLICY_DEFINITION_ID; + + private final AtomicInteger assetCounter = new AtomicInteger(0); + + public String createAsset() { + val dummyDataSource = UiDataSource.builder() + .type(DataSourceType.HTTP_DATA) + .httpData(UiDataSourceHttpData.builder() + .baseUrl("http://example.com") + .build()) + .build(); + + return internalCreateAsset("asset-" + assetCounter.getAndIncrement(), dummyDataSource).getId(); + } + + public String createAsset(String id, UiDataSourceHttpData uiDataSourceHttpData) { + val uiDataSource = UiDataSource.builder() + .type(DataSourceType.HTTP_DATA) + .httpData(uiDataSourceHttpData) + .build(); + + return internalCreateAsset(id, uiDataSource).getId(); + } + + public MockedAsset createAssetWithMockResource(String id) { + + val path = "/assets/" + id; + val url = "http://localhost:" + mockServer.getPort() + path; + + val uiDataSource = UiDataSource.builder() + .type(DataSourceType.HTTP_DATA) + .httpData(UiDataSourceHttpData.builder().baseUrl(url).build()) + .build(); + + val accesses = new AtomicInteger(0); + + mockServer.when(HttpRequest.request(path).withMethod("GET")).respond(it -> { + accesses.incrementAndGet(); + return HttpResponse.response().withStatusCode(200); + }); + + internalCreateAsset(id, uiDataSource); + + return new MockedAsset(id, accesses); + } + + private IdResponseDto internalCreateAsset(String assetId, UiDataSource dataSource) { + return providerClient.uiApi() + .createAsset(UiAssetCreateRequest.builder() + .id(assetId) + .title("AssetName " + assetId) + .version("1.0.0") + .language("en") + .dataSource(dataSource) + .build()); + } + + public String createPolicyDefinition(String policyId, UiPolicyConstraint... constraints) { + return createPolicyDefinition(policyId, Arrays.stream(constraints).toList()).getId(); + } + + private IdResponseDto createPolicyDefinition(String policyId, List constraints) { + var policyDefinition = PolicyDefinitionCreateRequest.builder() + .policyDefinitionId(policyId) + .policy(UiPolicyCreateRequest.builder() + .constraints(constraints) + .build() + ) + .build(); + + return providerClient.uiApi().createPolicyDefinition(policyDefinition); + } + + public String createContractDefinition(String assetId) { + return createContractDefinition(POLICY_DEFINITION_ID, assetId).getId(); + } + + public IdResponseDto createContractDefinition(String policyId, String assetId) { + return providerClient.uiApi().createContractDefinition(ContractDefinitionRequest.builder() + .contractDefinitionId("cd-" + policyId + "-" + assetId) + .accessPolicyId(policyId) + .contractPolicyId(policyId) + .assetSelector(List.of(UiCriterion.builder() + .operandLeft(Prop.Edc.ID) + .operator(UiCriterionOperator.EQ) + .operandRight(UiCriterionLiteral.builder() + .type(UiCriterionLiteralType.VALUE) + .value(assetId) + .build()) + .build())) + .build()); + } + + public UiContractNegotiation negotiateAssetAndAwait(String assetId) { + val connectorEndpoint = providerConfig.getProtocolEndpoint().getUri().toString(); + val offers = consumerClient.uiApi().getCatalogPageDataOffers(connectorEndpoint); + + val offersContainingContract = offers.stream() + .filter(offer -> offer.getAsset().getAssetId().equals(assetId)) + .toList(); + + assertThat(offersContainingContract).hasSize(1); + + val firstContractOffer = offersContainingContract.get(0).getContractOffers().get(0); + val dataOffer = offersContainingContract.get(0); + var negotiationRequest = ContractNegotiationRequest.builder() + .counterPartyAddress(dataOffer.getEndpoint()) + .counterPartyParticipantId(dataOffer.getParticipantId()) + .assetId(dataOffer.getAsset().getAssetId()) + .contractOfferId(firstContractOffer.getContractOfferId()) + .policyJsonLd(firstContractOffer.getPolicy().getPolicyJsonLd()) + .build(); + + val negotiation = consumerClient.uiApi().initiateContractNegotiation(negotiationRequest); + + val neg = Awaitility.await().atMost(timeout).until( + () -> consumerClient.uiApi().getContractNegotiation(negotiation.getContractNegotiationId()), + it -> it.getState().getSimplifiedState() != ContractNegotiationSimplifiedState.IN_PROGRESS + ); + + assertThat(neg.getState().getSimplifiedState()).isEqualTo(ContractNegotiationSimplifiedState.AGREED); + + return neg; + } + + public void createPolicy(String id, OffsetDateTime from, OffsetDateTime until) { + val startConstraint = UiPolicyConstraint.builder() + .left("POLICY_EVALUATION_TIME") + .operator(OperatorDto.GT) + .right(UiPolicyLiteral.builder() + .type(UiPolicyLiteralType.STRING) + .value(from.toString()) + .build()) + .build(); + + val endConstraint = UiPolicyConstraint.builder() + .left("POLICY_EVALUATION_TIME") + .operator(OperatorDto.LT) + .right(UiPolicyLiteral.builder() + .type(UiPolicyLiteralType.STRING) + .value(until.toString()) + .build()) + .build(); + + var policyDefinition = PolicyDefinitionCreateRequest.builder() + .policyDefinitionId(id) + .policy(UiPolicyCreateRequest.builder() + .constraints(List.of(startConstraint, endConstraint)) + .build()) + .build(); + + providerClient.uiApi().createPolicyDefinition(policyDefinition); + } + + public String transferAndAwait(InitiateTransferRequest transferRequest) { + val transferInit = consumerClient.uiApi().initiateTransfer(transferRequest).getId(); + awaitTransferCompletion(transferInit); + return transferInit; + } + + public String transferAndAwait(InitiateCustomTransferRequest transferRequest) { + val transferInit = consumerClient.uiApi().initiateCustomTransfer(transferRequest).getId(); + awaitTransferCompletion(transferInit); + return transferInit; + } + + public void awaitTransferCompletion(String transferId) { + Awaitility.await().atMost(timeout).until( + () -> consumerClient.uiApi() + .getTransferHistoryPage() + .getTransferEntries() + .stream() + .filter(it -> it.getTransferProcessId().equals(transferId)) + .findFirst() + .map(it -> it.getState().getSimplifiedState()), + it -> it.orElse(RUNNING) != RUNNING + ); + } + + public IdResponseDto terminateContractAgreementAndAwait( + ContractNegotiation.Type party, + String contractAgreementId, + ContractTerminationRequest terminationRequest + ) { + if (party.equals(ContractNegotiation.Type.CONSUMER)) { + return consumerClient.uiApi().terminateContractAgreement(contractAgreementId, terminationRequest); + } else { + return providerClient.uiApi().terminateContractAgreement(contractAgreementId, terminationRequest); + } + } +} 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 new file mode 100644 index 000000000..ddbd592ae --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eTestExtension.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.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.connector.config.ConnectorRemoteConfig; +import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; +import de.sovity.edc.extension.utils.Lazy; +import lombok.val; +import org.jetbrains.annotations.NotNull; +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 org.eclipse.edc.junit.testfixtures.TestUtils.getFreePort; +import static org.mockserver.stop.Stop.stopQuietly; + +public class E2eTestExtension + implements BeforeAllCallback, AfterAllCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver { + + private final String consumerParticipantId; + private ConnectorConfig consumerConfig; + private final EdcRuntimeExtensionWithTestDatabase consumerExtension; + + private final String providerParticipantId; + 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() { + this("consumer", "provider"); + } + + public E2eTestExtension(String consumerParticipantId, String providerParticipantId) { + this.consumerParticipantId = consumerParticipantId; + this.providerParticipantId = providerParticipantId; + + consumerExtension = new EdcRuntimeExtensionWithTestDatabase( + ":launchers:connectors:sovity-dev", + "consumer", + testDatabase -> { + consumerConfig = forTestDatabase(this.consumerParticipantId, testDatabase); + return consumerConfig.getProperties(); + } + ); + providerExtension = new EdcRuntimeExtensionWithTestDatabase( + ":launchers:connectors:sovity-dev", + "provider", + testDatabase -> { + providerConfig = forTestDatabase(this.providerParticipantId, testDatabase); + 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 newConnectorRemote(consumerParticipantId, 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 newConnectorRemote(providerParticipantId, 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 @NotNull ConnectorRemote newConnectorRemote(String participantId, ConnectorConfig config) { + return new ConnectorRemote( + new ConnectorRemoteConfig( + participantId, + config.getDefaultEndpoint(), + config.getManagementEndpoint(), + config.getProtocolEndpoint())); + } + + 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.getManagementEndpoint().getUri().toString()) + .managementApiKey(consumerConfig.getProperties().get("edc.api.auth.key")) + .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/extension/MockedAsset.java new file mode 100644 index 000000000..45609e48f --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/MockedAsset.java @@ -0,0 +1,29 @@ +/* + * 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 java.util.concurrent.atomic.AtomicInteger; + +/** + * An asset that uses a mocked network resource. + * + * @param assetId The related asset's ID + * @param networkAccesses How many times the resource was accessed via the network. + */ +public record MockedAsset( + String assetId, + AtomicInteger networkAccesses +) { +} 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/extension/Provider.java new file mode 100644 index 000000000..e3cff34b2 --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/Provider.java @@ -0,0 +1,25 @@ +/* + * 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 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 + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface Provider { +} diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/utils/Lazy.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/utils/Lazy.java new file mode 100644 index 000000000..ce89df5ee --- /dev/null +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/utils/Lazy.java @@ -0,0 +1,38 @@ +/* + * 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.utils; + +import lombok.RequiredArgsConstructor; + +import java.util.function.Supplier; + +@RequiredArgsConstructor +public class Lazy { + private final Supplier supplier; + + private T tt; + + public synchronized T get() { + if (tt == null) { + tt = supplier.get(); + } + + return tt; + } + + public boolean isInitialized() { + return tt != null; + } +} 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 6c91ac61c..f0382d096 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 @@ -11,6 +11,7 @@ * sovity GmbH - initial API and implementation * */ + package de.sovity.edc.extension.utils.junit; import org.junit.jupiter.api.Tag;