583 lines
32 KiB
C++
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)
|