Skip to content

Commit

Permalink
Added test case to check if existing profiles can properly validated (#…
Browse files Browse the repository at this point in the history
…837)

Fixed validation of TxProfile(s) by checking profile id so profiles are the same profiles do not conflict
Fixed check for overlapping validity period. The chargingProfileKind was used although K01.FR.06 requires chargingProfilePurpose instead

Signed-off-by: Piet Gömpel <[email protected]>
  • Loading branch information
Pietfried authored Oct 16, 2024
1 parent c6a6e01 commit 83172ee
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 8 deletions.
17 changes: 9 additions & 8 deletions lib/ocpp/v201/smart_charging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,11 @@ SmartChargingHandler::validate_tx_profile(const ChargingProfile& profile, int32_
return ProfileValidationResultEnum::TxProfileTransactionNotOnEvse;
}

auto conflicts_stmt = this->database_handler->new_statement(
"SELECT PROFILE FROM CHARGING_PROFILES WHERE TRANSACTION_ID = @transaction_id AND STACK_LEVEL = @stack_level");
auto conflicts_stmt =
this->database_handler->new_statement("SELECT PROFILE FROM CHARGING_PROFILES WHERE TRANSACTION_ID = "
"@transaction_id AND STACK_LEVEL = @stack_level AND ID != @id");
conflicts_stmt->bind_int("@stack_level", profile.stackLevel);
conflicts_stmt->bind_int("@id", profile.id);
if (profile.transactionId.has_value()) {
conflicts_stmt->bind_text("@transaction_id", profile.transactionId.value().get(),
common::SQLiteString::Transient);
Expand Down Expand Up @@ -510,22 +512,21 @@ std::vector<ChargingProfile> SmartChargingHandler::get_station_wide_tx_default_p

bool SmartChargingHandler::is_overlapping_validity_period(const ChargingProfile& candidate_profile,
int candidate_evse_id) const {

if (candidate_profile.chargingProfilePurpose == ChargingProfilePurposeEnum::TxProfile) {
// This only applies to non TxProfile types.
return false;
}

auto overlap_stmt = this->database_handler->new_statement(
"SELECT PROFILE, json_extract(PROFILE, '$.chargingProfileKind') AS KIND FROM CHARGING_PROFILES WHERE EVSE_ID = "
"@evse_id AND ID != @profile_id AND CHARGING_PROFILES.STACK_LEVEL = @stack_level AND KIND = @kind");
"SELECT PROFILE FROM CHARGING_PROFILES WHERE CHARGING_PROFILE_PURPOSE = @purpose AND EVSE_ID = "
"@evse_id AND ID != @profile_id AND CHARGING_PROFILES.STACK_LEVEL = @stack_level");

overlap_stmt->bind_int("@evse_id", candidate_evse_id);
overlap_stmt->bind_int("@profile_id", candidate_profile.id);
overlap_stmt->bind_int("@stack_level", candidate_profile.stackLevel);
overlap_stmt->bind_text("@kind",
conversions::charging_profile_kind_enum_to_string(candidate_profile.chargingProfileKind),
common::SQLiteString::Transient);
overlap_stmt->bind_text(
"@purpose", conversions::charging_profile_purpose_enum_to_string(candidate_profile.chargingProfilePurpose),
common::SQLiteString::Transient);
while (overlap_stmt->step() != SQLITE_DONE) {
ChargingProfile existing_profile = json::parse(overlap_stmt->column_text(0));
if (candidate_profile.validFrom <= existing_profile.validTo &&
Expand Down
61 changes: 61 additions & 0 deletions tests/lib/ocpp/v201/test_smart_charging_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <optional>

#include "comparators.hpp"
#include "smart_charging_test_utils.hpp"
#include <sstream>
#include <vector>

Expand Down Expand Up @@ -912,6 +913,33 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K01FR06_ExisitingProfileHasValidPeri
EXPECT_THAT(sut, testing::Eq(ProfileValidationResultEnum::DuplicateProfileValidityPeriod));
}

TEST_F(SmartChargingHandlerTestFixtureV201,
K01FR06_ExisitingProfileHasValidPeriodIncomingOverlaps_IfProfileHasDifferentPurpose_ThenProfileIsValid) {
auto periods = create_charging_schedule_periods(0);
auto existing_profile = create_charging_profile(
DEFAULT_PROFILE_ID, ChargingProfilePurposeEnum::TxDefaultProfile,
create_charge_schedule(ChargingRateUnitEnum::A, periods, ocpp::DateTime("2024-01-17T17:00:00")), {},
ChargingProfileKindEnum::Absolute, DEFAULT_STACK_LEVEL, ocpp::DateTime("2024-01-01T13:00:00"),
ocpp::DateTime("2024-02-01T13:00:00"));
auto response = handler.validate_and_add_profile(existing_profile, DEFAULT_EVSE_ID);
EXPECT_THAT(response.status, testing::Eq(ChargingProfileStatusEnum::Accepted));

this->evse_manager->open_transaction(DEFAULT_EVSE_ID, DEFAULT_TX_ID);

auto profile = create_charging_profile(
DEFAULT_PROFILE_ID + 1, ChargingProfilePurposeEnum::TxProfile,
create_charge_schedule(ChargingRateUnitEnum::A, periods, ocpp::DateTime("2024-01-17T17:00:00")), DEFAULT_TX_ID,
ChargingProfileKindEnum::Absolute, DEFAULT_STACK_LEVEL, ocpp::DateTime("2024-01-15T13:00:00"),
ocpp::DateTime("2024-02-01T13:00:00"));

response = handler.validate_and_add_profile(profile, DEFAULT_EVSE_ID);
EXPECT_THAT(response.status, testing::Eq(ChargingProfileStatusEnum::Accepted));

// verify TxDefaultProfile can still be validated when TxProfile was added
auto sut = handler.validate_profile(existing_profile, DEFAULT_EVSE_ID);
EXPECT_THAT(sut, testing::Eq(ProfileValidationResultEnum::Valid));
}

TEST_F(SmartChargingHandlerTestFixtureV201, K01_ValidateProfile_IfEvseDoesNotExist_ThenProfileIsInvalid) {
auto profile = create_charging_profile(DEFAULT_PROFILE_ID, ChargingProfilePurposeEnum::TxProfile,
create_charge_schedule(ChargingRateUnitEnum::A), DEFAULT_TX_ID);
Expand Down Expand Up @@ -1678,4 +1706,37 @@ TEST_F(SmartChargingHandlerTestFixtureV201, K05FR02_RequestStartTransactionReque
ASSERT_THAT(sut, testing::Eq(ProfileValidationResultEnum::RequestStartTransactionNonTxProfile));
}

TEST_F(SmartChargingHandlerTestFixtureV201, K01_ValidateChargingStationMaxProfile_AllowsExistingMatchingProfile) {
auto profile =
SmartChargingTestUtils::get_charging_profile_from_file("max/ChargingStationMaxProfile_grid_hourly.json");
auto res = handler.validate_and_add_profile(profile, STATION_WIDE_ID);
ASSERT_THAT(res.status, testing::Eq(ChargingProfileStatusEnum::Accepted));

auto sut = handler.validate_charging_station_max_profile(profile, STATION_WIDE_ID);

EXPECT_THAT(sut, testing::Eq(ProfileValidationResultEnum::Valid));
}

TEST_F(SmartChargingHandlerTestFixtureV201, K01_ValidateTxDefaultProfile_AllowsExistingMatchingProfile) {
auto profile = SmartChargingTestUtils::get_charging_profile_from_file("singles/Absolute_301.json");
auto res = handler.validate_and_add_profile(profile, DEFAULT_EVSE_ID);
ASSERT_THAT(res.status, testing::Eq(ChargingProfileStatusEnum::Accepted));

auto sut = handler.validate_tx_default_profile(profile, DEFAULT_EVSE_ID);

EXPECT_THAT(sut, testing::Eq(ProfileValidationResultEnum::Valid));
}

TEST_F(SmartChargingHandlerTestFixtureV201, K01_ValidateTxProfile_AllowsExistingMatchingProfile) {
auto profile = SmartChargingTestUtils::get_charging_profile_from_file("baseline/TxProfile_1.json");
this->evse_manager->open_transaction(DEFAULT_EVSE_ID, profile.transactionId.value());

auto res = handler.validate_and_add_profile(profile, DEFAULT_EVSE_ID);
ASSERT_THAT(res.status, testing::Eq(ChargingProfileStatusEnum::Accepted));

auto sut = handler.validate_tx_profile(profile, DEFAULT_EVSE_ID);

EXPECT_THAT(sut, testing::Eq(ProfileValidationResultEnum::Valid));
}

} // namespace ocpp::v201

0 comments on commit 83172ee

Please sign in to comment.