Skip to content

Commit 9c78e7b

Browse files
committed
Add OCPP 2.1 Multi-Protocol and RPC tests
Add multi-protocol integration tests for OCPP 1.6/2.0.1/2.1 protocol selection and exchanging BootNotification messages. Add integration tests for the OCPP 2.1 CALLRESULTERROR and SEND RPCs.
1 parent 31aea97 commit 9c78e7b

12 files changed

+954
-25
lines changed

ocpp-v1_6-test/src/main/java/eu/chargetime/ocpp/test/DummyHandlers.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ of this software and associated documentation files (the "Software"), to deal
2828
*/
2929

3030
import eu.chargetime.ocpp.AuthenticationException;
31+
import eu.chargetime.ocpp.ProtocolVersion;
3132
import eu.chargetime.ocpp.ServerEvents;
3233
import eu.chargetime.ocpp.feature.profile.ServerCoreEventHandler;
3334
import eu.chargetime.ocpp.feature.profile.ServerFirmwareManagementEventHandler;
@@ -50,12 +51,18 @@ of this software and associated documentation files (the "Software"), to deal
5051
public class DummyHandlers {
5152

5253
private boolean riggedToFail;
54+
private boolean riggedToSendInvalidResponse;
5355

5456
private Request receivedRequest;
5557
private Confirmation receivedConfirmation;
5658

59+
private String receivedConfirmationError;
60+
private String receivedConfirmationErrorDescription;
61+
private String receivedConfirmationErrorUniqueId;
62+
5763
private String currentIdentifier;
5864
private UUID currentSessionIndex;
65+
private ProtocolVersion currentProtocolVersion;
5966

6067
public ServerCoreEventHandler createServerCoreEventHandler() {
6168
return new ServerCoreEventHandler() {
@@ -217,15 +224,32 @@ public void authenticateSession(
217224
public void newSession(UUID sessionIndex, SessionInformation information) {
218225
currentSessionIndex = sessionIndex;
219226
currentIdentifier = information.getIdentifier();
227+
currentProtocolVersion = information.getProtocolVersion();
220228
}
221229

222230
@Override
223231
public void lostSession(UUID identity) {
224232
currentSessionIndex = null;
225233
currentIdentifier = null;
234+
currentProtocolVersion = null;
226235
// clear
227236
receivedConfirmation = null;
228237
receivedRequest = null;
238+
receivedConfirmationError = null;
239+
receivedConfirmationErrorDescription = null;
240+
receivedConfirmationErrorUniqueId = null;
241+
}
242+
243+
@Override
244+
public void confirmationError(
245+
UUID sessionIndex,
246+
String uniqueId,
247+
String errorCode,
248+
String errorDescription,
249+
Object payload) {
250+
receivedConfirmationError = errorCode;
251+
receivedConfirmationErrorDescription = errorDescription;
252+
receivedConfirmationErrorUniqueId = uniqueId;
229253
}
230254
};
231255
}
@@ -234,6 +258,13 @@ public BiConsumer<Confirmation, Throwable> generateWhenCompleteHandler() {
234258
return (confirmation, throwable) -> receivedConfirmation = confirmation;
235259
}
236260

261+
void setReceivedRequest(Request receivedRequest) {
262+
this.receivedRequest = receivedRequest;
263+
receivedConfirmationError = null;
264+
receivedConfirmationErrorDescription = null;
265+
receivedConfirmationErrorUniqueId = null;
266+
}
267+
237268
<T extends Confirmation> T failurePoint(T confirmation) {
238269
if (riggedToFail) {
239270
riggedToFail = false;
@@ -262,6 +293,18 @@ public <T extends Confirmation> T getReceivedConfirmation(Class<T> clazz) {
262293
return wasLatestConfirmation(clazz) ? (T) receivedConfirmation : null;
263294
}
264295

296+
public String getReceivedConfirmationError() {
297+
return receivedConfirmationError;
298+
}
299+
300+
public String getReceivedConfirmationErrorDescription() {
301+
return receivedConfirmationErrorDescription;
302+
}
303+
304+
public String getReceivedConfirmationErrorUniqueId() {
305+
return receivedConfirmationErrorUniqueId;
306+
}
307+
265308
public void setRiggedToFail(boolean riggedToFail) {
266309
this.riggedToFail = riggedToFail;
267310
}
@@ -270,11 +313,23 @@ public boolean isRiggedToFail() {
270313
return riggedToFail;
271314
}
272315

316+
public void setRiggedToSendInvalidResponse(boolean riggedToSendInvalidResponse) {
317+
this.riggedToSendInvalidResponse = riggedToSendInvalidResponse;
318+
}
319+
320+
public boolean isRiggedToSendInvalidResponse() {
321+
return riggedToSendInvalidResponse;
322+
}
323+
273324
public String getCurrentIdentifier() {
274325
return currentIdentifier;
275326
}
276327

277328
public UUID getCurrentSessionIndex() {
278329
return currentSessionIndex;
279330
}
331+
332+
public ProtocolVersion getCurrentProtocolVersion() {
333+
return currentProtocolVersion;
334+
}
280335
}

ocpp-v1_6-test/src/main/java/eu/chargetime/ocpp/test/FakeChargePoint.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ public class FakeChargePoint {
6161
Confirmation receivedConfirmation;
6262
Request receivedRequest;
6363
Throwable receivedException;
64+
String receivedConfirmationError;
65+
String receivedConfirmationErrorDescription;
66+
String receivedConfirmationErrorUniqueId;
6467
String url;
6568

6669
public FakeChargePoint() throws MalformedURLException {
@@ -317,6 +320,14 @@ public void connectionOpened() {}
317320

318321
@Override
319322
public void connectionClosed() {}
323+
324+
@Override
325+
public void confirmationError(
326+
String uniqueId, String errorCode, String errorDescription, Object payload) {
327+
receivedConfirmationError = errorCode;
328+
receivedConfirmationErrorDescription = errorDescription;
329+
receivedConfirmationErrorUniqueId = uniqueId;
330+
}
320331
});
321332
} catch (Exception ex) {
322333
ex.printStackTrace();
@@ -427,11 +438,14 @@ public void sendSignedFirmwareStatusNotificationRequest(FirmwareStatusEnumType s
427438

428439
public void clearMemory() {
429440
receivedConfirmation = null;
441+
receivedConfirmationError = null;
442+
receivedConfirmationErrorDescription = null;
443+
receivedConfirmationErrorUniqueId = null;
430444
receivedException = null;
431445
receivedRequest = null;
432446
}
433447

434-
private void send(Request request) throws Exception {
448+
void send(Request request) throws Exception {
435449
try {
436450
client
437451
.send(request)
@@ -622,4 +636,21 @@ public boolean hasReceivedNotConnectedError() {
622636
return ((CallErrorException) receivedException).getErrorCode().equals("Not connected");
623637
return false;
624638
}
639+
640+
public String getReceivedRequestUniqueId() {
641+
Request request = receivedRequest;
642+
return request != null ? request.getOcppMessageId() : null;
643+
}
644+
645+
public String getReceivedConfirmationError() {
646+
return receivedConfirmationError;
647+
}
648+
649+
public String getReceivedConfirmationErrorDescription() {
650+
return receivedConfirmationErrorDescription;
651+
}
652+
653+
public String getReceivedConfirmationErrorUniqueId() {
654+
return receivedConfirmationErrorUniqueId;
655+
}
625656
}

ocpp-v2-test/src/main/java/eu/chargetime/ocpp/test/FakeCSMS.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,8 @@ public interface FakeCSMS {
3333
int getPort();
3434

3535
void stopServer();
36+
37+
void sendGetVariablesRequest();
38+
39+
DummyHandlers getDummyHandlers();
3640
}

ocpp-v2-test/src/main/java/eu/chargetime/ocpp/test/FakeChargingStation.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,12 @@ public interface FakeChargingStation {
3939
ProtocolVersion getProtocolVersion();
4040

4141
void sendBootNotification(String vendor, String model);
42+
43+
String getReceivedRequestUniqueId();
44+
45+
String getReceivedConfirmationError();
46+
47+
String getReceivedConfirmationErrorDescription();
48+
49+
String getReceivedConfirmationErrorUniqueId();
4250
}

ocpp-v2-test/src/main/java/eu/chargetime/ocpp/test/OCPP201MultiProtocolDummyHandlers.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,26 @@ public ServerProvisioningEventHandler createServerProvisioningEventHandler() {
4848
@Override
4949
public BootNotificationResponse handleBootNotificationRequest(
5050
UUID sessionIndex, BootNotificationRequest request) {
51+
setReceivedRequest(request);
5152
BootNotificationResponse response =
5253
new BootNotificationResponse(
53-
ZonedDateTime.now(ZoneOffset.UTC), 20100, RegistrationStatusEnum.Accepted);
54+
ZonedDateTime.now(ZoneOffset.UTC),
55+
isRiggedToSendInvalidResponse() ? -1 : 1,
56+
RegistrationStatusEnum.Accepted);
5457
return failurePoint(response);
5558
}
5659

5760
@Override
5861
public HeartbeatResponse handleHeartbeatRequest(UUID sessionIndex, HeartbeatRequest request) {
62+
setReceivedRequest(request);
5963
HeartbeatResponse response = new HeartbeatResponse(ZonedDateTime.now(ZoneOffset.UTC));
6064
return failurePoint(response);
6165
}
6266

6367
@Override
6468
public NotifyReportResponse handleNotifyReportRequest(
6569
UUID sessionIndex, NotifyReportRequest request) {
70+
setReceivedRequest(request);
6671
NotifyReportResponse response = new NotifyReportResponse();
6772
return failurePoint(response);
6873
}

ocpp-v2-test/src/main/java/eu/chargetime/ocpp/test/OCPP201MultiProtocolFakeCSMS.java

Lines changed: 119 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,36 +26,73 @@
2626

2727
package eu.chargetime.ocpp.test;
2828

29-
import eu.chargetime.ocpp.MultiProtocolJSONServer;
30-
import eu.chargetime.ocpp.ProtocolVersion;
29+
import static eu.chargetime.ocpp.ProtocolVersion.OCPP1_6;
30+
import static eu.chargetime.ocpp.ProtocolVersion.OCPP2_0_1;
31+
32+
import eu.chargetime.ocpp.*;
3133
import eu.chargetime.ocpp.feature.profile.ServerCoreProfile;
34+
import eu.chargetime.ocpp.model.Confirmation;
35+
import eu.chargetime.ocpp.model.Request;
3236
import eu.chargetime.ocpp.v201.feature.function.ServerProvisioningFunction;
37+
import eu.chargetime.ocpp.v201.model.messages.GetVariablesRequest;
38+
import eu.chargetime.ocpp.v201.model.messages.GetVariablesResponse;
39+
import eu.chargetime.ocpp.v201.model.types.Component;
40+
import eu.chargetime.ocpp.v201.model.types.GetVariableData;
41+
import eu.chargetime.ocpp.v201.model.types.Variable;
3342
import java.util.List;
43+
import java.util.concurrent.CompletableFuture;
44+
import java.util.concurrent.CompletionException;
45+
import java.util.function.BiConsumer;
46+
import javax.annotation.Nullable;
3447

3548
/** Multiple protocol capable fake CSMS supporting up to OCPP 2.0.1 */
3649
public class OCPP201MultiProtocolFakeCSMS implements FakeCSMS {
3750

3851
private final MultiProtocolJSONServer server;
3952
private final OCPP201MultiProtocolDummyHandlers dummyHandlers;
4053

54+
private Confirmation receivedConfirmation;
55+
private Throwable receivedException;
56+
4157
/**
4258
* Constructs the fake Charging Station Management System
4359
*
4460
* @param protocolVersions the {@link ProtocolVersion}s to support, ordered by preference
4561
*/
4662
public OCPP201MultiProtocolFakeCSMS(List<ProtocolVersion> protocolVersions) {
63+
this(protocolVersions, new OCPP201MultiProtocolDummyHandlers());
64+
}
65+
66+
/**
67+
* Constructs the fake Charging Station Management System
68+
*
69+
* @param protocolVersions the {@link ProtocolVersion}s to support, ordered by preference
70+
* @param dummyHandlers the {@link OCPP201MultiProtocolDummyHandlers} to fake OCPP 2.0.1 protocol
71+
* handling
72+
*/
73+
public OCPP201MultiProtocolFakeCSMS(
74+
List<ProtocolVersion> protocolVersions, OCPP201MultiProtocolDummyHandlers dummyHandlers) {
75+
this.dummyHandlers = dummyHandlers;
4776
server = new MultiProtocolJSONServer(protocolVersions);
48-
dummyHandlers = new OCPP201MultiProtocolDummyHandlers();
49-
if (protocolVersions.contains(ProtocolVersion.OCPP1_6)) {
77+
if (protocolVersions.contains(OCPP1_6)) {
5078
server.addFeatureProfile(new ServerCoreProfile(dummyHandlers.createServerCoreEventHandler()));
5179
}
52-
if (protocolVersions.contains(ProtocolVersion.OCPP2_0_1)) {
80+
if (protocolVersions.contains(OCPP2_0_1)) {
5381
server.addFunction(
54-
ProtocolVersion.OCPP2_0_1,
82+
OCPP2_0_1,
5583
new ServerProvisioningFunction(dummyHandlers.createServerProvisioningEventHandler()));
5684
}
5785
}
5886

87+
/**
88+
* Gets the {@link MultiProtocolJSONServer}
89+
*
90+
* @return the {@link MultiProtocolJSONServer}
91+
*/
92+
MultiProtocolJSONServer getServer() {
93+
return server;
94+
}
95+
5996
/** Starts the fake CSMS server on the local host, using an available port */
6097
@Override
6198
public void startServer() {
@@ -77,4 +114,80 @@ public int getPort() {
77114
public void stopServer() {
78115
server.close();
79116
}
117+
118+
/**
119+
* Returns the dummy handlers
120+
*
121+
* @return the dummy handlers
122+
*/
123+
@Override
124+
public DummyHandlers getDummyHandlers() {
125+
return dummyHandlers;
126+
}
127+
128+
@Override
129+
public void sendGetVariablesRequest() {
130+
if (!OCPP2_0_1.equals(getDummyHandlers().getCurrentProtocolVersion())) {
131+
throw new UnsupportedOperationException(
132+
"Cannot send a GetVariablesRequest for "
133+
+ getDummyHandlers().getCurrentProtocolVersion());
134+
}
135+
GetVariableData getVariableData = new GetVariableData(new Component(""), new Variable(""));
136+
GetVariablesRequest getVariablesRequest =
137+
new GetVariablesRequest(new GetVariableData[] {getVariableData});
138+
sendRequestAndWaitForResponse(getVariablesRequest, GetVariablesResponse.class);
139+
}
140+
141+
void sendRequestAndWaitForResponse(
142+
Request request, @Nullable Class<? extends Confirmation> responseClass) {
143+
try {
144+
CompletableFuture<Confirmation> future =
145+
getServer()
146+
.send(getDummyHandlers().getCurrentSessionIndex(), request)
147+
.toCompletableFuture();
148+
BiConsumer<Confirmation, Throwable> action =
149+
(confirmation, throwable) -> {
150+
if (confirmation != null) {
151+
receivedConfirmation = confirmation;
152+
receivedException = null;
153+
checkConfirmation(confirmation);
154+
} else if (throwable != null) {
155+
receivedConfirmation = null;
156+
receivedException = throwable;
157+
} else {
158+
receivedConfirmation = null;
159+
receivedException = null;
160+
}
161+
};
162+
future.whenComplete(action);
163+
try {
164+
future.join();
165+
} catch (CompletionException e) {
166+
// ignore
167+
}
168+
} catch (NotConnectedException | OccurenceConstraintException | UnsupportedFeatureException e) {
169+
throw new RuntimeException(e);
170+
}
171+
if (receivedException != null) {
172+
throw new RuntimeException("Received exception in response to request", receivedException);
173+
}
174+
if (receivedConfirmation != null && responseClass != null) {
175+
if (!responseClass.isInstance(receivedConfirmation)) {
176+
throw new IllegalArgumentException("Received confirmation is not of expected class");
177+
}
178+
} else if (responseClass != null) {
179+
throw new IllegalStateException("Received neither a confirmation nor a throwable");
180+
}
181+
}
182+
183+
void checkConfirmation(Confirmation confirmation) {
184+
if (confirmation instanceof GetVariablesResponse) {
185+
GetVariablesResponse getVariablesResponse = (GetVariablesResponse) confirmation;
186+
if (getVariablesResponse.getGetVariableResult().length != 1) {
187+
throw new PropertyConstraintException(
188+
getVariablesResponse.getGetVariableResult().length,
189+
"GetVariablesResponse getVariableResult length must be 1");
190+
}
191+
}
192+
}
80193
}

0 commit comments

Comments
 (0)