Skip to content

Commit

Permalink
test(dsp): create test fixture for delegates
Browse files Browse the repository at this point in the history
  • Loading branch information
ronjaquensel committed Apr 25, 2023
1 parent c658b46 commit cb4648d
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 253 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ dependencies {
api(project(":spi:common:catalog-spi"))

api(libs.jakartaJson)

testImplementation(testFixtures(project(":data-protocols:dsp:dsp-http-spi")))
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,14 @@

package org.eclipse.edc.protocol.dsp.catalog.dispatcher.delegate;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.json.Json;
import jakarta.json.JsonObject;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import org.eclipse.edc.catalog.spi.Catalog;
import org.eclipse.edc.catalog.spi.CatalogRequestMessage;
import org.eclipse.edc.jsonld.spi.transformer.JsonLdTransformerRegistry;
import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer;
import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate;
import org.eclipse.edc.protocol.dsp.spi.testfixtures.dispatcher.DspHttpDispatcherDelegateTestBase;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.result.Result;
Expand All @@ -46,11 +43,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class CatalogRequestMessageHttpDelegateTest {

private final JsonLdRemoteMessageSerializer serializer = mock(JsonLdRemoteMessageSerializer.class);
private final ObjectMapper mapper = mock(ObjectMapper.class);
private final JsonLdTransformerRegistry registry = mock(JsonLdTransformerRegistry.class);
class CatalogRequestMessageHttpDelegateTest extends DspHttpDispatcherDelegateTestBase<CatalogRequestMessage> {

private CatalogRequestHttpDelegate delegate;

Expand All @@ -66,26 +59,12 @@ void getMessageType_returnCatalogRequest() {

@Test
void buildRequest_returnRequest() throws IOException {
var message = getCatalogRequest();
var serializedBody = "catalog request";

when(serializer.serialize(eq(message), any(JsonObject.class))).thenReturn(serializedBody);

var httpRequest = delegate.buildRequest(message);

assertThat(httpRequest.url().url()).hasToString(message.getCallbackAddress() + BASE_PATH + CATALOG_REQUEST);
assertThat(readRequestBody(httpRequest)).isEqualTo(serializedBody);

verify(serializer, times(1)).serialize(eq(message), any(JsonObject.class));
testBuildRequest_shouldReturnRequest(message(), BASE_PATH + CATALOG_REQUEST);
}

@Test
void buildRequest_serializationFails_throwException() {
var message = getCatalogRequest();

when(serializer.serialize(eq(message), any(JsonObject.class))).thenThrow(EdcException.class);

assertThatThrownBy(() -> delegate.buildRequest(message)).isInstanceOf(EdcException.class);
void buildRequest_serializationFails_throwException() throws IOException {
testBuildRequest_shouldReturnRequest(message(), BASE_PATH + CATALOG_REQUEST);
}

@Test
Expand Down Expand Up @@ -124,23 +103,12 @@ void parseResponse_transformationFails_throwException() throws IOException {

@Test
void parseResponse_readingResponseBodyFails_throwException() throws IOException {
var response = mock(Response.class);
var responseBody = mock(ResponseBody.class);

when(response.body()).thenReturn(responseBody);
when(responseBody.bytes()).thenReturn("test".getBytes());
when(mapper.readValue(any(byte[].class), eq(JsonObject.class))).thenThrow(IOException.class);

assertThatThrownBy(() -> delegate.parseResponse().apply(response)).isInstanceOf(EdcException.class);
testParseResponse_shouldThrowException_whenReadingResponseBodyFails();
}

@Test
void parseResponse_responseBodyNull_throwException() throws IOException {
var response = mock(Response.class);

when(response.body()).thenReturn(null);

assertThatThrownBy(() -> delegate.parseResponse().apply(response)).isInstanceOf(EdcException.class);
void parseResponse_responseBodyNull_throwException() {
testParseResponse_shouldThrowException_whenResponseBodyNull();
}

@Test
Expand All @@ -166,19 +134,17 @@ private JsonObject getJsonObject() {
.build();
}

private CatalogRequestMessage getCatalogRequest() {
private CatalogRequestMessage message() {
return CatalogRequestMessage.Builder.newInstance()
.callbackAddress("http://connector")
.connectorId("connector-id")
.protocol("protocol")
.querySpec(QuerySpec.max())
.build();
}

private String readRequestBody(Request request) throws IOException {
var buffer = new Buffer();
request.body().writeTo(buffer);
return buffer.readUtf8();

@Override
protected DspHttpDispatcherDelegate<CatalogRequestMessage, ?> delegate() {
return delegate;
}

}
6 changes: 6 additions & 0 deletions data-protocols/dsp/dsp-http-spi/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@

plugins {
`java-library`
`java-test-fixtures`
}

dependencies {
api(project(":spi:common:core-spi"))
api(libs.okhttp)
api(libs.jakartaJson)

testFixturesApi(project(":core:common:junit"))
testFixturesApi(project(":spi:common:json-ld-spi"))
testFixturesImplementation(libs.mockito.core)
testFixturesImplementation(libs.assertj)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* Copyright (c) 2023 Fraunhofer Institute for Software and Systems Engineering
*
* 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:
* Fraunhofer Institute for Software and Systems Engineering - initial API and implementation
*
*/

package org.eclipse.edc.protocol.dsp.spi.testfixtures.dispatcher;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.json.JsonObject;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import org.eclipse.edc.jsonld.spi.transformer.JsonLdTransformerRegistry;
import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate;
import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.types.domain.message.RemoteMessage;

import java.io.IOException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
* Test base for implementations of {@link DspHttpDispatcherDelegate}. Provides methods that test
* common behaviour of delegate methods. Each sub-class of this test base should choose the
* respective methods for the delegate implementation it's testing.
*/
public abstract class DspHttpDispatcherDelegateTestBase<M extends RemoteMessage> {

protected JsonLdRemoteMessageSerializer serializer = mock(JsonLdRemoteMessageSerializer.class);
protected ObjectMapper mapper = mock(ObjectMapper.class);
protected JsonLdTransformerRegistry registry = mock(JsonLdTransformerRegistry.class);

/**
* Returns the delegate to test.
*
* @return the delegate
*/
protected abstract DspHttpDispatcherDelegate<M, ?> delegate();

/**
* Checks that a delegate, given a message, builds the expected HTTP request. The message should
* be serialized and added as the request body. Validates that the delegate sets the expected
* request path. Relevant for all delegates.
*
* @param message the message
* @param path the expected path
*/
protected void testBuildRequest_shouldReturnRequest(M message, String path) throws IOException {
var serializedBody = "serialized";

when(serializer.serialize(eq(message), any(JsonObject.class))).thenReturn(serializedBody);

var httpRequest = delegate().buildRequest(message);

assertThat(httpRequest.url().url()).hasToString(message.getCallbackAddress() + path);
assertThat(readRequestBody(httpRequest)).isEqualTo(serializedBody);

verify(serializer, times(1)).serialize(eq(message), any(JsonObject.class));
}

/**
* Checks that a delegate throws an exception if serialization of the message to send fails.
* Relevant for all delegates.
*
* @param message the message
*/
protected void testBuildRequest_shouldThrowException_whenSerializationFails(M message) {
when(serializer.serialize(eq(message), any(JsonObject.class))).thenThrow(EdcException.class);

assertThatThrownBy(() -> delegate().buildRequest(message)).isInstanceOf(EdcException.class);
}

/**
* Checks that a delegate throws an exception when the response body is missing. Only relevant
* for delegates that process the response body.
*/
protected void testParseResponse_shouldThrowException_whenResponseBodyNull() {
var response = mock(Response.class);

when(response.body()).thenReturn(null);

assertThatThrownBy(() -> delegate().parseResponse().apply(response)).isInstanceOf(EdcException.class);
}

/**
* Checks that a delegate throws an exception when the response body cannot be read. Only
* relevant for delegates that process the response body.
*/
protected void testParseResponse_shouldThrowException_whenReadingResponseBodyFails() throws IOException {
var response = mock(Response.class);
var responseBody = mock(ResponseBody.class);

when(response.body()).thenReturn(responseBody);
when(responseBody.bytes()).thenReturn("test".getBytes());
when(mapper.readValue(any(byte[].class), eq(JsonObject.class))).thenThrow(IOException.class);

assertThatThrownBy(() -> delegate().parseResponse().apply(response)).isInstanceOf(EdcException.class);
}

/**
* Checks that a delegate returns a null function for parsing the response body. Only relevant
* for delegates that do not process the response body.
*/
protected void testParseResponse_shouldReturnNullFunction_whenResponseBodyNotProcessed() {
var response = mock(Response.class);

assertThat(delegate().parseResponse().apply(response)).isNull();
}

protected String readRequestBody(Request request) throws IOException {
var buffer = new Buffer();
request.body().writeTo(buffer);
return buffer.readUtf8();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ dependencies {
api(project(":spi:control-plane:contract-spi"))

api(libs.jakartaJson)

testImplementation(testFixtures(project(":data-protocols:dsp:dsp-http-spi")))
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,26 @@

package org.eclipse.edc.protocol.dsp.negotiation.dispatcher.delegate;

import jakarta.json.JsonObject;
import okhttp3.Request;
import okhttp3.Response;
import okio.Buffer;
import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement;
import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreementMessage;
import org.eclipse.edc.policy.model.Action;
import org.eclipse.edc.policy.model.Duty;
import org.eclipse.edc.policy.model.Permission;
import org.eclipse.edc.policy.model.Policy;
import org.eclipse.edc.policy.model.Prohibition;
import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate;
import org.eclipse.edc.protocol.dsp.spi.testfixtures.dispatcher.DspHttpDispatcherDelegateTestBase;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.util.UUID;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.eclipse.edc.protocol.dsp.negotiation.spi.NegotiationApiPaths.AGREEMENT;
import static org.eclipse.edc.protocol.dsp.negotiation.spi.NegotiationApiPaths.BASE_PATH;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class ContractAgreementMessageHttpDelegateTest {

private final JsonLdRemoteMessageSerializer serializer = mock(JsonLdRemoteMessageSerializer.class);
class ContractAgreementMessageHttpDelegateTest extends DspHttpDispatcherDelegateTestBase<ContractAgreementMessage> {

private ContractAgreementMessageHttpDelegate delegate;

Expand All @@ -63,32 +50,17 @@ void getMessageType() {
@Test
void buildRequest() throws IOException {
var message = message();
var serializedBody = "message";

when(serializer.serialize(eq(message), any(JsonObject.class))).thenReturn(serializedBody);

var httpRequest = delegate.buildRequest(message);

assertThat(httpRequest.url().url()).hasToString(message.getCallbackAddress() + BASE_PATH + message.getProcessId() + AGREEMENT);
assertThat(readRequestBody(httpRequest)).isEqualTo(serializedBody);

verify(serializer, times(1)).serialize(eq(message), any(JsonObject.class));
testBuildRequest_shouldReturnRequest(message, BASE_PATH + message.getProcessId() + AGREEMENT);
}

@Test
void buildRequest_serializationFails_throwException() {
var message = message();

when(serializer.serialize(eq(message), any(JsonObject.class))).thenThrow(EdcException.class);

assertThatThrownBy(() -> delegate.buildRequest(message)).isInstanceOf(EdcException.class);
testBuildRequest_shouldThrowException_whenSerializationFails(message());
}

@Test
void parseResponse_returnNull() {
var response = mock(Response.class);

assertThat(delegate.parseResponse().apply(response)).isNull();
testParseResponse_shouldReturnNullFunction_whenResponseBodyNotProcessed();
}

private ContractAgreementMessage message() {
Expand Down Expand Up @@ -121,10 +93,9 @@ private Policy policy() {
.duty(duty)
.build();
}

private String readRequestBody(Request request) throws IOException {
var buffer = new Buffer();
request.body().writeTo(buffer);
return buffer.readUtf8();

@Override
protected DspHttpDispatcherDelegate<ContractAgreementMessage, ?> delegate() {
return delegate;
}
}
Loading

0 comments on commit cb4648d

Please sign in to comment.