powersync-energy-plugin-etm/tests/auto/spotmarket/testspotmarket.cpp

583 lines
32 KiB
C++

// 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 <https://www.gnu.org/licenses/>.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "testspotmarket.h"
#include <hardware/electricity.h>
#include "../../../energyplugin/smartchargingmanager.h"
#include "../../mocks/spotmarketprovider/spotmarketdataprovidermock.h"
TestSpotmarket::TestSpotmarket(QObject *parent):
EnergyTestBase(parent)
{
qRegisterMetaType<TimeFrames>();
}
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<bool>("addingCharger");
QTest::addColumn<bool>("addingCar");
QTest::addColumn<bool>("carValid");
QTest::addColumn<QString>("chargingMode");
QTest::addColumn<QDateTime>("endDateTime");
QTest::addColumn<QList<int>>("repeatDays");
QTest::addColumn<int>("targetPercentage");
QTest::addColumn<bool>("spotMarketEnabled");
QTest::addColumn<bool>("spotMarketChargingEnabled");
QTest::addColumn<int>("dailySpotMarketPercentage");
QTest::addColumn<EnergyManager::EnergyError>("expectedError");
QDateTime endDateTime = QDateTime::currentDateTime().addDays(1);
endDateTime.setTime(QTime(7, 0));
QTest::newRow("Default ON") << true << true << true << "ChargingModeEco" << endDateTime << QList<int>{} << 100 << true << true << 0 << EnergyManager::EnergyErrorNoError;
QTest::newRow("Default OFF") << true << true << true << "ChargingModeEco" << endDateTime << QList<int>{} << 100 << false << false << 0 << EnergyManager::EnergyErrorNoError;
QTest::newRow("Spot market not enabled") << true << true << true << "ChargingModeEco" << endDateTime << QList<int>{} << 100 << false << true << 0 << EnergyManager::EnergyErrorInvalidParameter;
QTest::newRow("Spot market enabled, charging disabled") << true << true << true << "ChargingModeEco" << endDateTime << QList<int>{} << 100 << false << true << 0 << EnergyManager::EnergyErrorInvalidParameter;
QTest::newRow("Daily percentage out of range") << true << true << true << "ChargingModeEco" << endDateTime << QList<int>{} << 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<int>, 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<bool>("enabled");
QTest::addColumn<bool>("useValidProvider");
QTest::addColumn<bool>("useNullProvider");
QTest::addColumn<EnergyManager::EnergyError>("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<QDateTime>("currentDateTime");
QTest::addColumn<int>("expectedScheduleCount");
QTest::addColumn<bool>("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<SpotMarketDataProvider*>(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>("timeFrames");
QTest::addColumn<TimeFrames>("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<QString>("dataset");
QTest::addColumn<QDateTime>("currentDateTime");
QTest::addColumn<int>("minutes");
QTest::addColumn<int>("minimumScheduleDuration");
QTest::addColumn<bool>("currentFrameLocked");
QTest::addColumn<TimeFrames>("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<SpotMarketDataProvider*>(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)