Skip to content

Commit

Permalink
feat(test): adds E2E tests to the CI (#294)
Browse files Browse the repository at this point in the history
* feat(test): add e2e test

* checkstyle

* run e2e tests on push

* enable verbosity
  • Loading branch information
paullatzelsperger authored Jul 16, 2024
1 parent 0c90667 commit 2c7701c
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 39 deletions.
25 changes: 15 additions & 10 deletions .github/workflows/run-terraform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
---
name: "Run DCP Demo locally"
on:
push:
pull_request:
branches:
- main

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
workflow_run:
workflows: [ "Verify" ]
types:
- completed

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand All @@ -49,7 +51,7 @@ jobs:
- uses: eclipse-edc/.github/.github/actions/setup-build@main

- name: "Build runtime images"
working-directory: ./runtimes
working-directory: ./
run: |
./gradlew -Ppersistence=true dockerize
Expand All @@ -61,7 +63,7 @@ jobs:
cluster_name: dcp-demo

- name: "Load runtime images into KinD"
run: kind load docker-image controlplane:latest identity-hub:latest catalog-server:latest -n dcp-demo
run: kind load docker-image controlplane:latest dataplane:latest identity-hub:latest catalog-server:latest -n dcp-demo

- name: "Install nginx ingress controller"
run: |-
Expand All @@ -88,11 +90,14 @@ jobs:
run: |-
terraform apply "$GITHUB_SHA.out"
- name: "Run Health Checks"
- name: "Seed dataspace"
run: |-
chmod +x seed-k8s.sh
./seed-k8s.sh
- name: "Run E2E Test"
run: |-
curl --fail http://localhost/provider-qna/health/check/readiness -H "x-api-key: password"
curl --fail http://localhost/provider-manufacturing/health/check/readiness -H "x-api-key: password"
curl --fail http://localhost/consumer/health/check/readiness -H "x-api-key: password"
./gradlew -DincludeTags="EndToEndTest" test -DverboseTest=true
- name: "Destroy the KinD cluster"
run: >-
Expand Down
13 changes: 10 additions & 3 deletions .github/workflows/verify.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ name: "Verify"

on:
push:
branches:
- main
pull_request:
branches:
- main
Expand Down Expand Up @@ -51,14 +49,23 @@ jobs:
exit 1;
fi
validate-formating:
checkstyle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: eclipse-edc/.github/.github/actions/setup-build@main
- name: Run Checkstyle
run: ./gradlew checkstyleMain checkstyleTest

- name: Check Terraform files are properly formatted (run "terraform fmt -recursive" to fix)
run: |
terraform fmt -recursive
git diff --exit-code
validate-terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check Terraform files are properly formatted (run "terraform fmt -recursive" to fix)
run: |
terraform fmt -recursive
Expand Down
12 changes: 9 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ format.version = "1.1"

[versions]
assertj = "3.24.2"
awaitility = "4.2.0"
awaitility = "4.2.1"
edc = "0.8.1-SNAPSHOT"
failsafe = "3.3.2"
jackson = "2.14.2"
jakarta-json = "2.1.3"
jupiter = "5.10.1"
mockserver = "5.15.0"
nimbus = "9.40"
parsson = "1.1.6"
postgres = "42.7.3"
restAssured = "5.3.2"
restAssured = "5.5.0"
swagger = "2.2.18"
rsApi = "3.1.0"
testcontainers = "1.19.1"
Expand Down Expand Up @@ -148,7 +150,11 @@ edc-controlplane-contract = { module = "org.eclipse.edc:control-plane-contract",
# Third party libs
nimbus-jwt = { module = "com.nimbusds:nimbus-jose-jwt", version.ref = "nimbus" }
postgres = { module = "org.postgresql:postgresql", version.ref = "postgres" }

awaitility = { module = "org.awaitility:awaitility", version.ref = "awaitility" }
restAssured = { module = "io.rest-assured:rest-assured", version.ref = "restAssured" }
jakarta-json-api = { module = "jakarta.json:jakarta.json-api", version.ref = "jakarta-json" }
jackson-datatype-jakarta-jsonp = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jakarta-jsonp", version.ref = "jackson" }
parsson = { module = "org.eclipse.parsson:parsson", version.ref = "parsson" }

[bundles]
dpf = ["edc-dpf-selector-core", "edc-spi-dataplane-selector", "edc-dpf-selector-control-api", "edc-dpf-signaling-client", "edc-dpf-transfer-signaling"]
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ include(":extensions:catalog-node-resolver")
include(":extensions:dcp-impl")
include(":extensions:superuser-seed")
//include(":tests:performance")
include(":tests:system-tests")
include(":tests:end2end")

// launcher modules
include(":launchers:identity-hub")
Expand Down
26 changes: 26 additions & 0 deletions tests/end2end/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2024 Metaform Systems, Inc.
*
* 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:
* Metaform Systems, Inc. - initial API and implementation
*
*/

plugins {
`java-library`
}

dependencies {
testImplementation(libs.edc.junit)
testImplementation(libs.jakarta.json.api)
testImplementation(libs.jackson.datatype.jakarta.jsonp)
testImplementation(libs.parsson)
testImplementation(libs.restAssured)
testImplementation(libs.awaitility)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* Copyright (c) 2024 Metaform Systems, Inc.
*
* 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:
* Metaform Systems, Inc. - initial API and implementation
*
*/

package org.eclipse.edc.demo.tests.transfer;

import io.restassured.specification.RequestSpecification;
import jakarta.json.Json;
import org.eclipse.edc.junit.annotations.EndToEndTest;
import org.eclipse.edc.junit.testfixtures.TestUtils;
import org.junit.jupiter.api.Test;

import java.time.Duration;
import java.util.concurrent.atomic.AtomicReference;

import static io.restassured.RestAssured.given;
import static io.restassured.http.ContentType.JSON;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

/**
* This test is designed to run against an MVD deployed in a Kubernetes cluster, with an active ingress controller.
* The cluster MUST be deployed and seeded according to the README before running this test!
*/
@EndToEndTest
public class TransferEndToEndTest {
// Management API base URL of the consumer connector, goes through Ingress controller
private static final String CONSUMER_MANAGEMENT_URL = "http://127.0.0.1/consumer/cp";
// Catalog Query API URL of the consumer connector, goes through ingress controller
private static final String CONSUMER_CATALOG_URL = "http://127.0.0.1/consumer/fc";
// DSP service URL of the provider, not reachable outside the cluster
private static final String PROVIDER_DSP_URL = "http://provider-qna-controlplane:8082";
// DID of the provider company
private static final String PROVIDER_ID = "did:web:provider-identityhub%3A7083:provider";
// public API endpoint of the provider-qna connector, goes through the incress controller
private static final String PROVIDER_PUBLIC_URL = "http://127.0.0.1/provider-qna/public";
private static final Duration TEST_TIMEOUT_DURATION = Duration.ofSeconds(60);

private static RequestSpecification baseRequest() {
return given()
.header("X-Api-Key", "password")
.contentType(JSON)
.when();
}

@Test
void transferData() {
var emptyQueryBody = Json.createObjectBuilder()
.add("@context", Json.createObjectBuilder().add("edc", "https://w3id.org/edc/v0.0.1/ns/"))
.add("@type", "QuerySpec")
.build();
var offerId = new AtomicReference<String>();
// get catalog, extract offer ID
await().atMost(TEST_TIMEOUT_DURATION)
.untilAsserted(() -> {
var oid = baseRequest()
.body(emptyQueryBody)
.post(CONSUMER_CATALOG_URL + "/api/catalog/v1alpha/catalog/query")
.then()
.log().ifError()
.statusCode(200)
// yes, it's a bit brittle with the hardcoded indexes, but it appears to work.
.extract().body().jsonPath().getString("[0]['http://www.w3.org/ns/dcat#dataset'][1]['http://www.w3.org/ns/dcat#dataset'][0]['odrl:hasPolicy']['@id']");

assertThat(oid).isNotNull();
offerId.set(oid);
});

// initiate negotiation
var negotiationRequest = TestUtils.getResourceFileContentAsString("negotiation-request.json")
.replace("{{PROVIDER_ID}}", PROVIDER_ID)
.replace("{{PROVIDER_DSP_URL}}", PROVIDER_DSP_URL)
.replace("{{OFFER_ID}}", offerId.get());
var negotiationId = baseRequest()
.body(negotiationRequest)
.post(CONSUMER_MANAGEMENT_URL + "/api/management/v3/contractnegotiations")
.then()
.log().ifError()
.statusCode(200)
.extract().body().jsonPath().getString("@id");
assertThat(negotiationId).isNotNull();

//wait until negotiation is FINALIZED
var agreementId = new AtomicReference<String>();
await().atMost(TEST_TIMEOUT_DURATION)
.untilAsserted(() -> {
var jp = baseRequest()
.get(CONSUMER_MANAGEMENT_URL + "/api/management/v3/contractnegotiations/" + negotiationId)
.then()
.statusCode(200)
.extract().body().jsonPath();
var state = jp.getString("state");
assertThat(state).isEqualTo("FINALIZED");
agreementId.set(jp.getString("contractAgreementId"));

});

//start transfer process
var tpRequest = TestUtils.getResourceFileContentAsString("transfer-request.json")
.replace("{{PROVIDER_ID}}", PROVIDER_ID)
.replace("{{PROVIDER_DSP_URL}}", PROVIDER_DSP_URL)
.replace("{{CONTRACT_ID}}", agreementId.get());

var transferProcessId = baseRequest()
.body(tpRequest)
.post(CONSUMER_MANAGEMENT_URL + "/api/management/v3/transferprocesses")
.then()
.log().ifError()
.statusCode(200)
.extract().body().jsonPath().getString("@id");

// fetch EDR for transfer process
var endpoint = new AtomicReference<String>();
var token = new AtomicReference<String>();
await().atMost(TEST_TIMEOUT_DURATION)
.untilAsserted(() -> {
var jp = baseRequest()
.get(CONSUMER_MANAGEMENT_URL + "/api/management/v3/edrs/%s/dataaddress".formatted(transferProcessId))
.then()
.statusCode(200)
.extract().body().jsonPath();

endpoint.set(jp.getString("endpoint"));
token.set(jp.getString("authorization"));

assertThat(endpoint.get()).isNotNull().endsWith("/api/public");
assertThat(token.get()).isNotNull();
});

//download exemplary JSON data from public endpoint
var response = given()
.header("Authorization", token.get())
.get(PROVIDER_PUBLIC_URL + "/api/public")
.then()
.log().ifError()
.statusCode(200)
.extract().body().asString();

assertThat(response).isNotEmpty();
}
}
33 changes: 33 additions & 0 deletions tests/end2end/src/test/resources/negotiation-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"@context": {
"@vocab": "https://w3id.org/edc/v0.0.1/ns/"
},
"@type": "https://w3id.org/edc/v0.0.1/ns/ContractRequest",
"counterPartyAddress": "{{PROVIDER_DSP_URL}}/api/dsp",
"counterPartyId": "{{PROVIDER_ID}}",
"protocol": "dataspace-protocol-http",
"policy": {
"@context": "http://www.w3.org/ns/odrl.jsonld",
"@type": "http://www.w3.org/ns/odrl/2/Offer",
"@id": "{{OFFER_ID}}",
"assigner": "{{PROVIDER_ID}}",
"permission": [],
"prohibition": [],
"odrl:obligation": {
"odrl:action": {
"@id": "use"
},
"odrl:constraint": {
"odrl:leftOperand": {
"@id": "FrameworkCredential.pcf"
},
"odrl:operator": {
"@id": "odrl:eq"
},
"odrl:rightOperand": "active"
}
},
"target": "asset-1"
},
"callbackAddresses": []
}
14 changes: 14 additions & 0 deletions tests/end2end/src/test/resources/transfer-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"@context": {
"odrl": "http://www.w3.org/ns/odrl/2/"
},
"assetId": "asset-1",
"counterPartyAddress": "{{PROVIDER_DSP_URL}}/api/dsp",
"connectorId": "{{PROVIDER_ID}}",
"contractId": "{{CONTRACT_ID}}",
"dataDestination": {
"type": "HttpProxy"
},
"protocol": "dataspace-protocol-http",
"transferType": "HttpData-PULL"
}
22 changes: 0 additions & 22 deletions tests/system-tests/build.gradle.kts

This file was deleted.

0 comments on commit 2c7701c

Please sign in to comment.