- CitrineOS core extracted (CSMS OCPP 2.0.1) - OpenOCPP extracted (firmware OCPP 1.6J/2.0.1) - ShapeShifter library installed (pip install -e) - ShapeShifter specification extracted - EVerest extracted TODO updated with progress
878 lines
44 KiB
C++
878 lines
44 KiB
C++
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright chargebyte GmbH and Contributors to EVerest
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <thread>
|
|
|
|
#include "../data/DataStore.hpp"
|
|
#include "../helpers/ErrorHandler.hpp"
|
|
#include "../helpers/JsonRpcUtils.hpp"
|
|
#include "../helpers/RequestHandlerDummy.hpp"
|
|
#include "../helpers/WebSocketTestClient.hpp"
|
|
#include "../rpc/RpcHandler.hpp"
|
|
#include "../server/WebsocketServer.hpp"
|
|
|
|
using namespace server;
|
|
using namespace rpc;
|
|
using namespace json_rpc_utils;
|
|
|
|
class RpcHandlerTest : public ::testing::Test {
|
|
protected:
|
|
int test_port = 8080;
|
|
void SetUp() override {
|
|
// Start the WebSocket server
|
|
m_websocket_server = std::make_unique<server::WebSocketServer>(false, test_port, "lo");
|
|
lws_set_log_level(LLL_ERR | LLL_WARN, NULL);
|
|
|
|
// Create RpcHandler instance. Move the transport interfaces and request handler to the RpcHandler
|
|
std::vector<std::shared_ptr<server::TransportInterface>> transport_interfaces;
|
|
request_handler = std::make_unique<RequestHandlerDummy>(data_store);
|
|
transport_interfaces.push_back(std::shared_ptr<server::TransportInterface>(std::move(m_websocket_server)));
|
|
m_rpc_handler =
|
|
std::make_unique<RpcHandler>(std::move(transport_interfaces), data_store, std::move(request_handler));
|
|
m_rpc_handler->start_server();
|
|
initialize_data_store();
|
|
}
|
|
|
|
void TearDown() override {
|
|
m_rpc_handler->stop_server();
|
|
}
|
|
|
|
void initialize_data_store() {
|
|
// Set up the data store with test data
|
|
RPCDataTypes::ChargerInfoObj charger_info;
|
|
charger_info.firmware_version = "1.0.0";
|
|
charger_info.model = "Test Charger";
|
|
charger_info.serial = "123456789";
|
|
charger_info.vendor = "Test Vendor";
|
|
data_store.chargerinfo.set_data(charger_info);
|
|
data_store.everest_version = "2025.1.0";
|
|
// Properly initialize EVSE objects
|
|
data_store.evses.emplace_back(std::make_unique<data::DataStoreEvse>());
|
|
}
|
|
|
|
void send_req_and_validate_res(WebSocketTestClient& client, const nlohmann::json& request,
|
|
const nlohmann::json& expected_response,
|
|
bool (*cmp_f)(const nlohmann::json&, const nlohmann::json&) = nullptr) {
|
|
// Send the request
|
|
client.send(request.dump());
|
|
// Wait for the response
|
|
std::string data = client.wait_for_data(std::chrono::seconds(1));
|
|
// Check if the response is not empty
|
|
ASSERT_FALSE(data.empty());
|
|
nlohmann::json response = nlohmann::json::parse(data);
|
|
// Check if the response is valid
|
|
if (cmp_f != nullptr) {
|
|
// Compare the response with the expected response using the provided comparison function
|
|
bool res = cmp_f(response, expected_response);
|
|
if (!res) {
|
|
// If the comparison fails, print the response and expected response for debugging
|
|
EVLOG_error << "Expected equality of these values: response: " << response.dump();
|
|
EVLOG_error << "Expected response: " << expected_response.dump();
|
|
}
|
|
ASSERT_TRUE(res);
|
|
} else {
|
|
// Compare the response with the expected response
|
|
ASSERT_EQ(response, expected_response);
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<server::WebSocketServer> m_websocket_server;
|
|
std::unique_ptr<rpc::RpcHandler> m_rpc_handler;
|
|
|
|
// Condition variable to wait for response
|
|
std::condition_variable cv;
|
|
std::mutex cv_mutex;
|
|
|
|
// Data store object used to manage and access charger-related data, including EVSEs, connectors, and charger info.
|
|
data::DataStoreCharger data_store;
|
|
// Dummy request handler. Needed to create the responses of synchronous requests
|
|
std::unique_ptr<request_interface::RequestHandlerInterface> request_handler;
|
|
};
|
|
|
|
// Test: Connect to WebSocket server and check if API.Hello timeout occurs
|
|
TEST_F(RpcHandlerTest, ApiHelloTimeout) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Wait for the client hello timeout
|
|
EVLOG_info << "Waiting for client hello timeout...";
|
|
std::this_thread::sleep_for(std::chrono::seconds(CLIENT_HELLO_TIMEOUT) + std::chrono::milliseconds(100));
|
|
|
|
// Check if the client is still connected
|
|
ASSERT_FALSE(client.is_connected());
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send API.Hello request
|
|
TEST_F(RpcHandlerTest, ApiHelloReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up the expected response
|
|
RPCDataTypes::HelloResObj result;
|
|
result.authentication_required = false;
|
|
result.api_version = API_VERSION;
|
|
result.charger_info = data_store.chargerinfo.get_data().value();
|
|
result.everest_version = data_store.everest_version;
|
|
|
|
nlohmann::json expected_response = {{"jsonrpc", JSON_RPC_SPEC_VERSION}, {"result", result}, {"id", 1}};
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
// Wait for the response
|
|
std::string data = client.wait_for_data(std::chrono::seconds(1));
|
|
// Check if the response is not empty
|
|
ASSERT_FALSE(data.empty());
|
|
// Check if the response is valid
|
|
nlohmann::json response = nlohmann::json::parse(data);
|
|
ASSERT_EQ(response, expected_response);
|
|
// Check if the client is still connected
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send EVSEInfo request
|
|
TEST_F(RpcHandlerTest, ChargePointGetEVSEInfosReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::ChargePointGetEVSEInfosResObj result; // Expected response
|
|
data_store.evses.emplace_back(std::make_unique<data::DataStoreEvse>());
|
|
data_store.evses.emplace_back(std::make_unique<data::DataStoreEvse>());
|
|
RPCDataTypes::EVSEInfoObj evse_info;
|
|
evse_info.index = 1;
|
|
evse_info.available_connectors.emplace_back();
|
|
evse_info.available_connectors[0].index = 1;
|
|
evse_info.available_connectors[0].type = types::json_rpc_api::ConnectorTypeEnum::cCCS2;
|
|
evse_info.available_connectors.emplace_back();
|
|
evse_info.available_connectors[1].index = 2;
|
|
evse_info.available_connectors[1].type = types::json_rpc_api::ConnectorTypeEnum::cCCS1;
|
|
evse_info.description = "Test EVSE 1";
|
|
|
|
result.error = RPCDataTypes::ResponseErrorEnum::NoError; ///< No error
|
|
|
|
// Set up request and expected response
|
|
nlohmann::json charge_point_get_evse_infos_req = create_json_rpc_request("ChargePoint.GetEVSEInfos", {}, 1);
|
|
nlohmann::json expected_error_no_data = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorNoDataAvailable)}};
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send ChargePoint.GetEVSEInfos request and validate response, no data available
|
|
send_req_and_validate_res(client, charge_point_get_evse_infos_req, expected_error_no_data,
|
|
is_key_value_in_json_rpc_result);
|
|
// Set up the data store with test data
|
|
data_store.evses[0]->evseinfo.set_data(evse_info);
|
|
result.infos.push_back(evse_info);
|
|
evse_info.index = 2;
|
|
evse_info.description = "Test EVSE 2";
|
|
data_store.evses[1]->evseinfo.set_data(evse_info);
|
|
result.infos.push_back(evse_info);
|
|
// Set up expected response
|
|
nlohmann::json expected_response = create_json_rpc_response(result, 1);
|
|
// Send ChargePoint.GetEVSEInfos request and validate response
|
|
send_req_and_validate_res(client, charge_point_get_evse_infos_req, expected_response);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send ChargePoint.GetActiveErrors request
|
|
TEST_F(RpcHandlerTest, ChargePointGetActiveErrorsReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::EVSEInfoObj evse_info;
|
|
evse_info.index = 1; ///< Unique identifier
|
|
evse_info.available_connectors.emplace_back();
|
|
evse_info.available_connectors[0].index = 1;
|
|
evse_info.available_connectors[0].type = types::json_rpc_api::ConnectorTypeEnum::cCCS2;
|
|
evse_info.description = "Test EVSE 1";
|
|
data_store.evses[0]->evseinfo.set_data(evse_info);
|
|
// Add a second EVSE with a different index
|
|
data_store.evses.emplace_back(std::make_unique<data::DataStoreEvse>());
|
|
evse_info.index = 2; ///< Unique identifier
|
|
evse_info.description = "Test EVSE 2";
|
|
data_store.evses[1]->evseinfo.set_data(evse_info);
|
|
// Set up the EVSE status for both EVSEs
|
|
RPCDataTypes::EVSEStatusObj evse_status1, evse_status2;
|
|
evse_status1.error_present = false;
|
|
evse_status2.error_present = false;
|
|
data_store.evses[0]->evsestatus.set_data(evse_status1);
|
|
data_store.evses[1]->evsestatus.set_data(evse_status2);
|
|
|
|
types::json_rpc_api::ErrorObj error0, error1, error2;
|
|
error0.origin.evse_index = 1;
|
|
error0.origin.connector_index = 0;
|
|
error0.origin.module_id = "evse_1";
|
|
error0.origin.implementation_id = "board_support";
|
|
error0.message = "Test error message";
|
|
error0.description = "Test error description";
|
|
error0.uuid = "6db8758b-194d-48e1-99af-c8f0b1d2e3f3";
|
|
error0.severity = types::json_rpc_api::Severity::Low;
|
|
error0.timestamp = "2025-01-01T12:00:00Z";
|
|
error0.type = "TestErrorType";
|
|
|
|
error1.origin.evse_index = 2;
|
|
error1.origin.connector_index = 1;
|
|
error1.origin.module_id = "evse_2";
|
|
error1.origin.implementation_id = "board_support";
|
|
error1.message = "Test error message";
|
|
error1.description = "Test error description";
|
|
error1.uuid = "7db8758b-194d-48e1-99af-c8f0b1d2e3f4";
|
|
error1.severity = types::json_rpc_api::Severity::Medium;
|
|
error1.timestamp = "2025-01-01T12:00:00Z";
|
|
error1.type = "TestErrorType";
|
|
|
|
error2.origin.evse_index = 2;
|
|
error2.origin.connector_index = 1;
|
|
error2.origin.module_id = "evse_2";
|
|
error2.origin.implementation_id = "board_support";
|
|
error2.message = "Another test error message";
|
|
error2.description = "Another test error description";
|
|
error2.uuid = "8db8758b-194d-48e1-99af-c8f0b1d2e3f5";
|
|
error2.severity = types::json_rpc_api::Severity::High;
|
|
error2.timestamp = "2025-01-01T12:00:01Z";
|
|
error2.type = "AnotherTestErrorType";
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::ChargePointGetActiveErrorsResObj result; // Expected response
|
|
result.active_errors.push_back(error1);
|
|
result.active_errors.push_back(error2);
|
|
result.error = RPCDataTypes::ResponseErrorEnum::NoError; ///< No error
|
|
// Set up request and expected response
|
|
nlohmann::json charge_point_get_active_errors_req = create_json_rpc_request("ChargePoint.GetActiveErrors", {}, 1);
|
|
nlohmann::json expected_response = create_json_rpc_response(result, 1);
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Raise the error in the data store for the first EVSE
|
|
helpers::handle_error_raised(data_store, error0);
|
|
// Check if the error is set to present in the EVSE status
|
|
auto tmp_evse_store_1 = data_store.get_evse_store(1);
|
|
ASSERT_TRUE(tmp_evse_store_1 != nullptr);
|
|
ASSERT_TRUE(tmp_evse_store_1->evsestatus.get_data().value().error_present);
|
|
// Clear the error in the data store for the first EVSE
|
|
helpers::handle_error_cleared(data_store, error0);
|
|
// Check if the error is cleared in the EVSE status
|
|
ASSERT_FALSE(tmp_evse_store_1->evsestatus.get_data().value().error_present);
|
|
// Raise the second error in the data store for the second EVSE
|
|
helpers::handle_error_raised(data_store, error1);
|
|
helpers::handle_error_raised(data_store, error2);
|
|
// Check if error is set to present in the EVSE status
|
|
ASSERT_FALSE(tmp_evse_store_1->evsestatus.get_data().value().error_present);
|
|
auto tmp_evse_store_2 = data_store.get_evse_store(2);
|
|
ASSERT_TRUE(tmp_evse_store_2 != nullptr);
|
|
ASSERT_TRUE(tmp_evse_store_2->evsestatus.get_data().value().error_present);
|
|
// Send ChargePoint.GetActiveErrors request and validate response
|
|
send_req_and_validate_res(client, charge_point_get_active_errors_req, expected_response);
|
|
// Clear the errors for the second EVSE
|
|
helpers::handle_error_cleared(data_store, error1);
|
|
// Check if the error is still present in the EVSE status
|
|
ASSERT_TRUE(tmp_evse_store_2->evsestatus.get_data().value().error_present);
|
|
// Clear the second error
|
|
helpers::handle_error_cleared(data_store, error2);
|
|
// Check if error is cleared in the EVSE status
|
|
ASSERT_FALSE(tmp_evse_store_1->evsestatus.get_data().value().error_present);
|
|
ASSERT_FALSE(tmp_evse_store_2->evsestatus.get_data().value().error_present);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send EVSE.Infos request with valid and invalid index
|
|
TEST_F(RpcHandlerTest, EvseGetEVSEInfosReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up requests
|
|
nlohmann::json evse_get_evse_infos_req_1 = create_json_rpc_request("EVSE.GetInfo", {{"evse_index", 1}}, 1);
|
|
nlohmann::json evse_get_evse_infos_req_2 = create_json_rpc_request("EVSE.GetInfo", {{"evse_index", 2}}, 1);
|
|
nlohmann::json evse_get_infos_req_invalid_index = create_json_rpc_request("EVSE.GetInfo", {{"evse_index", 99}}, 1);
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::EVSEInfoObj evse_info;
|
|
evse_info.index = 1; ///< Unique identifier
|
|
evse_info.available_connectors.emplace_back();
|
|
evse_info.available_connectors[0].index = 1;
|
|
evse_info.available_connectors[0].type = types::json_rpc_api::ConnectorTypeEnum::cCCS2;
|
|
evse_info.available_connectors.emplace_back();
|
|
evse_info.available_connectors[1].index = 2;
|
|
evse_info.available_connectors[1].type = types::json_rpc_api::ConnectorTypeEnum::cCCS1;
|
|
evse_info.description = "Test EVSE 1";
|
|
data_store.evses[0]->evseinfo.set_data(evse_info);
|
|
|
|
// Expected response 1
|
|
RPCDataTypes::EVSEGetInfoResObj result_1;
|
|
result_1.info = evse_info;
|
|
result_1.error = RPCDataTypes::ResponseErrorEnum::NoError; ///< No error
|
|
|
|
// Set up the second EVSE info
|
|
evse_info.index = 2;
|
|
evse_info.available_connectors[0].type = types::json_rpc_api::ConnectorTypeEnum::cType2;
|
|
evse_info.available_connectors[1].type = types::json_rpc_api::ConnectorTypeEnum::sType2;
|
|
data_store.evses.emplace_back(std::make_unique<data::DataStoreEvse>());
|
|
data_store.evses[1]->evseinfo.set_data(evse_info);
|
|
|
|
// Set up the expected responses
|
|
nlohmann::json expected_response_index_1 = create_json_rpc_response(result_1, 1);
|
|
|
|
// Expected response 2
|
|
RPCDataTypes::EVSEGetInfoResObj result_2;
|
|
result_2.info = evse_info;
|
|
result_2.error = RPCDataTypes::ResponseErrorEnum::NoError; ///< No error
|
|
nlohmann::json expected_response_index_2 = create_json_rpc_response(result_2, 1);
|
|
|
|
// Expected error object in case of invalid ID
|
|
nlohmann::json expected_error = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorInvalidEVSEIndex)}};
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send EVSE.GetEVSEInfos request 1 and validate response
|
|
send_req_and_validate_res(client, evse_get_evse_infos_req_1, expected_response_index_1);
|
|
// Send EVSE.GetEVSEInfos request 2 and validate response
|
|
send_req_and_validate_res(client, evse_get_evse_infos_req_2, expected_response_index_2);
|
|
// Send EVSE.GetEVSEInfos request with invalid ID and validate response
|
|
send_req_and_validate_res(client, evse_get_infos_req_invalid_index, expected_error,
|
|
is_key_value_in_json_rpc_result);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send Evse.GetStatusReq request with valid and invalid index
|
|
TEST_F(RpcHandlerTest, EvseGetStatusReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
// Set up the requests
|
|
nlohmann::json evse_get_status_req_valid_index = create_json_rpc_request("EVSE.GetStatus", {{"evse_index", 1}}, 1);
|
|
nlohmann::json evse_get_status_req_invalid_index =
|
|
create_json_rpc_request("EVSE.GetStatus", {{"evse_index", 99}}, 1);
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::EVSEInfoObj evse_info;
|
|
evse_info.index = 1; ///< Unique identifier
|
|
data_store.evses[0]->evseinfo.set_data(evse_info);
|
|
|
|
RPCDataTypes::EVSEStatusObj evse_status;
|
|
evse_status.charged_energy_wh = 123.45;
|
|
evse_status.discharged_energy_wh = 123.45;
|
|
evse_status.charging_duration_s = 600;
|
|
evse_status.charging_allowed = true;
|
|
evse_status.available = true;
|
|
evse_status.active_connector_index = 1;
|
|
evse_status.error_present = false;
|
|
evse_status.charge_protocol = types::json_rpc_api::ChargeProtocolEnum::ISO15118; ///< charge_protocol
|
|
evse_status.state = types::json_rpc_api::EVSEStateEnum::Charging;
|
|
evse_status.ac_charge_status.emplace().evse_active_phase_count = 3;
|
|
|
|
// Set up the expected responses
|
|
RPCDataTypes::EVSEGetStatusResObj res_valid_id;
|
|
res_valid_id.status = evse_status;
|
|
res_valid_id.error = RPCDataTypes::ResponseErrorEnum::NoError;
|
|
nlohmann::json expected_error_no_data = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorNoDataAvailable)}};
|
|
nlohmann::json res_obj_invalid_index = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorInvalidEVSEIndex)}};
|
|
nlohmann::json expected_response = create_json_rpc_response(res_valid_id, 1);
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send EVSE.GetStatus request with valid ID, but no data available
|
|
send_req_and_validate_res(client, evse_get_status_req_valid_index, expected_error_no_data,
|
|
is_key_value_in_json_rpc_result);
|
|
// Set the EVSE status in the data store
|
|
data_store.evses[0]->evsestatus.set_data(evse_status);
|
|
// Send EVSE.GetStatus request with valid ID
|
|
send_req_and_validate_res(client, evse_get_status_req_valid_index, expected_response);
|
|
// Send EVSE.GetStatus request with invalid ID
|
|
send_req_and_validate_res(client, evse_get_status_req_invalid_index, res_obj_invalid_index,
|
|
is_key_value_in_json_rpc_result);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send EVSE.GetHardwareCapabilities request with valid and invalid index
|
|
TEST_F(RpcHandlerTest, EvseGetHardwareCapabilitiesReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up requests
|
|
nlohmann::json evse_get_hardware_capabilities_req_valid_index =
|
|
create_json_rpc_request("EVSE.GetHardwareCapabilities", {{"evse_index", 1}}, 1);
|
|
nlohmann::json evse_get_hardware_capabilities_req_invalid_index =
|
|
create_json_rpc_request("EVSE.GetHardwareCapabilities", {{"evse_index", 99}}, 1);
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::EVSEInfoObj evse_info;
|
|
evse_info.index = 1;
|
|
data_store.evses[0]->evseinfo.set_data(evse_info);
|
|
|
|
RPCDataTypes::EVSEGetHardwareCapabilitiesResObj result;
|
|
result.error = RPCDataTypes::ResponseErrorEnum::NoError;
|
|
result.hardware_capabilities.max_current_A_export = 32.0;
|
|
result.hardware_capabilities.max_current_A_import = 16.0;
|
|
result.hardware_capabilities.max_phase_count_export = 3;
|
|
result.hardware_capabilities.max_phase_count_import = 3;
|
|
result.hardware_capabilities.min_current_A_export = 6.0;
|
|
result.hardware_capabilities.min_current_A_import = 6.0;
|
|
result.hardware_capabilities.min_phase_count_export = 1;
|
|
result.hardware_capabilities.min_phase_count_import = 1;
|
|
result.hardware_capabilities.phase_switch_during_charging = true;
|
|
|
|
// Set up the expected responses
|
|
nlohmann::json expected_response = create_json_rpc_response(result, 1);
|
|
nlohmann::json expected_error_no_data = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorNoDataAvailable)}};
|
|
nlohmann::json expected_error_invalid_index = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorInvalidEVSEIndex)}};
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
|
|
// Send EVSE.GetHardwareCapabilities request with valid ID, but no hardware capabilities available
|
|
send_req_and_validate_res(client, evse_get_hardware_capabilities_req_valid_index, expected_error_no_data,
|
|
is_key_value_in_json_rpc_result);
|
|
// Set the hardware capabilities in the data store
|
|
data_store.evses[0]->hardwarecapabilities.set_data(result.hardware_capabilities);
|
|
// Send EVSE.GetHardwareCapabilities request with valid ID
|
|
send_req_and_validate_res(client, evse_get_hardware_capabilities_req_valid_index, expected_response);
|
|
// Send EVSE.GetHardwareCapabilities request with invalid ID
|
|
send_req_and_validate_res(client, evse_get_hardware_capabilities_req_invalid_index, expected_error_invalid_index,
|
|
is_key_value_in_json_rpc_result);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send EVSE.SetChargingAllowed request with valid and invalid index
|
|
TEST_F(RpcHandlerTest, EvseSetChargingAllowedReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up requests
|
|
nlohmann::json evse_set_charging_allowed_req_valid_index =
|
|
create_json_rpc_request("EVSE.SetChargingAllowed", {{"evse_index", 1}, {"charging_allowed", true}}, 1);
|
|
nlohmann::json evse_set_charging_allowed_req_valid_index_false =
|
|
create_json_rpc_request("EVSE.SetChargingAllowed", {{"evse_index", 1}, {"charging_allowed", false}}, 1);
|
|
nlohmann::json evse_set_charging_allowed_req_invalid_index =
|
|
create_json_rpc_request("EVSE.SetChargingAllowed", {{"evse_index", 99}, {"charging_allowed", true}}, 1);
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::EVSEInfoObj evse_info;
|
|
evse_info.index = 1;
|
|
data_store.evses[0]->evseinfo.set_data(evse_info);
|
|
|
|
RPCDataTypes::EVSEStatusObj evse_status;
|
|
evse_status.available = false;
|
|
data_store.evses[0]->evsestatus.set_data(evse_status);
|
|
|
|
// Set up the expected responses
|
|
types::json_rpc_api::ErrorResObj result{RPCDataTypes::ResponseErrorEnum::NoError};
|
|
nlohmann::json expected_response = create_json_rpc_response(result, 1);
|
|
nlohmann::json expected_error = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorInvalidEVSEIndex)}};
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send EVSE.SetChargingAllowed request with valid ID
|
|
send_req_and_validate_res(client, evse_set_charging_allowed_req_valid_index, expected_response);
|
|
// Check if the EVSE status is updated
|
|
ASSERT_TRUE(data_store.evses[0]->evsestatus.get_data().has_value());
|
|
ASSERT_TRUE(data_store.evses[0]->evsestatus.get_data().value().charging_allowed);
|
|
// Send EVSE.SetChargingAllowed request with valid ID and false
|
|
send_req_and_validate_res(client, evse_set_charging_allowed_req_valid_index_false, expected_response);
|
|
// Check if the EVSE status is updated
|
|
ASSERT_TRUE(data_store.evses[0]->evsestatus.get_data().has_value());
|
|
ASSERT_FALSE(data_store.evses[0]->evsestatus.get_data().value().charging_allowed);
|
|
|
|
// Send EVSE.SetChargingAllowed request with invalid ID
|
|
send_req_and_validate_res(client, evse_set_charging_allowed_req_invalid_index, expected_error,
|
|
is_key_value_in_json_rpc_result);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send EVSE.MeterData request with valid and invalid index
|
|
TEST_F(RpcHandlerTest, EvseMeterDataReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up requests
|
|
nlohmann::json evse_meter_data_req_valid_index =
|
|
create_json_rpc_request("EVSE.GetMeterData", {{"evse_index", 1}}, 1);
|
|
nlohmann::json evse_meter_data_req_invalid_index =
|
|
create_json_rpc_request("EVSE.GetMeterData", {{"evse_index", 99}}, 1);
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::EVSEInfoObj evse_info;
|
|
evse_info.index = 1;
|
|
data_store.evses[0]->evseinfo.set_data(evse_info);
|
|
|
|
// Configure meter data, but do not set it in the data store
|
|
RPCDataTypes::MeterDataObj meter_data{};
|
|
meter_data.energy_Wh_import.total = 123.45;
|
|
meter_data.timestamp = "2025-06-10T09:51:56Z";
|
|
|
|
// Set up the expected responses
|
|
types::json_rpc_api::EVSEGetMeterDataResObj result{{meter_data}, RPCDataTypes::ResponseErrorEnum::NoError};
|
|
nlohmann::json expected_response_no_error = create_json_rpc_response(result, 1);
|
|
nlohmann::json expected_error_no_data = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorNoDataAvailable)}};
|
|
nlohmann::json expected_error_invalid_index = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorInvalidEVSEIndex)}};
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send EVSE.MeterData request with valid ID, but no meter data available
|
|
send_req_and_validate_res(client, evse_meter_data_req_valid_index, expected_error_no_data,
|
|
is_key_value_in_json_rpc_result);
|
|
|
|
// Set the meter data in the data store
|
|
data_store.evses[0]->meterdata.set_data(meter_data);
|
|
|
|
// Send EVSE.MeterData request with valid ID and meter data available
|
|
send_req_and_validate_res(client, evse_meter_data_req_valid_index, expected_response_no_error);
|
|
|
|
// Send EVSE.MeterData request with invalid ID
|
|
send_req_and_validate_res(client, evse_meter_data_req_invalid_index, expected_error_invalid_index,
|
|
is_key_value_in_json_rpc_result);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send EVSE.SetACCharging request with valid and invalid index
|
|
TEST_F(RpcHandlerTest, EvseSetACChargingReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up requests
|
|
nlohmann::json evse_set_ac_charging_req_valid_index = create_json_rpc_request(
|
|
"EVSE.SetACCharging",
|
|
{{"evse_index", 1}, {"charging_allowed", true}, {"max_current", 12.3}, {"phase_count", 3}}, 1);
|
|
|
|
// As long as the method is not implemented, we expect an error response that the method is not implemented
|
|
nlohmann::json expected_res = create_json_rpc_error_response(-32601, "method not found: EVSE.SetACCharging", 1);
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send EVSE.SetACCharging request with valid ID
|
|
client.send(evse_set_ac_charging_req_valid_index.dump());
|
|
// Wait for the response
|
|
std::string received_data = client.wait_for_data(std::chrono::seconds(1), false);
|
|
// Check if the response is valid
|
|
nlohmann::json response = nlohmann::json::parse(received_data);
|
|
ASSERT_EQ(response, expected_res);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send EVSE.SetACChargingCurrent request with valid and invalid index
|
|
TEST_F(RpcHandlerTest, EvseSetACChargingCurrentReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up requests
|
|
nlohmann::json evse_set_ac_charging_current_req_valid_index =
|
|
create_json_rpc_request("EVSE.SetACChargingCurrent", {{"evse_index", 1}, {"max_current", 12.3}}, 1);
|
|
nlohmann::json evse_set_ac_charging_current_req_invalid_index =
|
|
create_json_rpc_request("EVSE.SetACChargingCurrent", {{"evse_index", 99}, {"max_current", 12.3}}, 1);
|
|
nlohmann::json evse_set_ac_charging_current_req_invalid_max_current =
|
|
create_json_rpc_request("EVSE.SetACChargingCurrent", {{"evse_index", 1}, {"max_current", 15.0}}, 1);
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::EVSEInfoObj evse_info{};
|
|
evse_info.index = 1;
|
|
data_store.evses[0]->evseinfo.set_data(evse_info);
|
|
|
|
RPCDataTypes::EVSEStatusObj evse_status{};
|
|
evse_status.charging_allowed = true;
|
|
data_store.evses[0]->evsestatus.set_data(evse_status);
|
|
data_store.evses[0]->evsestatus.set_ac_charge_param_evse_max_current(12.3);
|
|
|
|
// Set up the expected responses
|
|
types::json_rpc_api::ErrorResObj result{RPCDataTypes::ResponseErrorEnum::NoError};
|
|
nlohmann::json expected_response = create_json_rpc_response(result, 1);
|
|
nlohmann::json expected_error_invalid_index = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorInvalidEVSEIndex)}};
|
|
nlohmann::json expected_error_invalid_current = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorValuesNotApplied)}};
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send EVSE.SetACChargingCurrent request with valid ID
|
|
send_req_and_validate_res(client, evse_set_ac_charging_current_req_valid_index, expected_response);
|
|
|
|
// Send EVSE.SetACChargingCurrent request with invalid ID
|
|
send_req_and_validate_res(client, evse_set_ac_charging_current_req_invalid_index, expected_error_invalid_index,
|
|
is_key_value_in_json_rpc_result);
|
|
|
|
// Send EVSE.SetACChargingCurrent request with invalid AC charging current
|
|
send_req_and_validate_res(client, evse_set_ac_charging_current_req_invalid_max_current,
|
|
expected_error_invalid_current, is_key_value_in_json_rpc_result);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send EVSE.SetACChargingPhaseCount request with valid and invalid index
|
|
TEST_F(RpcHandlerTest, EvseSetACChargingPhaseCountReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up requests
|
|
nlohmann::json evse_set_ac_charging_phase_count_req_valid_index =
|
|
create_json_rpc_request("EVSE.SetACChargingPhaseCount", {{"evse_index", 1}, {"phase_count", 3}}, 1);
|
|
nlohmann::json evse_set_ac_charging_phase_count_req_invalid_index =
|
|
create_json_rpc_request("EVSE.SetACChargingPhaseCount", {{"evse_index", 99}, {"phase_count", 3}}, 1);
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::EVSEInfoObj evse_info;
|
|
evse_info.index = 1;
|
|
data_store.evses[0]->evseinfo.set_data(evse_info);
|
|
|
|
RPCDataTypes::EVSEStatusObj evse_status;
|
|
evse_status.available = false;
|
|
evse_status.ac_charge_param.emplace();
|
|
evse_status.ac_charge_param->evse_max_current = 12.3;
|
|
data_store.evses[0]->evsestatus.set_data(evse_status);
|
|
|
|
RPCDataTypes::EVSEGetHardwareCapabilitiesResObj hw_cap;
|
|
hw_cap.error = RPCDataTypes::ResponseErrorEnum::NoError;
|
|
hw_cap.hardware_capabilities.max_current_A_export = 32.0;
|
|
hw_cap.hardware_capabilities.max_current_A_import = 16.0;
|
|
hw_cap.hardware_capabilities.max_phase_count_export = 3;
|
|
hw_cap.hardware_capabilities.max_phase_count_import = 3;
|
|
hw_cap.hardware_capabilities.min_current_A_export = 6.0;
|
|
hw_cap.hardware_capabilities.min_current_A_import = 6.0;
|
|
hw_cap.hardware_capabilities.min_phase_count_export = 1;
|
|
hw_cap.hardware_capabilities.min_phase_count_import = 1;
|
|
hw_cap.hardware_capabilities.phase_switch_during_charging = true;
|
|
data_store.evses[0]->hardwarecapabilities.set_data(hw_cap.hardware_capabilities);
|
|
|
|
// Set up the expected responses
|
|
types::json_rpc_api::ErrorResObj result{RPCDataTypes::ResponseErrorEnum::NoError};
|
|
nlohmann::json expected_response = create_json_rpc_response(result, 1);
|
|
nlohmann::json expected_error = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorInvalidEVSEIndex)}};
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send EVSE.SetACChargingPhaseCount request with valid ID
|
|
send_req_and_validate_res(client, evse_set_ac_charging_phase_count_req_valid_index, expected_response);
|
|
// Send EVSE.SetACChargingPhaseCount request with invalid ID
|
|
send_req_and_validate_res(client, evse_set_ac_charging_phase_count_req_invalid_index, expected_error,
|
|
is_key_value_in_json_rpc_result);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send EVSE.SetACChargingPhaseCount request with invalid phases and disabled
|
|
// phase switching
|
|
TEST_F(RpcHandlerTest, EvseSetACChargingPhaseCountReqBadCases) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up requests
|
|
nlohmann::json evse_set_ac_charging_phase_count_req_valid_phase_count =
|
|
create_json_rpc_request("EVSE.SetACChargingPhaseCount", {{"evse_index", 1}, {"phase_count", 1}}, 1);
|
|
nlohmann::json evse_set_ac_charging_phase_count_req_invalid_phase_count =
|
|
create_json_rpc_request("EVSE.SetACChargingPhaseCount", {{"evse_index", 1}, {"phase_count", 2}}, 1);
|
|
nlohmann::json evse_set_ac_charging_phase_count_req_out_of_range =
|
|
create_json_rpc_request("EVSE.SetACChargingPhaseCount", {{"evse_index", 1}, {"phase_count", 3}}, 1);
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::EVSEInfoObj evse_info;
|
|
evse_info.index = 1;
|
|
data_store.evses[0]->evseinfo.set_data(evse_info);
|
|
|
|
RPCDataTypes::EVSEStatusObj evse_status;
|
|
evse_status.available = false;
|
|
evse_status.ac_charge_param.emplace();
|
|
evse_status.ac_charge_param->evse_max_current = 12.3;
|
|
evse_status.ac_charge_status.emplace();
|
|
evse_status.ac_charge_status->evse_active_phase_count = 1;
|
|
data_store.evses[0]->evsestatus.set_data(evse_status);
|
|
|
|
RPCDataTypes::EVSEGetHardwareCapabilitiesResObj hw_cap;
|
|
hw_cap.error = RPCDataTypes::ResponseErrorEnum::NoError;
|
|
hw_cap.hardware_capabilities.max_current_A_export = 32.0;
|
|
hw_cap.hardware_capabilities.max_current_A_import = 16.0;
|
|
hw_cap.hardware_capabilities.max_phase_count_export = 1;
|
|
hw_cap.hardware_capabilities.max_phase_count_import = 1;
|
|
hw_cap.hardware_capabilities.min_current_A_export = 6.0;
|
|
hw_cap.hardware_capabilities.min_current_A_import = 6.0;
|
|
hw_cap.hardware_capabilities.min_phase_count_export = 1;
|
|
hw_cap.hardware_capabilities.min_phase_count_import = 1;
|
|
hw_cap.hardware_capabilities.phase_switch_during_charging = false;
|
|
data_store.evses[0]->hardwarecapabilities.set_data(hw_cap.hardware_capabilities);
|
|
|
|
// Set up the expected responses
|
|
types::json_rpc_api::ErrorResObj result{RPCDataTypes::ResponseErrorEnum::NoError};
|
|
nlohmann::json expected_no_error = create_json_rpc_response(result, 1);
|
|
nlohmann::json expected_invalid_param = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorInvalidParameter)}};
|
|
nlohmann::json expected_error_out_of_range = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorOutOfRange)}};
|
|
nlohmann::json expected_error_operation_not_supported = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorOperationNotSupported)}};
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send EVSE.SetACChargingPhaseCount request with phase count. This should not lead to an error, because
|
|
// an initialization of the phase count should be still possible.
|
|
send_req_and_validate_res(client, evse_set_ac_charging_phase_count_req_valid_phase_count, expected_no_error);
|
|
|
|
// Try to switch phase count although phase switching is not allowed (phase_switch_during_charging == false)
|
|
send_req_and_validate_res(client, evse_set_ac_charging_phase_count_req_invalid_phase_count,
|
|
expected_error_operation_not_supported, is_key_value_in_json_rpc_result);
|
|
|
|
// Send EVSE.SetACChargingPhaseCount request with phase count out of range
|
|
// Enable phase switching, because otherwise it returns an ErrorOperationNotSupported error
|
|
hw_cap.hardware_capabilities.phase_switch_during_charging = true;
|
|
data_store.evses[0]->hardwarecapabilities.set_data(hw_cap.hardware_capabilities);
|
|
send_req_and_validate_res(client, evse_set_ac_charging_phase_count_req_out_of_range, expected_error_out_of_range,
|
|
is_key_value_in_json_rpc_result);
|
|
|
|
// Invalid phase count error occurs when phase_count is configured to 2
|
|
hw_cap.hardware_capabilities.max_phase_count_export = 3;
|
|
data_store.evses[0]->hardwarecapabilities.set_data(hw_cap.hardware_capabilities);
|
|
send_req_and_validate_res(client, evse_set_ac_charging_phase_count_req_invalid_phase_count, expected_invalid_param,
|
|
is_key_value_in_json_rpc_result);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send EVSE.SetDCCharging request with valid and invalid index
|
|
TEST_F(RpcHandlerTest, EvseSetDCChargingReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up requests
|
|
nlohmann::json evse_set_dc_charging_req_valid_index = create_json_rpc_request(
|
|
"EVSE.SetDCCharging", {{"evse_index", 1}, {"charging_allowed", true}, {"max_power", 12.3}}, 1);
|
|
|
|
// As long as the method is not implemented, we expect an error response that the method is not implemented
|
|
nlohmann::json expected_res = create_json_rpc_error_response(-32601, "method not found: EVSE.SetDCCharging", 1);
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send EVSE.SetDCCharging request with valid ID
|
|
client.send(evse_set_dc_charging_req_valid_index.dump());
|
|
// Wait for the response
|
|
std::string received_data = client.wait_for_data(std::chrono::seconds(1), false);
|
|
// Check if the response is valid
|
|
nlohmann::json response = nlohmann::json::parse(received_data);
|
|
ASSERT_EQ(response, expected_res);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send EVSE.SetDCChargingPower request with valid and invalid index
|
|
TEST_F(RpcHandlerTest, EvseSetDCChargingPowerReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up requests
|
|
nlohmann::json evse_set_dc_charging_power_req_valid_index =
|
|
create_json_rpc_request("EVSE.SetDCChargingPower", {{"evse_index", 1}, {"max_power", 12.3}}, 1);
|
|
nlohmann::json evse_set_dc_charging_power_req_invalid_index =
|
|
create_json_rpc_request("EVSE.SetDCChargingPower", {{"evse_index", 99}, {"max_power", 12.3}}, 1);
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::EVSEInfoObj evse_info;
|
|
evse_info.index = 1;
|
|
data_store.evses[0]->evseinfo.set_data(evse_info);
|
|
|
|
RPCDataTypes::EVSEStatusObj evse_status;
|
|
evse_status.available = false;
|
|
evse_status.dc_charge_param.emplace();
|
|
data_store.evses[0]->evsestatus.set_data(evse_status);
|
|
|
|
// Set up the expected responses
|
|
types::json_rpc_api::ErrorResObj result{RPCDataTypes::ResponseErrorEnum::NoError};
|
|
nlohmann::json expected_response = create_json_rpc_response(result, 1);
|
|
nlohmann::json expected_error = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorInvalidEVSEIndex)}};
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send EVSE.SetDCChargingPower request with valid ID
|
|
send_req_and_validate_res(client, evse_set_dc_charging_power_req_valid_index, expected_response);
|
|
// Send EVSE.SetDCChargingPower request with invalid ID
|
|
send_req_and_validate_res(client, evse_set_dc_charging_power_req_invalid_index, expected_error,
|
|
is_key_value_in_json_rpc_result);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send EVSE.EnableConnector request with valid and invalid index
|
|
TEST_F(RpcHandlerTest, EvseEnableConnectorReq) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Set up requests
|
|
nlohmann::json evse_enable_connector_req_valid_index = create_json_rpc_request(
|
|
"EVSE.EnableConnector", {{"evse_index", 1}, {"enable", true}, {"priority", 1}, {"connector_index", 1}}, 1);
|
|
nlohmann::json evse_enable_connector_req_invalid_index = create_json_rpc_request(
|
|
"EVSE.EnableConnector", {{"evse_index", 99}, {"enable", true}, {"priority", 1}, {"connector_index", 1}}, 1);
|
|
nlohmann::json evse_enable_connector_req_invalid_connector_index = create_json_rpc_request(
|
|
"EVSE.EnableConnector", {{"evse_index", 1}, {"enable", true}, {"priority", 1}, {"connector_index", 99}}, 1);
|
|
|
|
// Set up the expected responses
|
|
types::json_rpc_api::ErrorResObj result{RPCDataTypes::ResponseErrorEnum::NoError};
|
|
nlohmann::json expected_response = create_json_rpc_response(result, 1);
|
|
nlohmann::json expected_error = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorInvalidEVSEIndex)}};
|
|
|
|
nlohmann::json expected_error_invalid_connector_index = {
|
|
{"error", response_error_enum_to_string(RPCDataTypes::ResponseErrorEnum::ErrorInvalidConnectorIndex)}};
|
|
|
|
// Set up the data store with test data
|
|
RPCDataTypes::EVSEInfoObj evse_info;
|
|
evse_info.index = 1;
|
|
evse_info.available_connectors.emplace_back();
|
|
evse_info.available_connectors[0].index = 1;
|
|
evse_info.available_connectors[0].type = types::json_rpc_api::ConnectorTypeEnum::cCCS2;
|
|
data_store.evses[0]->evseinfo.set_data(evse_info);
|
|
|
|
RPCDataTypes::EVSEStatusObj evse_status;
|
|
evse_status.available = false;
|
|
data_store.evses[0]->evsestatus.set_data(evse_status);
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send EVSE.EnableConnector request with valid ID
|
|
send_req_and_validate_res(client, evse_enable_connector_req_valid_index, expected_response);
|
|
// Send EVSE.EnableConnector request with invalid ID
|
|
send_req_and_validate_res(client, evse_enable_connector_req_invalid_index, expected_error,
|
|
is_key_value_in_json_rpc_result);
|
|
// Send EVSE.EnableConnector request with invalid connector ID
|
|
send_req_and_validate_res(client, evse_enable_connector_req_invalid_connector_index,
|
|
expected_error_invalid_connector_index, is_key_value_in_json_rpc_result);
|
|
}
|
|
|
|
// Test: Connect to WebSocket server and send invalid request
|
|
TEST_F(RpcHandlerTest, InvalidRequest) {
|
|
WebSocketTestClient client("localhost", test_port);
|
|
ASSERT_TRUE(client.connect());
|
|
ASSERT_TRUE(client.wait_until_connected(std::chrono::milliseconds(100)));
|
|
|
|
// Send Api.Hello request
|
|
client.send_api_hello_req();
|
|
// Wait for the response
|
|
client.wait_for_data(std::chrono::seconds(1));
|
|
// Send invalid request
|
|
nlohmann::json invalid_request = create_json_rpc_request("API.InvalidMethod", {}, 1);
|
|
// Expected response
|
|
nlohmann::json expected_response = create_json_rpc_error_response(-32601, "method not found: API.InvalidMethod", 1);
|
|
// Send invalid request
|
|
client.send(invalid_request.dump());
|
|
// Wait for the response
|
|
std::string received_data = client.wait_for_data(std::chrono::seconds(1), false);
|
|
// Check if the response is not empty
|
|
ASSERT_FALSE(received_data.empty());
|
|
// Check if the response is valid
|
|
nlohmann::json response = nlohmann::json::parse(received_data);
|
|
ASSERT_EQ(response, expected_response);
|
|
}
|