Skip to content

Commit

Permalink
* Removed plug_in_mutex from EVSEContext type because it is not requi…
Browse files Browse the repository at this point in the history
…red anymore

* Notifying all waiting threads instead of only using notify_one when an EV has been plugged in

Signed-off-by: Piet Gömpel <[email protected]>
  • Loading branch information
Pietfried committed Dec 16, 2024
1 parent a4d660e commit 564c9ec
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 21 deletions.
2 changes: 0 additions & 2 deletions modules/Auth/include/AuthHandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,6 @@ class AuthHandler {
*/
int select_evse(const std::vector<int>& selected_evses);

void lock_plug_in_mutex(const std::vector<int>& evse_ids);
void unlock_plug_in_mutex(const std::vector<int>& evse_ids);
int get_latest_plugin(const std::vector<int>& evse_ids);
void notify_evse(int evse_id, const ProvidedIdToken& provided_token, const ValidationResult& validation_result);
Identifier get_identifier(const ValidationResult& validation_result, const std::string& id_token,
Expand Down
1 change: 0 additions & 1 deletion modules/Auth/include/Connector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ struct EVSEContext {
std::optional<Identifier> identifier = std::nullopt;
std::vector<Connector> connectors;
Everest::SteadyTimer timeout_timer;
std::mutex plug_in_mutex;
bool plugged_in;

bool is_available();
Expand Down
20 changes: 2 additions & 18 deletions modules/Auth/lib/AuthHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ TokenHandlingResult AuthHandler::on_token(const ProvidedIdToken& provided_token)

EVLOG_info << "Result for token: " << everest::staging::helpers::redact(provided_token.id_token.value) << ": "
<< conversions::token_handling_result_to_string(result);
this->unlock_plug_in_mutex(referenced_evses); // in select_evse mutexes have been locked, here we can unlock
this->event_mutex.unlock();
return result;
}
Expand Down Expand Up @@ -449,32 +448,18 @@ int AuthHandler::get_latest_plugin(const std::vector<int>& evse_ids) {
return -1;
}

void AuthHandler::lock_plug_in_mutex(const std::vector<int>& evse_ids) {
for (const auto evse_id : evse_ids) {
this->evses.at(evse_id)->plug_in_mutex.lock();
}
}

void AuthHandler::unlock_plug_in_mutex(const std::vector<int>& evse_ids) {
for (const auto evse_id : evse_ids) {
this->evses.at(evse_id)->plug_in_mutex.unlock();
}
}

int AuthHandler::select_evse(const std::vector<int>& selected_evses) {

std::unique_lock<std::mutex> lk(this->event_mutex);
if (selected_evses.size() == 1) {
return selected_evses.at(0);
}

if (this->selection_algorithm == SelectionAlgorithm::PlugEvents) {
// locks all referenced evses for this request. Subsequent requests referencing one or more of the locked
// evses are blocked until handle_token returns
this->lock_plug_in_mutex(selected_evses);
if (this->get_latest_plugin(selected_evses) == -1) {
// no EV has been plugged in yet at the referenced evses
EVLOG_debug << "No evse in authorization queue. Waiting for a plug in...";
std::unique_lock<std::mutex> lk(this->event_mutex);
// blocks until respective plugin for evse occured or until timeout
if (!this->cv.wait_for(lk, std::chrono::seconds(this->connection_timeout),
[this, selected_evses] { return this->get_latest_plugin(selected_evses) != -1; })) {
Expand All @@ -485,7 +470,6 @@ int AuthHandler::select_evse(const std::vector<int>& selected_evses) {
return this->get_latest_plugin(selected_evses);
} else if (this->selection_algorithm == SelectionAlgorithm::FindFirst) {
EVLOG_debug << "SelectionAlgorithm FindFirst: Selecting first available evse without an active transaction";
this->lock_plug_in_mutex(selected_evses);
const auto selected_evse_id = this->get_latest_plugin(selected_evses);
if (selected_evse_id != -1 and !this->evses.at(selected_evse_id)->transaction_active) {
// an EV has been plugged in yet at the referenced evses
Expand Down Expand Up @@ -656,7 +640,7 @@ void AuthHandler::handle_session_event(const int evse_id, const SessionEvent& ev
switch (event_type) {
case SessionEventEnum::SessionStarted: {
this->plug_in_queue.push_back(evse_id);
this->cv.notify_one();
this->cv.notify_all();

// only set plug in timeout when SessionStart is caused by plug in
if (event.session_started.value().reason == StartSessionReason::EVConnected) {
Expand Down
73 changes: 73 additions & 0 deletions modules/Auth/tests/auth_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,79 @@ TEST_F(AuthTest, test_multiple_referenced_connectors) {
ASSERT_TRUE(result1 == TokenHandlingResult::TIMEOUT);
}

/// \brief Test three authorization requests for different referenced EVSEs with only one EV plugin. Two requests should
/// timeout, one should receive authorization
TEST_F(AuthTest, test_multiple_authorization_requests) {
std::vector<int32_t> connectors1{1, 2};
std::vector<int32_t> connectors2{3, 4};
std::vector<int32_t> connectors3{5, 6};

this->auth_handler->init_evse(3, 2, {Connector(1, types::evse_manager::ConnectorTypeEnum::sType2)});
this->auth_handler->init_evse(4, 3, {Connector(1, types::evse_manager::ConnectorTypeEnum::sType2)});
this->auth_handler->init_evse(5, 4, {Connector(1, types::evse_manager::ConnectorTypeEnum::sType2)});
this->auth_handler->init_evse(6, 5, {Connector(1, types::evse_manager::ConnectorTypeEnum::sType2)});
this->auth_receiver->add_evse_index(2);
this->auth_receiver->add_evse_index(3);
this->auth_receiver->add_evse_index(4);
this->auth_receiver->add_evse_index(5);

ProvidedIdToken provided_token1 = get_provided_token(VALID_TOKEN_1, connectors1);
ProvidedIdToken provided_token2 = get_provided_token(VALID_TOKEN_2, connectors2);
ProvidedIdToken provided_token3 = get_provided_token(VALID_TOKEN_3, connectors3);

EXPECT_CALL(mock_publish_token_validation_status_callback,
Call(Field(&ProvidedIdToken::id_token, provided_token1.id_token), TokenValidationStatus::Processing));
EXPECT_CALL(mock_publish_token_validation_status_callback,
Call(Field(&ProvidedIdToken::id_token, provided_token1.id_token), TokenValidationStatus::Accepted));
EXPECT_CALL(mock_publish_token_validation_status_callback,
Call(Field(&ProvidedIdToken::id_token, provided_token1.id_token), TokenValidationStatus::TimedOut));
EXPECT_CALL(mock_publish_token_validation_status_callback,
Call(Field(&ProvidedIdToken::id_token, provided_token2.id_token), TokenValidationStatus::Processing));
EXPECT_CALL(mock_publish_token_validation_status_callback,
Call(Field(&ProvidedIdToken::id_token, provided_token2.id_token), TokenValidationStatus::Accepted));
EXPECT_CALL(mock_publish_token_validation_status_callback,
Call(Field(&ProvidedIdToken::id_token, provided_token2.id_token), TokenValidationStatus::TimedOut));
EXPECT_CALL(mock_publish_token_validation_status_callback,
Call(Field(&ProvidedIdToken::id_token, provided_token3.id_token), TokenValidationStatus::Processing));
EXPECT_CALL(mock_publish_token_validation_status_callback,
Call(Field(&ProvidedIdToken::id_token, provided_token3.id_token), TokenValidationStatus::Accepted));
EXPECT_CALL(mock_publish_token_validation_status_callback,
Call(Field(&ProvidedIdToken::id_token, provided_token3.id_token), TokenValidationStatus::TimedOut))
.Times(0);

TokenHandlingResult result1;
TokenHandlingResult result2;
TokenHandlingResult result3;

std::thread t1([this, provided_token1, &result1]() { result1 = this->auth_handler->on_token(provided_token1); });
std::thread t2([this, provided_token2, &result2]() { result2 = this->auth_handler->on_token(provided_token2); });
std::thread t3([this, provided_token3, &result3]() { result3 = this->auth_handler->on_token(provided_token3); });

SessionEvent session_event = get_session_started_event(types::evse_manager::StartSessionReason::EVConnected);
this->auth_handler->handle_session_event(6, session_event);

t3.join();

SessionEvent transaction_started_event = get_transaction_started_event(provided_token3);
this->auth_handler->handle_session_event(6, transaction_started_event);

ASSERT_TRUE(this->auth_receiver->get_authorization(5));
ASSERT_TRUE(result3 == TokenHandlingResult::ACCEPTED);

t1.join();
t2.join();

ASSERT_TRUE(result1 == TokenHandlingResult::TIMEOUT);
ASSERT_TRUE(result2 == TokenHandlingResult::TIMEOUT);
ASSERT_FALSE(this->auth_receiver->get_authorization(0));
ASSERT_FALSE(this->auth_receiver->get_authorization(1));
ASSERT_FALSE(this->auth_receiver->get_authorization(2));
ASSERT_FALSE(this->auth_receiver->get_authorization(3));
ASSERT_FALSE(this->auth_receiver->get_authorization(4));

EVLOG_critical << "HQH";
}

/// \brief Test if a transaction is stopped when an id_token is swiped twice
TEST_F(AuthTest, test_stop_transaction) {
std::vector<int32_t> connectors{1};
Expand Down

0 comments on commit 564c9ec

Please sign in to comment.