Skip to content
This repository was archived by the owner on Sep 9, 2024. It is now read-only.

Commit aaef35d

Browse files
committed
feat: Add verifier using the new connector style
1 parent 0f5a912 commit aaef35d

13 files changed

Lines changed: 378 additions & 107 deletions

src/main/java/io/contract_testing/contractcase/BoundaryCrashReporter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
class BoundaryCrashReporter {
66

77
static void handleAndRethrow(Throwable e) {
8+
// This method should not call BoundaryResultMapper
89
if (e instanceof ContractCaseConfigurationError) {
910
throw (ContractCaseConfigurationError) e;
1011
} else if (e instanceof ContractCaseExpectationsNotMet) {
@@ -26,7 +27,8 @@ static void handleAndRethrow(Throwable e) {
2627
+ e.toString()
2728
+ "\n"
2829
+ BoundaryExceptionMapper.stackTraceToString(e)
29-
+ (e.getCause() != null ? "Caused by: " + e.getCause().toString() + "\n" + BoundaryExceptionMapper.stackTraceToString(e.getCause()) : "")
30+
+ (e.getCause() != null ? "Caused by: " + e.getCause().toString() + "\n"
31+
+ BoundaryExceptionMapper.stackTraceToString(e.getCause()) : "")
3032
+ "\n\n"
3133
+ BoundaryCrashMessage.CRASH_MESSAGE_END);
3234
}

src/main/java/io/contract_testing/contractcase/BoundaryResultMapper.java

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
import io.contract_testing.contractcase.case_boundary.BoundaryFailureKindConstants;
55
import io.contract_testing.contractcase.case_boundary.BoundaryResult;
66
import io.contract_testing.contractcase.case_boundary.BoundaryResultTypeConstants;
7+
import io.contract_testing.contractcase.case_boundary.BoundarySuccessWithAny;
8+
import java.util.List;
79

810
class BoundaryResultMapper {
911

10-
public static void map(BoundaryResult result) {
12+
static void mapVoid(BoundaryResult result) {
1113
final var resultType = result.getResultType();
1214

1315
if (resultType.equals(BoundaryResultTypeConstants.RESULT_SUCCESS)) {
@@ -16,10 +18,15 @@ public static void map(BoundaryResult result) {
1618
if (resultType.equals(BoundaryResultTypeConstants.RESULT_FAILURE)) {
1719
mapFailure((BoundaryFailure) result);
1820
}
21+
22+
throw new ContractCaseCoreError(
23+
"Unexpected non-void BoundaryResult typa '" + resultType + "'",
24+
"BoundaryResultMapper.mapVoid"
25+
);
1926
}
2027

2128
private static void mapFailure(BoundaryFailure result) {
22-
String kind = result.getKind();
29+
final var kind = result.getKind();
2330

2431
if (kind.equals(BoundaryFailureKindConstants.CASE_BROKER_ERROR)
2532
|| kind.equals(BoundaryFailureKindConstants.CASE_CONFIGURATION_ERROR)
@@ -34,6 +41,24 @@ private static void mapFailure(BoundaryFailure result) {
3441

3542
throw new ContractCaseCoreError(
3643
"Unhandled error kind (" + kind + "): " + result.getMessage(),
37-
result.getLocation());
44+
result.getLocation()
45+
);
46+
}
47+
48+
public static List<ContractDescription> mapListAvailableContracts(BoundaryResult result) {
49+
final var resultType = result.getResultType();
50+
if (resultType.equals(BoundaryResultTypeConstants.RESULT_SUCCESS_HAS_ANY_PAYLOAD)) {
51+
// TODO implement this
52+
System.out.println(((BoundarySuccessWithAny) result).getPayload());
53+
throw new ContractCaseCoreError("The parsing of this object hasn't yet been implemented"
54+
+ ((BoundarySuccessWithAny) result).getPayload());
55+
}
56+
if (resultType.equals(BoundaryResultTypeConstants.RESULT_FAILURE)) {
57+
mapFailure((BoundaryFailure) result);
58+
}
59+
throw new ContractCaseCoreError(
60+
"Unexpected non-void BoundaryResult typa '" + resultType + "'",
61+
"BoundaryResultMapper.mapListAvailableContracts"
62+
);
3863
}
3964
}

src/main/java/io/contract_testing/contractcase/ContractDefiner.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,29 @@ public ContractDefiner(final @NotNull ContractCaseConfig config) {
1515
LogPrinter logPrinter = new LogPrinter();
1616
InternalDefinerClient definer = null;
1717
try {
18-
definer = new InternalDefinerClient(BoundaryConfigMapper.map(config, TEST_RUN_ID),
18+
definer = new InternalDefinerClient(
19+
BoundaryConfigMapper.map(config, TEST_RUN_ID),
1920
logPrinter,
2021
logPrinter,
21-
new BoundaryVersionGenerator().getVersions());
22+
new BoundaryVersionGenerator().getVersions()
23+
);
2224
} catch (Throwable e) {
2325
BoundaryCrashReporter.handleAndRethrow(e);
2426
}
2527
this.definer = definer;
2628
}
2729

2830
public void endRecord() {
29-
BoundaryResultMapper.map(this.definer.endRecord());
31+
BoundaryResultMapper.mapVoid(this.definer.endRecord());
3032
}
3133

3234
public <T, M extends AnyMockDescriptor> void runExample(ExampleDefinition<M> definition,
3335
final @NotNull IndividualSuccessTestConfig<T> additionalConfig) {
3436
try {
35-
BoundaryResultMapper.map(definer.runExample(definition.toJSON(),
36-
BoundaryConfigMapper.mapSuccessExample(additionalConfig, TEST_RUN_ID)));
37+
BoundaryResultMapper.mapVoid(definer.runExample(
38+
definition.toJSON(),
39+
BoundaryConfigMapper.mapSuccessExample(additionalConfig, TEST_RUN_ID)
40+
));
3741
} catch (Throwable e) {
3842
BoundaryCrashReporter.handleAndRethrow(e);
3943
}
@@ -50,14 +54,17 @@ public <M extends AnyMockDescriptor> void runExample(ExampleDefinition<M> defini
5054
IndividualSuccessTestConfig
5155
.IndividualSuccessTestConfigBuilder
5256
.builder()
53-
.build());
57+
.build()
58+
);
5459
}
5560

5661
public <T, M extends AnyMockDescriptor> void runThrowingExample(ExampleDefinition<M> definition,
5762
IndividualFailedTestConfig<T> additionalConfig) {
5863
try {
59-
BoundaryResultMapper.map(definer.runRejectingExample(definition.toJSON(),
60-
BoundaryConfigMapper.mapFailingExample(additionalConfig, TEST_RUN_ID)));
64+
BoundaryResultMapper.mapVoid(definer.runRejectingExample(
65+
definition.toJSON(),
66+
BoundaryConfigMapper.mapFailingExample(additionalConfig, TEST_RUN_ID)
67+
));
6168
} catch (Throwable e) {
6269
BoundaryCrashReporter.handleAndRethrow(e);
6370
}
@@ -74,7 +81,8 @@ public <M extends AnyMockDescriptor> void runThrowingExample(ExampleDefinition<M
7481
IndividualFailedTestConfig
7582
.IndividualFailedTestConfigBuilder
7683
.builder()
77-
.build());
84+
.build()
85+
);
7886
}
7987

8088
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package io.contract_testing.contractcase;
2+
3+
public record ContractDescription(String consumerName, String providerName) {
4+
5+
}

src/main/java/io/contract_testing/contractcase/ContractVerifier.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
package io.contract_testing.contractcase;
22

3-
import io.contract_testing.contractcase.case_boundary.BoundaryContractVerifier;
43
import io.contract_testing.contractcase.case_boundary.BoundaryResult;
54
import io.contract_testing.contractcase.case_boundary.BoundarySuccess;
65
import io.contract_testing.contractcase.case_boundary.IInvokeCoreTest;
76
import io.contract_testing.contractcase.case_boundary.IRunTestCallback;
7+
import io.contract_testing.contractcase.client.InternalVerifierClient;
8+
import java.util.List;
89
import org.jetbrains.annotations.NotNull;
910

1011
public class ContractVerifier {
1112

12-
private final BoundaryContractVerifier verifier;
13+
private final InternalVerifierClient verifier;
1314

1415
public ContractVerifier(ContractCaseConfig config) {
1516
LogPrinter logPrinter = new LogPrinter();
1617

17-
BoundaryContractVerifier verification = null;
18+
InternalVerifierClient verification = null;
1819
try {
19-
verification = new BoundaryContractVerifier(
20+
verification = new InternalVerifierClient(
2021
BoundaryConfigMapper.map(config, "VERIFICATION"),
2122
new IRunTestCallback() {
2223
@Override
@@ -25,7 +26,7 @@ public ContractVerifier(ContractCaseConfig config) {
2526
// TODO replace this with something that knows about JUnit
2627
try {
2728
try {
28-
BoundaryResultMapper.map(invoker.verify());
29+
BoundaryResultMapper.mapVoid(invoker.verify());
2930
} catch (Exception e) {
3031
System.err.println(e);
3132
}
@@ -35,13 +36,24 @@ public ContractVerifier(ContractCaseConfig config) {
3536
}
3637
}
3738

38-
}, logPrinter, logPrinter, new BoundaryVersionGenerator().getVersions());
39+
}, logPrinter, logPrinter, new BoundaryVersionGenerator().getVersions()
40+
);
3941
} catch (Throwable e) {
4042
BoundaryCrashReporter.handleAndRethrow(e);
4143
}
4244
this.verifier = verification;
4345
}
4446

47+
public List<ContractDescription> availableContractDescriptions() {
48+
try {
49+
return BoundaryResultMapper.mapListAvailableContracts(this.verifier.availableContractDescriptions());
50+
} catch (Throwable e) {
51+
BoundaryCrashReporter.handleAndRethrow(e);
52+
// This is actually unreachable, since the above method always throws
53+
return List.of();
54+
}
55+
}
56+
4557
public void runVerification(ContractCaseConfig configOverrides) {
4658
try {
4759
this.verifier.runVerification(

src/main/java/io/contract_testing/contractcase/client/RpcConnector.java renamed to src/main/java/io/contract_testing/contractcase/client/AbstractRpcConnector.java

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
package io.contract_testing.contractcase.client;
22

3+
import com.google.protobuf.AbstractMessage;
4+
import com.google.protobuf.GeneratedMessageV3.Builder;
5+
import com.google.protobuf.StringValue;
36
import io.contract_testing.contractcase.ContractCaseCoreError;
47
import io.contract_testing.contractcase.case_boundary.BoundaryFailure;
58
import io.contract_testing.contractcase.case_boundary.BoundaryFailureKindConstants;
69
import io.contract_testing.contractcase.case_boundary.ILogPrinter;
710
import io.contract_testing.contractcase.case_boundary.IResultPrinter;
11+
import io.contract_testing.contractcase.case_boundary.IRunTestCallback;
812
import io.contract_testing.contractcase.grpc.ContractCaseGrpc;
913
import io.contract_testing.contractcase.grpc.ContractCaseGrpc.ContractCaseStub;
1014
import io.contract_testing.contractcase.grpc.ContractCaseStream.BoundaryResult;
11-
import io.contract_testing.contractcase.grpc.ContractCaseStream.DefinitionRequest;
12-
import io.contract_testing.contractcase.grpc.ContractCaseStream.DefinitionRequest.Builder;
13-
import io.grpc.ManagedChannel;
15+
import io.contract_testing.contractcase.grpc.ContractCaseStream.ResultResponse;
1416
import io.grpc.ManagedChannelBuilder;
1517
import io.grpc.Status;
1618
import io.grpc.stub.StreamObserver;
@@ -23,34 +25,49 @@
2325
import java.util.concurrent.atomic.AtomicInteger;
2426
import org.jetbrains.annotations.NotNull;
2527

26-
class RpcConnector {
28+
abstract class AbstractRpcConnector<T extends AbstractMessage, B extends Builder<B>> {
2729

2830
private static final int DEFAULT_PORT = 50200;
2931

30-
private final StreamObserver<DefinitionRequest> requestObserver;
32+
private final StreamObserver<T> requestObserver;
3133
private final ConcurrentMap<String, CompletableFuture<BoundaryResult>> responseFutures = new ConcurrentHashMap<String, CompletableFuture<BoundaryResult>>();
3234
private final AtomicInteger nextId = new AtomicInteger();
33-
3435
private Status errorStatus;
3536

3637

37-
public RpcConnector(@NotNull ILogPrinter logPrinter, @NotNull IResultPrinter resultPrinter,
38-
ConfigHandle configHandle) {
39-
// TODO: Allow configuration of the port
40-
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", DEFAULT_PORT)
41-
.usePlaintext()
42-
.build();
43-
ContractCaseStub asyncStub = ContractCaseGrpc.newStub(channel);
44-
requestObserver = createConnection(asyncStub,new ContractResponseStreamObserver(this, logPrinter, resultPrinter, configHandle));
38+
public AbstractRpcConnector(
39+
@NotNull ILogPrinter logPrinter,
40+
@NotNull IResultPrinter resultPrinter,
41+
@NotNull ConfigHandle configHandle,
42+
@NotNull IRunTestCallback runTestCallback) {
43+
this.requestObserver = createConnection(
44+
ContractCaseGrpc.newStub(
45+
ManagedChannelBuilder
46+
// TODO: Allow configuration of the port
47+
.forAddress("localhost", DEFAULT_PORT)
48+
.usePlaintext()
49+
.build()),
50+
new ContractResponseStreamObserver<>(
51+
this,
52+
logPrinter,
53+
resultPrinter,
54+
configHandle,
55+
runTestCallback
56+
)
57+
);
4558
}
4659

47-
private StreamObserver<DefinitionRequest> createConnection(ContractCaseStub asyncStub,
48-
ContractResponseStreamObserver contractResponseStreamObserver) {
49-
return asyncStub.contractDefinition(contractResponseStreamObserver);
50-
}
60+
abstract StreamObserver<T> createConnection(ContractCaseStub asyncStub,
61+
ContractResponseStreamObserver<T, B> contractResponseStreamObserver);
62+
63+
abstract T setId(B builder, StringValue id);
64+
65+
abstract B makeResponse(ResultResponse response);
66+
67+
abstract B makeInvokeTest(StringValue invokerId);
5168

52-
io.contract_testing.contractcase.case_boundary.BoundaryResult executeCallAndWait(Builder builder) {
53-
var id = "" + nextId.getAndIncrement();
69+
io.contract_testing.contractcase.case_boundary.BoundaryResult executeCallAndWait(B builder) {
70+
final var id = "" + nextId.getAndIncrement();
5471
if (errorStatus != null) {
5572
return new BoundaryFailure(
5673
BoundaryFailureKindConstants.CASE_CONFIGURATION_ERROR,
@@ -61,7 +78,7 @@ io.contract_testing.contractcase.case_boundary.BoundaryResult executeCallAndWait
6178

6279
var future = new CompletableFuture<BoundaryResult>();
6380
responseFutures.put(id, future);
64-
requestObserver.onNext(builder.setId(ConnectorOutgoingMapper.map(id)).build());
81+
requestObserver.onNext(setId(builder, ConnectorOutgoingMapper.map(id)));
6582

6683
try {
6784
return ConnectorIncomingMapper.mapBoundaryResult(future.get(60, TimeUnit.SECONDS));
@@ -97,7 +114,7 @@ io.contract_testing.contractcase.case_boundary.BoundaryResult executeCallAndWait
97114
void completeWait(String id, BoundaryResult result) {
98115
MaintainerLog.log("Completing wait for: " + id);
99116

100-
var future = responseFutures.get(id);
117+
final var future = responseFutures.get(id);
101118
if (future == null) {
102119
throw new ContractCaseCoreError(
103120
"There was no future with id '" + id + "'. This is a bug in the wrapper or the boundary.",
@@ -107,8 +124,12 @@ void completeWait(String id, BoundaryResult result) {
107124
responseFutures.get(id).complete(result);
108125
}
109126

110-
void sendResponse(DefinitionRequest.Builder builder, String id) {
111-
requestObserver.onNext(builder.setId(ConnectorOutgoingMapper.map(id)).build());
127+
void sendResponse(B builder, String id) {
128+
requestObserver.onNext(setId(builder, ConnectorOutgoingMapper.map(id)));
129+
}
130+
131+
void sendResponse(ResultResponse response, String id) {
132+
sendResponse(makeResponse(response), id);
112133
}
113134

114135
public void setErrorStatus(Status errorStatus) {
@@ -118,4 +139,6 @@ public void setErrorStatus(Status errorStatus) {
118139
public void close() {
119140
requestObserver.onCompleted();
120141
}
142+
143+
121144
}

src/main/java/io/contract_testing/contractcase/client/ConnectorOutgoingMapper.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,12 @@ static ContractCaseConfig mapConfig(final @NotNull ContractCaseBoundaryConfig co
7272
}
7373
if (config.getTriggerAndTests() != null) {
7474
config.getTriggerAndTests()
75-
.forEach((key, value) -> builder.putTriggerAndTests(key,
75+
.forEach((key, value) -> builder.putTriggerAndTests(
76+
key,
7677
TriggerFunctionHandle.newBuilder()
7778
.setHandle(ConnectorOutgoingMapper.map(key))
78-
.build()));
79+
.build()
80+
));
7981
}
8082
if (config.getTriggerAndTest() != null) {
8183
builder.setTriggerAndTest(TriggerFunctionHandle.newBuilder()
@@ -139,7 +141,8 @@ static ContractCaseStream.DefinitionRequest.Builder mapRunExampleRequest(JsonNod
139141
.build());
140142
}
141143

142-
static ContractCaseStream.DefinitionRequest.Builder mapRunRejectingExampleRequest(JsonNode definition, ContractCaseBoundaryConfig runConfig) {
144+
static ContractCaseStream.DefinitionRequest.Builder mapRunRejectingExampleRequest(JsonNode definition,
145+
ContractCaseBoundaryConfig runConfig) {
143146
final var structBuilder = getStructBuilder(definition);
144147
return DefinitionRequest.newBuilder()
145148
.setRunExample(RunExampleRequest.newBuilder()
@@ -188,11 +191,9 @@ static ContractCaseStream.BoundaryResult mapResult(@NotNull BoundaryResult resul
188191
};
189192
}
190193

191-
@NotNull
192-
static ContractCaseStream.DefinitionRequest.Builder mapResultResponse(BoundaryResult result) {
193-
return DefinitionRequest.newBuilder()
194-
.setResultResponse(ResultResponse.newBuilder()
195-
.setResult(mapResult(result)));
194+
static ResultResponse mapResultResponse(BoundaryResult result) {
195+
return ResultResponse.newBuilder()
196+
.setResult(mapResult(result)).build();
196197
}
197198

198199
private static Value mapMapToValue(Object payload) {

0 commit comments

Comments
 (0)