From e3ddbe9bc7483466f304c7fd49d9df7e12b5a7ee Mon Sep 17 00:00:00 2001 From: Usman Sule <114589596+usuletw022@users.noreply.github.com> Date: Tue, 26 Mar 2024 16:18:10 +0000 Subject: [PATCH] E2e mqtt tests (#38) * e2e tests: Added the e2e test folder and included the docker compose file with Everest configurations * ci fix: skipped current e2e tests and removed hyperlink for directories in README * e2e tests: moved existing e2e test resources to another folder, included a script that start docker compose and run the e2e tests * e2e tests: refactored e2e-test scripts for starting docker compose and invoking tests * ci fix: skipping e2e tests * e2e tests: included e2e tests as part of talisman's ignore file config, removed t.Skip in e2e test, updated function in e2e test script * e2e tests: removed e2e tests as part of talisman's ignore file * e2e tests: add test file to talisman to ignore, add go doc, updated file locations * e2e tests: renamed e2e test folder, updated e2e test script variables and commands * e2e tests: add CI workflow for e2e tests, adjusted directory path for csms * e2e tests: add sudo permissions for update and installation * ci fix: add statement to print current directory * ci fix: add full directory path to volume source * ci debug: capture the actual file location for the volume source, revert volume source path for Everest * ci fix: add full path to directory for volume source * ci debug: print current directory after make up, revert path for volume source * ci debug: print current directory after make up * ci fix: add new folders for certificate generation, adjusted script for copying csms certificates, add everest scripts to e2e test script * ci fix: add setup to generate csms certificates * ci fix: update README * ci fix: adjusted wait time for Everest * ci fix: adjusted wait time for Everest * ci fix: adjusted wait time for Everest * ci fix: debug mqtt server for everest * ci fix: debug websocket server for csms * ci fix: give access permission to tls key certificate * ci fix: run full e2e test * ci fix: debug everest * ci fix: run e2e tests without container logs * ci fix: run e2e tests without container logs * ci fix: run e2e tests with mqtt logs * ci fix: run e2e tests with available services * ci fix: run e2e tests with mqtt server logs * ci fix: removed logging definition from docker-compose and decreased wait time * ci fix: add logging for mqtt in csms * ci fix: add logging for both csms and everest * ci fix: add logging for everest after test * ci fix: add logging for everest after test * ci fix: add logging for everest after test * ci fix: add logging for everest after test * ci fix: add logging for everest after test * debug: install library package for mosquitto on Ubuntu, add mosquitto command for subscription * debug: ignoring exit code 1 output for failed test execution to see docker-compose logs after failure * debug: ignoring exit code 1 output for failed test execution to see docker-compose logs after failure * debug: changed mqtt broker address * refactor: removed docker compose version, renamed some steps within the build job, removed docker compose logs from script * doc: add README for step to run e2e tests locally * improvment: add Gosec Security Scanner to CI workflow * improvement: remove Gosec Security Scanner from CI workflow * doc: minor adjustment to README --- .github/workflows/end-to-end-tests.yml | 22 + .talismanrc | 2 + e2e_tests/Makefile | 19 + e2e_tests/README.md | 18 + e2e_tests/docker-compose.yml | 52 ++ .../certificates/HUBOpenProvCert001.pem | 47 ++ .../certificates/HUBOpenProvCert002.pem | 47 ++ .../certificates/HUBOpenProvCert003.pem | 47 ++ ...OpenProvCert005-EMP77TWTW99999-Revoked.pem | 47 ++ .../config/certificates/root-V2G-cert.pem | 17 + .../everest/config/certificates/trust.pem | 16 + e2e_tests/everest/config/everest/README.md | 97 +++ .../config/everest/certs/ca/csms/.gitkeep | 0 .../config/everest/certs/ca/cso/.gitkeep | 0 .../config/everest/certs/ca/oem/.gitkeep | 0 .../config/everest/certs/ca/v2g/.gitkeep | 0 .../config/everest/certs/client/csms/.gitkeep | 0 .../config/everest/certs/client/cso/.gitkeep | 0 .../config/everest/certs/client/oem/.gitkeep | 0 .../config/everest/config-sil-ocpp-pnc.yaml | 197 +++++ .../config/everest/config-sil-ocpp.yaml | 189 +++++ .../config/everest/config-sil-ocpp201.yaml | 188 +++++ .../config/everest/default_logging.cfg | 18 + .../config/everest/ocpp/OCPP/config.json | 58 ++ .../everest/config/everest/ocpp/OCPP/init.sql | 61 ++ .../config/everest/ocpp/OCPP/logging.ini | 18 + .../ocpp/OCPP/profile_schemas/Config.json | 45 ++ .../ocpp/OCPP/profile_schemas/Core.json | 191 +++++ .../ocpp/OCPP/profile_schemas/Custom.json | 15 + .../profile_schemas/FirmwareManagement.json | 13 + .../ocpp/OCPP/profile_schemas/Internal.json | 230 ++++++ .../LocalAuthListManagement.json | 27 + .../ocpp/OCPP/profile_schemas/PnC.json | 48 ++ .../OCPP/profile_schemas/Reservation.json | 13 + .../ocpp/OCPP/profile_schemas/Security.json | 46 ++ .../OCPP/profile_schemas/SmartCharging.json | 40 ++ .../config/everest/ocpp/OCPP/user_config.json | 1 + .../config/everest/ocpp/OCPP201/config.json | 679 ++++++++++++++++++ .../ocpp/OCPP201/device_model_storage.db | Bin 0 -> 65536 bytes .../config/everest/ocpp/OCPP201/init_core.sql | 80 +++ .../config/everest/ocpp/OCPP201/logging.ini | 18 + e2e_tests/everest/config/everest/release.json | 1 + .../everest/rise_v2g/EVCCConfig.properties | 14 + .../everest/rise_v2g/SECCConfig.properties | 130 ++++ .../config/everest/rise_v2g/log4j2.properties | 15 + .../config/everest/user-config/.gitkeep | 0 .../everest/user-config/ocpp/user_config.json | 1 + e2e_tests/everest/scripts/copy-csms-cert.sh | 8 + e2e_tests/everest/scripts/generate-cs-cert.sh | 28 + e2e_tests/everest/scripts/generate-mo-cert.sh | 34 + .../everest/scripts/generate-oem-cert.sh | 34 + e2e_tests/everest/scripts/get-ca-cert.sh | 30 + .../everest/scripts/register-oem-cert.sh | 37 + e2e_tests/everest/scripts/setup-everest.sh | 107 +++ e2e_tests/run-e2e-tests.sh | 93 +++ e2e_tests/test_driver/README.md | 6 + e2e_tests/test_driver/doc.go | 3 + e2e_tests/test_driver/end_to_end_test.go | 164 +++++ e2e_tests/test_driver/go.mod | 11 + e2e_tests/test_driver/go.sum | 8 + 60 files changed, 3330 insertions(+) create mode 100644 .github/workflows/end-to-end-tests.yml create mode 100644 e2e_tests/Makefile create mode 100644 e2e_tests/README.md create mode 100644 e2e_tests/docker-compose.yml create mode 100644 e2e_tests/everest/config/certificates/HUBOpenProvCert001.pem create mode 100644 e2e_tests/everest/config/certificates/HUBOpenProvCert002.pem create mode 100644 e2e_tests/everest/config/certificates/HUBOpenProvCert003.pem create mode 100644 e2e_tests/everest/config/certificates/HUBOpenProvCert005-EMP77TWTW99999-Revoked.pem create mode 100644 e2e_tests/everest/config/certificates/root-V2G-cert.pem create mode 100644 e2e_tests/everest/config/certificates/trust.pem create mode 100644 e2e_tests/everest/config/everest/README.md create mode 100644 e2e_tests/everest/config/everest/certs/ca/csms/.gitkeep create mode 100644 e2e_tests/everest/config/everest/certs/ca/cso/.gitkeep create mode 100644 e2e_tests/everest/config/everest/certs/ca/oem/.gitkeep create mode 100644 e2e_tests/everest/config/everest/certs/ca/v2g/.gitkeep create mode 100644 e2e_tests/everest/config/everest/certs/client/csms/.gitkeep create mode 100644 e2e_tests/everest/config/everest/certs/client/cso/.gitkeep create mode 100644 e2e_tests/everest/config/everest/certs/client/oem/.gitkeep create mode 100644 e2e_tests/everest/config/everest/config-sil-ocpp-pnc.yaml create mode 100644 e2e_tests/everest/config/everest/config-sil-ocpp.yaml create mode 100644 e2e_tests/everest/config/everest/config-sil-ocpp201.yaml create mode 100644 e2e_tests/everest/config/everest/default_logging.cfg create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/config.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/init.sql create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/logging.ini create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Config.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Core.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Custom.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/FirmwareManagement.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Internal.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/LocalAuthListManagement.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/PnC.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Reservation.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Security.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/SmartCharging.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP/user_config.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP201/config.json create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP201/device_model_storage.db create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP201/init_core.sql create mode 100644 e2e_tests/everest/config/everest/ocpp/OCPP201/logging.ini create mode 100644 e2e_tests/everest/config/everest/release.json create mode 100644 e2e_tests/everest/config/everest/rise_v2g/EVCCConfig.properties create mode 100644 e2e_tests/everest/config/everest/rise_v2g/SECCConfig.properties create mode 100644 e2e_tests/everest/config/everest/rise_v2g/log4j2.properties create mode 100644 e2e_tests/everest/config/everest/user-config/.gitkeep create mode 100644 e2e_tests/everest/config/everest/user-config/ocpp/user_config.json create mode 100755 e2e_tests/everest/scripts/copy-csms-cert.sh create mode 100755 e2e_tests/everest/scripts/generate-cs-cert.sh create mode 100755 e2e_tests/everest/scripts/generate-mo-cert.sh create mode 100755 e2e_tests/everest/scripts/generate-oem-cert.sh create mode 100755 e2e_tests/everest/scripts/get-ca-cert.sh create mode 100755 e2e_tests/everest/scripts/register-oem-cert.sh create mode 100755 e2e_tests/everest/scripts/setup-everest.sh create mode 100755 e2e_tests/run-e2e-tests.sh create mode 100644 e2e_tests/test_driver/README.md create mode 100644 e2e_tests/test_driver/doc.go create mode 100644 e2e_tests/test_driver/end_to_end_test.go create mode 100644 e2e_tests/test_driver/go.mod create mode 100644 e2e_tests/test_driver/go.sum diff --git a/.github/workflows/end-to-end-tests.yml b/.github/workflows/end-to-end-tests.yml new file mode 100644 index 0000000..aa91190 --- /dev/null +++ b/.github/workflows/end-to-end-tests.yml @@ -0,0 +1,22 @@ +name: End-to-End Tests +on: + push: + branches: [ '*' ] + +jobs: + build-and-test: + name: Install docker and Run E2E Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: '1.20' + - name: Install Docker Compose + run: | + sudo apt-get update + sudo apt-get install docker-compose + docker-compose --version + - name: Build docker and Run E2E Tests + run: ./e2e_tests/run-e2e-tests.sh \ No newline at end of file diff --git a/.talismanrc b/.talismanrc index bf608c8..e7cde87 100644 --- a/.talismanrc +++ b/.talismanrc @@ -11,6 +11,8 @@ fileignoreconfig: checksum: d28fa545deef6c383ac1cf401b2a9561a02ed17ffa6efdf665922580acf3e3e9 - filename: docker-compose.yml checksum: bebfd6c63f4d2a688fdda876093b7f4a95e38c331cb70bcec548b43b80c93cd7 + - filename: e2e_tests/test_driver/end_to_end_test.go + checksum: 6ef0f09822b2d48b0367364818d47c895e36c4d8d4adae4446642428942a8599 - filename: gateway/cmd/serve.go checksum: f08fe8f8c8710239376098c6e1b778d3fa9a1fb5f0653ff2a9a34e9c70d4194e - filename: gateway/registry/remote.go diff --git a/e2e_tests/Makefile b/e2e_tests/Makefile new file mode 100644 index 0000000..e24813a --- /dev/null +++ b/e2e_tests/Makefile @@ -0,0 +1,19 @@ +.PHONY: up +up: register-cs setup-rfid setup-contract + OCPP_VERSION=ocpp docker-compose --profile everest up -d + +.PHONY: test +test: # password 123456 + websocat --client-pkcs12-der ./config/certificates/cs001.pem --client-pkcs12-passwd 123456 wss://localhost:443 + +.PHONY: setup-rfid +setup-rfid: + curl -i http://localhost:9410/api/v0/token -H 'content-type: application/json' -d '{"countryCode": "GB","partyId": "TWK","type": "RFID","uid": "DEADBEEF","contractId": "GBTWK012345678V","issuer": "Thoughtworks","valid": true,"cacheMode": "ALWAYS"}' + +.PHONY: setup-contract +setup-contract: + curl -i http://localhost:9410/api/v0/token -H 'content-type: application/json' -d '{"countryCode": "GB","partyId": "TWK","type": "RFID","uid": "EMP77TWTW99999","contractId": "GBTWK012345678V","issuer": "Thoughtworks","valid": true,"cacheMode": "ALWAYS"}' + +.PHONY: register-cs +register-cs: + curl -i http://localhost:9410/api/v0/cs/cs001 -H 'content-type: application/json' -d '{"securityProfile":2}' diff --git a/e2e_tests/README.md b/e2e_tests/README.md new file mode 100644 index 0000000..970d92c --- /dev/null +++ b/e2e_tests/README.md @@ -0,0 +1,18 @@ +# End-to-end tests + +## Description + +Runs end-to-end tests against Everest (Charge station simulator) along with CSMS + + +## Steps + +1. Run the following bash script to start the docker containers for Everest and CSMS and execute the end-to-end tests +```shell +./run-e2e-tests.sh +``` + + + + + diff --git a/e2e_tests/docker-compose.yml b/e2e_tests/docker-compose.yml new file mode 100644 index 0000000..7b0830f --- /dev/null +++ b/e2e_tests/docker-compose.yml @@ -0,0 +1,52 @@ +networks: + default: + name: maeve-csms + external: true + +services: + mqtt-server: + image: ghcr.io/everest/everest-demo/mqtt-server:0.0.10 + ports: + - "1884:1883" + - "9001:9000" + user: "10000:10000" + healthcheck: + test: [ "CMD-SHELL", "timeout 5 mosquitto_sub -t '$$SYS/#' -C 1 | grep -v Error || exit 1" ] + interval: 10s + timeout: 10s + retries: 3 + + manager: + image: ghcr.io/everest/everest-demo/manager:0.0.10 + depends_on: + - mqtt-server + environment: + MQTT_SERVER_ADDRESS: mqtt-server + entrypoint: "sh ./build/run-scripts/run-sil-${OCPP_VERSION}.sh" + sysctls: + - net.ipv6.conf.all.disable_ipv6=0 + volumes: + - type: bind + source: ./everest/config/everest + target: /ext/source/config + - type: bind + source: ./everest/config/everest/ocpp/OCPP + target: /workspace/dist/share/everest/modules/OCPP + - type: bind + source: ./everest/config/everest/ocpp/OCPP201 + target: /workspace/dist/share/everest/modules/OCPP201 + - type: bind + source: ./everest/config/everest/certs + target: /workspace/dist/etc/everest/certs + + nodered: + image: ghcr.io/everest/everest-demo/nodered:0.0.10 + depends_on: + - mqtt-server + environment: + - MQTT_SERVER_ADDRESS=mqtt-server + - FLOWS=/config/config-sil-two-evse-flow.json + ports: + - 1880:1880 + sysctls: + - net.ipv6.conf.all.disable_ipv6=0 diff --git a/e2e_tests/everest/config/certificates/HUBOpenProvCert001.pem b/e2e_tests/everest/config/certificates/HUBOpenProvCert001.pem new file mode 100644 index 0000000..5fb4694 --- /dev/null +++ b/e2e_tests/everest/config/certificates/HUBOpenProvCert001.pem @@ -0,0 +1,47 @@ +-----BEGIN CERTIFICATE----- +MIIB9jCCAZygAwIBAgIQXAGaGc0odduhH6YnK05NazAKBggqhkjOPQQDAjBDMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMR0wGwYDVQQDExRNTyBT +dWIyIENBIFFBIEcxLjIuMTAeFw0yMzA1MjMxMjU1NTNaFw0yNDAzMDEwMDAwMDBa +MCsxEDAOBgNVBAoTB0h1YmplY3QxFzAVBgNVBAMTDkVNUDc3VFdUVzAwMDAyMFkw +EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUVJxF0Z81GW4LZ3fnvC+z5fn7QvPe+nx +ZBOGtzpB6RRmafqwTL9ctzWMMkaB6nuIUyyTKR0Rs+XKYJeToK7S8qOBiTCBhjAP +BgNVHRMBAf8EBTADAQEAMBEGA1UdDgQKBAhGBfp1bBhxXDATBgNVHSMEDDAKgAhF +LmmhNiJsSDA7BggrBgEFBQcBAQQvMC0wKwYIKwYBBQUHMAGGH2h0dHA6Ly9vY3Nw +LXFhLmh1YmplY3QuY29tOjgwODAwDgYDVR0PAQH/BAQDAgPoMAoGCCqGSM49BAMC +A0gAMEUCIBV5rlKEeHjernJPfzxA3HyPH742YcS8oEmUlWccrH62AiEAln/HGazM +NZqhoS5SSscViysAOQGvvcjHMKucJ5CjdLg= +-----END CERTIFICATE----- +subject=/C=DE/O=Hubject GmbH/CN=MO Sub2 CA QA G1.2.1 +issuer=/C=DE/O=Hubject GmbH/CN=MO Sub1 CA QA G1.2 +-----BEGIN CERTIFICATE----- +MIICDzCCAbWgAwIBAgIQXd9CzQy8+VxpQt9IwNrOETAKBggqhkjOPQQDAjBBMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMRswGQYDVQQDExJNTyBT +dWIxIENBIFFBIEcxLjIwHhcNMjIwNDEwMjE1OTU5WhcNMzIwNDEwMjE1OTU5WjBD +MQswCQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMR0wGwYDVQQDExRN +TyBTdWIyIENBIFFBIEcxLjIuMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGRs +p5TTDIGpB+PEwmeG8D7Pgo/WN3U35Rxhe5ttLLlyF2jlmtOPHeHxWgGb0AO7H3L6 +nso0A7Nn2KfDP8tG+OujgYwwgYkwEgYDVR0TAQH/BAgwBgEB/wIBADARBgNVHQ4E +CgQIRS5poTYibEgwEwYDVR0jBAwwCoAISw94EhgPO18wOwYIKwYBBQUHAQEELzAt +MCsGCCsGAQUFBzABhh9odHRwOi8vb2NzcC1xYS5odWJqZWN0LmNvbTo4MDgwMA4G +A1UdDwEB/wQEAwIBxjAKBggqhkjOPQQDAgNIADBFAiBqFxXTwnpm0eEgBPj/Px0k +aEvZWdyZPm7BLJVJM6fT3QIhAKZPDhuau2DcN9xrrRPqqZLjfqPSMWw1D0VlCTqC +uv2k +-----END CERTIFICATE----- + +subject=/C=DE/O=Hubject GmbH/CN=MO Sub1 CA QA G1.2 +issuer=/C=DE/O=Hubject GmbH/DC=V2G/CN=V2G Root CA QA G1 +-----BEGIN CERTIFICATE----- +MIICIjCCAcegAwIBAgIQIOuk+8fAbyXQizBVpSI55zAKBggqhkjOPQQDAjBVMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMRMwEQYKCZImiZPyLGQB +GRYDVjJHMRowGAYDVQQDExFWMkcgUm9vdCBDQSBRQSBHMTAeFw0yMjA0MDcxNDEz +MDdaFw00MjA0MDcxNDEzMDdaMEExCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxIdWJq +ZWN0IEdtYkgxGzAZBgNVBAMTEk1PIFN1YjEgQ0EgUUEgRzEuMjBZMBMGByqGSM49 +AgEGCCqGSM49AwEHA0IABLWnWSw4NPNInduDQp6H0IFgeY0WtO0F3utqV191XLIe +spoAoSIz7s4Vhf+BhbbeX+UyftbGDp2m9EjGIBhog+mjgYwwgYkwEgYDVR0TAQH/ +BAgwBgEB/wIBATARBgNVHQ4ECgQISw94EhgPO18wEwYDVR0jBAwwCoAIS0X/giX8 +EJYwOwYIKwYBBQUHAQEELzAtMCsGCCsGAQUFBzABhh9odHRwOi8vb2NzcC1xYS5o +dWJqZWN0LmNvbTo4MDgwMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAgNJADBG +AiEAsApDKLvPUVuDCtsIAnn/+prsGu5aekwd59tLiCHAFwACIQCFGJHvTz7JUrq/ +QJhQzehduW/+oaROsqOp8L3JdEO6XA== +-----END CERTIFICATE----- + diff --git a/e2e_tests/everest/config/certificates/HUBOpenProvCert002.pem b/e2e_tests/everest/config/certificates/HUBOpenProvCert002.pem new file mode 100644 index 0000000..fa529d4 --- /dev/null +++ b/e2e_tests/everest/config/certificates/HUBOpenProvCert002.pem @@ -0,0 +1,47 @@ +-----BEGIN CERTIFICATE----- +MIIB9jCCAZygAwIBAgIQWg+8k4JcqPIZeX5bj3LoBzAKBggqhkjOPQQDAjBDMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMR0wGwYDVQQDExRNTyBT +dWIyIENBIFFBIEcxLjIuMTAeFw0yMzA1MjMxMjU3MDlaFw0yNDAzMDEwMDAwMDBa +MCsxEDAOBgNVBAoTB0h1YmplY3QxFzAVBgNVBAMTDkVNUDc3VFdUVzAwMDAzMFkw +EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKsUiYDu/OGHjKEq39spSiS6CdE9q4jg6 +ysuA3ACCKCH5S9Y8YGqy73Dy+fHUZpdzFOAPoYJEK4srYAwgH221z6OBiTCBhjAP +BgNVHRMBAf8EBTADAQEAMBEGA1UdDgQKBAhJFUMGc8ldDzATBgNVHSMEDDAKgAhF +LmmhNiJsSDA7BggrBgEFBQcBAQQvMC0wKwYIKwYBBQUHMAGGH2h0dHA6Ly9vY3Nw +LXFhLmh1YmplY3QuY29tOjgwODAwDgYDVR0PAQH/BAQDAgPoMAoGCCqGSM49BAMC +A0gAMEUCIBYBkDz5gexjKLYJsQZua4AktjO6IqYSFXp9bJ2MOE6/AiEA3iAuGdty +i24pSc5F8qCbDQKnNASWWMrFVOOJFVh1n7c= +-----END CERTIFICATE----- +subject=/C=DE/O=Hubject GmbH/CN=MO Sub2 CA QA G1.2.1 +issuer=/C=DE/O=Hubject GmbH/CN=MO Sub1 CA QA G1.2 +-----BEGIN CERTIFICATE----- +MIICDzCCAbWgAwIBAgIQXd9CzQy8+VxpQt9IwNrOETAKBggqhkjOPQQDAjBBMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMRswGQYDVQQDExJNTyBT +dWIxIENBIFFBIEcxLjIwHhcNMjIwNDEwMjE1OTU5WhcNMzIwNDEwMjE1OTU5WjBD +MQswCQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMR0wGwYDVQQDExRN +TyBTdWIyIENBIFFBIEcxLjIuMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGRs +p5TTDIGpB+PEwmeG8D7Pgo/WN3U35Rxhe5ttLLlyF2jlmtOPHeHxWgGb0AO7H3L6 +nso0A7Nn2KfDP8tG+OujgYwwgYkwEgYDVR0TAQH/BAgwBgEB/wIBADARBgNVHQ4E +CgQIRS5poTYibEgwEwYDVR0jBAwwCoAISw94EhgPO18wOwYIKwYBBQUHAQEELzAt +MCsGCCsGAQUFBzABhh9odHRwOi8vb2NzcC1xYS5odWJqZWN0LmNvbTo4MDgwMA4G +A1UdDwEB/wQEAwIBxjAKBggqhkjOPQQDAgNIADBFAiBqFxXTwnpm0eEgBPj/Px0k +aEvZWdyZPm7BLJVJM6fT3QIhAKZPDhuau2DcN9xrrRPqqZLjfqPSMWw1D0VlCTqC +uv2k +-----END CERTIFICATE----- + +subject=/C=DE/O=Hubject GmbH/CN=MO Sub1 CA QA G1.2 +issuer=/C=DE/O=Hubject GmbH/DC=V2G/CN=V2G Root CA QA G1 +-----BEGIN CERTIFICATE----- +MIICIjCCAcegAwIBAgIQIOuk+8fAbyXQizBVpSI55zAKBggqhkjOPQQDAjBVMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMRMwEQYKCZImiZPyLGQB +GRYDVjJHMRowGAYDVQQDExFWMkcgUm9vdCBDQSBRQSBHMTAeFw0yMjA0MDcxNDEz +MDdaFw00MjA0MDcxNDEzMDdaMEExCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxIdWJq +ZWN0IEdtYkgxGzAZBgNVBAMTEk1PIFN1YjEgQ0EgUUEgRzEuMjBZMBMGByqGSM49 +AgEGCCqGSM49AwEHA0IABLWnWSw4NPNInduDQp6H0IFgeY0WtO0F3utqV191XLIe +spoAoSIz7s4Vhf+BhbbeX+UyftbGDp2m9EjGIBhog+mjgYwwgYkwEgYDVR0TAQH/ +BAgwBgEB/wIBATARBgNVHQ4ECgQISw94EhgPO18wEwYDVR0jBAwwCoAIS0X/giX8 +EJYwOwYIKwYBBQUHAQEELzAtMCsGCCsGAQUFBzABhh9odHRwOi8vb2NzcC1xYS5o +dWJqZWN0LmNvbTo4MDgwMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAgNJADBG +AiEAsApDKLvPUVuDCtsIAnn/+prsGu5aekwd59tLiCHAFwACIQCFGJHvTz7JUrq/ +QJhQzehduW/+oaROsqOp8L3JdEO6XA== +-----END CERTIFICATE----- + diff --git a/e2e_tests/everest/config/certificates/HUBOpenProvCert003.pem b/e2e_tests/everest/config/certificates/HUBOpenProvCert003.pem new file mode 100644 index 0000000..c28ce7d --- /dev/null +++ b/e2e_tests/everest/config/certificates/HUBOpenProvCert003.pem @@ -0,0 +1,47 @@ +-----BEGIN CERTIFICATE----- +MIIB9jCCAZygAwIBAgIQZ/iEHFFyEM7joJp41zEGOzAKBggqhkjOPQQDAjBDMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMR0wGwYDVQQDExRNTyBT +dWIyIENBIFFBIEcxLjIuMTAeFw0yMzA1MjMxMjU3MjZaFw0yNDAzMDEwMDAwMDBa +MCsxEDAOBgNVBAoTB0h1YmplY3QxFzAVBgNVBAMTDkVNUDc3VFdUVzAwMDA1MFkw +EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE94PGl/toW+FCYVVMJum/2h1QotR8275q +pCdFOrAUDTSxKBkj1hQcaGMYx2AUkmqljcq6htB6rZclDjmEKlqOrqOBiTCBhjAP +BgNVHRMBAf8EBTADAQEAMBEGA1UdDgQKBAhPvTG0pH/qpzATBgNVHSMEDDAKgAhF +LmmhNiJsSDA7BggrBgEFBQcBAQQvMC0wKwYIKwYBBQUHMAGGH2h0dHA6Ly9vY3Nw +LXFhLmh1YmplY3QuY29tOjgwODAwDgYDVR0PAQH/BAQDAgPoMAoGCCqGSM49BAMC +A0gAMEUCIQDCBvO4dcgI3lqyG6Ks1W5fY5/P3vWWmv9Cv55reGiExgIgI7SkY1qL +bjZaCXkZpGBaKzHLV0tUtewazKJQfYwDkyE= +-----END CERTIFICATE----- +subject=/C=DE/O=Hubject GmbH/CN=MO Sub2 CA QA G1.2.1 +issuer=/C=DE/O=Hubject GmbH/CN=MO Sub1 CA QA G1.2 +-----BEGIN CERTIFICATE----- +MIICDzCCAbWgAwIBAgIQXd9CzQy8+VxpQt9IwNrOETAKBggqhkjOPQQDAjBBMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMRswGQYDVQQDExJNTyBT +dWIxIENBIFFBIEcxLjIwHhcNMjIwNDEwMjE1OTU5WhcNMzIwNDEwMjE1OTU5WjBD +MQswCQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMR0wGwYDVQQDExRN +TyBTdWIyIENBIFFBIEcxLjIuMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGRs +p5TTDIGpB+PEwmeG8D7Pgo/WN3U35Rxhe5ttLLlyF2jlmtOPHeHxWgGb0AO7H3L6 +nso0A7Nn2KfDP8tG+OujgYwwgYkwEgYDVR0TAQH/BAgwBgEB/wIBADARBgNVHQ4E +CgQIRS5poTYibEgwEwYDVR0jBAwwCoAISw94EhgPO18wOwYIKwYBBQUHAQEELzAt +MCsGCCsGAQUFBzABhh9odHRwOi8vb2NzcC1xYS5odWJqZWN0LmNvbTo4MDgwMA4G +A1UdDwEB/wQEAwIBxjAKBggqhkjOPQQDAgNIADBFAiBqFxXTwnpm0eEgBPj/Px0k +aEvZWdyZPm7BLJVJM6fT3QIhAKZPDhuau2DcN9xrrRPqqZLjfqPSMWw1D0VlCTqC +uv2k +-----END CERTIFICATE----- + +subject=/C=DE/O=Hubject GmbH/CN=MO Sub1 CA QA G1.2 +issuer=/C=DE/O=Hubject GmbH/DC=V2G/CN=V2G Root CA QA G1 +-----BEGIN CERTIFICATE----- +MIICIjCCAcegAwIBAgIQIOuk+8fAbyXQizBVpSI55zAKBggqhkjOPQQDAjBVMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMRMwEQYKCZImiZPyLGQB +GRYDVjJHMRowGAYDVQQDExFWMkcgUm9vdCBDQSBRQSBHMTAeFw0yMjA0MDcxNDEz +MDdaFw00MjA0MDcxNDEzMDdaMEExCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxIdWJq +ZWN0IEdtYkgxGzAZBgNVBAMTEk1PIFN1YjEgQ0EgUUEgRzEuMjBZMBMGByqGSM49 +AgEGCCqGSM49AwEHA0IABLWnWSw4NPNInduDQp6H0IFgeY0WtO0F3utqV191XLIe +spoAoSIz7s4Vhf+BhbbeX+UyftbGDp2m9EjGIBhog+mjgYwwgYkwEgYDVR0TAQH/ +BAgwBgEB/wIBATARBgNVHQ4ECgQISw94EhgPO18wEwYDVR0jBAwwCoAIS0X/giX8 +EJYwOwYIKwYBBQUHAQEELzAtMCsGCCsGAQUFBzABhh9odHRwOi8vb2NzcC1xYS5o +dWJqZWN0LmNvbTo4MDgwMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAgNJADBG +AiEAsApDKLvPUVuDCtsIAnn/+prsGu5aekwd59tLiCHAFwACIQCFGJHvTz7JUrq/ +QJhQzehduW/+oaROsqOp8L3JdEO6XA== +-----END CERTIFICATE----- + diff --git a/e2e_tests/everest/config/certificates/HUBOpenProvCert005-EMP77TWTW99999-Revoked.pem b/e2e_tests/everest/config/certificates/HUBOpenProvCert005-EMP77TWTW99999-Revoked.pem new file mode 100644 index 0000000..3ddfadc --- /dev/null +++ b/e2e_tests/everest/config/certificates/HUBOpenProvCert005-EMP77TWTW99999-Revoked.pem @@ -0,0 +1,47 @@ +-----BEGIN CERTIFICATE----- +MIIB9jCCAZygAwIBAgIQazcroeTeaDS6WpsfbBP3JTAKBggqhkjOPQQDAjBDMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMR0wGwYDVQQDExRNTyBT +dWIyIENBIFFBIEcxLjIuMTAeFw0yMzA1MjMxMjU3NDNaFw0yNDAzMDEwMDAwMDBa +MCsxEDAOBgNVBAoTB0h1YmplY3QxFzAVBgNVBAMTDkVNUDc3VFdUVzk5OTk5MFkw +EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhCgvKb4w3S/VxeaV/EG1CNF8cF3J+so3 +YNj3T43tbrSb1ocDrge2nfQrWCMurEtPHvYQ4MVjvDDbQpVx8Hps1qOBiTCBhjAP +BgNVHRMBAf8EBTADAQEAMBEGA1UdDgQKBAhHKJn2kLZBoTATBgNVHSMEDDAKgAhF +LmmhNiJsSDA7BggrBgEFBQcBAQQvMC0wKwYIKwYBBQUHMAGGH2h0dHA6Ly9vY3Nw +LXFhLmh1YmplY3QuY29tOjgwODAwDgYDVR0PAQH/BAQDAgPoMAoGCCqGSM49BAMC +A0gAMEUCICMpsI6btdkUvEs5pRUCSPl6ks+qX+MO9cCTrNVNJ+UZAiEA/8bm+eYr +FiaWO2Nym5joYn2CJVhripcDioniaYyPAhg= +-----END CERTIFICATE----- +subject=/C=DE/O=Hubject GmbH/CN=MO Sub2 CA QA G1.2.1 +issuer=/C=DE/O=Hubject GmbH/CN=MO Sub1 CA QA G1.2 +-----BEGIN CERTIFICATE----- +MIICDzCCAbWgAwIBAgIQXd9CzQy8+VxpQt9IwNrOETAKBggqhkjOPQQDAjBBMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMRswGQYDVQQDExJNTyBT +dWIxIENBIFFBIEcxLjIwHhcNMjIwNDEwMjE1OTU5WhcNMzIwNDEwMjE1OTU5WjBD +MQswCQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMR0wGwYDVQQDExRN +TyBTdWIyIENBIFFBIEcxLjIuMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGRs +p5TTDIGpB+PEwmeG8D7Pgo/WN3U35Rxhe5ttLLlyF2jlmtOPHeHxWgGb0AO7H3L6 +nso0A7Nn2KfDP8tG+OujgYwwgYkwEgYDVR0TAQH/BAgwBgEB/wIBADARBgNVHQ4E +CgQIRS5poTYibEgwEwYDVR0jBAwwCoAISw94EhgPO18wOwYIKwYBBQUHAQEELzAt +MCsGCCsGAQUFBzABhh9odHRwOi8vb2NzcC1xYS5odWJqZWN0LmNvbTo4MDgwMA4G +A1UdDwEB/wQEAwIBxjAKBggqhkjOPQQDAgNIADBFAiBqFxXTwnpm0eEgBPj/Px0k +aEvZWdyZPm7BLJVJM6fT3QIhAKZPDhuau2DcN9xrrRPqqZLjfqPSMWw1D0VlCTqC +uv2k +-----END CERTIFICATE----- + +subject=/C=DE/O=Hubject GmbH/CN=MO Sub1 CA QA G1.2 +issuer=/C=DE/O=Hubject GmbH/DC=V2G/CN=V2G Root CA QA G1 +-----BEGIN CERTIFICATE----- +MIICIjCCAcegAwIBAgIQIOuk+8fAbyXQizBVpSI55zAKBggqhkjOPQQDAjBVMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMRMwEQYKCZImiZPyLGQB +GRYDVjJHMRowGAYDVQQDExFWMkcgUm9vdCBDQSBRQSBHMTAeFw0yMjA0MDcxNDEz +MDdaFw00MjA0MDcxNDEzMDdaMEExCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxIdWJq +ZWN0IEdtYkgxGzAZBgNVBAMTEk1PIFN1YjEgQ0EgUUEgRzEuMjBZMBMGByqGSM49 +AgEGCCqGSM49AwEHA0IABLWnWSw4NPNInduDQp6H0IFgeY0WtO0F3utqV191XLIe +spoAoSIz7s4Vhf+BhbbeX+UyftbGDp2m9EjGIBhog+mjgYwwgYkwEgYDVR0TAQH/ +BAgwBgEB/wIBATARBgNVHQ4ECgQISw94EhgPO18wEwYDVR0jBAwwCoAIS0X/giX8 +EJYwOwYIKwYBBQUHAQEELzAtMCsGCCsGAQUFBzABhh9odHRwOi8vb2NzcC1xYS5o +dWJqZWN0LmNvbTo4MDgwMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAgNJADBG +AiEAsApDKLvPUVuDCtsIAnn/+prsGu5aekwd59tLiCHAFwACIQCFGJHvTz7JUrq/ +QJhQzehduW/+oaROsqOp8L3JdEO6XA== +-----END CERTIFICATE----- + diff --git a/e2e_tests/everest/config/certificates/root-V2G-cert.pem b/e2e_tests/everest/config/certificates/root-V2G-cert.pem new file mode 100644 index 0000000..caa8de6 --- /dev/null +++ b/e2e_tests/everest/config/certificates/root-V2G-cert.pem @@ -0,0 +1,17 @@ +subject=C=DE, O=Hubject GmbH, DC=V2G, CN=V2G Root CA QA G1 +issuer=C=DE, O=Hubject GmbH, DC=V2G, CN=V2G Root CA QA G1 +-----BEGIN CERTIFICATE----- +MIICUzCCAfmgAwIBAgIQaasA0lm730LOgFKa0wzl7TAKBggqhkjOPQQDAjBVMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMRMwEQYKCZImiZPyLGQB +GRYDVjJHMRowGAYDVQQDExFWMkcgUm9vdCBDQSBRQSBHMTAgFw0xOTA0MjYwODM3 +MTVaGA8yMDU5MDQyNjA4MzcxNVowVTELMAkGA1UEBhMCREUxFTATBgNVBAoTDEh1 +YmplY3QgR21iSDETMBEGCgmSJomT8ixkARkWA1YyRzEaMBgGA1UEAxMRVjJHIFJv +b3QgQ0EgUUEgRzEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAShT8kSNcC+74TN +D82On2Y2TOf8mYfxw73lKZ7t9cmEXHpMdAgsWBQ4LI+pOMhe6NOHzJbzP38kQTg4 +zLfw3kU0o4GoMIGlMBMGA1UdJQQMMAoGCCsGAQUFBwMJMA8GA1UdEwEB/wQFMAMB +Af8wEQYDVR0OBAoECEtF/4Il/BCWMEUGA1UdIAQ+MDwwOgYMKwYBBAGCxDUBAgEA +MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3Lmh1YmplY3QuY29tL3BraS8wEwYD +VR0jBAwwCoAIS0X/giX8EJYwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMCA0gA +MEUCIQCq3Qx2BLYVFb7Lt5XXpSlUViYv4cIUOQE1Ce9o2Jyy1QIgZRmVzMVjHZA+ +toiM000PCUrLppqbLpcRN4MP8kE0OhU= +-----END CERTIFICATE----- diff --git a/e2e_tests/everest/config/certificates/trust.pem b/e2e_tests/everest/config/certificates/trust.pem new file mode 100644 index 0000000..9439e9f --- /dev/null +++ b/e2e_tests/everest/config/certificates/trust.pem @@ -0,0 +1,16 @@ +subject=C=DE, O=Hubject GmbH, CN=CPO Sub1 CA QA G1.2 +issuer=C=DE, O=Hubject GmbH, DC=V2G, CN=V2G Root CA QA G1 +-----BEGIN CERTIFICATE----- +MIICIjCCAcigAwIBAgIQcNHZPf7SMsnpLbJvOgtUYjAKBggqhkjOPQQDAjBVMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMSHViamVjdCBHbWJIMRMwEQYKCZImiZPyLGQB +GRYDVjJHMRowGAYDVQQDExFWMkcgUm9vdCBDQSBRQSBHMTAeFw0yMjA0MDcxNDEx +MjBaFw0yNjA0MDcxNDExMjBaMEIxCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxIdWJq +ZWN0IEdtYkgxHDAaBgNVBAMTE0NQTyBTdWIxIENBIFFBIEcxLjIwWTATBgcqhkjO +PQIBBggqhkjOPQMBBwNCAAQu+9a26mDSIAgSACu3WCOth7bcQnJhqmMa+OYlCnc8 ++QMhgl1wLS15agYgDptdD5kJK+jt/CYRFZ4alwrXCf2po4GMMIGJMBIGA1UdEwEB +/wQIMAYBAf8CAQEwEQYDVR0OBAoECEAU+/DnqWOsMBMGA1UdIwQMMAqACEtF/4Il +/BCWMDsGCCsGAQUFBwEBBC8wLTArBggrBgEFBQcwAYYfaHR0cDovL29jc3AtcWEu +aHViamVjdC5jb206ODA4MDAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwIDSAAw +RQIhAL/4EvlWVR6+Z7+efMrttafXPoUfQWqqv1xIkGRo1wPQAiBbEmj7MeHZwV23 +XPHkCjWCfzHwYlvQ4c8Cwo8ndW6law== +-----END CERTIFICATE----- diff --git a/e2e_tests/everest/config/everest/README.md b/e2e_tests/everest/config/everest/README.md new file mode 100644 index 0000000..3e2db13 --- /dev/null +++ b/e2e_tests/everest/config/everest/README.md @@ -0,0 +1,97 @@ +# Configuring EVerest + +There are two configuration files for EVerest: + +For OCPP 2.0.1 +* [config-sil-ocpp201.yaml](config-sil-ocpp201.yaml) +* [ocpp/OCPP201/config.json](ocpp/OCPP201/config.json) + +For OCPP 1.6 +* [config-sil-ocpp.yaml](config-sil-ocpp.yaml) +* [ocpp/OCPP/config.json](ocpp/OCPP/config.json) + +In addition, there are various certificates that can be configured. + +## Overview + +There are three parts to the main configuration file: +* settings +* active_modules +* x-module-layout + +There is a [schema file](https://github.com/EVerest/everest-framework/blob/main/schemas/config.yaml) +that describes the syntax for the configuration file. + +### Settings + +There are a number of settings that we may configure. However, the principal setting is the address +of the MQTT broker which is set via the: `mqtt_broker_host` and `mqtt_broker_port` settings. The host +defaults to `localhost` and the port defaults to `1883`. These settings can also be overridden using +the environment variables `MQTT_SERVER_ADDRESS` and `MQTT_SERVER_PORT`. + +### Active Modules + +EVerest has a modular structure and these modules are connected via MQTT. The set of modules +is configured in the [config-sil-ocpp201.yaml](config-sil-ocpp201.yaml) file. Each module +takes a set of configuration parameters and sets up links to other modules. + +You can see the configuration options, provided and consumed interfaces by looking at the +manifest files associated with each module. These can be found in the +[EVerest core modules directory](https://github.com/EVerest/everest-core/tree/main/modules). + +The configuration is complex and requires a deep understanding of EVerest so we are using +sample configurations from the +[EVerest core config directory](https://github.com/EVerest/everest-core/tree/main/config) +and then tweaking them. + +### Module Layout + +The `x-module-layout` key contains details of how to layout the modules in the management +UI. It has no other meaning beyond that. + +## OCPP + +There is a separate file for configuring OCPP. This is consumed by the EVerest dependency +[libocpp](https://github.com/EVerest/libocpp). Many of the sections in this configuration +have an almost 1:1 correspondence with Appendix 3 of the OCPP specification. However, there +are some additional sections. + +The `InternalCtrlr` section provides a number of details about the charge station that will +be sent to the central system as part of a boot notification: +* ChargePointId +* ChargeBoxSerialNumber +* ChargePointModel +* ChargePointVendor + +There are also details used for connecting to the central system: +* CentralSystemURI +* SupportedCiphers12 +* SupportedCiphers13 +* WebsocketReconnectInterval + +Within the `SecurityCtrlr` section: + +`SecurityProfile` specifies the security profile used when connecting: +* `1`: Basic auth over unsecured connection +* `2`: Basic auth over TLS +* `3`: Certificate auth over TLS + +Additional examples of configuration files can be found in: +* [OCPP 1.6 configs](https://github.com/EVerest/libocpp/tree/main/config/v16) +* [OCPP 2.0.1 configs](https://github.com/EVerest/libocpp/tree/main/config/v201) + +Schemas showing all the configuration options can be found in: +* [OCPP 1.6 schemas](https://github.com/EVerest/libocpp/tree/main/config/v16/profile_schemas) +* [OCPP 2.0.1 schemas](https://github.com/EVerest/libocpp/tree/main/config/v201/component_schemas) + +## Certificates + +The trusted CSMS CA certificate must be added to the `certs/ca/csms` +directory. If it is a DER encoded certificate then it must have a `.der` extension, +otherwise it is assumed to be a PEM encoded file. + +The client certificate details must be added to the `certs/client/csms` +directory. The certificate and key must be PEM encoded and called `CSMS_LEAF.pem` and +`CSMS_LEAF.key` respectively. + + diff --git a/e2e_tests/everest/config/everest/certs/ca/csms/.gitkeep b/e2e_tests/everest/config/everest/certs/ca/csms/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/e2e_tests/everest/config/everest/certs/ca/cso/.gitkeep b/e2e_tests/everest/config/everest/certs/ca/cso/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/e2e_tests/everest/config/everest/certs/ca/oem/.gitkeep b/e2e_tests/everest/config/everest/certs/ca/oem/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/e2e_tests/everest/config/everest/certs/ca/v2g/.gitkeep b/e2e_tests/everest/config/everest/certs/ca/v2g/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/e2e_tests/everest/config/everest/certs/client/csms/.gitkeep b/e2e_tests/everest/config/everest/certs/client/csms/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/e2e_tests/everest/config/everest/certs/client/cso/.gitkeep b/e2e_tests/everest/config/everest/certs/client/cso/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/e2e_tests/everest/config/everest/certs/client/oem/.gitkeep b/e2e_tests/everest/config/everest/certs/client/oem/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/e2e_tests/everest/config/everest/config-sil-ocpp-pnc.yaml b/e2e_tests/everest/config/everest/config-sil-ocpp-pnc.yaml new file mode 100644 index 0000000..6479188 --- /dev/null +++ b/e2e_tests/everest/config/everest/config-sil-ocpp-pnc.yaml @@ -0,0 +1,197 @@ +active_modules: + iso15118_charger: + module: EvseV2G + config_module: + device: auto + tls_security: allow + verify_contract_cert_chain: true + connections: + security: + - module_id: evse_security + implementation_id: main + iso15118_car: + module: PyEvJosev + config_module: + device: auto + supported_ISO15118_2: true + tls_active: true + is_cert_install_needed: true + evse_manager_1: + module: EvseManager + config_module: + connector_id: 1 + three_phases: true + has_ventilation: true + country_code: DE + rcd_enabled: true + evse_id: "DE*PNX*00001" + session_logging: true + session_logging_xml: false + session_logging_path: /tmp/everest-logs + ac_hlc_enabled: true + ac_hlc_use_5percent: false + ac_enforce_hlc: false + connections: + bsp: + - module_id: yeti_driver_1 + implementation_id: board_support + powermeter_grid_side: + - module_id: yeti_driver_1 + implementation_id: powermeter + slac: + - module_id: slac + implementation_id: evse + hlc: + - module_id: iso15118_charger + implementation_id: charger + evse_manager_2: + module: EvseManager + config_module: + connector_id: 2 + three_phases: true + has_ventilation: true + country_code: DE + rcd_enabled: true + evse_id: "2" + session_logging: true + session_logging_xml: false + session_logging_path: /tmp + ac_hlc_enabled: false + ac_hlc_use_5percent: false + ac_enforce_hlc: false + connections: + bsp: + - module_id: yeti_driver_2 + implementation_id: board_support + powermeter_grid_side: + - module_id: yeti_driver_2 + implementation_id: powermeter + slac: + - module_id: slac + implementation_id: evse + hlc: + - module_id: iso15118_charger + implementation_id: charger + yeti_driver_1: + module: JsYetiSimulator + yeti_driver_2: + module: JsYetiSimulator + slac: + module: JsSlacSimulator + car_simulator_1: + module: JsCarSimulator + config_module: + connector_id: 1 + auto_enable: true + auto_exec: false + auto_exec_commands: sleep 1;iec_wait_pwr_ready;sleep 1;draw_power_regulated 16,3;sleep 30;unplug + connections: + simulation_control: + - module_id: yeti_driver_1 + implementation_id: yeti_simulation_control + ev: + - module_id: iso15118_car + implementation_id: ev + slac: + - module_id: slac + implementation_id: ev + car_simulator_2: + module: JsCarSimulator + config_module: + connector_id: 2 + auto_enable: true + auto_exec: false + connections: + simulation_control: + - module_id: yeti_driver_2 + implementation_id: yeti_simulation_control + ev: + - module_id: iso15118_car + implementation_id: ev + slac: + - module_id: slac + implementation_id: ev + auth: + module: Auth + config_module: + connection_timeout: 120 + selection_algorithm: PlugEvents + connections: + token_provider: + - module_id: token_provider_1 + implementation_id: main + - module_id: ocpp + implementation_id: auth_provider + - module_id: evse_manager_1 + implementation_id: token_provider + - module_id: evse_manager_2 + implementation_id: token_provider + token_validator: + - module_id: ocpp + implementation_id: auth_validator + evse_manager: + - module_id: evse_manager_1 + implementation_id: evse + - module_id: evse_manager_2 + implementation_id: evse + ocpp: + module: OCPP + config_module: + ChargePointConfigPath: config.json + PublishChargingScheduleIntervalS: 0 + connections: + evse_manager: + - module_id: evse_manager_1 + implementation_id: evse + - module_id: evse_manager_2 + implementation_id: evse + reservation: + - module_id: auth + implementation_id: reservation + auth: + - module_id: auth + implementation_id: main + system: + - module_id: system + implementation_id: main + security: + - module_id: evse_security + implementation_id: main + evse_security: + module: EvseSecurity + config_module: + csms_ca_bundle: ca/csms/csms.pem + private_key_password: "123456" + token_provider_1: + module: DummyTokenProviderManual + energy_manager: + module: EnergyManager + connections: + energy_trunk: + - module_id: grid_connection_point + implementation_id: energy_grid + grid_connection_point: + module: EnergyNode + config_module: + fuse_limit_A: 40.0 + phase_count: 3 + connections: + price_information: [] + energy_consumer: + - module_id: evse_manager_1 + implementation_id: energy_grid + - module_id: evse_manager_2 + implementation_id: energy_grid + powermeter: + - module_id: yeti_driver_1 + implementation_id: powermeter + api: + module: API + connections: + evse_manager: + - module_id: evse_manager_1 + implementation_id: evse + system: + module: System + +x-module-layout: {} diff --git a/e2e_tests/everest/config/everest/config-sil-ocpp.yaml b/e2e_tests/everest/config/everest/config-sil-ocpp.yaml new file mode 100644 index 0000000..ca6e3f1 --- /dev/null +++ b/e2e_tests/everest/config/everest/config-sil-ocpp.yaml @@ -0,0 +1,189 @@ +active_modules: + iso15118_charger: + module: EvseV2G + config_module: + device: auto + tls_security: allow + connections: + security: + - module_id: evse_security + implementation_id: main + iso15118_car: + module: PyEvJosev + config_module: + device: auto + supported_ISO15118_2: true + evse_manager_1: + module: EvseManager + config_module: + connector_id: 1 + three_phases: true + has_ventilation: true + country_code: DE + rcd_enabled: true + evse_id: "1" + session_logging: true + session_logging_xml: false + session_logging_path: /tmp/everest-logs + ac_hlc_enabled: false + ac_hlc_use_5percent: false + ac_enforce_hlc: false + connections: + bsp: + - module_id: yeti_driver_1 + implementation_id: board_support + powermeter_grid_side: + - module_id: yeti_driver_1 + implementation_id: powermeter + slac: + - module_id: slac + implementation_id: evse + hlc: + - module_id: iso15118_charger + implementation_id: charger + evse_manager_2: + module: EvseManager + config_module: + connector_id: 2 + three_phases: true + has_ventilation: true + country_code: DE + rcd_enabled: true + evse_id: "2" + session_logging: true + session_logging_xml: false + session_logging_path: /tmp + ac_hlc_enabled: false + ac_hlc_use_5percent: false + ac_enforce_hlc: false + connections: + bsp: + - module_id: yeti_driver_2 + implementation_id: board_support + powermeter_grid_side: + - module_id: yeti_driver_2 + implementation_id: powermeter + slac: + - module_id: slac + implementation_id: evse + hlc: + - module_id: iso15118_charger + implementation_id: charger + yeti_driver_1: + module: JsYetiSimulator + yeti_driver_2: + module: JsYetiSimulator + slac: + module: JsSlacSimulator + car_simulator_1: + module: JsCarSimulator + config_module: + connector_id: 1 + auto_enable: true + auto_exec: false + auto_exec_commands: sleep 1;iec_wait_pwr_ready;sleep 1;draw_power_regulated 16,3;sleep 30;unplug + connections: + simulation_control: + - module_id: yeti_driver_1 + implementation_id: yeti_simulation_control + ev: + - module_id: iso15118_car + implementation_id: ev + slac: + - module_id: slac + implementation_id: ev + car_simulator_2: + module: JsCarSimulator + config_module: + connector_id: 2 + auto_enable: true + auto_exec: false + connections: + simulation_control: + - module_id: yeti_driver_2 + implementation_id: yeti_simulation_control + ev: + - module_id: iso15118_car + implementation_id: ev + slac: + - module_id: slac + implementation_id: ev + auth: + module: Auth + config_module: + connection_timeout: 10 + selection_algorithm: FindFirst + connections: + token_provider: + - module_id: token_provider_1 + implementation_id: main + - module_id: ocpp + implementation_id: auth_provider + token_validator: + - module_id: ocpp + implementation_id: auth_validator + evse_manager: + - module_id: evse_manager_1 + implementation_id: evse + - module_id: evse_manager_2 + implementation_id: evse + ocpp: + module: OCPP + config_module: + ChargePointConfigPath: config.json + connections: + evse_manager: + - module_id: evse_manager_1 + implementation_id: evse + - module_id: evse_manager_2 + implementation_id: evse + reservation: + - module_id: auth + implementation_id: reservation + auth: + - module_id: auth + implementation_id: main + system: + - module_id: system + implementation_id: main + security: + - module_id: evse_security + implementation_id: main + evse_security: + module: EvseSecurity + config_module: + csms_ca_bundle: ca/csms/csms.pem + private_key_password: "123456" + token_provider_1: + module: DummyTokenProviderManual + energy_manager: + module: EnergyManager + connections: + energy_trunk: + - module_id: grid_connection_point + implementation_id: energy_grid + grid_connection_point: + module: EnergyNode + config_module: + fuse_limit_A: 40.0 + phase_count: 3 + connections: + price_information: [] + energy_consumer: + - module_id: evse_manager_1 + implementation_id: energy_grid + - module_id: evse_manager_2 + implementation_id: energy_grid + powermeter: + - module_id: yeti_driver_1 + implementation_id: powermeter + api: + module: API + connections: + evse_manager: + - module_id: evse_manager_1 + implementation_id: evse + system: + module: System + +x-module-layout: {} diff --git a/e2e_tests/everest/config/everest/config-sil-ocpp201.yaml b/e2e_tests/everest/config/everest/config-sil-ocpp201.yaml new file mode 100644 index 0000000..a523fd7 --- /dev/null +++ b/e2e_tests/everest/config/everest/config-sil-ocpp201.yaml @@ -0,0 +1,188 @@ +active_modules: + iso15118_charger: + module: EvseV2G + config_module: + device: auto + tls_security: allow + connections: + security: + - module_id: evse_security + implementation_id: main + iso15118_car: + module: PyEvJosev + config_module: + device: auto + supported_ISO15118_2: true + evse_manager_1: + module: EvseManager + config_module: + connector_id: 1 + three_phases: true + has_ventilation: true + country_code: DE + rcd_enabled: true + evse_id: "1" + session_logging: true + session_logging_xml: false + session_logging_path: /tmp + ac_hlc_enabled: false + ac_hlc_use_5percent: false + ac_enforce_hlc: false + connections: + bsp: + - module_id: yeti_driver_1 + implementation_id: board_support + powermeter_grid_side: + - module_id: yeti_driver_1 + implementation_id: powermeter + slac: + - module_id: slac + implementation_id: evse + hlc: + - module_id: iso15118_charger + implementation_id: charger + evse_manager_2: + module: EvseManager + config_module: + connector_id: 2 + three_phases: true + has_ventilation: true + country_code: DE + rcd_enabled: true + evse_id: "2" + session_logging: true + session_logging_xml: false + session_logging_path: /tmp + ac_hlc_enabled: false + ac_hlc_use_5percent: false + ac_enforce_hlc: false + connections: + bsp: + - module_id: yeti_driver_2 + implementation_id: board_support + powermeter_grid_side: + - module_id: yeti_driver_2 + implementation_id: powermeter + slac: + - module_id: slac + implementation_id: evse + hlc: + - module_id: iso15118_charger + implementation_id: charger + yeti_driver_1: + module: JsYetiSimulator + yeti_driver_2: + module: JsYetiSimulator + slac: + module: JsSlacSimulator + car_simulator_1: + module: JsCarSimulator + config_module: + connector_id: 1 + auto_enable: true + auto_exec: false + auto_exec_commands: sleep 1;iec_wait_pwr_ready;sleep 1;draw_power_regulated 16,3;sleep 30;unplug + connections: + simulation_control: + - module_id: yeti_driver_1 + implementation_id: yeti_simulation_control + ev: + - module_id: iso15118_car + implementation_id: ev + slac: + - module_id: slac + implementation_id: ev + car_simulator_2: + module: JsCarSimulator + config_module: + connector_id: 2 + auto_enable: true + auto_exec: false + connections: + simulation_control: + - module_id: yeti_driver_2 + implementation_id: yeti_simulation_control + ev: + - module_id: iso15118_car + implementation_id: ev + slac: + - module_id: slac + implementation_id: ev + ocpp: + module: OCPP201 + config_module: + ChargePointConfigPath: config.json + connections: + evse_manager: + - module_id: evse_manager_1 + implementation_id: evse + - module_id: evse_manager_2 + implementation_id: evse + system: + - module_id: system + implementation_id: main + security: + - module_id: evse_security + implementation_id: main + kvs: + - module_id: persistent_store + implementation_id: main + persistent_store: + module: PersistentStore + evse_security: + module: EvseSecurity + config_module: + csms_ca_bundle: ca/csms/csms.pem + private_key_password: "123456" + token_provider_1: + module: DummyTokenProviderManual + auth: + module: Auth + config_module: + connection_timeout: 60 + selection_algorithm: FindFirst + connections: + token_provider: + - module_id: token_provider_1 + implementation_id: main + - module_id: ocpp + implementation_id: auth_provider + token_validator: + - module_id: ocpp + implementation_id: auth_validator + evse_manager: + - module_id: evse_manager_1 + implementation_id: evse + - module_id: evse_manager_2 + implementation_id: evse + energy_manager: + module: EnergyManager + connections: + energy_trunk: + - module_id: grid_connection_point + implementation_id: energy_grid + grid_connection_point: + module: EnergyNode + config_module: + fuse_limit_A: 40.0 + phase_count: 3 + connections: + price_information: [] + energy_consumer: + - module_id: evse_manager_1 + implementation_id: energy_grid + - module_id: evse_manager_2 + implementation_id: energy_grid + powermeter: + - module_id: yeti_driver_1 + implementation_id: powermeter + api: + module: API + connections: + evse_manager: + - module_id: evse_manager_1 + implementation_id: evse + system: + module: System + +x-module-layout: {} diff --git a/e2e_tests/everest/config/everest/default_logging.cfg b/e2e_tests/everest/config/everest/default_logging.cfg new file mode 100644 index 0000000..9a9d892 --- /dev/null +++ b/e2e_tests/everest/config/everest/default_logging.cfg @@ -0,0 +1,18 @@ +# for documentation on this file format see: +# https://www.boost.org/doc/libs/1_54_0/libs/log/doc/html/log/detailed/utilities.html#log.detailed.utilities.setup.filter_formatter + +[Core] +DisableLogging=false +Filter="%Severity% >= INFO" + +[Sinks.Console] +Destination=Console +# Filter="%Target% contains \"MySink1\"" +Format="%TimeStamp% [%Severity%] \033[1;32m%Process%\033[0m \033[1;36m%function%\033[0m \033[1;30m%file%:\033[0m\033[1;32m%line%\033[0m: %Message%" +Asynchronous=false +AutoFlush=true +SeverityStringColorDebug="\033[1;30m" +SeverityStringColorInfo="\033[1;37m" +SeverityStringColorWarning="\033[1;33m" +SeverityStringColorError="\033[1;31m" +SeverityStringColorCritical="\033[1;35m" diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/config.json b/e2e_tests/everest/config/everest/ocpp/OCPP/config.json new file mode 100644 index 0000000..dcd8757 --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/config.json @@ -0,0 +1,58 @@ +{ + "Internal": { + "ChargePointId": "cs001", + "CentralSystemURI": "lb/ws/cs001", + "ChargeBoxSerialNumber": "cs001", + "ChargePointModel": "Yeti", + "ChargePointVendor": "Pionix", + "FirmwareVersion": "0.1", + "LogMessagesFormat": [] + }, + "Core": { + "AuthorizeRemoteTxRequests": false, + "ClockAlignedDataInterval": 900, + "ConnectionTimeOut": 10, + "ConnectorPhaseRotation": "0.RST,1.RST", + "GetConfigurationMaxKeys": 100, + "HeartbeatInterval": 86400, + "LocalAuthorizeOffline": false, + "LocalPreAuthorize": false, + "MeterValuesAlignedData": "Energy.Active.Import.Register", + "MeterValuesSampledData": "Energy.Active.Import.Register", + "MeterValueSampleInterval": 0, + "NumberOfConnectors": 1, + "ResetRetries": 1, + "StopTransactionOnEVSideDisconnect": true, + "StopTransactionOnInvalidId": true, + "StopTxnAlignedData": "Energy.Active.Import.Register", + "StopTxnSampledData": "Energy.Active.Import.Register", + "SupportedFeatureProfiles": "Core,FirmwareManagement,RemoteTrigger,Reservation,LocalAuthListManagement,SmartCharging", + "TransactionMessageAttempts": 1, + "TransactionMessageRetryInterval": 10, + "UnlockConnectorOnEVSideDisconnect": true + }, + "FirmwareManagement": { + "SupportedFileTransferProtocols": "FTP" + }, + "LocalAuthListManagement": { + "LocalAuthListEnabled": true, + "LocalAuthListMaxLength": 42, + "SendLocalListMaxLength": 42 + }, + "SmartCharging": { + "ChargeProfileMaxStackLevel": 42, + "ChargingScheduleAllowedChargingRateUnit": "Current", + "ChargingScheduleMaxPeriods": 42, + "MaxChargingProfilesInstalled": 42 + }, + "Security": { + "SecurityProfile": 3 + }, + "PnC": { + "ISO15118PnCEnabled": true, + "ContractValidationOffline": true + }, + "Custom": { + "ExampleConfigurationKey": "example" + } +} diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/init.sql b/e2e_tests/everest/config/everest/ocpp/OCPP/init.sql new file mode 100644 index 0000000..5865d16 --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/init.sql @@ -0,0 +1,61 @@ +PRAGMA foreign_keys = ON; +CREATE TABLE IF NOT EXISTS CONNECTORS ( + ID INT PRIMARY KEY NOT NULL, + AVAILABILITY TEXT +); +CREATE TABLE IF NOT EXISTS AUTH_CACHE ( + ID_TAG TEXT PRIMARY KEY NOT NULL, + AUTH_STATUS TEXT NOT NULL, + EXPIRY_DATE TEXT, + PARENT_ID_TAG TEXT +); +CREATE TABLE IF NOT EXISTS AUTH_LIST_VERSION ( + ID INT PRIMARY KEY NOT NULL, + VERSION INT +); +CREATE TABLE IF NOT EXISTS AUTH_LIST ( + ID_TAG TEXT PRIMARY KEY NOT NULL, + AUTH_STATUS TEXT NOT NULL, + EXPIRY_DATE TEXT, + PARENT_ID_TAG TEXT +); +CREATE TABLE IF NOT EXISTS TRANSACTIONS ( + ID INT PRIMARY KEY NOT NULL, + TRANSACTION_ID INT, + CONNECTOR INT NOT NULL, + ID_TAG_START TEXT NOT NULL, + TIME_START TEXT NOT NULL, + METER_START INT NOT NULL, + CSMS_ACK INT NOT NULL, + METER_LAST INT NOT NULL, + METER_LAST_TIME TEXT NOT NULL, + LAST_UPDATE TEXT NOT NULL, + RESERVATION_ID INT, + PARENT_ID_TAG TEXT, + ID_TAG_END TEXT, + TIME_END TEXT, + METER_STOP INT, + STOP_REASON TEXT, + FOREIGN KEY(CONNECTOR) REFERENCES CONNECTORS(ID) +); +INSERT + OR IGNORE INTO AUTH_LIST_VERSION (ID, VERSION) +VALUES (0, 0); + +CREATE TABLE IF NOT EXISTS CHARGING_PROFILES ( + ID INT PRIMARY KEY NOT NULL, + CONNECTOR_ID INT NOT NULL, + PROFILE TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS OCSP_REQUEST ( + LAST_UPDATE TEXT PRIMARY KEY NOT NULL +); + +CREATE TABLE IF NOT EXISTS TRANSACTION_QUEUE( + UNIQUE_ID TEXT PRIMARY KEY NOT NULL, + MESSAGE TEXT NOT NULL, + MESSAGE_TYPE TEXT NOT NULL, + MESSAGE_ATTEMPTS INT NOT NULL, + MESSAGE_TIMESTAMP TEXT NOT NULL +); diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/logging.ini b/e2e_tests/everest/config/everest/ocpp/OCPP/logging.ini new file mode 100644 index 0000000..65d801f --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/logging.ini @@ -0,0 +1,18 @@ +# for documentation on this file format see: +# https://www.boost.org/doc/libs/1_54_0/libs/log/doc/html/log/detailed/utilities.html#log.detailed.utilities.setup.filter_formatter + +[Core] +DisableLogging=false +Filter="%Severity% >= INFO" + +[Sinks.Console] +Destination=Console +# Filter="%Target% contains \"MySink1\"" +Format="%TimeStamp% \033[1;32m%Process%\033[0m [\033[1;32m%ProcessID%\033[0m] [%Severity%] {\033[1;34m%ThreadID%\033[0m} \033[1;36m%function%\033[0m \033[1;30m%file%:\033[0m\033[1;32m%line%\033[0m: %Message%" +Asynchronous=false +AutoFlush=true +SeverityStringColorDebug="\033[1;30m" +SeverityStringColorInfo="\033[1;37m" +SeverityStringColorWarning="\033[1;33m" +SeverityStringColorError="\033[1;31m" +SeverityStringColorCritical="\033[1;35m" diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Config.json b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Config.json new file mode 100644 index 0000000..6a0d6ce --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Config.json @@ -0,0 +1,45 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Json schema for OCPP 1.6 config", + "type": "object", + "required": [ + "Internal", + "Core", + "Security" + ], + "properties": { + "Internal": { + "type": "object", + "$ref": "Internal.json" + }, + "Core": { + "type": "object", + "$ref": "Core.json" + }, + "LocalAuthListManagement": { + "type": "object", + "$ref": "LocalAuthListManagement.json" + }, + "SmartCharging": { + "type": "object", + "$ref": "SmartCharging.json" + }, + "FirmwareManagement": { + "type": "object", + "$ref": "FirmwareManagement.json" + }, + "Reservation": { + "type": "object", + "$ref": "Reservation.json" + }, + "Security": { + "type": "object", + "$ref": "Security.json" + }, + "PnC": { + "type": "object", + "$ref": "PnC.json" + } + }, + "additionalProperties": false +} diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Core.json b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Core.json new file mode 100644 index 0000000..efad7a9 --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Core.json @@ -0,0 +1,191 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Json schema for Core Profile config", + "type": "object", + "required": [ + "AuthorizeRemoteTxRequests", + "ClockAlignedDataInterval", + "ConnectionTimeOut", + "ConnectorPhaseRotation", + "GetConfigurationMaxKeys", + "HeartbeatInterval", + "LocalAuthorizeOffline", + "LocalPreAuthorize", + "MeterValuesAlignedData", + "MeterValuesSampledData", + "MeterValueSampleInterval", + "NumberOfConnectors", + "ResetRetries", + "StopTransactionOnEVSideDisconnect", + "StopTransactionOnInvalidId", + "StopTxnAlignedData", + "StopTxnSampledData", + "SupportedFeatureProfiles", + "TransactionMessageAttempts", + "TransactionMessageRetryInterval", + "UnlockConnectorOnEVSideDisconnect" + ], + "properties": { + "AllowOfflineTxForUnknownId": { + "type": "boolean", + "readOnly": false, + "description": "If this config entry exists the charge point supports Unknown Offline Auth. If it is set to true the feature is enabled" + }, + "AuthorizationCacheEnabled": { + "type": "boolean", + "readOnly": false, + "description": "If this config entry exists the charge point supports an Auth Cache. If it is set to true the feature is enabled" + }, + "AuthorizeRemoteTxRequests": { + "type": "boolean", + "readOnly": false, + "description": "Authorize a RemoteStartTransaction request like a local StartTransaction. Readonly setting is up to the implementation." + }, + "BlinkRepeat": { + "type": "integer", + "readOnly": false, + "minimum": 0 + }, + "ClockAlignedDataInterval": { + "type": "integer", + "readOnly": false, + "minimum": 0 + }, + "ConnectionTimeOut": { + "type": "integer", + "readOnly": false, + "minimum": 0 + }, + "ConnectorPhaseRotation": { + "type": "string", + "readOnly": false + }, + "ConnectorPhaseRotationMaxLength": { + "type": "integer", + "readOnly": true, + "minimum": 0 + }, + "GetConfigurationMaxKeys": { + "type": "integer", + "readOnly": true, + "minimum": 0 + }, + "HeartbeatInterval": { + "type": "integer", + "readOnly": false, + "minimum": 0 + }, + "LightIntensity": { + "type": "integer", + "readOnly": false, + "minimum": 0, + "maximum": 100 + }, + "LocalAuthorizeOffline": { + "type": "boolean", + "readOnly": false + }, + "LocalPreAuthorize": { + "type": "boolean", + "readOnly": false + }, + "MaxEnergyOnInvalidId": { + "type": "integer", + "readOnly": false, + "minimum": 0 + }, + "MeterValuesAlignedData": { + "type": "string", + "readOnly": false + }, + "MeterValuesAlignedDataMaxLength": { + "type": "integer", + "readOnly": true, + "minimum": 0 + }, + "MeterValuesSampledData": { + "type": "string", + "readOnly": false + }, + "MeterValuesSampledDataMaxLength": { + "type": "integer", + "readOnly": true, + "minimum": 0 + }, + "MeterValueSampleInterval": { + "type": "integer", + "readOnly": false, + "minimum": 0 + }, + "MinimumStatusDuration": { + "type": "integer", + "readOnly": false, + "minimum": 0 + }, + "NumberOfConnectors": { + "type": "integer", + "readOnly": true, + "minimum": 0 + }, + "ResetRetries": { + "type": "integer", + "readOnly": false, + "minimum": 0 + }, + "StopTransactionOnEVSideDisconnect": { + "type": "boolean", + "readOnly": false + }, + "StopTransactionOnInvalidId": { + "type": "boolean", + "readOnly": false + }, + "StopTxnAlignedData": { + "type": "string", + "readOnly": false + }, + "StopTxnAlignedDataMaxLength": { + "type": "integer", + "readOnly": true, + "minimum": 0 + }, + "StopTxnSampledData": { + "type": "string", + "readOnly": false + }, + "StopTxnSampledDataMaxLength": { + "type": "integer", + "readOnly": true, + "minimum": 0 + }, + "SupportedFeatureProfiles": { + "type": "string", + "readOnly": true + }, + "SupportedFeatureProfilesMaxLength": { + "type": "integer", + "readOnly": true, + "minimum": 0 + }, + "TransactionMessageAttempts": { + "type": "integer", + "readOnly": false, + "minimum": 0 + }, + "TransactionMessageRetryInterval": { + "type": "integer", + "readOnly": false, + "minimum": 0 + }, + "UnlockConnectorOnEVSideDisconnect": { + "type": "boolean", + "readOnly": false + }, + "WebsocketPingInterval": { + "type": "integer", + "readOnly": false, + "minimum": 0 + } + }, + "additionalProperties": false +} diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Custom.json b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Custom.json new file mode 100644 index 0000000..5d23b20 --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Custom.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Json schema for Custom configuration keys", + "$comment": "This is just an example schema and can be modified according to custom requirements", + "type": "object", + "required": [], + "properties": { + "ExampleConfigurationKey": { + "type": "string", + "description": "Custom key", + "readOnly": false + } + } + } + \ No newline at end of file diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/FirmwareManagement.json b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/FirmwareManagement.json new file mode 100644 index 0000000..4a892ce --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/FirmwareManagement.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Json schema for Firmware Management Profile config", + "type": "object", + "required": [], + "properties": { + "SupportedFileTransferProtocols": { + "type": "string", + "readOnly": true + } + }, + "additionalProperties": false +} diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Internal.json b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Internal.json new file mode 100644 index 0000000..06764ad --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Internal.json @@ -0,0 +1,230 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Json schema for internal config", + "type": "object", + "required": [ + "ChargePointId", + "CentralSystemURI", + "ChargeBoxSerialNumber", + "ChargePointModel", + "ChargePointVendor", + "FirmwareVersion" + ], + "properties": { + "ChargePointId": { + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "CentralSystemURI": { + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "ChargeBoxSerialNumber": { + "type": "string", + "readOnly": true, + "minLength": 1, + "maxLength": 25 + }, + "ChargePointModel": { + "type": "string", + "readOnly": true, + "minLength": 1, + "maxLength": 20 + }, + "ChargePointSerialNumber": { + "type": "string", + "readOnly": true, + "minLength": 1, + "maxLength": 25 + }, + "ChargePointVendor": { + "type": "string", + "readOnly": true, + "minLength": 1, + "maxLength": 20 + }, + "FirmwareVersion": { + "type": "string", + "readOnly": true, + "minLength": 1, + "maxLength": 50 + }, + "ICCID": { + "type": "string", + "readOnly": true, + "minLength": 1, + "maxLength": 20 + }, + "HostName": { + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "IMSI": { + "type": "string", + "readOnly": true, + "minLength": 1, + "maxLength": 20 + }, + "MeterSerialNumber": { + "type": "string", + "readOnly": true, + "minLength": 1, + "maxLength": 25 + }, + "MeterType": { + "type": "string", + "readOnly": true, + "minLength": 1, + "maxLength": 25 + }, + "SupportedCiphers12": { + "type": "array", + "items": { + "type": "string" + }, + "readOnly": true, + "default": [ + "ECDHE-ECDSA-AES128-GCM-SHA256", + "ECDHE-ECDSA-AES256-GCM-SHA384", + "AES128-GCM-SHA256", + "AES256-GCM-SHA384", + "TLS_AES_256_GCM_SHA384", + "TLS_AES_128_GCM_SHA256" + ] + }, + "SupportedCiphers13": { + "type": "array", + "items": { + "type": "string" + }, + "readOnly": true, + "default": [ + "TLS_AES_256_GCM_SHA384", + "TLS_AES_128_GCM_SHA256" + ] + }, + "RetryBackoffRandomRange": { + "$comment": "maximum value for the random part of the websocket reconnect back-off time", + "type": "integer", + "readOnly": false, + "default": 10 + }, + "RetryBackoffRepeatTimes": { + "$comment": "amount of times previous reconnect back-off time will be doubled", + "type": "integer", + "readOnly": false, + "default": 3 + }, + "RetryBackoffWaitMinimum": { + "$comment": "minimum back-off time of the first reconnect", + "type": "integer", + "readOnly": false, + "default": 3 + }, + "AuthorizeConnectorZeroOnConnectorOne": { + "$comment": "Automatically authorize id tags on connector 1 when there is only one connector", + "type": "boolean", + "readOnly": true, + "default": true + }, + "LogMessages": { + "$comment": "Automatically log all sent and received messages to a temporary file at /tmp/libocpp_messages_.txt", + "type": "boolean", + "readOnly": true, + "default": true + }, + "LogMessagesFormat": { + "$comment": "Supported log formats are console, log, html, console_detailed and session_logging", + "type": "array", + "items": { + "type": "string" + }, + "readOnly": true, + "default": [ + "log", + "html", + "session_logging" + ] + }, + "SupportedChargingProfilePurposeTypes": { + "$comment": "Indicates which ChargingProfilePurposeTypes are supported. SetChargingProfile.req for profiles not listed will be rejected.", + "type": "array", + "items": { + "type": "string" + }, + "readOnly": true, + "default": [ + "ChargePointMaxProfile", + "TxDefaultProfile", + "TxProfile" + ] + }, + "MaxCompositeScheduleDuration": { + "$comment": "Maximum duration in seconds of GetCompositeSchedule.req. For GetCompositeSchedule.req with a greater duration the schedule for only the MaxCompositeScheduleDuration will be calculated", + "type": "integer", + "readOnly": true, + "default": 31536000 + }, + "WebsocketPingPayload": { + "$comment": "The payload sent in a websocket ping.", + "type": "string", + "readOnly": true, + "default": "hello there" + }, + "WebsocketPongTimeout": { + "$comment": "Maximum timeout for receiving a pong message in seconds", + "type": "integer", + "readOnly": true, + "default": 5 + }, + "UseSslDefaultVerifyPaths": { + "$comment": "Use default verify paths for validating CSMS server certificate", + "type": "boolean", + "readOnly": true, + "default": true + }, + "OcspRequestInterval": { + "$comment": "Interval in seconds used to request OCSP revocation status information on the CSO Sub-CA certificates", + "type": "integer", + "readOnly": false, + "default": 604800, + "minimum": 86400 + }, + "SeccLeafSubjectCommonName": { + "$comment": "Common Name(s) of the SECC (EVSE) leaf certificate(s). The CN must be a SECCID. The field can contain optional multiple SECCIDs if necessary.", + "type": "string", + "readOnly": false + }, + "SeccLeafSubjectCountry": { + "$comment": "County of the SECC (EVSE) leaf certificate. Indicates in which country the CPO operates.", + "type": "string", + "readOnly": false + }, + "SeccLeafSubjectOrganization": { + "$comment": "Organization of the SECC (EVSE) leaf certificate. Indicates which CPO operates this EVSE. Example: Hubject GmbH", + "type": "string", + "readOnly": false + }, + "ConnectorEvseIds": { + "$comment": "Comma separated EVSEIDs for OCPP connectors starting with connector 1 in one string.", + "type": "string", + "readOnly": false + }, + "AllowChargingProfileWithoutStartSchedule": { + "$comment": "OCPP1.6 specifies that for certain ChargingProfiles the startSchedule field needs to be set. This flag ignores this requirement and will accept those profiles without startSchedule, assuming startSchedule is now.", + "type": "boolean", + "readOnly": false + }, + "WaitForStopTransactionsOnResetTimeout": { + "$comment": "Specifies the timeout that is used when transactions are stopped because of a Reset.req . If timeout exceeds, the reset callback is executed even if StopTransaction.conf messages not yet received for transactions that have been active.", + "type": "integer", + "readOnly": false, + "minimum": 0, + "default": 60 + } + }, + "additionalProperties": false +} diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/LocalAuthListManagement.json b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/LocalAuthListManagement.json new file mode 100644 index 0000000..50f851a --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/LocalAuthListManagement.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Json schema for Local Auth List Management Profile config", + "type": "object", + "required": [ + "LocalAuthListEnabled", + "LocalAuthListMaxLength", + "SendLocalListMaxLength" + ], + "properties": { + "LocalAuthListEnabled": { + "type": "boolean", + "readOnly": false + }, + "LocalAuthListMaxLength": { + "type": "integer", + "readOnly": true, + "minimum": 0 + }, + "SendLocalListMaxLength": { + "type": "integer", + "readOnly": true, + "minimum": 0 + } + }, + "additionalProperties": false +} diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/PnC.json b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/PnC.json new file mode 100644 index 0000000..b3624f3 --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/PnC.json @@ -0,0 +1,48 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Json schema for ISO15118 PnC extension", + "type": "object", + "required": ["ISO15118PnCEnabled", "ContractValidationOffline"], + "properties": { + "ISO15118PnCEnabled": { + "type": "boolean", + "description": "If this variable set to true, then the Charge Point supports ISO 15118 plug and charge messages via the DataTransfer mechanism as described in this application note.", + "readOnly": false + }, + "CentralContractValidationAllowed": { + "type": "boolean", + "description": "If this variable exists and has the value true, then the Charge Point can provide a contract certificate that it cannot validate to the Central System for validation as part of the Authorize.req.", + "readOnly": false + }, + "CertificateSignedMaxChainSize": { + "type": "integer", + "description": "This configuration key can be used to limit the size of the 'certificateChain' field from the CertificateSigned.req PDU", + "maximum": 10000, + "minimum": 0, + "readOnly": true + }, + "CertSigningWaitMinimum": { + "type": "integer", + "description": "This configuration key defines how long the Charge Point has to wait (in seconds) before generating another CSR, in the case the Central System accepts the SignCertificate.req, but never returns the signed certificate back.", + "minimum": 0, + "readOnly": false + }, + "CertSigningRepeatTimes": { + "type": "integer", + "description": "This configuration key can be used to configure the amount of times the Charge Point SHALL double the previous back-off time", + "minimum": 0, + "readOnly": false + }, + "CertificateStoreMaxLength": { + "type": "integer", + "description": "Maximum number of Root/CA certificates that can be installed in the Charge Point.", + "minimum": 1, + "readOnly": true + }, + "ContractValidationOffline": { + "type": "boolean", + "description": "If this variable is true, then the Charge Point will try to validate a contract certificate when it is offline.", + "readOnly": false + } + } +} diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Reservation.json b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Reservation.json new file mode 100644 index 0000000..f0d495c --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Reservation.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Json schema for Reservation Profile config", + "type": "object", + "required": [], + "properties": { + "ReserveConnectorZeroSupported": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false +} diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Security.json b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Security.json new file mode 100644 index 0000000..1316f30 --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/Security.json @@ -0,0 +1,46 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Json schema for Security Profile config", + "type": "object", + "required": [ + "SecurityProfile" + ], + "properties": { + "AdditionalRootCertificateCheck": { + "type": "boolean", + "description": "When set to true, only one certificate (plus a temporarily fallback certificate) of certificateType CentralSystemRootCertificate is allowed to be installed at a time", + "readOnly": true + }, + "AuthorizationKey": { + "type": "string", + "description": "The basic authentication password is used for HTTP Basic Authentication", + "minLength": 8, + "readOnly": false + }, + "CertificateSignedMaxChainSize": { + "type": "integer", + "description": "This configuration key can be used to limit the size of the 'certificateChain' field from the CertificateSigned.req PDU.", + "maximum": 10000, + "readOnly": true + }, + "CertificateStoreMaxLength": { + "type": "integer", + "description": "Maximum number of Root/CA certificates that can be installed in the Charge Point.", + "minimum": 0, + "readOnly": true + }, + "CpoName": { + "type": "string", + "description": "This configuration key contains CPO name (or an organization trusted by the CPO) as used in the Charge Point Certificate.", + "readOnly": false + }, + "SecurityProfile": { + "type": "integer", + "default": 0, + "minimum": 0, + "maximum": 3, + "description": "This configuration key is used to set the security profile used by the Charge Point", + "readOnly": false + } + } +} diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/SmartCharging.json b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/SmartCharging.json new file mode 100644 index 0000000..880a858 --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/profile_schemas/SmartCharging.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Json schema for Smart Charging Profile config", + "type": "object", + "required": [ + "ChargeProfileMaxStackLevel", + "ChargingScheduleAllowedChargingRateUnit", + "ChargingScheduleMaxPeriods", + "MaxChargingProfilesInstalled" + ], + "properties": { + "ChargeProfileMaxStackLevel": { + "type": "integer", + "readOnly": true, + "minimum": 0 + }, + "ChargingScheduleAllowedChargingRateUnit": { + "type": "string", + "readOnly": true, + "default": "Current,Power" + }, + "ChargingScheduleMaxPeriods": { + "type": "integer", + "readOnly": true, + "minimum": 0, + "default": 1440 + }, + "ConnectorSwitch3to1PhaseSupported": { + "type": "boolean", + "readOnly": true + }, + "MaxChargingProfilesInstalled": { + "type": "integer", + "readOnly": true, + "minimum": 0, + "default": 500 + } + }, + "additionalProperties": false +} diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP/user_config.json b/e2e_tests/everest/config/everest/ocpp/OCPP/user_config.json new file mode 100644 index 0000000..ea348a9 --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP/user_config.json @@ -0,0 +1 @@ +{"Core":{"HeartbeatInterval":300}} diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP201/config.json b/e2e_tests/everest/config/everest/ocpp/OCPP201/config.json new file mode 100644 index 0000000..4500026 --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP201/config.json @@ -0,0 +1,679 @@ +[ + { + "name": "Connector", + "evse_id": 1, + "connector_id": 1, + "variables": { + "ConnectorAvailable": { + "variable_name": "Available", + "attributes": { + "Actual": true + } + }, + "ConnectorType": { + "variable_name": "ConnectorType", + "attributes": { + "Actual": "" + } + }, + "ConnectorSupplyPhases": { + "variable_name": "SupplyPhases", + "attributes": { + "Actual": 42 + } + } + } + }, + { + "name": "EVSE", + "evse_id": 1, + "variables": { + "EVSEAvailabilityState": { + "variable_name": "AvailabilityState", + "attributes": { + "Actual": "" + } + }, + "EVSEAvailable": { + "variable_name": "Available", + "attributes": { + "Actual": true + } + }, + "EVSEPower": { + "variable_name": "Power", + "attributes": { + "Actual": 42 + } + }, + "EVSESupplyPhases": { + "variable_name": "SupplyPhases", + "attributes": { + "Actual": 42 + } + } + } + }, + { + "name": "Connector", + "evse_id": 1, + "connector_id": 2, + "variables": { + "ConnectorAvailable": { + "variable_name": "Available", + "attributes": { + "Actual": true + } + }, + "ConnectorType": { + "variable_name": "ConnectorType", + "attributes": { + "Actual": "" + } + }, + "ConnectorSupplyPhases": { + "variable_name": "SupplyPhases", + "attributes": { + "Actual": 42 + } + } + } + }, + { + "name": "EVSE", + "evse_id": 1, + "variables": { + "EVSEAvailabilityState": { + "variable_name": "AvailabilityState", + "attributes": { + "Actual": "" + } + }, + "EVSEAvailable": { + "variable_name": "Available", + "attributes": { + "Actual": true + } + }, + "EVSEPower": { + "variable_name": "Power", + "attributes": { + "Actual": 42 + } + }, + "EVSESupplyPhases": { + "variable_name": "SupplyPhases", + "attributes": { + "Actual": 42 + } + } + } + }, + { + "name": "SampledDataCtrlr", + "variables": { + "SampledDataTxEndedInterval": { + "variable_name": "TxEndedInterval", + "attributes": { + "Actual": "60" + } + }, + "SampledDataTxEndedMeasurands": { + "variable_name": "TxEndedMeasurands", + "attributes": { + "Actual": "Energy.Active.Import.Register,Current.Import" + } + }, + "SampledDataTxStartedMeasurands": { + "variable_name": "TxStartedMeasurands", + "attributes": { + "Actual": "Energy.Active.Import.Register,Current.Import" + } + }, + "SampledDataTxUpdatedInterval": { + "variable_name": "TxUpdatedInterval", + "attributes": { + "Actual": "120" + } + }, + "SampledDataTxUpdatedMeasurands": { + "variable_name": "TxUpdatedMeasurands", + "attributes": { + "Actual": "Energy.Active.Import.Register,Current.Import,Voltage,Power.Active.Import,Power.Reactive.Import,Frequency" + } + } + } + }, + { + "name": "LocalAuthListCtrlr", + "variables": { + "BytesPerMessageSendLocalList": { + "variable_name": "BytesPerMessageSendLocalList", + "attributes": { + "Actual": 42 + } + }, + "LocalAuthListCtrlrEntries": { + "variable_name": "Entries", + "attributes": { + "Actual": 42 + } + }, + "ItemsPerMessageSendLocalList": { + "variable_name": "ItemsPerMessageSendLocalList", + "attributes": { + "Actual": 42 + } + } + } + }, + { + "name": "InternalCtrlr", + "variables": { + "ChargePointId": { + "variable_name": "ChargePointId", + "attributes": { + "Actual": "cp001" + } + }, + "NetworkConnectionProfiles": { + "variable_name": "NetworkConnectionProfiles", + "attributes": { + "Actual": "[{\"configurationSlot\": 1, \"connectionData\": {\"messageTimeout\": 30, \"ocppCsmsUrl\": \"wss://cs.maeve-csms.co.uk/ws/dlpnew\", \"ocppInterface\": \"Wired0\", \"ocppTransport\": \"JSON\", \"ocppVersion\": \"OCPP20\", \"securityProfile\": 3}}]" + } + }, + "ChargeBoxSerialNumber": { + "variable_name": "ChargeBoxSerialNumber", + "attributes": { + "Actual": "" + } + }, + "ChargePointModel": { + "variable_name": "ChargePointModel", + "attributes": { + "Actual": "" + } + }, + "ChargePointVendor": { + "variable_name": "ChargePointVendor", + "attributes": { + "Actual": "" + } + }, + "FirmwareVersion": { + "variable_name": "FirmwareVersion", + "attributes": { + "Actual": "" + } + }, + "SupportedCiphers12": { + "variable_name": "SupportedCiphers12", + "attributes": { + "Actual": "ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES256,GCM-SHA384,AES128-GCM-SHA256,AES256-GCM-SHA384,TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256" + } + }, + "SupportedCiphers13": { + "variable_name": "SupportedCiphers13", + "attributes": { + "Actual": "TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256" + } + }, + "NumberOfConnectors": { + "variable_name": "NumberOfConnectors", + "attributes": { + "Actual": "1" + } + } + } + }, + { + "name": "OCPPCommCtrlr", + "variables": { + "FileTransferProtocols": { + "variable_name": "FileTransferProtocols", + "attributes": { + "Actual": "" + } + }, + "MessageTimeout": { + "variable_name": "MessageTimeout", + "attributes": { + "Actual": "60" + }, + "instance": "Default" + }, + "MessageAttemptInterval": { + "variable_name": "MessageAttemptInterval", + "attributes": { + "Actual": "10" + }, + "instance": "TransactionEvent" + }, + "MessageAttempts": { + "variable_name": "MessageAttempts", + "attributes": { + "Actual": "5" + }, + "instance": "TransactionEvent" + }, + "NetworkConfigurationPriority": { + "variable_name": "NetworkConfigurationPriority", + "attributes": { + "Actual": "1" + } + }, + "NetworkProfileConnectionAttempts": { + "variable_name": "NetworkProfileConnectionAttempts", + "attributes": { + "Actual": "3" + } + }, + "OfflineThreshold": { + "variable_name": "OfflineThreshold", + "attributes": { + "Actual": "60" + } + }, + "ResetRetries": { + "variable_name": "ResetRetries", + "attributes": { + "Actual": "3" + } + }, + "RetryBackOffRandomRange": { + "variable_name": "RetryBackOffRandomRange", + "attributes": { + "Actual": "2" + } + }, + "RetryBackOffRepeatTimes": { + "variable_name": "RetryBackOffRepeatTimes", + "attributes": { + "Actual": "2" + } + }, + "RetryBackOffWaitMinimum": { + "variable_name": "RetryBackOffWaitMinimum", + "attributes": { + "Actual": "1" + } + }, + "UnlockOnEVSideDisconnect": { + "variable_name": "UnlockOnEVSideDisconnect", + "attributes": { + "Actual": "1" + } + }, + "WebSocketPingInterval": { + "variable_name": "WebSocketPingInterval", + "attributes": { + "Actual": "30" + } + } + } + }, + { + "name": "DisplayMessageCtrlr", + "variables": { + "NumberOfDisplayMessages": { + "variable_name": "NumberOfDisplayMessages", + "attributes": { + "Actual": 42 + } + }, + "DisplayMessageSupportedFormats": { + "variable_name": "SupportedFormats", + "attributes": { + "Actual": "" + } + }, + "DisplayMessageSupportedPriorities": { + "variable_name": "SupportedPriorities", + "attributes": { + "Actual": "" + } + } + } + }, + { + "name": "ClockCtrlr", + "variables": { + "DateTime": { + "variable_name": "DateTime", + "attributes": { + "Actual": "" + } + }, + "TimeSource": { + "variable_name": "TimeSource", + "attributes": { + "Actual": "Heartbeat" + } + } + } + }, + { + "name": "ReservationCtrlr", + "variables": {} + }, + { + "name": "ISO15118Ctrlr", + "variables": { + "ContractValidationOffline": { + "variable_name": "ContractValidationOffline", + "attributes": { + "Actual": true + } + } + } + }, + { + "name": "TxCtrlr", + "variables": { + "EVConnectionTimeOut": { + "variable_name": "EVConnectionTimeOut", + "attributes": { + "Actual": "120" + } + }, + "StopTxOnEVSideDisconnect": { + "variable_name": "StopTxOnEVSideDisconnect", + "attributes": { + "Actual": "1" + } + }, + "StopTxOnInvalidId": { + "variable_name": "StopTxOnInvalidId", + "attributes": { + "Actual": "1" + } + }, + "TxStartPoint": { + "variable_name": "TxStartPoint", + "attributes": { + "Actual": "PowerPathClosed" + } + }, + "TxStopPoint": { + "variable_name": "TxStopPoint", + "attributes": { + "Actual": "EVConnected,Authorized" + } + } + } + }, + { + "name": "AlignedDataCtrlr", + "variables": { + "AlignedDataInterval": { + "variable_name": "Interval", + "attributes": { + "Actual": "900" + } + }, + "AlignedDataMeasurands": { + "variable_name": "Measurands", + "attributes": { + "Actual": "Energy.Active.Import.Register,Voltage" + } + }, + "AlignedDataTxEndedInterval": { + "variable_name": "TxEndedInterval", + "attributes": { + "Actual": "60" + } + }, + "AlignedDataTxEndedMeasurands": { + "variable_name": "TxEndedMeasurands", + "attributes": { + "Actual": "Energy.Active.Import.Register" + } + }, + "AlignedDataSendDuringIdle": { + "variable_name": "SendDuringIdle", + "attributes": { + "Actual": false + } + } + } + }, + { + "name": "AuthCtrlr", + "variables": { + "AuthorizeRemoteStart": { + "variable_name": "AuthorizeRemoteStart", + "attributes": { + "Actual": "1" + } + }, + "LocalAuthorizeOffline": { + "variable_name": "LocalAuthorizeOffline", + "attributes": { + "Actual": "1" + } + }, + "LocalPreAuthorize": { + "variable_name": "LocalPreAuthorize", + "attributes": { + "Actual": "1" + } + }, + "MasterPassGroupId": { + "variable_name": "MasterPassGroupId", + "attributes": { + "Actual": "123" + } + } + } + }, + { + "name": "AuthCacheCtrlr", + "variables": { + "AuthCacheCtrlrAvailable": { + "variable_name": "Available", + "attributes": { + "Actual": true + } + }, + "AuthCacheCtrlrEnabled": { + "variable_name": "Enabled", + "attributes": { + "Actual": false + } + }, + "AuthCacheStorage": { + "variable_name": "Storage", + "attributes": { + "Actual": 0 + } + } + } + }, + { + "name": "ChargingStation", + "variables": { + "ChargingStationAvailabilityState": { + "variable_name": "AvailabilityState", + "attributes": { + "Actual": "" + } + }, + "ChargingStationAvailable": { + "variable_name": "Available", + "attributes": { + "Actual": true + } + }, + "ChargingStationSupplyPhases": { + "variable_name": "SupplyPhases", + "attributes": { + "Actual": 42 + } + }, + "ChargingStationPhaseRotation": { + "variable_name": "PhaseRotation", + "attributes": { + "Actual": "RST" + } + } + } + }, + { + "name": "CustomizationCtrlr", + "variables": {} + }, + { + "name": "DeviceDataCtrlr", + "variables": { + "BytesPerMessageGetReport": { + "variable_name": "BytesPerMessage", + "attributes": { + "Actual": 42 + }, + "instance": "GetReport" + }, + "BytesPerMessageGetVariables": { + "variable_name": "BytesPerMessage", + "attributes": { + "Actual": 250 + }, + "instance": "GetVariables" + }, + "BytesPerMessageSetVariables": { + "variable_name": "BytesPerMessage", + "attributes": { + "Actual": 42 + }, + "instance": "SetVariables" + }, + "ItemsPerMessageGetReport": { + "variable_name": "ItemsPerMessage", + "attributes": { + "Actual": 42 + }, + "instance": "GetReport" + }, + "ItemsPerMessageGetVariables": { + "variable_name": "ItemsPerMessage", + "attributes": { + "Actual": 2 + }, + "instance": "GetVariables" + }, + "ItemsPerMessageSetVariables": { + "variable_name": "ItemsPerMessage", + "attributes": { + "Actual": 42 + }, + "instance": "SetVariables" + } + } + }, + { + "name": "TariffCostCtrlr", + "variables": { + "TariffCostCtrlrCurrency": { + "variable_name": "Currency", + "attributes": { + "Actual": "" + } + }, + "TariffFallbackMessage": { + "variable_name": "TariffFallbackMessage", + "attributes": { + "Actual": "" + } + }, + "TotalCostFallbackMessage": { + "variable_name": "TotalCostFallbackMessage", + "attributes": { + "Actual": "" + } + } + } + }, + { + "name": "SecurityCtrlr", + "variables": { + "CertificateEntries": { + "variable_name": "CertificateEntries", + "attributes": { + "Actual": 42 + } + }, + "OrganizationName": { + "variable_name": "OrganizationName", + "attributes": { + "Actual": "Pionix" + } + }, + "SecurityProfile": { + "variable_name": "SecurityProfile", + "attributes": { + "Actual": "1" + } + }, + "BasicAuthPassword": { + "variable_name": "BasicAuthPassword", + "attributes": { + "Actual": "DEADBEEFDEADBEEF" + } + } + } + }, + { + "name": "SmartChargingCtrlr", + "variables": { + "EntriesChargingProfiles": { + "variable_name": "Entries", + "attributes": { + "Actual": 42 + }, + "instance": "ChargingProfiles" + }, + "LimitChangeSignificance": { + "variable_name": "LimitChangeSignificance", + "attributes": { + "Actual": 42 + } + }, + "PeriodsPerSchedule": { + "variable_name": "PeriodsPerSchedule", + "attributes": { + "Actual": 42 + } + }, + "ChargingProfileMaxStackLevel": { + "variable_name": "ProfileStackLevel", + "attributes": { + "Actual": 42 + } + }, + "ChargingScheduleChargingRateUnit": { + "variable_name": "RateUnit", + "attributes": { + "Actual": "" + } + } + } + }, + { + "name": "MonitoringCtrlr", + "variables": { + "BytesPerMessageSetVariableMonitoring": { + "variable_name": "BytesPerMessage", + "attributes": { + "Actual": 42 + }, + "instance": "SetVariableMonitoring" + }, + "ItemsPerMessageSetVariableMonitoring": { + "variable_name": "ItemsPerMessage", + "attributes": { + "Actual": 42 + }, + "instance": "SetVariableMonitoring" + } + } + } +] \ No newline at end of file diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP201/device_model_storage.db b/e2e_tests/everest/config/everest/ocpp/OCPP201/device_model_storage.db new file mode 100644 index 0000000000000000000000000000000000000000..3192af4151d898241bd35b430f11b4b04474ad36 GIT binary patch literal 65536 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 W?X%{b9SK{B1R-F5IUx`e-SqGJn3b3S literal 0 HcmV?d00001 diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP201/init_core.sql b/e2e_tests/everest/config/everest/ocpp/OCPP201/init_core.sql new file mode 100644 index 0000000..974cd61 --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP201/init_core.sql @@ -0,0 +1,80 @@ +PRAGMA foreign_keys = ON; + +-- Authorization cache -- +CREATE TABLE IF NOT EXISTS AUTH_CACHE( + ID_TOKEN_HASH TEXT PRIMARY KEY NOT NULL, + ID_TOKEN_INFO TEXT NOT NULL +); + +-- Availability -- +CREATE TABLE IF NOT EXISTS AVAILABILITY( + EVSE_ID INT PRIMARY KEY NOT NULL, + CONNECTOR_ID INT, + OPERATIONAL_STATUS TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS TRANSACTION_QUEUE( + UNIQUE_ID TEXT PRIMARY KEY NOT NULL, + MESSAGE TEXT NOT NULL, + MESSAGE_TYPE TEXT NOT NULL, + MESSAGE_ATTEMPTS INT NOT NULL, + MESSAGE_TIMESTAMP TEXT NOT NULL +); + + +-- Auth list -- +CREATE TABLE IF NOT EXISTS AUTH_LIST_VERSION ( + ID INT PRIMARY KEY NOT NULL, + VERSION INT +); + +CREATE TABLE IF NOT EXISTS AUTH_LIST ( + ID_TOKEN_HASH TEXT PRIMARY KEY NOT NULL, + ID_TOKEN_INFO TEXT NOT NULL +); + +INSERT OR IGNORE INTO AUTH_LIST_VERSION (ID, VERSION) VALUES + (0, 0); + + +-- Metervalues -- +CREATE TABLE IF NOT EXISTS READING_CONTEXT_ENUM ( + ID INT PRIMARY KEY, + READING_CONTEXT TEXT +); + +CREATE TABLE IF NOT EXISTS MEASURAND_ENUM ( + ID INT PRIMARY KEY, + MEASURAND TEXT +); + +CREATE TABLE IF NOT EXISTS PHASE_ENUM ( + ID INT PRIMARY KEY, + PHASE TEXT +); + +CREATE TABLE IF NOT EXISTS LOCATION_ENUM ( + ID INT PRIMARY KEY, + LOCATION TEXT +); + +CREATE TABLE IF NOT EXISTS METER_VALUES ( + ROWID INTEGER PRIMARY KEY, + TRANSACTION_ID TEXT NOT NULL, + TIMESTAMP INT64 NOT NULL, + READING_CONTEXT INTEGER REFERENCES READING_CONTEXT_ENUM (ID), + CUSTOM_DATA TEXT, + UNIQUE(TRANSACTION_ID, TIMESTAMP, READING_CONTEXT) +); + +CREATE TABLE IF NOT EXISTS METER_VALUE_ITEMS ( + METER_VALUE_ID INTEGER REFERENCES METER_VALUES (ROWID), + VALUE REAL NOT NULL, + MEASURAND INTEGER REFERENCES MEASURAND_ENUM (ID), + PHASE INTEGER REFERENCES PHASE_ENUM (ID), + LOCATION INTEGER REFERENCES LOCATION_ENUM (ID), + CUSTOM_DATA TEXT, + UNIT_CUSTOM_DATA TEXT, + UNIT_TEXT TEXT, + UNIT_MULTIPLIER INT +); diff --git a/e2e_tests/everest/config/everest/ocpp/OCPP201/logging.ini b/e2e_tests/everest/config/everest/ocpp/OCPP201/logging.ini new file mode 100644 index 0000000..65d801f --- /dev/null +++ b/e2e_tests/everest/config/everest/ocpp/OCPP201/logging.ini @@ -0,0 +1,18 @@ +# for documentation on this file format see: +# https://www.boost.org/doc/libs/1_54_0/libs/log/doc/html/log/detailed/utilities.html#log.detailed.utilities.setup.filter_formatter + +[Core] +DisableLogging=false +Filter="%Severity% >= INFO" + +[Sinks.Console] +Destination=Console +# Filter="%Target% contains \"MySink1\"" +Format="%TimeStamp% \033[1;32m%Process%\033[0m [\033[1;32m%ProcessID%\033[0m] [%Severity%] {\033[1;34m%ThreadID%\033[0m} \033[1;36m%function%\033[0m \033[1;30m%file%:\033[0m\033[1;32m%line%\033[0m: %Message%" +Asynchronous=false +AutoFlush=true +SeverityStringColorDebug="\033[1;30m" +SeverityStringColorInfo="\033[1;37m" +SeverityStringColorWarning="\033[1;33m" +SeverityStringColorError="\033[1;31m" +SeverityStringColorCritical="\033[1;35m" diff --git a/e2e_tests/everest/config/everest/release.json b/e2e_tests/everest/config/everest/release.json new file mode 100644 index 0000000..da74a44 --- /dev/null +++ b/e2e_tests/everest/config/everest/release.json @@ -0,0 +1 @@ +{"channel": "unknown", "datetime": "2024-02-22T23:21:34.215923Z", "version": "2023.10.0", "components": [{"name": "Catch2", "version": "v3.4.0", "description": "A modern, C++-native, test framework for unit-tests, TDD and BDD - using C++14, C++17 and later", "license": "BSL-1.0"}, {"name": "Date", "version": "v3.0.1", "description": "A date and time library based on the C++11/14/17 header", "license": "MIT"}, {"name": "everest-core", "version": "2023.10.0", "description": "This is the main part of EVerest containing the actual charge controller logic included in a large set of modules", "license": "Apache-2.0"}, {"name": "everest-framework", "version": "v0.8.0", "description": "Provides a mechanism to manage dependencies between different modules communicating with a wrapped MQTT protocol", "license": "Apache-2.0"}, {"name": "everest-utils", "version": "v0.1.6", "description": "", "license": "unknown"}, {"name": "Mbed TLS", "version": "8b3f26a", "description": "An open source, portable, easy to use, readable and flexible SSL library", "license": "Apache-2.0"}, {"name": "OpenV2G", "version": "2023.3.0", "description": "An open source project implementing the basic functionality of the ISO IEC 15118 vehicle to grid (V2G) communication interface", "license": "LGPL-3.0+"}, {"name": "GoogleTest", "version": "release-1.12.1", "description": "GoogleTest - Google Testing and Mocking Framework", "license": "BSD-3-Clause"}, {"name": "libcurl", "version": "curl-8_4_0", "description": "", "license": "unknown"}, {"name": "libevse-security", "version": "v0.2.0", "description": "", "license": "unknown"}, {"name": "{fmt}", "version": "10.1.0", "description": "A modern formatting library", "license": "MIT"}, {"name": "libfsm", "version": "v0.2.0", "description": "A tiny C++14 library for writing maintainable finite state machines", "license": "Apache-2.0"}, {"name": "liblog", "version": "v0.2.1", "description": "C++ logging and exceptions library for the EVerest framework", "license": "Apache-2.0"}, {"name": "libmodbus", "version": "v0.3.0", "description": "This is an implementation of the MODBUS communication protocol", "license": "Apache-2.0"}, {"name": "libocpp", "version": "v0.9.4", "description": "This is a C++ library implementation of OCPP for version 1.6 and 2.0.1", "license": "Apache-2.0"}, {"name": "libslac", "version": "486cd8b", "description": "Simple ISO15118-3 SLAC library", "license": "Apache-2.0"}, {"name": "libsunspec", "version": "v0.2.0", "description": "This is an implementation of SunSpec for utilization within EVerest", "license": "Apache-2.0"}, {"name": "libtimer", "version": "v0.1.1", "description": "C++ timer library for the EVerest framework", "license": "Apache-2.0"}, {"name": "Libwebsockets", "version": "v4.3.2", "description": "Canonical libwebsockets.org networking library", "license": "MIT"}, {"name": "MQTT-C", "version": "v1.1.6", "description": "A portable MQTT C client for embedded systems and PCs alike.", "license": "MIT"}, {"name": "nlohmann_json", "version": "v3.11.2", "description": "JSON for Modern C++", "license": "MIT"}, {"name": "nlohmann_json_schema_validator", "version": "f4194d7e24e2e2365660ff35b57a7c4e088b27fa", "description": "JSON schema validator for JSON for Modern C++", "license": "MIT"}, {"name": "pugixml", "version": "v1.12.1", "description": "Light-weight, simple and fast XML parser for C++ with XPath support", "license": "MIT"}, {"name": "pybind11", "version": "v2.11.1", "description": "Seamless operability between C++11 and Python", "license": "BSD-3-Clause"}, {"name": "pybind11_json", "version": "0.2.13", "description": "Using nlohmann::json with pybind11", "license": "BSD-3-Clause"}, {"name": "Rapid YAML", "version": "v0.4.1", "description": "Rapid YAML - a library to parse and emit YAML, and do it fast.", "license": "MIT"}, {"name": "Sigslot, a signal-slot library", "version": "v1.2.0", "description": "A simple C++14 signal-slots implementation ", "license": "MIT"}, {"name": "WebSocket++", "version": "0.8.2", "description": "C++ websocket client/server library", "license": "BSD-3-Clause"}, {"name": "Josev", "version": "a3852ba", "description": "Implementation of the ISO 15118 Communication Protocol (-2, -20, -8)", "license": "Apache-2.0"}]} \ No newline at end of file diff --git a/e2e_tests/everest/config/everest/rise_v2g/EVCCConfig.properties b/e2e_tests/everest/config/everest/rise_v2g/EVCCConfig.properties new file mode 100644 index 0000000..4314654 --- /dev/null +++ b/e2e_tests/everest/config/everest/rise_v2g/EVCCConfig.properties @@ -0,0 +1,14 @@ +# +#Fri Jun 30 19:17:39 UTC 2023 +network.interface=eth0 +exi.messages.showhex=true +energy.transfermode.requested=AC_three_phase_core +exi.messages.showxml=true +signature.verification.showlog=true +contract.certificate.update.timespan=14 +implementation.evcc.controller=com.v2gclarity.risev2g.evcc.evController.EverestEVController +authentication.mode= +voltage.accuracy=5 +tls=false +session.id=00 +exi.codec=exificient diff --git a/e2e_tests/everest/config/everest/rise_v2g/SECCConfig.properties b/e2e_tests/everest/config/everest/rise_v2g/SECCConfig.properties new file mode 100644 index 0000000..72d30fc --- /dev/null +++ b/e2e_tests/everest/config/everest/rise_v2g/SECCConfig.properties @@ -0,0 +1,130 @@ +############################################################################### +# The MIT License (MIT) +# +# Copyright (c) 2015 - 2019 Dr. Marc Mueltin (V2G Clarity) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +############################################################################### +# ============================================================================== +# Configuration properties for a unique electric vehicle supply equipment (EVSE) +# ============================================================================== + +# Network interface +#------------------ +# +# The network interface name like en3 or eth1 of the network interface on which to communicate with the EVCC via a +# link-local IPv6 address +network.interface = eth0 + + +# Supported energy transfer modes +# ------------------------------- +# +# Refer to table 63 "Semantics for EnergyTransferModeType" +# Select one value or a comma-separated list of the following values: +# - AC_single_phase_core +# - AC_three_phase_core +# - DC_core +# - DC_extended +# - DC_combo_core +# - DC_unique +energy.transfermodes.supported = AC_three_phase_core, AC_single_phase_core + + +# Is charging a free service? +#---------------------------- +# +# Possible values: +# - true +# - false +charging.free = true + + +# PaymentOptions +# -------------- +# +# Select from the following values: +# - Contract +# - ExternalPayment +# The supported values must be separated by the comma delimiter (","). It does not matter +# if you add white spaces between the values or not. +authentication.modes.supported = Contract, ExternalPayment + + +# Is the SECC located in a private environment? +#--------------------------------------------- +#In a private environment, TLS mechanisms work a bit differently than in a public environment. + +# Possible values: +# - true +# - false +environment.private = false + +# +# Implementation classes +#--------------------------------------------- +# If you want to replace the implementations then set the following values +# to the name of your classes +# When omitted default dummy implementations will be used +implementation.secc.backend = com.v2gclarity.risev2g.secc.backend.EverestBackendInterface +implementation.secc.acevsecontroller = com.v2gclarity.risev2g.secc.evseController.EverestEVSEController +implementation.secc.dcevsecontroller = com.v2gclarity.risev2g.secc.evseController.EverestEVSEController + +# XML representation of messages +#------------------------------- +# +# Possible values: +# - true +# - false +# If this value is set to 'true', the EXICodec will print each message's XML representation (for debugging purposes) +# If no correct value is provided here, 'false' will be chosen +exi.messages.showxml = true + + +# Hexadecimal and Base64 representation of messages +#-------------------------------------------------- +# +# Possible values: +# - true +# - false +# If this value is set to 'true', the EXICodec will print each message's hexadecimal and Base64 representation (for debugging purposes) +# If no correct value is provided here, 'false' will be chosen +exi.messages.showhex = false + + +# Extended logging of signature verification +#------------------------------------------- +# +# Possible values: +# - true +# - false +# If this value is set to 'true', extended logging will be printed upon verification of signatures (for debugging purposes) +# If no correct value is provided here, 'false' will be chosen +signature.verification.showlog = false + + +# EXI codec +#-------------------------------- +# +# This (single!) value tells the program which EXI codec to use to en-/decode EXI messages +# Possible values are: +# - exificient +# - open_exi +# If no correct value is provided here, 'exificient' will be used +exi.codec = exificient diff --git a/e2e_tests/everest/config/everest/rise_v2g/log4j2.properties b/e2e_tests/everest/config/everest/rise_v2g/log4j2.properties new file mode 100644 index 0000000..b8a2d7d --- /dev/null +++ b/e2e_tests/everest/config/everest/rise_v2g/log4j2.properties @@ -0,0 +1,15 @@ +appender.file.type = File +appender.file.name = FILE +appender.file.fileName = /tmp/rise.log +appender.file.layout.type = PatternLayout +appender.file.layout.pattern = %m%n + +logger.evcc.level = debug +logger.evcc.appenderRef.file.ref = FILE +logger.evcc.name = StartEVCC +logger.evcc.additivity = false + +logger.codec.level = debug +logger.codec.appenderRef.file.ref = FILE +logger.codec.name = EXIficientCodec +logger.codec.additivity = false \ No newline at end of file diff --git a/e2e_tests/everest/config/everest/user-config/.gitkeep b/e2e_tests/everest/config/everest/user-config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/e2e_tests/everest/config/everest/user-config/ocpp/user_config.json b/e2e_tests/everest/config/everest/user-config/ocpp/user_config.json new file mode 100644 index 0000000..9564f6e --- /dev/null +++ b/e2e_tests/everest/config/everest/user-config/ocpp/user_config.json @@ -0,0 +1 @@ +{"Core":{"HeartbeatInterval":60}} diff --git a/e2e_tests/everest/scripts/copy-csms-cert.sh b/e2e_tests/everest/scripts/copy-csms-cert.sh new file mode 100755 index 0000000..dfb1391 --- /dev/null +++ b/e2e_tests/everest/scripts/copy-csms-cert.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +default_csms_dir="${script_dir}"/../../.. +csms_dir="${1:-$default_csms_dir}" + +cp "$csms_dir"/config/certificates/csms.pem "$script_dir"/../config/certificates +cp "$csms_dir"/config/certificates/csms.pem "$script_dir"/../config/everest/certs/ca/csms diff --git a/e2e_tests/everest/scripts/generate-cs-cert.sh b/e2e_tests/everest/scripts/generate-cs-cert.sh new file mode 100755 index 0000000..103733e --- /dev/null +++ b/e2e_tests/everest/scripts/generate-cs-cert.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +BEARER_TOKEN="$1" +CS_NAME="${2:-cs001}" + +if [[ "$BEARER_TOKEN" == "" ]]; then + echo "You must provide a bearer token" + exit 1 +fi + +BEARER_TOKEN=${BEARER_TOKEN#"Bearer "} + +script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +openssl ecparam -name prime256v1 -genkey -noout -out "${script_dir}"/../config/certificates/"${CS_NAME}".key +openssl req -new -key "${script_dir}"/../config/certificates/"${CS_NAME}".key \ + -subj "/CN=${CS_NAME}/O=Thoughtworks" \ + -out "${script_dir}"/../config/certificates/"${CS_NAME}".csr \ + -outform DER \ + -sha256 + +curl -s https://open.plugncharge-test.hubject.com/cpo/simpleenroll/ISO15118-2 \ + -H 'Accept: application/pkcs7' \ + -H "Authorization: Bearer ${BEARER_TOKEN}" \ + -H 'Content-Type: application/pkcs10' \ + -d "$(cat "${script_dir}"/../config/certificates/"${CS_NAME}".csr | base64)" | openssl enc -base64 -d > "${script_dir}"/../config/certificates/"${CS_NAME}".p7 + +openssl pkcs7 -in "${script_dir}"/../config/certificates/"${CS_NAME}".p7 -inform DER -print_certs -out "${script_dir}"/../config/certificates/"${CS_NAME}".pem diff --git a/e2e_tests/everest/scripts/generate-mo-cert.sh b/e2e_tests/everest/scripts/generate-mo-cert.sh new file mode 100755 index 0000000..f3b784a --- /dev/null +++ b/e2e_tests/everest/scripts/generate-mo-cert.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +BEARER_TOKEN="$1" +EMAID="${2}" + +if [[ "$BEARER_TOKEN" == "" ]]; then + echo "You must provide a bearer token" + exit 1 +fi + +BEARER_TOKEN=${BEARER_TOKEN#"Bearer "} + +if [[ "$EMAID" == "" ]]; then + echo "You must provide a EMAID" + exit 1 +fi + +script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +openssl ecparam -name prime256v1 -genkey -noout -out "${script_dir}"/../config/certificates/"${EMAID}".key +openssl req -new -key "${script_dir}"/../config/certificates/"${EMAID}".key \ + -subj "/CN=${EMAID}/O=Thoughtworks" \ + -out "${script_dir}"/../config/certificates/"${EMAID}".csr \ + -outform DER \ + -sha256 + +curl -s https://open.plugncharge-test.hubject.com/mo/simpleenroll/ISO15118-2 \ + -H 'Accept: application/pkcs7' \ + -H "Authorization: Bearer ${BEARER_TOKEN}" \ + -H 'Content-Type: application/pkcs10' \ + -d "$(cat "${script_dir}"/../config/certificates/"${EMAID}".csr | base64)" | openssl enc -base64 -d > "${script_dir}"/../config/certificates/"${EMAID}".p7 + +openssl pkcs7 -in "${script_dir}"/../config/certificates/"${EMAID}".p7 -inform DER -print_certs -out "${script_dir}"/../config/certificates/"${EMAID}".pem +openssl pkcs12 -export -inkey "${script_dir}"/../config/certificates/"${EMAID}".key -in "${script_dir}"/../config/certificates/"${EMAID}".pem -name contract_cert -out "${script_dir}"/../config/certificates/"${EMAID}".p12 -password pass:123456 diff --git a/e2e_tests/everest/scripts/generate-oem-cert.sh b/e2e_tests/everest/scripts/generate-oem-cert.sh new file mode 100755 index 0000000..a7fd678 --- /dev/null +++ b/e2e_tests/everest/scripts/generate-oem-cert.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +BEARER_TOKEN="$1" +PCID="${2}" + +if [[ "$BEARER_TOKEN" == "" ]]; then + echo "You must provide a bearer token" + exit 1 +fi + +BEARER_TOKEN=${BEARER_TOKEN#"Bearer "} + +if [[ "$PCID" == "" ]]; then + echo "You must provide a PCID" + exit 1 +fi + +script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +openssl ecparam -name prime256v1 -genkey -noout -out "${script_dir}"/../config/certificates/"${PCID}".key +openssl req -new -key "${script_dir}"/../config/certificates/"${PCID}".key \ + -subj "/CN=${PCID}/O=Thoughtworks" \ + -out "${script_dir}"/../config/certificates/"${PCID}".csr \ + -outform DER \ + -sha256 + +curl -s https://open.plugncharge-test.hubject.com/oem/simpleenroll/ISO15118-2 \ + -H 'Accept: application/pkcs7' \ + -H "Authorization: Bearer ${BEARER_TOKEN}" \ + -H 'Content-Type: application/pkcs10' \ + -d "$(cat "${script_dir}"/../config/certificates/"${PCID}".csr | base64)" | openssl enc -base64 -d > "${script_dir}"/../config/certificates/"${PCID}".p7 + +openssl pkcs7 -in "${script_dir}"/../config/certificates/"${PCID}".p7 -inform DER -print_certs -out "${script_dir}"/../config/certificates/"${PCID}".pem +openssl pkcs12 -export -inkey "${script_dir}"/../config/certificates/"${PCID}".key -in "${script_dir}"/../config/certificates/"${PCID}".pem -name oem_prov_cert -out "${script_dir}"/../config/certificates/"${PCID}".p12 -password pass:123456 diff --git a/e2e_tests/everest/scripts/get-ca-cert.sh b/e2e_tests/everest/scripts/get-ca-cert.sh new file mode 100755 index 0000000..0fb2206 --- /dev/null +++ b/e2e_tests/everest/scripts/get-ca-cert.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +BEARER_TOKEN="$1" +if [[ "$BEARER_TOKEN" == "" ]]; then + echo "You must provide a bearer token" + exit 1 +fi + +BEARER_TOKEN=${BEARER_TOKEN#"Bearer "} + +script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +certs=$(curl -s https://open.plugncharge-test.hubject.com/cpo/cacerts/ISO15118-2 \ + -H 'Accept: application/pkcs10, application/pkcs7' \ + -H "Authorization: Bearer ${BEARER_TOKEN}" \ + -H 'Content-Transfer-Encoding: application/pkcs10' | openssl enc -base64 -d | openssl pkcs7 -inform DER -print_certs) + +echo "${certs}" | awk '/subject.*CN.*=.*CPO Sub1 CA QA G1.2/,/END CERTIFICATE/' > "${script_dir}"/../config/certificates/cpo_sub_ca1.pem +echo "${certs}" | awk '/subject.*CN.*=.*CPO Sub2 CA QA G1.2.1/,/END CERTIFICATE/' > "${script_dir}"/../config/certificates/cpo_sub_ca2.pem +echo "${certs}" | awk '/subject.*CN.*=.*V2G Root CA QA G1/,/END CERTIFICATE/' > "${script_dir}"/../config/certificates/root-V2G-cert.pem +cat "${script_dir}"/../config/certificates/cpo_sub_ca1.pem "${script_dir}"/../config/certificates/cpo_sub_ca2.pem > "${script_dir}"/../config/certificates/trust.pem + +certs=$(curl -s https://open.plugncharge-test.hubject.com/mo/cacerts/ISO15118-2 \ + -H 'Accept: application/pkcs10, application/pkcs7' \ + -H "Authorization: Bearer ${BEARER_TOKEN}" \ + -H 'Content-Transfer-Encoding: application/pkcs10' | openssl enc -base64 -d | openssl pkcs7 -inform DER -print_certs) + +echo "${certs}" | awk '/subject.*CN.*=.*MO Sub1 CA QA G1.2/,/END CERTIFICATE/' > "${script_dir}"/../config/certificates/mo_sub_ca1.pem +echo "${certs}" | awk '/subject.*CN.*=.*MO Sub2 CA QA G1.2.1/,/END CERTIFICATE/' > "${script_dir}"/../config/certificates/mo_sub_ca2.pem + diff --git a/e2e_tests/everest/scripts/register-oem-cert.sh b/e2e_tests/everest/scripts/register-oem-cert.sh new file mode 100755 index 0000000..47f48f2 --- /dev/null +++ b/e2e_tests/everest/scripts/register-oem-cert.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +BEARER_TOKEN="$1" +PCID="${2}" + +if [[ "$BEARER_TOKEN" == "" ]]; then + echo "You must provide a bearer token" + exit 1 +fi + +BEARER_TOKEN=${BEARER_TOKEN#"Bearer "} + +if [[ "$PCID" == "" ]]; then + echo "You must provide a PCID" + exit 1 +fi + +script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +vehicleCertificate=$(cat "${script_dir}"/../config/certificates/"${PCID}".pem | awk '/subject.*CN.*=.*'${PCID}'/,/END CERTIFICATE/' | openssl x509 -outform DER | openssl enc -base64 -A) +subCA1Cert=$(cat "${script_dir}"/../config/certificates/"${PCID}".pem | awk '/subject.*CN.*=.*OEM Sub1 CA QA G1.2/,/END CERTIFICATE/' | openssl x509 -outform DER | openssl enc -base64 -A) +subCA2Cert=$(cat "${script_dir}"/../config/certificates/"${PCID}".pem | awk '/subject.*CN.*=.*OEM Sub2 CA QA G1.2.1/,/END CERTIFICATE/' | openssl x509 -outform DER | openssl enc -base64 -A) + +curl --request PUT \ + --url https://open.plugncharge-test.hubject.com/v1/oem/provCerts \ + --header 'Accept: application/json, application/xml' \ + --header "Authorization: Bearer ${BEARER_TOKEN}" \ + --header 'Content-Type: application/json' \ + --data '{ + "subCA1Certificate": "'$subCA1Cert'", + "subCA2Certificate": "'$subCA2Cert'", + "vehicleCertificate": "'$vehicleCertificate'", + "xsdMsgDefNamespace": "urn:iso:15118:2:2013:MsgDef", + "rootIssuerDistinguishedName": "CN=V2G Root CA QA G1, DC=V2G, O=Hubject GmbH, C=DE", + "rootIssuerSerialNumber": "69ab00d259bbdf42ce80529ad30ce5ed", + "v2gRootAuthorityKeyIdentifier": "4b:45:ff:82:25:fc:10:96", + "rootAuthorityKeyIdentifier": "4b:45:ff:82:25:fc:10:96"}' diff --git a/e2e_tests/everest/scripts/setup-everest.sh b/e2e_tests/everest/scripts/setup-everest.sh new file mode 100755 index 0000000..9561a41 --- /dev/null +++ b/e2e_tests/everest/scripts/setup-everest.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash + +set -euo pipefail + +bearer_token=$(curl -s https://hubject.stoplight.io/api/v1/projects/cHJqOjk0NTg5/nodes/6bb8b3bc79c2e-authorization-token | jq -r .data | sed -n '/Bearer/s/^.*Bearer //p') +cs_id=cs001 +store_pass=123456 +emaid="EMP77TWTW99999" +pcid="HUBOPENPROVCERT999" + +while getopts ":b:c:e:p:" opt; do + case "${opt}" in + b ) + bearer_token="$OPTARG" + ;; + c ) + cs_id="$OPTARG" + ;; + e) + emaid="$OPTARG" + ;; + p) + pcid="$OPTARG" + ;; + \? ) + echo "Invalid option: $OPTARG" 1>&2 + echo "Usage: $0 [-b ] [-c ] [-e ] [-p ]" + exit 1 + ;; + : ) + echo "Invalid option: $OPTARG requires an argument" 1>&2 + exit 1 + esac +done +shift $((OPTIND -1)) + +script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +cert_dir="${script_dir}"/../config/certificates +everest_dir="${script_dir}"/../config/everest + +if [ ! -f "${cert_dir}"/cpo_sub_ca1.pem ]; then + echo "Retrieving CPO cert chain..." + "$script_dir"/get-ca-cert.sh "${bearer_token}" +fi + +echo "Settings CS CPO cert chain..." +cp "${cert_dir}"/cpo_sub_ca1.pem "$everest_dir"/certs/ca/cso/CPO_SUB_CA1.pem +cp "${cert_dir}"/cpo_sub_ca2.pem "$everest_dir"/certs/ca/cso/CPO_SUB_CA2.pem + +echo "Setting CS V2G root..." +cp "${cert_dir}"/root-V2G-cert.pem "$everest_dir"/certs/ca/v2g/V2G_ROOT_CA.pem + +if [ ! -f "${cert_dir}/evccTruststore.jks" ]; then + echo "Creating EVCC trust store with V2G root" + keytool -import -keystore "${cert_dir}/evccTruststore.jks" -storepass "${store_pass}" -alias v2g_root -noprompt -file "${cert_dir}"/root-V2G-cert.pem +fi + +echo "Setting EV trust store..." +cp "${cert_dir}"/evccTruststore.jks "${everest_dir}"/certs/client/oem/EVCC_TRUSTSTORE.jks + +echo "Setting CSMS server certificate as EVerest TLS trust root" + +if [ ! -f "${cert_dir}/csms.pem" ]; then + echo "CSMS server certificate must be copied into the config/certificates directory" + exit 1 +fi + +cp "${cert_dir}"/csms.pem "${everest_dir}"/certs/ca/csms + +if [ ! -f "${cert_dir}"/${cs_id}.pem ]; then + echo "Creating CS certificate..." + "$script_dir"/generate-cs-cert.sh "${bearer_token}" "${cs_id}" +fi + +echo "Setting CS certificate as EVerest SECC client certificate" +cp "${cert_dir}"/${cs_id}.pem "${everest_dir}"/certs/client/csms/CSMS_LEAF.pem +cp "${cert_dir}"/${cs_id}.key "${everest_dir}"/certs/client/csms/CSMS_LEAF.key + +echo "Setting CS certificate as EVerest SECC server certificate" +cp "${cert_dir}"/${cs_id}.pem "${everest_dir}"/certs/client/cso/SECC_LEAF.pem +cp "${cert_dir}"/${cs_id}.key "${everest_dir}"/certs/client/cso/SECC_LEAF.key +echo "" > "${everest_dir}/certs/client/cso/SECC_LEAF_PASSWORD.txt" + +if [ ! -f "${cert_dir}"/"${pcid}".p12 ]; then + echo "Creating OEM provisioning certificate..." + "$script_dir"/generate-oem-cert.sh "${bearer_token}" "${pcid}" + "$script_dir"/register-oem-cert.sh "${bearer_token}" "${pcid}" +fi + +if [ ! -f "${cert_dir}"/evccKeystore.jks ]; then + echo "Creating EVCC key store with OEM provisioning certificate..." + keytool -importkeystore -srckeystore "${cert_dir}"/${pcid}.p12 -srcstoretype pkcs12 -srcstorepass "${store_pass}" \ + -srcalias oem_prov_cert -destalias oem_prov_cert -destkeystore "${cert_dir}"/evccKeystore.jks -storepass "${store_pass}" -noprompt +fi + +if [[ "${emaid}" != "" ]]; then + if [ ! -f "${cert_dir}"/"${emaid}".p12 ]; then + echo "Creating contract certificate..." + "$script_dir"/generate-mo-cert.sh "${bearer_token}" "${emaid}" + fi + + keytool -importkeystore -srckeystore "${cert_dir}"/"${emaid}".p12 -srcstoretype pkcs12 -srcstorepass "${store_pass}" \ + -srcalias contract_cert -destalias contract_cert -destkeystore "${cert_dir}"/evccKeystore.jks -storepass "${store_pass}" -noprompt +fi + +echo "Setting EV key store..." +cp "${cert_dir}"/evccKeystore.jks "${everest_dir}"/certs/client/oem/EVCC_KEYSTORE.jks diff --git a/e2e_tests/run-e2e-tests.sh b/e2e_tests/run-e2e-tests.sh new file mode 100755 index 0000000..355ad08 --- /dev/null +++ b/e2e_tests/run-e2e-tests.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +# Get the directory where the script is located +SCRIPT_DIR=$(dirname "$(readlink -f "$0")") + +# Get the directory where the CSMS is located +DEFAULT_CSMS_DIR="${SCRIPT_DIR}"/.. +CSMS_DIR="${1:-$DEFAULT_CSMS_DIR}" + +# Define paths relative to the script's location +EVEREST_DIR="$CSMS_DIR/e2e_tests" +TEST_DIR="$CSMS_DIR/e2e_tests/test_driver" + + +# Function to start Docker Compose +start_docker_compose_for_maeve_csms() { + cd "$CSMS_DIR" + (cd config/certificates && make) + chmod 755 $CSMS_DIR/config/certificates/csms.key + docker-compose up -d + if [ $? -eq 0 ]; then + echo "Docker Compose started successfully" + else + echo "Failed to start Docker Compose" + stop_docker_compose_for_maeve_csms + exit 1 + fi +} + +# Function to start Docker Compose +start_docker_compose_for_everest() { + source "$SCRIPT_DIR/everest/scripts/copy-csms-cert.sh" + source "$SCRIPT_DIR/everest/scripts/setup-everest.sh" + cd "$EVEREST_DIR" + make up + if [ $? -ne 0 ]; then + echo "Failed to start Docker Compose for tests" + stop_docker_compose_for_everest + exit 1 + fi + + echo "Waiting for services to initialize..." + sleep 10 +} + +# Function to stop Docker Compose +stop_docker_compose_for_everest() { + cd "$EVEREST_DIR" && docker-compose down +} + +stop_docker_compose_for_maeve_csms() { + cd "$CSMS_DIR" && docker-compose down +} + +# Function to check health endpoint +check_health_endpoint() { + docker-compose logs + HEALTH_ENDPOINT="http://localhost:9410/health" + echo "$(date +"%Y-%m-%d %H:%M:%S"):Waiting for the health endpoint to become available..." + while true; do + STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_ENDPOINT) + if [ $STATUS_CODE -eq 200 ]; then + echo "$(date +"%Y-%m-%d %H:%M:%S"):Health endpoint is available (HTTP 200)" + break + else + echo "$(date +"%Y-%m-%d %H:%M:%S"):Health endpoint is not yet available (HTTP $STATUS_CODE)" + sleep 5 + fi + done +} + +# Function to run tests +run_tests() { + echo "Running test command..." + cd "$TEST_DIR" + go test --tags=e2e -v ./... -count=1 + TEST_RESULT=$? + cd "$CSMS_DIR" + if [ $TEST_RESULT -eq 0 ]; then + echo "Tests completed successfully" + else + echo "Tests failed" + fi + + stop_docker_compose_for_everest + stop_docker_compose_for_maeve_csms +} + +# Main script execution +start_docker_compose_for_maeve_csms +check_health_endpoint +start_docker_compose_for_everest +run_tests diff --git a/e2e_tests/test_driver/README.md b/e2e_tests/test_driver/README.md new file mode 100644 index 0000000..19ea88c --- /dev/null +++ b/e2e_tests/test_driver/README.md @@ -0,0 +1,6 @@ +# End-to-End test + +```shell +$ go test --tags=e2e -v ./... -count=1 +``` + diff --git a/e2e_tests/test_driver/doc.go b/e2e_tests/test_driver/doc.go new file mode 100644 index 0000000..1435ab8 --- /dev/null +++ b/e2e_tests/test_driver/doc.go @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: Apache-2.0 + +package test_driver diff --git a/e2e_tests/test_driver/end_to_end_test.go b/e2e_tests/test_driver/end_to_end_test.go new file mode 100644 index 0000000..5efa764 --- /dev/null +++ b/e2e_tests/test_driver/end_to_end_test.go @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: Apache-2.0 +//go:build e2e + +package test_driver + +import ( + "fmt" + mqtt "github.com/eclipse/paho.mqtt.golang" + "os" + "sync" + "testing" + "time" +) + +func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool { + c := make(chan struct{}) + go func() { + defer close(c) + wg.Wait() + }() + select { + case <-c: + return false // completed normally + case <-time.After(timeout): + return true // timed out + } +} + +func shutdownBrokerConnection(t *testing.T, client mqtt.Client, wg *sync.WaitGroup) { + defer client.Disconnect(0) + + t.Log("unplugging...") + wg.Add(1) + tok := client.Publish("everest_external/nodered/1/carsim/cmd/modify_charging_session", 0, false, "unplug") + if tok.WaitTimeout(1 * time.Second); tok.Error() != nil { + t.Errorf("failed to publish unplug to topic: %v", tok.Error()) + } + timedOut := waitTimeout(wg, 5*time.Second) + if timedOut { + t.Errorf("timed out waiting for unplug to complete") + } +} + +func setupBrokerConnection(t *testing.T, wg *sync.WaitGroup) (mqtt.Client, func()) { + brokerAddr := os.Getenv("MQTT_BROKER_ADDR") + if brokerAddr == "" { + brokerAddr = "127.0.0.1:1884" + } + + opts := mqtt.NewClientOptions() + opts.AddBroker(brokerAddr) + + client := mqtt.NewClient(opts) + if token := client.Connect(); token.WaitTimeout(2*time.Second) && token.Error() != nil { + t.Fatalf("failed to connect to MQTT broker: %v", token.Error()) + } + + return client, func() { + shutdownBrokerConnection(t, client, wg) + } +} + +func TestRFIDCharge(t *testing.T) { + wg := sync.WaitGroup{} + + client, shutdown := setupBrokerConnection(t, &wg) + defer shutdown() + + state := "Unset" + + tok := client.Subscribe("everest_external/nodered/1/state/state_string", 0, func(client mqtt.Client, msg mqtt.Message) { + t.Logf("charger status changed to %s\n", msg.Payload()) + + switch string(msg.Payload()) { + case "Wait for Auth": + state = string(msg.Payload()) + wg.Done() + case "Charging": + state = string(msg.Payload()) + wg.Done() + case "Idle": + state = string(msg.Payload()) + wg.Done() + } + }) + if tok.WaitTimeout(1 * time.Second); tok.Error() != nil { + t.Fatalf("failed to subscribe to topic: %v", tok.Error()) + } + + wg.Add(1) + t.Logf("plug in...") + tok = client.Publish("everest_external/nodered/1/carsim/cmd/execute_charging_session", 0, false, + "sleep 1;iec_wait_pwr_ready;sleep 1;draw_power_regulated 16,3;sleep 5") + + if tok.WaitTimeout(1 * time.Second); tok.Error() != nil { + t.Fatalf("failed to publish start charge to topic: %v", tok.Error()) + } + + timedOut := waitTimeout(&wg, 5*time.Second) + if timedOut { + t.Errorf("timed out waiting for ready to authorise") + } + if state != "Wait for Auth" { + t.Fatalf("expected state to be Wait for Auth, got %s", state) + } + + wg.Add(1) + t.Logf("authorise charge...") + tok = client.Publish("everest_api/dummy_token_provider/cmd/provide", 0, false, + fmt.Sprintln("{\"id_token\":\"DEADBEEF\",\"authorization_type\":\"RFID\",\"prevalidated\":false,\"connectors\":[1]}")) + if tok.WaitTimeout(1 * time.Second); tok.Error() != nil { + t.Fatalf("failed to publish authorise to topic: %v", tok.Error()) + } + + timedOut = waitTimeout(&wg, 5*time.Second) + if timedOut { + t.Errorf("timed out waiting for authorise to complete") + } + if state != "Charging" { + t.Fatalf("expected state to be Charging, got %s", state) + } +} + +func TestISO15118Charge(t *testing.T) { + t.Skip("skipping test in short mode.") + wg := sync.WaitGroup{} + + client, shutdown := setupBrokerConnection(t, &wg) + defer shutdown() + + state := "Unset" + + tok := client.Subscribe("everest_external/nodered/1/state/state_string", 0, func(client mqtt.Client, msg mqtt.Message) { + t.Logf("charger status changed to %s\n", msg.Payload()) + + switch string(msg.Payload()) { + case "PrepareCharging": + state = string(msg.Payload()) + wg.Done() + case "Idle": + state = string(msg.Payload()) + wg.Done() + } + }) + if tok.WaitTimeout(1 * time.Second); tok.Error() != nil { + t.Fatalf("failed to subscribe to topic: %v", tok.Error()) + } + + wg.Add(1) + t.Logf("plug in...") + tok = client.Publish("everest_external/nodered/1/carsim/cmd/execute_charging_session", 0, false, + "sleep 1;iso_wait_slac_matched;iso_start_v2g_session Contract,AC_three_phase_core;iso_wait_pwr_ready;iso_draw_power_regulated 16,3;sleep 36000") + if tok.WaitTimeout(1 * time.Second); tok.Error() != nil { + t.Fatalf("failed to publish start charge to topic: %v", tok.Error()) + } + + timedOut := waitTimeout(&wg, 15*time.Second) + if timedOut { + t.Errorf("timed out waiting for charge to start") + } + if state != "PrepareCharging" { + t.Fatalf("expected state to be PrepareCharging, got %s", state) + } +} diff --git a/e2e_tests/test_driver/go.mod b/e2e_tests/test_driver/go.mod new file mode 100644 index 0000000..4a85b82 --- /dev/null +++ b/e2e_tests/test_driver/go.mod @@ -0,0 +1,11 @@ +module mqttbrokertest + +go 1.20 + +require github.com/eclipse/paho.mqtt.golang v1.4.3 + +require ( + github.com/gorilla/websocket v1.5.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sync v0.2.0 // indirect +) diff --git a/e2e_tests/test_driver/go.sum b/e2e_tests/test_driver/go.sum new file mode 100644 index 0000000..83214d8 --- /dev/null +++ b/e2e_tests/test_driver/go.sum @@ -0,0 +1,8 @@ +github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik= +github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=