// SPDX-License-Identifier: GPL-3.0-or-later /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2013 - 2024, nymea GmbH * Copyright (C) 2024 - 2025, chargebyte austria GmbH * * This file is part of nymea-energy-plugin-nymea. * * nymea-energy-plugin-nymea.s free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * nymea-energy-plugin-nymea.s distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with nymea-energy-plugin-nymea. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "testspotmarket.h" #include #include "../../../energyplugin/smartchargingmanager.h" #include "../../mocks/spotmarketprovider/spotmarketdataprovidermock.h" TestSpotmarket::TestSpotmarket(QObject *parent): EnergyTestBase(parent) { qRegisterMetaType(); } void TestSpotmarket::getAvailableProviders() { QVariant response = injectAndWait("NymeaEnergy.GetAvailableSpotMarketProviders"); QVariantList providerList = response.toMap().value("params").toMap().value("providers").toList(); QVERIFY2(providerList.count() > 0, "Available providers list is empty."); foreach (const QVariant &providerVariant, providerList) { QVariantMap providerMap = providerVariant.toMap(); QVERIFY(providerMap.contains("providerId")); QVERIFY(!providerMap.value("providerId").toUuid().isNull()); QVERIFY(providerMap.contains("name")); QVERIFY(providerMap.contains("website")); } } void TestSpotmarket::getSpotmarketEntriesAndChargingSchedules() { QVariant response, notification; QSignalSpy notificationSpy(m_mockTcpServer, &MockTcpServer::outgoingData);; // Initially disable response = injectAndWait("NymeaEnergy.SetSpotMarketConfiguration", {{"enabled", false}}); verifyEnergyError(response); // Make sure initially everything is disabled and unconfigured response = injectAndWait("NymeaEnergy.GetSpotMarketConfiguration"); //qCDebug(dcTests()) << qUtf8Printable(QJsonDocument::fromVariant(response).toJson()); QCOMPARE(response.toMap().value("params").toMap().value("enabled").toBool(), false); QCOMPARE(response.toMap().value("params").toMap().value("available").toBool(), false); // Get empty score entries response = injectAndWait("NymeaEnergy.GetSpotMarketScoreEntries"); QVariantList emptyScoreEnrties = response.toMap().value("params").toMap().value("spotMarketScoreEntries").toList(); QVERIFY2(emptyScoreEnrties.isEmpty(), "Fetched spotmarket entries list is empty."); // Get providers response = injectAndWait("NymeaEnergy.GetAvailableSpotMarketProviders"); QVariantList providerList = response.toMap().value("params").toMap().value("providers").toList(); QVERIFY2(providerList.count() > 0, "Available providers list is empty."); QUuid providerId = providerList.first().toMap().value("providerId").toUuid(); notificationSpy.clear(); // Enable spot market provider QVariantMap params; params.insert("enabled", true); params.insert("providerId", providerId); response = injectAndWait("NymeaEnergy.SetSpotMarketConfiguration", params); verifyEnergyError(response); // Verify notifications QVariantList scoreEnrties; // First notification is empty, since the entries are cleard if (notificationSpy.count() == 0) notificationSpy.wait(); notification = checkNotification(notificationSpy, "NymeaEnergy.SpotMarketScoreEntriesChanged"); //qCDebug(dcTests()) << qUtf8Printable(QJsonDocument::fromVariant(notification).toJson()); QVERIFY(notificationSpy.count() >= 1); scoreEnrties = notification.toMap().value("params").toMap().value("spotMarketScoreEntries").toList(); QVERIFY2(scoreEnrties.count() == 0, "Expected empty score entries notification"); notificationSpy.clear(); // Second notifications should contain actual data... if (notificationSpy.count() == 0) notificationSpy.wait(); notification = checkNotification(notificationSpy, "NymeaEnergy.SpotMarketScoreEntriesChanged"); //qCDebug(dcTests()) << qUtf8Printable(QJsonDocument::fromVariant(notification).toJson()); QVERIFY(notificationSpy.count() >= 1); scoreEnrties = notification.toMap().value("params").toMap().value("spotMarketScoreEntries").toList(); QVERIFY2(scoreEnrties.count() > 0, "Expected score entries in notification"); notificationSpy.clear(); // Get score entries response = injectAndWait("NymeaEnergy.GetSpotMarketScoreEntries"); QVariantList fetchedScoreEnrties = response.toMap().value("params").toMap().value("spotMarketScoreEntries").toList(); QVERIFY2(fetchedScoreEnrties.count() > 0, "Fetched spotmarket entries list is empty."); QCOMPARE(scoreEnrties.count(), fetchedScoreEnrties.count()); // ===================================================================================== // Now add a car and plan some charging schedules for today based on the available schedules // Set phase power limit params.clear(); response.clear(); notification.clear(); notificationSpy.clear(); response = injectAndWait("NymeaEnergy.SetPhasePowerLimit", QVariantMap({{"phasePowerLimit", 50}})); QVERIFY(response.toMap().value("params").toMap().value("energyError").toString() == "EnergyErrorNoError"); // Add mock meter QUuid meterThingId = addMeter(); QVERIFY2(!meterThingId.isNull(), "Did not receive valid ThingId"); if (notificationSpy.count() == 0) notificationSpy.wait(); notification = checkNotification(notificationSpy, "Energy.RootMeterChanged"); QCOMPARE(notification.toMap().value("params").toMap().value("rootMeterThingId").toUuid(), meterThingId); // Make sure this is our root meter now response = injectAndWait("Energy.GetRootMeter"); QCOMPARE(response.toMap().value("params").toMap().value("rootMeterThingId").toUuid(), meterThingId); notificationSpy.clear(); // Add the charger QUuid evChargerId = addCharger("ABC", 16); QVERIFY2(!evChargerId.isNull(), "Did not receive valid ThingId"); if (notificationSpy.count() == 0) notificationSpy.wait(); checkNotification(notificationSpy, "Integrations.ThingAdded"); // Add the car QUuid assignedCarId = addCar(); QVERIFY2(!assignedCarId.isNull(), "Did not receive valid ThingId"); if (notificationSpy.count() == 0) notificationSpy.wait(); checkNotification(notificationSpy, "Integrations.ThingAdded"); // Set charger states QNetworkReply *reply = nullptr; reply = setChargerStates(true, false, true, "ABC", 6, 32); QSignalSpy setChargerStatesReplySpy(reply, &QNetworkReply::finished); if (setChargerStatesReplySpy.count() == 0) setChargerStatesReplySpy.wait(); QCOMPARE(reply->error(), QNetworkReply::NoError); // Set charging info with our charger and car QVariantMap chargingInfoMap; chargingInfoMap.insert("evChargerId", evChargerId); chargingInfoMap.insert("assignedCarId", assignedCarId); chargingInfoMap.insert("chargingMode", "ChargingModeEco"); chargingInfoMap.insert("spotMarketChargingEnabled", true); chargingInfoMap.insert("dailySpotMarketPercentage", 20); notificationSpy.clear(); qCDebug(dcTests()) << "Sending charging info:" << qUtf8Printable(QJsonDocument::fromVariant(chargingInfoMap).toJson(QJsonDocument::Indented)); response = injectAndWait("NymeaEnergy.SetChargingInfo", QVariantMap({{"chargingInfo", chargingInfoMap}})); QCOMPARE(response.toMap().value("status").toString(), QString("success")); verifyEnergyError(response); // Verify notifications QVariantList chargingSchedules; if (notificationSpy.count() == 0) notificationSpy.wait(); notification = checkNotification(notificationSpy, "NymeaEnergy.ChargingSchedulesChanged"); qCDebug(dcTests()) << qUtf8Printable(QJsonDocument::fromVariant(notification).toJson()); QVERIFY(notificationSpy.count() >= 1); chargingSchedules = notification.toMap().value("params").toMap().value("chargingSchedules").toList(); QVERIFY2(!chargingSchedules.isEmpty(), "No score entries in the notification"); // Get score entries response = injectAndWait("NymeaEnergy.GetChargingSchedules"); QVariantList fetchedChargingSchedules = response.toMap().value("params").toMap().value("chargingSchedules").toList(); QVERIFY2(fetchedChargingSchedules.count() > 0, "Fetched spotmarket entries list is empty."); QCOMPARE(chargingSchedules.count(), fetchedChargingSchedules.count()); } void TestSpotmarket::addCharingInfo_data() { QTest::addColumn("addingCharger"); QTest::addColumn("addingCar"); QTest::addColumn("carValid"); QTest::addColumn("chargingMode"); QTest::addColumn("endDateTime"); QTest::addColumn>("repeatDays"); QTest::addColumn("targetPercentage"); QTest::addColumn("spotMarketEnabled"); QTest::addColumn("spotMarketChargingEnabled"); QTest::addColumn("dailySpotMarketPercentage"); QTest::addColumn("expectedError"); QDateTime endDateTime = QDateTime::currentDateTime().addDays(1); endDateTime.setTime(QTime(7, 0)); QTest::newRow("Default ON") << true << true << true << "ChargingModeEco" << endDateTime << QList{} << 100 << true << true << 0 << EnergyManager::EnergyErrorNoError; QTest::newRow("Default OFF") << true << true << true << "ChargingModeEco" << endDateTime << QList{} << 100 << false << false << 0 << EnergyManager::EnergyErrorNoError; QTest::newRow("Spot market not enabled") << true << true << true << "ChargingModeEco" << endDateTime << QList{} << 100 << false << true << 0 << EnergyManager::EnergyErrorInvalidParameter; QTest::newRow("Spot market enabled, charging disabled") << true << true << true << "ChargingModeEco" << endDateTime << QList{} << 100 << false << true << 0 << EnergyManager::EnergyErrorInvalidParameter; QTest::newRow("Daily percentage out of range") << true << true << true << "ChargingModeEco" << endDateTime << QList{} << 100 << true << true << 101 << EnergyManager::EnergyErrorInvalidParameter; } void TestSpotmarket::addCharingInfo() { QFETCH(bool, addingCharger); QFETCH(bool, addingCar); QFETCH(bool, carValid); QFETCH(QString, chargingMode); QFETCH(QDateTime, endDateTime); QFETCH(QList, repeatDays); QFETCH(int, targetPercentage); QFETCH(bool, spotMarketEnabled); QFETCH(bool, spotMarketChargingEnabled); QFETCH(int, dailySpotMarketPercentage); QFETCH(EnergyManager::EnergyError, expectedError); QVariant response, notification; QSignalSpy notificationSpy(m_mockTcpServer, &MockTcpServer::outgoingData);; // Set phase power limit uint phasePowerLimit = 25000; response = injectAndWait("NymeaEnergy.SetPhasePowerLimit", QVariantMap({{"phasePowerLimit", phasePowerLimit}})); verifyEnergyError(response); removeDevices(); // Add mock meter QUuid meterThingId = addMeter(); QVERIFY2(!meterThingId.isNull(), "Did not receive valid ThingId"); if (notificationSpy.count() == 0) notificationSpy.wait(); notification = checkNotification(notificationSpy, "Energy.RootMeterChanged"); QCOMPARE(notification.toMap().value("params").toMap().value("rootMeterThingId").toUuid(), meterThingId); // Make sure this is our root meter now response = injectAndWait("Energy.GetRootMeter"); QCOMPARE(response.toMap().value("params").toMap().value("rootMeterThingId").toUuid(), meterThingId); notificationSpy.clear(); // Add the charger QUuid evChargerId; if (addingCharger) { evChargerId = addCharger("ABC", 16); QVERIFY2(!evChargerId.isNull(), "Did not receive valid ThingId"); if (notificationSpy.count() == 0) notificationSpy.wait(); checkNotification(notificationSpy, "Integrations.ThingAdded"); } else { evChargerId = QUuid::createUuid(); } // Add the car QUuid assignedCarId; if (addingCar) { assignedCarId = addCar(); QVERIFY2(!assignedCarId.isNull(), "Did not receive valid ThingId"); if (notificationSpy.count() == 0) notificationSpy.wait(); checkNotification(notificationSpy, "Integrations.ThingAdded"); } if (!carValid) assignedCarId = QUuid::createUuid(); // Get the list of providers and set the first one... response = injectAndWait("NymeaEnergy.GetAvailableSpotMarketProviders"); QVariantList providerList = response.toMap().value("params").toMap().value("providers").toList(); QVERIFY2(providerList.count() > 0, "Available providers list is empty."); QUuid providerId = providerList.first().toMap().value("providerId").toUuid(); notificationSpy.clear(); QVariantMap params; params.insert("enabled", spotMarketEnabled); if (!providerId.isNull()) params.insert("providerId", providerId); // Configure spot market if desired response = injectAndWait("NymeaEnergy.SetSpotMarketConfiguration", params); verifyEnergyError(response); // Make sure it is enabled/disabled response = injectAndWait("NymeaEnergy.GetSpotMarketConfiguration"); qCDebug(dcTests()) << qUtf8Printable(QJsonDocument::fromVariant(response).toJson()); QCOMPARE(response.toMap().value("params").toMap().value("enabled").toBool(), spotMarketEnabled); // Set charging info with our charger and car QVariantMap chargingInfoMap; chargingInfoMap.insert("evChargerId", evChargerId); if (!assignedCarId.isNull()) chargingInfoMap.insert("assignedCarId", assignedCarId); chargingInfoMap.insert("chargingMode", chargingMode); chargingInfoMap.insert("spotMarketChargingEnabled", spotMarketChargingEnabled); chargingInfoMap.insert("dailySpotMarketPercentage", dailySpotMarketPercentage); chargingInfoMap.insert("endDateTime", endDateTime.toMSecsSinceEpoch() / 1000); QVariantList repDaysList; foreach (int day, repeatDays) { repDaysList.append(day); } chargingInfoMap.insert("repeatDays", repDaysList); chargingInfoMap.insert("targetPercentage", targetPercentage); //qCDebug(dcTests()) << "Sending charging info:" << qUtf8Printable(QJsonDocument::fromVariant(chargingInfoMap).toJson(QJsonDocument::Indented)); response = injectAndWait("NymeaEnergy.SetChargingInfo", QVariantMap({{"chargingInfo", chargingInfoMap}})); QCOMPARE(response.toMap().value("status").toString(), QString("success")); verifyEnergyError(response, expectedError); } void TestSpotmarket::setConfiguration_data() { QTest::addColumn("enabled"); QTest::addColumn("useValidProvider"); QTest::addColumn("useNullProvider"); QTest::addColumn("expectedError"); QTest::newRow("Enable valid") << true << true << false << EnergyManager::EnergyErrorNoError; QTest::newRow("Disable valid") << false << true << false << EnergyManager::EnergyErrorNoError; QTest::newRow("Enable with invalid provider") << true << false << false << EnergyManager::EnergyErrorInvalidParameter; QTest::newRow("Enable with null provider id") << true << false << true << EnergyManager::EnergyErrorInvalidParameter; } void TestSpotmarket::setConfiguration() { QFETCH(bool, enabled); QFETCH(bool, useValidProvider); QFETCH(bool, useNullProvider); QFETCH(EnergyManager::EnergyError, expectedError); QVariant response, notification; QSignalSpy notificationSpy(m_mockTcpServer, &MockTcpServer::outgoingData);; // Initially disable response = injectAndWait("NymeaEnergy.SetSpotMarketConfiguration", {{"enabled", false}}); verifyEnergyError(response); // Make sure initially everything is disabled and unconfigured response = injectAndWait("NymeaEnergy.GetSpotMarketConfiguration"); //qCDebug(dcTests()) << qUtf8Printable(QJsonDocument::fromVariant(response).toJson()); QCOMPARE(response.toMap().value("params").toMap().value("enabled").toBool(), false); QCOMPARE(response.toMap().value("params").toMap().value("available").toBool(), false); // Get the list of providers and set the first one... QUuid providerId; if (useValidProvider) { response = injectAndWait("NymeaEnergy.GetAvailableSpotMarketProviders"); QVariantList providerList = response.toMap().value("params").toMap().value("providers").toList(); QVERIFY2(providerList.count() > 0, "Available providers list is empty."); providerId = providerList.first().toMap().value("providerId").toUuid(); } if (!useValidProvider) providerId = QUuid::createUuid(); if (useNullProvider) providerId = QUuid(); notificationSpy.clear(); QVariantMap params; params.insert("enabled", enabled); if (!providerId.isNull()) params.insert("providerId", providerId); response = injectAndWait("NymeaEnergy.SetSpotMarketConfiguration", params); verifyEnergyError(response, expectedError); if (expectedError == EnergyManager::EnergyErrorNoError) { // Verify notification if (notificationSpy.count() == 0) notificationSpy.wait(); notification = checkNotification(notificationSpy, "NymeaEnergy.SpotMarketConfigurationChanged"); qCDebug(dcTests()) << qUtf8Printable(QJsonDocument::fromVariant(notification).toJson()); QVERIFY(notificationSpy.count() >= 1); response = injectAndWait("NymeaEnergy.GetSpotMarketConfiguration"); qCDebug(dcTests()) << qUtf8Printable(QJsonDocument::fromVariant(response).toJson()); QCOMPARE(response.toMap().value("params").toMap().value("enabled").toBool(), enabled); } } void TestSpotmarket::testMockProvider_data() { QTest::addColumn("currentDateTime"); QTest::addColumn("expectedScheduleCount"); QTest::addColumn("nextDayAvailableWeighted"); QTest::newRow("Mock provider 11:00") << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(11, 0, 0)) << 13 << false; QTest::newRow("Mock provider 11:15") << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(11, 15, 0)) << 13 << false; QTest::newRow("Mock provider 12:00") << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(12, 0, 0)) << 36 << true; QTest::newRow("Mock provider 12:15") << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(12, 15, 0)) << 36 << true; QTest::newRow("Mock provider 13:00") << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(13, 0, 0)) << 35 << true; QTest::newRow("Mock provider 13:15") << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(13, 15, 0)) << 35 << true; QTest::newRow("Mock provider 00:00") << EnergyTestBase::utcDateTime(QDate::currentDate().addDays(1), QTime(00, 00, 0)) << 24 << false; } void TestSpotmarket::testMockProvider() { QFETCH(QDateTime, currentDateTime); QFETCH(int, expectedScheduleCount); QFETCH(bool, nextDayAvailableWeighted); SpotMarketManager *manager = new SpotMarketManager(m_networkAccessManager, this); QVERIFY2(!manager->enabled(), "SpotMarketManager initally enabled"); SpotMarketDataProviderMock *mockProvider = new SpotMarketDataProviderMock(m_networkAccessManager, manager); QVERIFY2(mockProvider->prepareResourceData(":/resources/dataset-1.json", currentDateTime), "Could not load resource data for testing the spotmarket manager."); QVERIFY2(manager->registerProvider(mockProvider), "Failed to register mock provider"); QVERIFY2(manager->changeProvider(mockProvider->providerId()), "failed to change provider to mock provider"); mockProvider->setCurrentDataTime(currentDateTime); QCOMPARE(manager->currentProvider(), qobject_cast(mockProvider)); manager->setEnabled(true); QSignalSpy dataChangedSpy(manager, &SpotMarketManager::scoreEntriesUpdated); mockProvider->refreshData(); if (dataChangedSpy.count() == 0) dataChangedSpy.wait(); QCOMPARE(dataChangedSpy.count(), 1); QCOMPARE(manager->currentProvider()->scoreEntries().count(), expectedScheduleCount); QCOMPARE(manager->weightedScoreEntries(currentDateTime.date()).count(), (expectedScheduleCount > 24 ? expectedScheduleCount - 24 : expectedScheduleCount)); if (nextDayAvailableWeighted) { QCOMPARE(manager->weightedScoreEntries(currentDateTime.date().addDays(1)).count(), 24); } manager->setEnabled(false); delete manager; } void TestSpotmarket::testTimeFrameFusing_data() { QTest::addColumn("timeFrames"); QTest::addColumn("fusedTimeFrames"); QTest::newRow("2 hours") << TimeFrames({ TimeFrame(QDateTime(QDate::currentDate(), QTime(4, 0, 0)), QDateTime(QDate::currentDate(), QTime(5, 0, 0))), TimeFrame(QDateTime(QDate::currentDate(), QTime(5, 0, 0)), QDateTime(QDate::currentDate(), QTime(6, 0, 0))) }) << TimeFrames({ TimeFrame(QDateTime(QDate::currentDate(), QTime(4, 0, 0)), QDateTime(QDate::currentDate(), QTime(6, 0, 0))) }); QTest::newRow("4 hours") << TimeFrames({ TimeFrame(QDateTime(QDate::currentDate(), QTime(4, 0, 0)), QDateTime(QDate::currentDate(), QTime(5, 0, 0))), TimeFrame(QDateTime(QDate::currentDate(), QTime(5, 0, 0)), QDateTime(QDate::currentDate(), QTime(6, 0, 0))), TimeFrame(QDateTime(QDate::currentDate(), QTime(10, 0, 0)), QDateTime(QDate::currentDate(), QTime(11, 0, 0))), TimeFrame(QDateTime(QDate::currentDate(), QTime(11, 0, 0)), QDateTime(QDate::currentDate(), QTime(12, 0, 0))) }) << TimeFrames({ TimeFrame(QDateTime(QDate::currentDate(), QTime(4, 0, 0)), QDateTime(QDate::currentDate(), QTime(6, 0, 0))), TimeFrame(QDateTime(QDate::currentDate(), QTime(10, 0, 0)), QDateTime(QDate::currentDate(), QTime(12, 0, 0))) }); QTest::newRow("partial alone") << TimeFrames({ TimeFrame(QDateTime(QDate::currentDate(), QTime(4, 0, 0)), QDateTime(QDate::currentDate(), QTime(4, 30, 0))), TimeFrame(QDateTime(QDate::currentDate(), QTime(6, 0, 0)), QDateTime(QDate::currentDate(), QTime(7, 0, 0))) }) << TimeFrames({ TimeFrame(QDateTime(QDate::currentDate(), QTime(4, 0, 0)), QDateTime(QDate::currentDate(), QTime(4, 30, 0))), TimeFrame(QDateTime(QDate::currentDate(), QTime(6, 0, 0)), QDateTime(QDate::currentDate(), QTime(7, 0, 0))) }); QTest::newRow("2 partial fused") << TimeFrames({ TimeFrame(QDateTime(QDate::currentDate(), QTime(4, 0, 0)), QDateTime(QDate::currentDate(), QTime(4, 30, 0))), TimeFrame(QDateTime(QDate::currentDate(), QTime(5, 0, 0)), QDateTime(QDate::currentDate(), QTime(5, 30, 0))) }) << TimeFrames({ TimeFrame(QDateTime(QDate::currentDate(), QTime(4, 30, 0)), QDateTime(QDate::currentDate(), QTime(5, 30, 0))) }); QTest::newRow("3 partial fused") << TimeFrames({ TimeFrame(QDateTime(QDate::currentDate(), QTime(4, 0, 0)), QDateTime(QDate::currentDate(), QTime(4, 30, 0))), TimeFrame(QDateTime(QDate::currentDate(), QTime(5, 0, 0)), QDateTime(QDate::currentDate(), QTime(5, 30, 0))), TimeFrame(QDateTime(QDate::currentDate(), QTime(6, 0, 0)), QDateTime(QDate::currentDate(), QTime(6, 30, 0))) }) << TimeFrames({ TimeFrame(QDateTime(QDate::currentDate(), QTime(4, 30, 0)), QDateTime(QDate::currentDate(), QTime(5, 30, 0))), TimeFrame(QDateTime(QDate::currentDate(), QTime(6, 0, 0)), QDateTime(QDate::currentDate(), QTime(6, 30, 0)))}); } void TestSpotmarket::testTimeFrameFusing() { QFETCH(TimeFrames, timeFrames); QFETCH(TimeFrames, fusedTimeFrames); TimeFrames resultFrames = SpotMarketManager::fuseTimeFrames(timeFrames); QVERIFY2(resultFrames.count() == fusedTimeFrames.count(), "Expected frame count does not match the resulting frame count."); QCOMPARE(resultFrames, fusedTimeFrames); } void TestSpotmarket::testScheduleTime_data() { QTest::addColumn("dataset"); QTest::addColumn("currentDateTime"); QTest::addColumn("minutes"); QTest::addColumn("minimumScheduleDuration"); QTest::addColumn("currentFrameLocked"); QTest::addColumn("expectedTimeFrames"); QTest::newRow("Schedule at 04:00 dataset-1 120 min") << ":/resources/dataset-1.json" << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(4, 0, 0)) << 120 << 1 << false << TimeFrames({ TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(4, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(5, 0, 0))), TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(13, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(14, 0, 0))) }); QTest::newRow("Schedule at 04:00 dataset-1 260 min") << ":/resources/dataset-1.json" << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(4, 0, 0)) << 260 << 1 << false << TimeFrames({ TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(4, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(5, 20, 0))), TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(12, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(14, 0, 0))), TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(23, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(23, 0, 0)).addSecs(3600))}); QTest::newRow("Schedule at 04:20 dataset-1 260 min") << ":/resources/dataset-1.json" << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(4, 20, 0)) << 260 << 1 << false << TimeFrames({ TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(4, 20, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(5, 40, 0))), TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(12, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(14, 0, 0))), TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(23, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(23, 0, 0)).addSecs(3600))}); QTest::newRow("Schedule at 04:40 dataset-1 260 min") << ":/resources/dataset-1.json" << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(4, 40, 0)) << 260 << 1 << false << TimeFrames({ TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(4, 40, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(6, 0, 0))), TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(12, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(14, 0, 0))), TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(23, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(23, 0, 0)).addSecs(3600))}); QTest::newRow("Schedule at 04:41 dataset-1 260 min window 1") << ":/resources/dataset-1.json" << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(4, 41, 0)) << 260 << 1 << false << TimeFrames({ TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(4, 41, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(6, 0, 0))), TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(10, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(10, 1, 0))), TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(12, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(14, 0, 0))), TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(23, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(23, 0, 0)).addSecs(3600))}); QTest::newRow("Schedule at 04:41 dataset-1 260 min window 10") << ":/resources/dataset-1.json" << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(4, 41, 0)) << 260 << 10 << false << TimeFrames({ TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(4, 41, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(6, 0, 0))), TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(12, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(14, 0, 0))), TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(23, 0, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(23, 1, 0)).addSecs(3600))}); QTest::newRow("Schedule at 09:25 dataset-3 346 min window 10") << ":/resources/dataset-3.json" << EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(8, 41, 0)) << 331 << 10 << false << TimeFrames({ TimeFrame(EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(8, 41, 0)), EnergyTestBase::utcDateTime(QDate::currentDate(), QTime(14, 12, 0)))}); } void TestSpotmarket::testScheduleTime() { QFETCH(QString, dataset); QFETCH(QDateTime, currentDateTime); QFETCH(int, minutes); QFETCH(int, minimumScheduleDuration); QFETCH(bool, currentFrameLocked); QFETCH(TimeFrames, expectedTimeFrames); SpotMarketManager *manager = new SpotMarketManager(m_networkAccessManager, this); QVERIFY2(!manager->enabled(), "SpotMarketManager initally enabled"); SpotMarketDataProviderMock *mockProvider = new SpotMarketDataProviderMock(m_networkAccessManager, manager); QVERIFY2(mockProvider->prepareResourceData(dataset, currentDateTime), "Could not load resource data for testing the spotmarket manager."); QVERIFY2(manager->registerProvider(mockProvider), "Failed to register mock provider"); QVERIFY2(manager->changeProvider(mockProvider->providerId()), "failed to change provider to mock provider"); mockProvider->setCurrentDataTime(currentDateTime); QCOMPARE(manager->currentProvider(), qobject_cast(mockProvider)); manager->setEnabled(true); QVERIFY(manager->enabled()); QSignalSpy dataChangedSpy(manager, &SpotMarketManager::scoreEntriesUpdated); mockProvider->refreshData(); if (dataChangedSpy.count() == 0) dataChangedSpy.wait(); ScoreEntries weigthedScorings = manager->weightedScoreEntries(currentDateTime.date()); weigthedScorings.sortByWeighting(); qCDebug(dcTests()) << "Best timeframes" << weigthedScorings; TimeFrames resultingTimeFrames = manager->scheduleCharingTimeForToday(currentDateTime, minutes, minimumScheduleDuration, currentFrameLocked); qCDebug(dcTests()) << "Resulting timeframes" << resultingTimeFrames; int summ = 0; foreach (const TimeFrame &frame, resultingTimeFrames) { summ += frame.durationMinutes(); } QCOMPARE(summ, minutes); QCOMPARE(resultingTimeFrames, expectedTimeFrames); manager->setEnabled(false); delete mockProvider; delete manager; } QTEST_MAIN(TestSpotmarket)