diff --git a/modules/Auth/include/Connector.hpp b/modules/Auth/include/Connector.hpp index 2ec2a2a0d..b2d86246c 100644 --- a/modules/Auth/include/Connector.hpp +++ b/modules/Auth/include/Connector.hpp @@ -66,7 +66,12 @@ struct EVSEContext { } EVSEContext(int evse_id, int evse_index, const std::vector& connectors) : - evse_id(evse_id), evse_index(evse_index), transaction_active(false), connectors(connectors), plugged_in(false) { + evse_id(evse_id), + evse_index(evse_index), + transaction_active(false), + connectors(connectors), + plugged_in(false), + plug_in_timeout(false) { } int32_t evse_id; @@ -80,6 +85,8 @@ struct EVSEContext { std::mutex plug_in_mutex; std::mutex event_mutex; bool plugged_in; + bool plug_in_timeout; // indicates no authorization received within connection_timeout. Replug is required for this + // EVSE to get authorization and start a transaction bool is_available(); bool is_unavailable(); diff --git a/modules/Auth/lib/AuthHandler.cpp b/modules/Auth/lib/AuthHandler.cpp index 5b3844757..476ad1481 100644 --- a/modules/Auth/lib/AuthHandler.cpp +++ b/modules/Auth/lib/AuthHandler.cpp @@ -668,14 +668,14 @@ void AuthHandler::handle_session_event(const int evse_id, const SessionEvent& ev this->evses.at(evse_id)->timeout_timer.timeout( [this, evse_id]() { - EVLOG_info << "Plug In timeout for evse#" << evse_id; + EVLOG_info << "Plug In timeout for evse#" << evse_id << ". Replug required for this EVSE"; this->withdraw_authorization_callback(this->evses.at(evse_id)->evse_index); { std::lock_guard lk(this->plug_in_queue_mutex); this->plug_in_queue.remove_if([evse_id](int value) { return value == evse_id; }); } - this->evses.at(evse_id)->plugged_in = false; + this->evses.at(evse_id)->plug_in_timeout = true; }, std::chrono::seconds(this->connection_timeout)); } @@ -693,6 +693,7 @@ void AuthHandler::handle_session_event(const int evse_id, const SessionEvent& ev break; case SessionEventEnum::SessionFinished: { this->evses.at(evse_id)->plugged_in = false; + this->evses.at(evse_id)->plug_in_timeout = false; this->evses.at(evse_id)->identifier.reset(); this->submit_event_for_connector(evse_id, connector_id, ConnectorEvent::SESSION_FINISHED); this->evses.at(evse_id)->timeout_timer.stop(); diff --git a/modules/Auth/lib/Connector.cpp b/modules/Auth/lib/Connector.cpp index 2bceff9f0..d3c841fb8 100644 --- a/modules/Auth/lib/Connector.cpp +++ b/modules/Auth/lib/Connector.cpp @@ -40,6 +40,10 @@ std::string connector_state_to_string(const ConnectorState& state) { } // namespace conversions bool EVSEContext::is_available() { + if (this->plug_in_timeout) { + return false; + } + bool occupied = false; bool available = false; for (const auto& connector : this->connectors) { diff --git a/modules/Auth/tests/auth_tests.cpp b/modules/Auth/tests/auth_tests.cpp index 3b9482009..0ed9d2b33 100644 --- a/modules/Auth/tests/auth_tests.cpp +++ b/modules/Auth/tests/auth_tests.cpp @@ -1401,4 +1401,30 @@ TEST_F(AuthTest, test_token_timed_out) { std::this_thread::sleep_for(std::chrono::seconds(CONNECTION_TIMEOUT + 1)); } +/// \brief Test that in case of a plug in timeout, no authorization is given to the EVSE afterwards +TEST_F(AuthTest, test_plug_in_time_out) { + const SessionEvent session_event = get_session_started_event(types::evse_manager::StartSessionReason::EVConnected); + this->auth_handler->handle_session_event(1, session_event); + + std::vector connectors{1}; + ProvidedIdToken provided_token = get_provided_token(VALID_TOKEN_1, connectors); + + std::this_thread::sleep_for(std::chrono::seconds(CONNECTION_TIMEOUT)); + + EXPECT_CALL(mock_publish_token_validation_status_callback, + Call(Field(&ProvidedIdToken::id_token, provided_token.id_token), TokenValidationStatus::Processing)); + EXPECT_CALL(mock_publish_token_validation_status_callback, + Call(Field(&ProvidedIdToken::id_token, provided_token.id_token), TokenValidationStatus::Rejected)); + + // no connector should be available since the plug-in event has timed out + TokenHandlingResult result; + std::thread t1([this, provided_token, &result]() { result = this->auth_handler->on_token(provided_token); }); + t1.join(); + + ASSERT_TRUE(result == TokenHandlingResult::NO_CONNECTOR_AVAILABLE); + + ASSERT_FALSE(this->auth_receiver->get_authorization(0)); + ASSERT_FALSE(this->auth_receiver->get_authorization(1)); +} + } // namespace module