Skip to content

Commit

Permalink
Add e2e test for double encoding of query params
Browse files Browse the repository at this point in the history
  • Loading branch information
kulgg committed Feb 2, 2024
1 parent 6fd6425 commit bf0b5d4
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.UriInfo;

import java.util.concurrent.atomic.AtomicReference;

Expand All @@ -45,4 +47,11 @@ public void setDataSinkValue(String incomingData) {
public String echoForDataSource(@QueryParam("data") String message) {
return message;
}

@GET
@Path("/data-source-params")
@Produces(MediaType.APPLICATION_JSON)
public String echoDataSourceQueryParams(@Context UriInfo uriInfo) {
return uriInfo.getRequestUri().getRawQuery();
}
}
213 changes: 213 additions & 0 deletions tests/src/test/java/de/sovity/edc/e2e/DataSourceQueryParamsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
/*
* Copyright (c) 2024 sovity GmbH
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* sovity GmbH - init
*/

package de.sovity.edc.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.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.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.utils.jsonld.vocab.Prop;
import org.awaitility.Awaitility;
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.util.List;
import java.util.Map;

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;

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 dateParam = "since=2023-10-13T00:00:00.000Z";
private final String encodedDateParam = "since=2023-10-13T00%3A00%3A00.000Z";
private final String doubleEncodedDateParam = "since=2023-10-13T00%253A00%253A00.000Z";
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();

// 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 testDirectQuerying() {
// arrange
var paramUrl = String.format("%s?{k}={v}", dataAddress.getDataSourceQueryParamsUrl());
var splitParam = dateParam.split("=");
var paramKey = splitParam[0];
var paramValue = splitParam[1];

// act
// assert
validateDataTransferred(paramUrl, encodedDateParam, paramValue, paramKey);
}

/**
* This test will fail as soon as the handling of query parameters is fixed in the EDC project
*/
@Test
void testQueryParamsDoubleEncoded() {
// arrange
createPolicy();
createAsset();
createContractDefinition();

// 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);

// assert
validateDataTransferred(dataAddress.getDataSinkSpyUrl(), doubleEncodedDateParam);
}

private void createAsset() {
var asset = UiAssetCreateRequest.builder()
.id(dataOfferId)
.title("My Data Offer")
.dataAddressProperties(Map.of(
Prop.Edc.TYPE, "HttpData",
Prop.Edc.METHOD, "GET",
Prop.Edc.BASE_URL, dataAddress.getDataSourceQueryParamsUrl(),
"https://w3id.org/edc/v0.0.1/ns/queryParams", encodedDateParam
))
.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) {
var contractAgreementId = negotiation.getContractAgreementId();
var transferRequest = InitiateTransferRequest.builder()
.contractAgreementId(contractAgreementId)
.dataSinkProperties(dataAddress.getDataSinkProperties())
.build();
consumerClient.uiApi().initiateTransfer(transferRequest);
}

private String getProtocolEndpoint(ConnectorRemote connector) {
return connector.getConfig().getProtocolEndpoint().getUri().toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ public static Map<String, String> buildDataAddressProperties(String baseUrl, Str
}


public static void validateDataTransferred(String checkUrl, String expectedData) {
public static void validateDataTransferred(String checkUrl, String expectedData, Object... params) {
await().atMost(TIMEOUT).untilAsserted(() -> {
var actual = when()
.get(checkUrl)
.get(checkUrl, params)
.then()
.statusCode(200)
.extract().body().asString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ public String getDataSourceUrl(String data) {
return getMockBackendUrl("data-source?data=%s".formatted(data));
}

public String getDataSourceQueryParamsUrl() {
return getMockBackendUrl("data-source-params");
}

public String getMockBackendUrl(String path) {
return "%s/test-backend/%s".formatted(defaultEndpoint.getUri().toString(), path);
}
Expand Down

0 comments on commit bf0b5d4

Please sign in to comment.