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

Commit c9a4cd3

Browse files
committed
refactor: Split out client classes in preparation for implementing Verifier
1 parent 2b40daf commit c9a4cd3

8 files changed

Lines changed: 435 additions & 306 deletions

File tree

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
class BoundaryResultMapper {
1212

13-
public static void map(BoundaryResult result) {
13+
static void map(BoundaryResult result) {
1414
final var resultType = result.getResultType();
1515

1616
if (resultType.equals(BoundaryResultTypeConstants.RESULT_SUCCESS)) {
@@ -39,4 +39,6 @@ private static void mapFailure(BoundaryFailure result) {
3939
"Unhandled error kind (" + kind + "): " + result.getMessage(),
4040
result.getLocation());
4141
}
42+
43+
4244
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package io.contract_testing.contractcase.client;
2+
3+
import static io.contract_testing.contractcase.client.ConnectorOutgoingMapper.CONTRACT_CASE_TRIGGER_AND_TEST;
4+
5+
import io.contract_testing.contractcase.ContractCaseCoreError;
6+
import io.contract_testing.contractcase.case_boundary.ContractCaseBoundaryConfig;
7+
import io.contract_testing.contractcase.case_boundary.ITriggerFunction;
8+
import org.jetbrains.annotations.NotNull;
9+
import org.jetbrains.annotations.Nullable;
10+
11+
class ConfigHandle {
12+
13+
public void setBoundaryConfig(ContractCaseBoundaryConfig boundaryConfig) {
14+
this.boundaryConfig = boundaryConfig;
15+
}
16+
17+
private ContractCaseBoundaryConfig boundaryConfig;
18+
19+
ConfigHandle(ContractCaseBoundaryConfig boundaryConfig) {
20+
this.boundaryConfig = boundaryConfig;
21+
}
22+
23+
@NotNull
24+
ITriggerFunction getTriggerFunction(String handle) {
25+
ITriggerFunction trigger = getTriggerInternal(handle);
26+
if (trigger == null) {
27+
throw new ContractCaseCoreError(
28+
"Unable to trigger the function with handle '" + handle + "', as it is null");
29+
}
30+
return trigger;
31+
}
32+
33+
@Nullable
34+
private ITriggerFunction getTriggerInternal(String handle) {
35+
if (handle.equals(CONTRACT_CASE_TRIGGER_AND_TEST)) {
36+
return boundaryConfig.getTriggerAndTest();
37+
}
38+
39+
var triggerMap = boundaryConfig.getTriggerAndTests();
40+
if (triggerMap == null) {
41+
throw new ContractCaseCoreError(
42+
"Unable to trigger the function with handle '" + handle
43+
+ "', as the entire trigger map is null");
44+
}
45+
return triggerMap.get(handle);
46+
}
47+
}

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
package io.contract_testing.contractcase.client;
22

3+
import static io.contract_testing.contractcase.client.MaintainerLog.CONTRACT_CASE_JAVA_WRAPPER;
4+
35
import com.google.protobuf.StringValue;
46
import com.google.protobuf.Struct;
57
import com.google.protobuf.Value;
68
import io.contract_testing.contractcase.ContractCaseCoreError;
9+
import io.contract_testing.contractcase.case_boundary.BoundaryFailure;
10+
import io.contract_testing.contractcase.case_boundary.BoundaryResult;
11+
import io.contract_testing.contractcase.case_boundary.BoundarySuccess;
12+
import io.contract_testing.contractcase.case_boundary.BoundarySuccessWithAny;
13+
import io.contract_testing.contractcase.case_boundary.BoundarySuccessWithMap;
714
import io.contract_testing.contractcase.case_boundary.PrintableMatchError;
815
import io.contract_testing.contractcase.case_boundary.PrintableMessageError;
916
import io.contract_testing.contractcase.case_boundary.PrintableTestTitle;
17+
import io.contract_testing.contractcase.grpc.ContractCaseStream;
1018
import io.contract_testing.contractcase.grpc.ContractCaseStream.PrintMatchErrorRequest;
1119
import io.contract_testing.contractcase.grpc.ContractCaseStream.PrintMessageErrorRequest;
1220
import io.contract_testing.contractcase.grpc.ContractCaseStream.PrintTestTitleRequest;
@@ -81,4 +89,54 @@ static PrintableTestTitle mapPrintableTestTitle(PrintTestTitleRequest printTestT
8189
}
8290

8391

92+
static BoundaryResult mapBoundaryResult(ContractCaseStream.BoundaryResult wireBoundaryResult) {
93+
if (wireBoundaryResult == null) {
94+
throw new ContractCaseCoreError(
95+
"There was a null boundaryResult. This is probably a bug in the connector server library.",
96+
CONTRACT_CASE_JAVA_WRAPPER);
97+
}
98+
var resultType = wireBoundaryResult.getValueCase();
99+
switch (resultType) {
100+
case FAILURE -> {
101+
var wireFailure = wireBoundaryResult.getFailure();
102+
if (wireFailure == null) {
103+
throw new ContractCaseCoreError(
104+
"undefined wireFailure in a boundary result. This is probably an error in the connector server library.",
105+
CONTRACT_CASE_JAVA_WRAPPER);
106+
}
107+
return new BoundaryFailure(ConnectorIncomingMapper.map(wireFailure.getKind()),
108+
ConnectorIncomingMapper.map(wireFailure.getMessage()),
109+
ConnectorIncomingMapper.map(wireFailure.getLocation()));
110+
}
111+
case SUCCESS -> {
112+
return new BoundarySuccess();
113+
}
114+
case SUCCESS_HAS_ANY -> {
115+
var wireWithAny = wireBoundaryResult.getSuccessHasAny();
116+
if (wireWithAny == null) {
117+
throw new ContractCaseCoreError(
118+
"undefined wire with any in a boundary result. This is probably an error in the connector server library.",
119+
CONTRACT_CASE_JAVA_WRAPPER);
120+
}
121+
return new BoundarySuccessWithAny(ConnectorIncomingMapper.map(wireWithAny.getPayload()));
122+
}
123+
case SUCCESS_HAS_MAP -> {
124+
var wireWithMap = wireBoundaryResult.getSuccessHasMap();
125+
if (wireWithMap == null) {
126+
throw new ContractCaseCoreError(
127+
"undefined wire with map in a boundary result. This is probably an error in the connector server library.",
128+
CONTRACT_CASE_JAVA_WRAPPER);
129+
}
130+
return new BoundarySuccessWithMap(ConnectorIncomingMapper.map(wireWithMap.getMap()));
131+
}
132+
case VALUE_NOT_SET -> throw new ContractCaseCoreError(
133+
"There was an unset boundaryResult. This is probably a bug in the connector server library.",
134+
CONTRACT_CASE_JAVA_WRAPPER);
135+
default -> throw new ContractCaseCoreError(
136+
"There was a boundary result type that we didn't understand '" + resultType
137+
+ "'. This is probably a bug in the connector server library.",
138+
CONTRACT_CASE_JAVA_WRAPPER);
139+
}
140+
}
141+
84142
}

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

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

3-
import static io.contract_testing.contractcase.client.InternalDefinerClient.CONTRACT_CASE_JAVA_WRAPPER;
4-
import static io.contract_testing.contractcase.client.InternalDefinerClient.CONTRACT_CASE_TRIGGER_AND_TEST;
3+
import static io.contract_testing.contractcase.client.MaintainerLog.CONTRACT_CASE_JAVA_WRAPPER;
54

65
import com.fasterxml.jackson.core.JsonProcessingException;
76
import com.fasterxml.jackson.databind.JsonNode;
@@ -14,7 +13,6 @@
1413
import com.google.protobuf.util.JsonFormat;
1514
import io.contract_testing.contractcase.case_boundary.BoundaryFailure;
1615
import io.contract_testing.contractcase.case_boundary.BoundaryFailureKindConstants;
17-
import io.contract_testing.contractcase.case_boundary.BoundaryMockDefinition;
1816
import io.contract_testing.contractcase.case_boundary.BoundaryResult;
1917
import io.contract_testing.contractcase.case_boundary.BoundarySuccessWithAny;
2018
import io.contract_testing.contractcase.case_boundary.BoundarySuccessWithMap;
@@ -23,7 +21,6 @@
2321
import io.contract_testing.contractcase.grpc.ContractCaseStream.ContractCaseConfig;
2422
import io.contract_testing.contractcase.grpc.ContractCaseStream.ContractCaseConfig.UsernamePassword;
2523
import io.contract_testing.contractcase.grpc.ContractCaseStream.DefinitionRequest;
26-
import io.contract_testing.contractcase.grpc.ContractCaseStream.DefinitionRequest.Builder;
2724
import io.contract_testing.contractcase.grpc.ContractCaseStream.ResultFailure;
2825
import io.contract_testing.contractcase.grpc.ContractCaseStream.ResultResponse;
2926
import io.contract_testing.contractcase.grpc.ContractCaseStream.ResultSuccess;
@@ -38,6 +35,8 @@
3835

3936
class ConnectorOutgoingMapper {
4037

38+
public static final String CONTRACT_CASE_TRIGGER_AND_TEST = "ContractCase::TriggerAndTest";
39+
4140
private static final ObjectMapper objectMapper = new ObjectMapper();
4241

4342
static StringValue map(String s) {
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package io.contract_testing.contractcase.client;
2+
3+
import static io.contract_testing.contractcase.client.ConnectorIncomingMapper.mapMatchErrorRequest;
4+
import static io.contract_testing.contractcase.client.ConnectorIncomingMapper.mapMessageErrorRequest;
5+
import static io.contract_testing.contractcase.client.ConnectorIncomingMapper.mapPrintableTestTitle;
6+
import static io.contract_testing.contractcase.client.ConnectorOutgoingMapper.mapResult;
7+
import static io.contract_testing.contractcase.client.ConnectorOutgoingMapper.mapResultResponse;
8+
9+
import io.contract_testing.contractcase.ContractCaseCoreError;
10+
import io.contract_testing.contractcase.case_boundary.ILogPrinter;
11+
import io.contract_testing.contractcase.case_boundary.IResultPrinter;
12+
import io.contract_testing.contractcase.grpc.ContractCaseStream;
13+
import io.contract_testing.contractcase.grpc.ContractCaseStream.ContractResponse;
14+
import io.contract_testing.contractcase.grpc.ContractCaseStream.DefinitionRequest;
15+
import io.contract_testing.contractcase.grpc.ContractCaseStream.ResultResponse;
16+
import io.contract_testing.contractcase.grpc.ContractCaseStream.ResultSuccess;
17+
import io.grpc.Status;
18+
import io.grpc.stub.StreamObserver;
19+
import org.jetbrains.annotations.NotNull;
20+
21+
class ContractResponseStreamObserver implements StreamObserver<ContractResponse> {
22+
23+
private final RpcConnector rpcConnector;
24+
private final ILogPrinter logPrinter;
25+
private final IResultPrinter resultPrinter;
26+
private final ConfigHandle configHandle;
27+
28+
29+
public ContractResponseStreamObserver(RpcConnector rpcConnector,
30+
@NotNull ILogPrinter logPrinter,
31+
@NotNull IResultPrinter resultPrinter,
32+
ConfigHandle configHandle) {
33+
this.rpcConnector = rpcConnector;
34+
this.logPrinter = logPrinter;
35+
this.resultPrinter = resultPrinter;
36+
this.configHandle = configHandle;
37+
}
38+
39+
@Override
40+
public void onNext(ContractResponse note) {
41+
/* For when we receive messages from the server */
42+
final var requestId = ConnectorIncomingMapper.map(note.getId());
43+
switch (note.getKindCase()) {
44+
case RUN_STATE_HANDLER -> {
45+
final var stateHandlerRunRequest = note.getRunStateHandler();
46+
// TODO Implement this properly
47+
rpcConnector.sendResponse(
48+
DefinitionRequest.newBuilder().setResultResponse(ResultResponse.newBuilder()
49+
.setResult(ContractCaseStream.BoundaryResult.newBuilder()
50+
.setSuccess(ResultSuccess.newBuilder().build())
51+
.build()
52+
)
53+
),
54+
requestId
55+
);
56+
}
57+
case LOG_REQUEST -> {
58+
final var logRequest = note.getLogRequest();
59+
rpcConnector.sendResponse(
60+
DefinitionRequest.newBuilder().setResultResponse(
61+
ResultResponse.newBuilder().setResult(
62+
mapResult(
63+
logPrinter.log(
64+
ConnectorIncomingMapper.map(logRequest.getLevel()),
65+
ConnectorIncomingMapper.map(logRequest.getTimestamp()),
66+
ConnectorIncomingMapper.map(logRequest.getVersion()),
67+
ConnectorIncomingMapper.map(logRequest.getTypeString()),
68+
ConnectorIncomingMapper.map(logRequest.getLocation()),
69+
ConnectorIncomingMapper.map(logRequest.getMessage()),
70+
ConnectorIncomingMapper.map(logRequest.getAdditional())
71+
)
72+
)
73+
)
74+
),
75+
requestId
76+
);
77+
}
78+
case PRINT_MATCH_ERROR_REQUEST -> {
79+
final var printMatchErrorRequest = note.getPrintMatchErrorRequest();
80+
rpcConnector.sendResponse(
81+
mapResultResponse(
82+
resultPrinter.printMatchError(
83+
mapMatchErrorRequest(printMatchErrorRequest)
84+
)
85+
),
86+
requestId
87+
);
88+
}
89+
case PRINT_MESSAGE_ERROR_REQUEST -> {
90+
rpcConnector.sendResponse(
91+
mapResultResponse(
92+
resultPrinter.printMessageError(
93+
mapMessageErrorRequest(
94+
note.getPrintMessageErrorRequest()
95+
)
96+
)
97+
),
98+
requestId
99+
);
100+
}
101+
case PRINT_TEST_TITLE_REQUEST -> {
102+
final var printTestTitleRequest = note.getPrintTestTitleRequest();
103+
rpcConnector.sendResponse(mapResultResponse(resultPrinter.printTestTitle(
104+
mapPrintableTestTitle(printTestTitleRequest))), requestId);
105+
}
106+
case TRIGGER_FUNCTION_REQUEST -> {
107+
var triggerFunctionRequest = note.getTriggerFunctionRequest();
108+
var handle = ConnectorIncomingMapper.map(triggerFunctionRequest.getTriggerFunction()
109+
.getHandle());
110+
if (handle == null) {
111+
throw new ContractCaseCoreError(
112+
"Received a trigger request message with a null trigger handle",
113+
"Java Internal Connector"
114+
);
115+
}
116+
117+
rpcConnector.sendResponse(
118+
DefinitionRequest.newBuilder().setResultResponse(
119+
ResultResponse.newBuilder().setResult(
120+
mapResult(
121+
configHandle.getTriggerFunction(handle).trigger(
122+
ConnectorIncomingMapper.map(triggerFunctionRequest.getConfig()
123+
)
124+
)
125+
)
126+
)
127+
),
128+
requestId
129+
);
130+
}
131+
case RESULT_RESPONSE -> {
132+
rpcConnector.completeWait(requestId, note.getResultResponse().getResult());
133+
}
134+
case KIND_NOT_SET -> {
135+
throw new ContractCaseCoreError(
136+
"Received a message with no kind set",
137+
"Java Internal Connector"
138+
);
139+
}
140+
case START_TEST_EVENT -> {
141+
throw new ContractCaseCoreError(
142+
"Received start test event incorrectly during a define contract",
143+
"Java Internal Connector"
144+
);
145+
}
146+
}
147+
}
148+
149+
@Override
150+
public void onError(Throwable t) {
151+
Status status = Status.fromThrowable(t);
152+
if (Status.Code.UNAVAILABLE.equals(status.getCode())) {
153+
System.err.println("""
154+
ContractCase was unable to contact its internal server.
155+
This is either a conflict while starting the server,
156+
a crash while the server was running, or a bug in
157+
ContractCase. Please see the rest of the log output
158+
for details.
159+
160+
If you are unable to resolve this locally,
161+
please open an issue here:
162+
163+
https://github.com/case-contract-testing/contract-case
164+
""");
165+
} else {
166+
System.err.println("ContractCase failed: " + status);
167+
}
168+
rpcConnector.setErrorStatus(status);
169+
}
170+
171+
@Override
172+
public void onCompleted() {
173+
}
174+
}

0 commit comments

Comments
 (0)