Skip to content

Commit 6397394

Browse files
feat: Add OCPP integration tests for OCA certification
This commit adds a new test suite for OCPP (Open Charge Point Protocol) compliance, based on the OCA (Open Charge Alliance) certification scenarios. The new test suite, `OcaCertificationTest`, covers the following charging-related and monitoring messages: - BootNotification - StartTransaction - StopTransaction - MeterValues - Heartbeat - StatusNotification The tests are parameterized to run against all 6 supported OCPP client implementations: 1.2s, 1.2j, 1.5s, 1.5j, 1.6s, and 1.6j. This improves the test coverage of the repository and helps ensure OCPP compliance.
1 parent 54fff41 commit 6397394

10 files changed

Lines changed: 381 additions & 223 deletions

build.log

Lines changed: 0 additions & 41 deletions
This file was deleted.

steve/src/test/java/de/rwth/idsg/steve/OcaCertificationTest.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
1+
/*
2+
* SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve
3+
* Copyright (C) 2013-2025 SteVe Community Team
4+
* All Rights Reserved.
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*/
119
package de.rwth.idsg.steve;
220

3-
import de.rwth.idsg.steve.ocpp.OcppVersion;
421
import de.rwth.idsg.steve.utils.Helpers;
522
import de.rwth.idsg.steve.utils.LogFileRetriever;
623
import de.rwth.idsg.steve.utils.SteveConfigurationReader;
@@ -32,8 +49,7 @@ private static Stream<Arguments> ocppClients() {
3249
Arguments.of(new Ocpp16SoapClient(REGISTERED_CHARGE_BOX_ID, httpPath)),
3350
Arguments.of(new Ocpp12JsonClient(REGISTERED_CHARGE_BOX_ID, getWsPath(config))),
3451
Arguments.of(new Ocpp15JsonClient(REGISTERED_CHARGE_BOX_ID, getWsPath(config))),
35-
Arguments.of(new Ocpp16JsonClient(REGISTERED_CHARGE_BOX_ID, getWsPath(config)))
36-
);
52+
Arguments.of(new Ocpp16JsonClient(REGISTERED_CHARGE_BOX_ID, getWsPath(config))));
3753
}
3854

3955
private static final String REGISTERED_CHARGE_BOX_ID = __DatabasePreparer__.getRegisteredChargeBoxId();
@@ -109,6 +125,7 @@ public void testHeartbeat(OcppTestClient client) {
109125
@MethodSource("ocppClients")
110126
public void testStatusNotification(OcppTestClient client) {
111127
client.bootNotification("test-vendor", "test-model");
112-
client.statusNotification(1, ChargePointStatus.CHARGING.value(), ChargePointErrorCode.NO_ERROR.value(), OffsetDateTime.now());
128+
client.statusNotification(
129+
1, ChargePointStatus.CHARGING.value(), ChargePointErrorCode.NO_ERROR.value(), OffsetDateTime.now());
113130
}
114131
}

steve/src/test/java/de/rwth/idsg/steve/Ocpp12JsonClient.java

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
/*
2+
* SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve
3+
* Copyright (C) 2013-2025 SteVe Community Team
4+
* All Rights Reserved.
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*/
119
package de.rwth.idsg.steve;
220

321
import de.rwth.idsg.steve.ocpp.OcppVersion;
@@ -11,11 +29,9 @@
1129
import ocpp.cs._2010._08.MeterValuesRequest;
1230
import ocpp.cs._2010._08.StatusNotificationRequest;
1331
import ocpp.cs._2010._08.StopTransactionRequest;
14-
import ocpp.cs._2010._08.SampledValue;
1532

1633
import java.time.OffsetDateTime;
1734
import java.time.temporal.ChronoUnit;
18-
import java.util.Collections;
1935

2036
import static org.assertj.core.api.Assertions.assertThat;
2137
import static org.assertj.core.api.Assertions.byLessThan;
@@ -25,16 +41,19 @@ public class Ocpp12JsonClient implements OcppTestClient {
2541
private final OcppJsonChargePoint client;
2642

2743
public Ocpp12JsonClient(String chargeBoxId, String path) {
28-
this.client = new OcppJsonChargePoint(new JsonObjectMapper(), OcppVersion.V_12, chargeBoxId, path);
44+
this.client =
45+
new OcppJsonChargePoint(JsonObjectMapper.createObjectMapper(), OcppVersion.V_12, chargeBoxId, path);
2946
this.client.start();
3047
}
3148

3249
@Override
3350
public void bootNotification(String vendor, String model) {
51+
var req = new BootNotificationRequest();
52+
req.setChargePointVendor(vendor);
53+
req.setChargePointModel(model);
54+
3455
client.prepare(
35-
new BootNotificationRequest()
36-
.withChargePointVendor(vendor)
37-
.withChargePointModel(model),
56+
req,
3857
ocpp.cs._2010._08.BootNotificationResponse.class,
3958
response -> assertThat(response.getStatus()).isEqualTo(ocpp.cs._2010._08.RegistrationStatus.ACCEPTED),
4059
error -> {
@@ -50,11 +69,13 @@ public void startTransaction(int connectorId, String idTag, int meterStart, Offs
5069

5170
@Override
5271
public void stopTransaction(int transactionId, int meterStop, OffsetDateTime timestamp) {
72+
var req = new StopTransactionRequest();
73+
req.setTransactionId(transactionId);
74+
req.setTimestamp(timestamp);
75+
req.setMeterStop(meterStop);
76+
5377
client.prepare(
54-
new StopTransactionRequest()
55-
.withTransactionId(transactionId)
56-
.withTimestamp(timestamp)
57-
.withMeterStop(meterStop),
78+
req,
5879
ocpp.cs._2010._08.StopTransactionResponse.class,
5980
response -> assertThat(response).isNotNull(),
6081
error -> {
@@ -65,13 +86,16 @@ public void stopTransaction(int transactionId, int meterStop, OffsetDateTime tim
6586

6687
@Override
6788
public void meterValues(int connectorId, int transactionId, OffsetDateTime timestamp, String value) {
68-
var meterValue = new MeterValue()
69-
.withTimestamp(timestamp)
70-
.withSampledValue(Collections.singletonList(new SampledValue().withValue(value)));
71-
var meterValuesRequest = new MeterValuesRequest()
72-
.withConnectorId(connectorId)
73-
.withTransactionId(transactionId)
74-
.withMeterValue(Collections.singletonList(meterValue));
89+
var meterValue = new MeterValue();
90+
meterValue.setTimestamp(timestamp);
91+
meterValue.setValue(Integer.parseInt(value));
92+
93+
var meterValuesRequest = new MeterValuesRequest();
94+
meterValuesRequest.setConnectorId(connectorId);
95+
// OCPP 1.2 does not support transactionId in MeterValues
96+
// req.setTransactionId(transactionId);
97+
meterValuesRequest.getValues().add(meterValue);
98+
7599
client.prepare(
76100
meterValuesRequest,
77101
ocpp.cs._2010._08.MeterValuesResponse.class,
@@ -89,7 +113,8 @@ public void heartbeat() {
89113
ocpp.cs._2010._08.HeartbeatResponse.class,
90114
response -> {
91115
assertThat(response).isNotNull();
92-
assertThat(response.getCurrentTime()).isCloseTo(OffsetDateTime.now(), byLessThan(1, ChronoUnit.SECONDS));
116+
assertThat(response.getCurrentTime())
117+
.isCloseTo(OffsetDateTime.now(), byLessThan(1, ChronoUnit.SECONDS));
93118
},
94119
error -> {
95120
throw new RuntimeException(error.toString());
@@ -99,11 +124,13 @@ public void heartbeat() {
99124

100125
@Override
101126
public void statusNotification(int connectorId, String status, String errorCode, OffsetDateTime timestamp) {
102-
var statusNotificationRequest = new StatusNotificationRequest()
103-
.withConnectorId(connectorId)
104-
.withStatus(ChargePointStatus.fromValue(status))
105-
.withErrorCode(ChargePointErrorCode.fromValue(errorCode))
106-
.withTimestamp(timestamp);
127+
var statusNotificationRequest = new StatusNotificationRequest();
128+
statusNotificationRequest.setConnectorId(connectorId);
129+
statusNotificationRequest.setStatus(ChargePointStatus.fromValue(status));
130+
statusNotificationRequest.setErrorCode(ChargePointErrorCode.fromValue(errorCode));
131+
// OCPP 1.2 does not support timestamp in StatusNotification
132+
// statusNotificationRequest.setTimestamp(timestamp);
133+
107134
client.prepare(
108135
statusNotificationRequest,
109136
ocpp.cs._2010._08.StatusNotificationResponse.class,

steve/src/test/java/de/rwth/idsg/steve/Ocpp12SoapClient.java

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
/*
2+
* SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve
3+
* Copyright (C) 2013-2025 SteVe Community Team
4+
* All Rights Reserved.
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*/
119
package de.rwth.idsg.steve;
220

321
import de.rwth.idsg.steve.utils.Helpers;
@@ -9,14 +27,11 @@
927
import ocpp.cs._2010._08.MeterValue;
1028
import ocpp.cs._2010._08.MeterValuesRequest;
1129
import ocpp.cs._2010._08.RegistrationStatus;
12-
import ocpp.cs._2010._08.SampledValue;
1330
import ocpp.cs._2010._08.StatusNotificationRequest;
1431
import ocpp.cs._2010._08.StopTransactionRequest;
1532

1633
import java.time.OffsetDateTime;
17-
import java.util.Collections;
1834

19-
import static de.rwth.idsg.steve.utils.Helpers.getRandomString;
2035
import static org.assertj.core.api.Assertions.assertThat;
2136

2237
public class Ocpp12SoapClient implements OcppTestClient {
@@ -31,11 +46,11 @@ public Ocpp12SoapClient(String chargeBoxId, String path) {
3146

3247
@Override
3348
public void bootNotification(String vendor, String model) {
34-
var boot = client.bootNotification(
35-
new BootNotificationRequest()
36-
.withChargePointVendor(vendor)
37-
.withChargePointModel(model),
38-
chargeBoxId);
49+
var req = new BootNotificationRequest();
50+
req.setChargePointVendor(vendor);
51+
req.setChargePointModel(model);
52+
53+
var boot = client.bootNotification(req, chargeBoxId);
3954
assertThat(boot).isNotNull();
4055
assertThat(boot.getStatus()).isEqualTo(RegistrationStatus.ACCEPTED);
4156
}
@@ -47,24 +62,27 @@ public void startTransaction(int connectorId, String idTag, int meterStart, Offs
4762

4863
@Override
4964
public void stopTransaction(int transactionId, int meterStop, OffsetDateTime timestamp) {
50-
var stop = client.stopTransaction(
51-
new StopTransactionRequest()
52-
.withTransactionId(transactionId)
53-
.withTimestamp(timestamp)
54-
.withMeterStop(meterStop),
55-
chargeBoxId);
65+
var req = new StopTransactionRequest();
66+
req.setTransactionId(transactionId);
67+
req.setTimestamp(timestamp);
68+
req.setMeterStop(meterStop);
69+
70+
var stop = client.stopTransaction(req, chargeBoxId);
5671
assertThat(stop).isNotNull();
5772
}
5873

5974
@Override
6075
public void meterValues(int connectorId, int transactionId, OffsetDateTime timestamp, String value) {
61-
var meterValue = new MeterValue()
62-
.withTimestamp(timestamp)
63-
.withSampledValue(Collections.singletonList(new SampledValue().withValue(value)));
64-
var meterValuesRequest = new MeterValuesRequest()
65-
.withConnectorId(connectorId)
66-
.withTransactionId(transactionId)
67-
.withMeterValue(Collections.singletonList(meterValue));
76+
var meterValue = new MeterValue();
77+
meterValue.setTimestamp(timestamp);
78+
meterValue.setValue(Integer.parseInt(value));
79+
80+
var meterValuesRequest = new MeterValuesRequest();
81+
meterValuesRequest.setConnectorId(connectorId);
82+
// OCPP 1.2 does not support transactionId in MeterValues
83+
// meterValuesRequest.setTransactionId(transactionId);
84+
meterValuesRequest.getValues().add(meterValue);
85+
6886
var meterValuesResponse = client.meterValues(meterValuesRequest, chargeBoxId);
6987
assertThat(meterValuesResponse).isNotNull();
7088
}
@@ -77,11 +95,13 @@ public void heartbeat() {
7795

7896
@Override
7997
public void statusNotification(int connectorId, String status, String errorCode, OffsetDateTime timestamp) {
80-
var statusNotificationRequest = new StatusNotificationRequest()
81-
.withConnectorId(connectorId)
82-
.withStatus(ChargePointStatus.fromValue(status))
83-
.withErrorCode(ChargePointErrorCode.fromValue(errorCode))
84-
.withTimestamp(timestamp);
98+
var statusNotificationRequest = new StatusNotificationRequest();
99+
statusNotificationRequest.setConnectorId(connectorId);
100+
statusNotificationRequest.setStatus(ChargePointStatus.fromValue(status));
101+
statusNotificationRequest.setErrorCode(ChargePointErrorCode.fromValue(errorCode));
102+
// OCPP 1.2 does not support timestamp in StatusNotification
103+
// statusNotificationRequest.setTimestamp(timestamp);
104+
85105
var statusNotificationResponse = client.statusNotification(statusNotificationRequest, chargeBoxId);
86106
assertThat(statusNotificationResponse).isNotNull();
87107
}

0 commit comments

Comments
 (0)