From 9b07216768082bd1c2681f027eb5fc81cdf74a1f Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 10 Dec 2019 23:40:51 +0100 Subject: [PATCH 1/9] Add system api to configure the system time This gets rid of the locally kept time zone which caused issues in plugins and the ScriptEngine. --- .../devices/devicemanagerimplementation.cpp | 6 - .../devices/devicemanagerimplementation.h | 3 - .../jsonrpc/configurationhandler.cpp | 39 +++--- libnymea-core/jsonrpc/jsonvalidator.cpp | 6 +- libnymea-core/jsonrpc/systemhandler.cpp | 112 +++++++++++++++++- libnymea-core/jsonrpc/systemhandler.h | 7 ++ libnymea-core/nymeacore.cpp | 11 +- libnymea-core/time/timemanager.cpp | 78 ++---------- libnymea-core/time/timemanager.h | 25 ++-- .../platform/platformsystemcontroller.cpp | 38 ++++++ libnymea/platform/platformsystemcontroller.h | 12 ++ tests/auto/timemanager/testtimemanager.cpp | 44 +------ 12 files changed, 230 insertions(+), 151 deletions(-) diff --git a/libnymea-core/devices/devicemanagerimplementation.cpp b/libnymea-core/devices/devicemanagerimplementation.cpp index 48c365e5..cdf9a477 100644 --- a/libnymea-core/devices/devicemanagerimplementation.cpp +++ b/libnymea-core/devices/devicemanagerimplementation.cpp @@ -1026,12 +1026,6 @@ DeviceActionInfo *DeviceManagerImplementation::executeAction(const Action &actio return info; } -/*! Centralized time tick for the NymeaTimer resource. Ticks every second. */ -void DeviceManagerImplementation::timeTick() -{ - -} - void DeviceManagerImplementation::loadPlugins() { foreach (const QString &path, pluginSearchDirs()) { diff --git a/libnymea-core/devices/devicemanagerimplementation.h b/libnymea-core/devices/devicemanagerimplementation.h index b3e7918e..25853ae2 100644 --- a/libnymea-core/devices/devicemanagerimplementation.h +++ b/libnymea-core/devices/devicemanagerimplementation.h @@ -114,9 +114,6 @@ public: signals: void loaded(); -public slots: - void timeTick(); - private slots: void loadPlugins(); void loadPlugin(DevicePlugin *pluginIface, const PluginMetadata &metaData); diff --git a/libnymea-core/jsonrpc/configurationhandler.cpp b/libnymea-core/jsonrpc/configurationhandler.cpp index faf2ebff..e67593d5 100644 --- a/libnymea-core/jsonrpc/configurationhandler.cpp +++ b/libnymea-core/jsonrpc/configurationhandler.cpp @@ -61,6 +61,8 @@ #include "configurationhandler.h" #include "nymeacore.h" #include "nymeaconfiguration.h" +#include "platform/platform.h" +#include "platform/platformsystemcontroller.h" namespace nymeaserver { @@ -80,21 +82,21 @@ ConfigurationHandler::ConfigurationHandler(QObject *parent): QString description; QVariantMap params; QVariantMap returns; description = "Get the list of available timezones."; returns.insert("timeZones", QVariantList() << enumValueName(String)); - registerMethod("GetTimeZones", description, params, returns); + registerMethod("GetTimeZones", description, params, returns, "Use System.GetTimeZones instead."); params.clear(); returns.clear(); - description = "DEPRECATED - Use the locale property in the Handshake message instead - Returns a list of locale codes available for the server. i.e. en_US, de_AT"; + description = "Returns a list of locale codes available for the server. i.e. en_US, de_AT"; returns.insert("languages", QVariantList() << enumValueName(String)); - registerMethod("GetAvailableLanguages", description, params, returns); + registerMethod("GetAvailableLanguages", description, params, returns, "Use the locale property in the Handshake message instead."); params.clear(); returns.clear(); description = "Get all configuration parameters of the server."; QVariantMap basicConfiguration; basicConfiguration.insert("serverName", enumValueName(String)); basicConfiguration.insert("serverUuid", enumValueName(Uuid)); - basicConfiguration.insert("serverTime", enumValueName(Uint)); - basicConfiguration.insert("timeZone", enumValueName(String)); - basicConfiguration.insert("language", enumValueName(String)); + basicConfiguration.insert("d:serverTime", enumValueName(Uint)); + basicConfiguration.insert("d:timeZone", enumValueName(String)); + basicConfiguration.insert("d:language", enumValueName(String)); basicConfiguration.insert("debugServerEnabled", enumValueName(Bool)); returns.insert("basicConfiguration", basicConfiguration); QVariantList tcpServerConfigurations; @@ -123,13 +125,13 @@ ConfigurationHandler::ConfigurationHandler(QObject *parent): description = "Set the time zone of the server. See also: \"GetTimeZones\""; params.insert("timeZone", enumValueName(String)); returns.insert("configurationError", enumRef()); - registerMethod("SetTimeZone", description, params, returns); + registerMethod("SetTimeZone", description, params, returns, "Use System.SetTimeZone instead."); params.clear(); returns.clear(); - description = "DEPRECATED - Use the locale property in the Handshake message instead - Sets the server language to the given language. See also: \"GetAvailableLanguages\""; + description = "Sets the server language to the given language. See also: \"GetAvailableLanguages\""; params.insert("language", enumValueName(String)); returns.insert("configurationError", enumRef()); - registerMethod("SetLanguage", description, params, returns); + registerMethod("SetLanguage", description, params, returns, "Use the locale property in the Handshake message instead."); params.clear(); returns.clear(); description = "Enable or disable the debug server."; @@ -339,7 +341,7 @@ JsonReply *ConfigurationHandler::GetTimeZones(const QVariantMap ¶ms) const { Q_UNUSED(params) QVariantList timeZones; - foreach (const QByteArray &timeZoneId, NymeaCore::instance()->timeManager()->availableTimeZones()) { + foreach (const QByteArray &timeZoneId, QTimeZone::availableTimeZoneIds()) { timeZones.append(QString::fromUtf8(timeZoneId)); } @@ -371,11 +373,18 @@ JsonReply *ConfigurationHandler::SetTimeZone(const QVariantMap ¶ms) const { qCDebug(dcJsonRpc()) << "Setting time zone to" << params.value("timeZone").toString(); - QByteArray timeZone = params.value("timeZone").toString().toUtf8(); - if (!NymeaCore::instance()->timeManager()->setTimeZone(timeZone)) - return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidTimeZone)); + QByteArray timeZoneName = params.value("timeZone").toString().toUtf8(); + + QTimeZone timeZone(timeZoneName); + if (!timeZone.isValid()) { + return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidTimeZone)); + } + + bool success = NymeaCore::instance()->platform()->systemController()->setTimeZone(timeZone); + if (!success) { + return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidTimeZone)); + } - NymeaCore::instance()->configuration()->setTimeZone(timeZone); return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorNoError)); } @@ -658,7 +667,7 @@ QVariantMap ConfigurationHandler::packBasicConfiguration() basicConfiguration.insert("serverName", NymeaCore::instance()->configuration()->serverName()); basicConfiguration.insert("serverUuid", NymeaCore::instance()->configuration()->serverUuid().toString()); basicConfiguration.insert("serverTime", NymeaCore::instance()->timeManager()->currentDateTime().toTime_t()); - basicConfiguration.insert("timeZone", QString::fromUtf8(NymeaCore::instance()->timeManager()->timeZone())); + basicConfiguration.insert("timeZone", QTimeZone::systemTimeZoneId()); basicConfiguration.insert("language", NymeaCore::instance()->configuration()->locale().name()); basicConfiguration.insert("debugServerEnabled", NymeaCore::instance()->configuration()->debugServerEnabled()); return basicConfiguration; diff --git a/libnymea-core/jsonrpc/jsonvalidator.cpp b/libnymea-core/jsonrpc/jsonvalidator.cpp index 9846e834..601ab04c 100644 --- a/libnymea-core/jsonrpc/jsonvalidator.cpp +++ b/libnymea-core/jsonrpc/jsonvalidator.cpp @@ -112,7 +112,7 @@ JsonValidator::Result JsonValidator::validateMap(const QVariantMap &map, const Q continue; } QString trimmedKey = key; - trimmedKey.remove(QRegExp("^(o:|r:)")); + trimmedKey.remove(QRegExp("^(o:|r:|d:)")); if (!map.contains(trimmedKey)) { return Result(false, "Missing required key: " + key, key); } @@ -123,7 +123,7 @@ JsonValidator::Result JsonValidator::validateMap(const QVariantMap &map, const Q // Is the key allowed in here? QVariant expectedValue = definition.value(key); foreach (const QString &definitionKey, definition.keys()) { - QRegExp regExp = QRegExp("(o:|r:)*" + key); + QRegExp regExp = QRegExp("(o:|r:|d:)*" + key); if (regExp.exactMatch(definitionKey)) { expectedValue = definition.value(definitionKey); } @@ -132,7 +132,7 @@ JsonValidator::Result JsonValidator::validateMap(const QVariantMap &map, const Q expectedValue = definition.value("o:" + key); } if (!expectedValue.isValid()) { - expectedValue = definition.value("o:" + key); + expectedValue = definition.value("d:" + key); } if (!expectedValue.isValid()) { return Result(false, "Invalid key: " + key); diff --git a/libnymea-core/jsonrpc/systemhandler.cpp b/libnymea-core/jsonrpc/systemhandler.cpp index c433f97b..b990ec1d 100644 --- a/libnymea-core/jsonrpc/systemhandler.cpp +++ b/libnymea-core/jsonrpc/systemhandler.cpp @@ -38,9 +38,14 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): // Methods QString description; QVariantMap params; QVariantMap returns; - description = "Get the list of capabilites on this system. This allows reading whether things like rebooting or shutting down the system running nymea:core is supported on this host."; + description = "Get the list of capabilites on this system. The property \"powerManagement\" indicates whether " + "rebooting or shutting down the system running nymea:core is supported on this host. The property " + "\"updateManagement indicates whether system update features are available in this API. The " + "property \"timeManagement\" indicates whether the system time can be configured on this system. " + "Note that GetTime will be available in any case."; returns.insert("powerManagement", enumValueName(Bool)); returns.insert("updateManagement", enumValueName(Bool)); + returns.insert("timeManagement", enumValueName(Bool)); registerMethod("GetCapabilities", description, params, returns); params.clear(); returns.clear(); @@ -116,6 +121,39 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): returns.insert("success", enumValueName(Bool)); registerMethod("EnableRepository", description, params, returns); + params.clear(); returns.clear(); + description = "Get the system time and configuraton. The \"serverTime\" and \"serverTimezone\" properties " + "give the current server time and time zone. \"automaticTimeAvailable\" indicates whether " + "this system supports automatically setting the clock (e.g. using NTP). \"automaticTime\" will " + "be true if the system is configured to automatically update the clock."; + returns.insert("time", enumValueName(Uint)); + returns.insert("timeZone", enumValueName(String)); + returns.insert("automaticTimeAvailable", enumValueName(Bool)); + returns.insert("automaticTime", enumValueName(Bool)); + registerMethod("GetTime", description, params, returns); + + params.clear(); returns.clear(); + description = "Set the system time configuraton. The system can be configured to update the time automatically " + "by setting \"automaticTime\" to true. This will only work if the \"timeManagement\" capability is " + "available on this system and \"GetTime\" indicates the availability of automatic time settngs. If " + "any of those requirements are not met, this method will return \"false\" in the \"success\" property. " + "In order to manually configure the time, \"automaticTime\" should be set to false and \"time\" should " + "be set. Note that if \"automaticTime\" is set to true and a manual \"time\" is still passed, the system " + "will attempt to configure automatic time updates and only set the manual time if automatic mode fails. " + "A time zone can always be passed optionally to change the system time zone and should be a IANA time zone " + "id."; + params.insert("o:automaticTime", enumValueName(Bool)); + params.insert("o:time", enumValueName(Uint)); + params.insert("o:timeZone", enumValueName(String)); + returns.insert("success", enumValueName(Bool)); + registerMethod("SetTime", description, params, returns); + + params.clear(); returns.clear(); + description = "Returns the list of IANA specified time zone IDs which can be used to select a time zone. It is not " + "required to use this method of the client toolkit already provides means to obtain a list of IANA time " + "zone ids."; + returns.insert("timeZones", enumValueName(StringList)); + registerMethod("GetTimeZones", description, params, returns); // Notifications params.clear(); @@ -160,6 +198,13 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): params.insert("repositoryId", enumValueName(String)); registerNotification("RepositoryRemoved", description, params); + params.clear(); + description = "Emitted whenever the time configuration is changed"; + params.insert("time", enumValueName(Uint)); + params.insert("timeZone", enumValueName(String)); + params.insert("automaticTimeAvailable", enumValueName(Bool)); + params.insert("automaticTime", enumValueName(Bool)); + registerNotification("TimeConfigurationChanged", description, params); connect(m_platform->systemController(), &PlatformSystemController::availableChanged, this, &SystemHandler::onCapabilitiesChanged); connect(m_platform->updateController(), &PlatformUpdateController::availableChanged, this, &SystemHandler::onCapabilitiesChanged); @@ -205,6 +250,14 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): params.insert("repositoryId", repositoryId); emit RepositoryRemoved(params); }); + connect(m_platform->systemController(), &PlatformSystemController::timeConfigurationChanged, this, [this](){ + QVariantMap params; + params.insert("time", QDateTime::currentDateTime().toSecsSinceEpoch()); + params.insert("timeZone", QTimeZone::systemTimeZoneId()); + params.insert("automaticTimeAvailable", m_platform->systemController()->automaticTimeAvailable()); + params.insert("automaticTime", m_platform->systemController()->automaticTime()); + emit TimeConfigurationChanged(params); + }, Qt::QueuedConnection); // Queued to give QDateTime a chance to sync itself to the system } QString SystemHandler::name() const @@ -218,6 +271,7 @@ JsonReply *SystemHandler::GetCapabilities(const QVariantMap ¶ms) QVariantMap data; data.insert("powerManagement", m_platform->systemController()->powerManagementAvailable()); data.insert("updateManagement", m_platform->updateController()->updateManagementAvailable()); + data.insert("timeManagement", m_platform->systemController()->timeManagementAvailable()); return createReply(data); } @@ -314,6 +368,62 @@ JsonReply *SystemHandler::EnableRepository(const QVariantMap ¶ms) const return createReply(returns); } +JsonReply *SystemHandler::GetTime(const QVariantMap ¶ms) const +{ + Q_UNUSED(params) + QVariantMap returns; + returns.insert("automaticTimeAvailable", m_platform->systemController()->automaticTimeAvailable()); + returns.insert("automaticTime", m_platform->systemController()->automaticTime()); + returns.insert("time", QDateTime::currentDateTime().toSecsSinceEpoch()); + returns.insert("timeZone", QTimeZone::systemTimeZoneId()); + return createReply(returns); +} + +JsonReply *SystemHandler::SetTime(const QVariantMap ¶ms) const +{ + QVariantMap returns; + bool handled = false; + bool automaticTime = params.value("automaticTime", false).toBool(); + if (params.contains("automaticTime") && m_platform->systemController()->automaticTimeAvailable()) { + if (!m_platform->systemController()->setAutomaticTime(automaticTime)) { + returns.insert("success", false); + return createReply(returns); + } + handled = true; + } + if (!automaticTime && params.contains("time")) { + QDateTime time = QDateTime::fromSecsSinceEpoch(params.value("time").toUInt()); + if (!m_platform->systemController()->setTime(time)) { + returns.insert("success", false); + return createReply(returns); + } + handled = true; + } + if (params.contains("timeZone")) { + QTimeZone timeZone(params.value("timeZone").toByteArray()); + if (!m_platform->systemController()->setTimeZone(timeZone)) { + returns.insert("success", false); + return createReply(returns); + } + handled = true; + } + returns.insert("success", handled); + return createReply(returns); +} + +JsonReply *SystemHandler::GetTimeZones(const QVariantMap ¶ms) const +{ + Q_UNUSED(params) + QVariantList timeZones; + foreach (const QByteArray &timeZoneId, QTimeZone::availableTimeZoneIds()) { + timeZones.append(QString::fromUtf8(timeZoneId)); + } + + QVariantMap returns; + returns.insert("timeZones", timeZones); + return createReply(returns); +} + void SystemHandler::onCapabilitiesChanged() { QVariantMap caps; diff --git a/libnymea-core/jsonrpc/systemhandler.h b/libnymea-core/jsonrpc/systemhandler.h index 4c43a4e8..b54f058a 100644 --- a/libnymea-core/jsonrpc/systemhandler.h +++ b/libnymea-core/jsonrpc/systemhandler.h @@ -53,8 +53,13 @@ public: Q_INVOKABLE JsonReply *GetRepositories(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *EnableRepository(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetTime(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *SetTime(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetTimeZones(const QVariantMap ¶ms) const; + signals: void CapabilitiesChanged(const QVariantMap ¶ms); + void UpdateStatusChanged(const QVariantMap ¶ms); void PackageAdded(const QVariantMap ¶ms); void PackageChanged(const QVariantMap ¶ms); @@ -63,6 +68,8 @@ signals: void RepositoryChanged(const QVariantMap ¶ms); void RepositoryRemoved(const QVariantMap ¶ms); + void TimeConfigurationChanged(const QVariantMap ¶ms); + private slots: void onCapabilitiesChanged(); diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index 6c98bf9c..b774b82c 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -98,6 +98,7 @@ #include "tagging/tagsstorage.h" #include "platform/platform.h" #include "experiences/experiencemanager.h" +#include "platform/platformsystemcontroller.h" #include "devices/devicemanagerimplementation.h" #include "devices/device.h" @@ -140,7 +141,14 @@ void NymeaCore::init() { m_configuration = new NymeaConfiguration(this); qCDebug(dcApplication()) << "Creating Time Manager"; - m_timeManager = new TimeManager(m_configuration->timeZone(), this); + // Migration path: nymea < 0.18 doesn't use system time zone but stores its own time zone in the config + // For migration, let's set the system's time zone to the config now to upgrade to the system time zone based nymea >= 0.18 + if (QTimeZone(m_configuration->timeZone()).isValid()) { + if (m_platform->systemController()->setTimeZone(QTimeZone(m_configuration->timeZone()))) { + m_configuration->setTimeZone(""); + } + } + m_timeManager = new TimeManager(this); qCDebug(dcApplication) << "Creating Log Engine"; m_logger = new LogEngine(m_configuration->logDBDriver(), m_configuration->logDBName(), m_configuration->logDBHost(), m_configuration->logDBUser(), m_configuration->logDBPassword(), m_configuration->logDBMaxEntries(), this); @@ -199,7 +207,6 @@ void NymeaCore::init() { connect(m_ruleEngine, &RuleEngine::ruleConfigurationChanged, this, &NymeaCore::ruleConfigurationChanged); connect(m_timeManager, &TimeManager::dateTimeChanged, this, &NymeaCore::onDateTimeChanged); - connect(m_timeManager, &TimeManager::tick, m_deviceManager, &DeviceManagerImplementation::timeTick); m_logger->logSystemEvent(m_timeManager->currentDateTime(), true); } diff --git a/libnymea-core/time/timemanager.cpp b/libnymea-core/time/timemanager.cpp index 14876caf..ccc200c5 100644 --- a/libnymea-core/time/timemanager.cpp +++ b/libnymea-core/time/timemanager.cpp @@ -40,71 +40,16 @@ namespace nymeaserver { /*! Constructs a new \l{TimeManager} with the given \a timeZone and \a parent. */ -TimeManager::TimeManager(const QByteArray &timeZone, QObject *parent) : +TimeManager::TimeManager(QObject *parent) : QObject(parent) { - m_dateTime = QDateTime::currentDateTimeUtc(); - m_dateTime.setTimeSpec(Qt::UTC); - - setTimeZone(timeZone); - - m_nymeaTimer = new QTimer(this); - m_nymeaTimer->setInterval(1000); - m_nymeaTimer->setSingleShot(false); - - connect(m_nymeaTimer, &QTimer::timeout, this, &TimeManager::nymeaTimeout); - - m_nymeaTimer->start(); -} - -/*! Returns the time zone of this \l{TimeManager}. */ -QByteArray TimeManager::timeZone() const -{ - return m_timeZone.id(); -} - -/*! Sets the \a timeZone of this \l{TimeManager}. Allowed values according to the \l{http://www.iana.org/time-zones}{IANA database}. - * Returns false if the given timezone is not valid. */ -bool TimeManager::setTimeZone(const QByteArray &timeZone) -{ - if (!QTimeZone(timeZone).isValid()) { - qCWarning(dcTimeManager()) << "Invalid time zone" << timeZone; - qCWarning(dcTimeManager()) << "Using system time zone" << QTimeZone::systemTimeZoneId(); - m_timeZone = QTimeZone(QTimeZone::systemTimeZoneId()); - emit dateTimeChanged(currentDateTime()); - return false; - } - - qCDebug(dcTimeManager()) << "Set time zone" << timeZone; - m_timeZone = QTimeZone(timeZone); - qCDebug(dcTimeManager()) << "UTC" << m_dateTime.toString("dd.MM.yyyy hh:mm:ss"); - qCDebug(dcTimeManager) << "Zone time" << currentDateTime().toString("dd.MM.yyyy hh:mm:ss"); - emit dateTimeChanged(currentDateTime()); - return true; + m_timerId = startTimer(1000, Qt::VeryCoarseTimer); } /*! Returns the current dateTime of this \l{TimeManager}. */ QDateTime TimeManager::currentDateTime() const { - return QDateTime::currentDateTimeUtc().toTimeZone(m_timeZone); -} - -/*! Returns the current time of this \l{TimeManager}. */ -QTime TimeManager::currentTime() const -{ - return QDateTime::currentDateTimeUtc().toTimeZone(m_timeZone).time(); -} - -/*! Returns the current date of this \l{TimeManager}. */ -QDate TimeManager::currentDate() const -{ - return QDateTime::currentDateTimeUtc().toTimeZone(m_timeZone).date(); -} - -/*! Returns a list of available time zones on this system. */ -QList TimeManager::availableTimeZones() const -{ - return QTimeZone::availableTimeZoneIds(); + return QDateTime::currentDateTime().addSecs(m_overrideDifference); } /*! Stop the time. @@ -115,7 +60,7 @@ void TimeManager::stopTimer() { qCWarning(dcTimeManager()) << "TimeManager timer stopped. You should only see this in tests."; // Stop clock (used for testing) - m_nymeaTimer->stop(); + killTimer(m_timerId); } /*! Set the current time of this TimeManager to the given \a dateTime. @@ -125,21 +70,22 @@ void TimeManager::stopTimer() void TimeManager::setTime(const QDateTime &dateTime) { qCWarning(dcTimeManager()) << "TimeManager time changed" << dateTime.toString("dd.MM.yyyy hh:mm:ss") << "You should only see this in tests."; + m_overrideDifference = QDateTime::currentDateTime().secsTo(dateTime); // This method will only be called for testing to set the internal time - emit tick(); emit dateTimeChanged(dateTime); } -void TimeManager::nymeaTimeout() +void TimeManager::timerEvent(QTimerEvent *event) { - // tick for deviceManager + Q_UNUSED(event) + emit tick(); // Minute based nymea time - QDateTime utcDateTime = QDateTime::currentDateTimeUtc(); - if (m_dateTime.time().minute() != utcDateTime.toTimeZone(m_timeZone).time().minute()) { - m_dateTime = utcDateTime; - emit dateTimeChanged(currentDateTime()); + QDateTime now = QDateTime::currentDateTime(); + if (m_lastEvent.time().minute() != now.time().minute()) { + m_lastEvent = now; + emit dateTimeChanged(now.addSecs(m_overrideDifference)); } } diff --git a/libnymea-core/time/timemanager.h b/libnymea-core/time/timemanager.h index 24bd7614..e49d0eb4 100644 --- a/libnymea-core/time/timemanager.h +++ b/libnymea-core/time/timemanager.h @@ -32,32 +32,27 @@ class TimeManager : public QObject { Q_OBJECT public: - explicit TimeManager(const QByteArray &timeZone, QObject *parent = 0); - - QByteArray timeZone() const; - bool setTimeZone(const QByteArray &timeZone = QTimeZone::systemTimeZoneId()); + explicit TimeManager(QObject *parent = nullptr); QDateTime currentDateTime() const; - QTime currentTime() const; - QDate currentDate() const; - - QList availableTimeZones() const; + // For testability only void stopTimer(); void setTime(const QDateTime &dateTime); -private: - QTimeZone m_timeZone; - QDateTime m_dateTime; - QTimer *m_nymeaTimer; - signals: void tick(); void dateTimeChanged(const QDateTime &dateTime); -private slots: - void nymeaTimeout(); +protected: + void timerEvent(QTimerEvent *event) override; +private: + int m_timerId = 0; + QDateTime m_lastEvent; + + // For testability + qint64 m_overrideDifference = 0; }; } diff --git a/libnymea/platform/platformsystemcontroller.cpp b/libnymea/platform/platformsystemcontroller.cpp index dda77859..a2380fe3 100644 --- a/libnymea/platform/platformsystemcontroller.cpp +++ b/libnymea/platform/platformsystemcontroller.cpp @@ -22,6 +22,8 @@ #include "platformsystemcontroller.h" +#include "loggingcategories.h" + PlatformSystemController::PlatformSystemController(QObject *parent) : QObject(parent) { @@ -41,3 +43,39 @@ bool PlatformSystemController::shutdown() { return false; } + +bool PlatformSystemController::timeManagementAvailable() const +{ + return false; +} + +bool PlatformSystemController::automaticTimeAvailable() const +{ + return false; +} + +bool PlatformSystemController::automaticTime() const +{ + return false; +} + +bool PlatformSystemController::setTime(const QDateTime &time) +{ + Q_UNUSED(time) + qCWarning(dcPlatform()) << "setTime not implemented in platform plugin"; + return false; +} + +bool PlatformSystemController::setAutomaticTime(bool automaticTime) +{ + Q_UNUSED(automaticTime) + qCWarning(dcPlatform()) << "setAutomaticTime not implemented in platform plugin"; + return false; +} + +bool PlatformSystemController::setTimeZone(const QTimeZone &timeZone) +{ + Q_UNUSED(timeZone) + qCWarning(dcPlatform()) << "setTimeZone not implemented in platform plugin"; + return false; +} diff --git a/libnymea/platform/platformsystemcontroller.h b/libnymea/platform/platformsystemcontroller.h index a1de5fa9..cced1db9 100644 --- a/libnymea/platform/platformsystemcontroller.h +++ b/libnymea/platform/platformsystemcontroller.h @@ -24,6 +24,7 @@ #define PLATFORMSYSTEMCONTROLLER_H #include +#include class PlatformSystemController : public QObject { @@ -36,8 +37,19 @@ public: virtual bool reboot(); virtual bool shutdown(); + virtual bool timeManagementAvailable() const; + virtual bool automaticTimeAvailable() const; + virtual bool automaticTime() const; + virtual bool setTime(const QDateTime &time); + virtual bool setAutomaticTime(bool automaticTime); + virtual bool setTimeZone(const QTimeZone &timeZone); + + signals: void availableChanged(); + void timeZoneManagementAvailableChanged(); + + void timeConfigurationChanged(); }; Q_DECLARE_INTERFACE(PlatformSystemController, "io.nymea.PlatformSystemController") diff --git a/tests/auto/timemanager/testtimemanager.cpp b/tests/auto/timemanager/testtimemanager.cpp index e15336f4..55c5fcf9 100644 --- a/tests/auto/timemanager/testtimemanager.cpp +++ b/tests/auto/timemanager/testtimemanager.cpp @@ -23,6 +23,9 @@ #include "nymeacore.h" #include "servers/mocktcpserver.h" +#include "platform/platform.h" +#include "platform/platformsystemcontroller.h" + using namespace nymeaserver; class TestTimeManager: public NymeaTestBase @@ -37,9 +40,6 @@ private: private slots: void initTestCase(); - void changeTimeZone_data(); - void changeTimeZone(); - void loadSaveTimeDescriptor_data(); void loadSaveTimeDescriptor(); @@ -142,41 +142,6 @@ void TestTimeManager::initTestCase() "TimeManager.debug=true"); } -void TestTimeManager::changeTimeZone_data() -{ - QTest::addColumn("timeZoneId"); - QTest::addColumn("valid"); - - QTest::newRow("valid timezone: Asia/Tokyo") << QByteArray("Asia/Tokyo") << true; - QTest::newRow("valid timezone: America/Lima") << QByteArray("America/Lima") << true; - QTest::newRow("valid timezone: Africa/Harare") << QByteArray("Africa/Harare") << true; - QTest::newRow("invalid timezone: Mars/Diacria") << QByteArray("Mars/Diacria") << false; - QTest::newRow("invalid timezone: Moon/Kepler") << QByteArray("Moon/Kepler") << false; -} - -void TestTimeManager::changeTimeZone() -{ - QFETCH(QByteArray, timeZoneId); - QFETCH(bool, valid); - - QTimeZone currentTimeZone(NymeaCore::instance()->timeManager()->timeZone()); - QTimeZone newTimeZone(timeZoneId); - - - QDateTime currentDateTime = NymeaCore::instance()->timeManager()->currentDateTime(); - - NymeaCore::instance()->timeManager()->setTimeZone(timeZoneId); - - QDateTime newDateTime = NymeaCore::instance()->timeManager()->currentDateTime(); - - int offsetOriginal = currentTimeZone.offsetFromUtc(currentDateTime); - int offsetNew = newTimeZone.offsetFromUtc(newDateTime); - - if (valid) - QVERIFY(offsetOriginal != offsetNew); - -} - void TestTimeManager::loadSaveTimeDescriptor_data() { // Repeating options @@ -2056,8 +2021,7 @@ void TestTimeManager::initTimeManager() removeAllRules(); enableNotifications({"Rules", "Devices", "Events"}); NymeaCore::instance()->timeManager()->stopTimer(); - qDebug() << NymeaCore::instance()->timeManager()->currentTime().toString(); - qDebug() << NymeaCore::instance()->timeManager()->currentDate().toString(); + qDebug() << NymeaCore::instance()->timeManager()->currentDateTime().toString(); } void TestTimeManager::verifyRuleExecuted(const ActionTypeId &actionTypeId) From 4e70f0f5f8d149c4a189e43cd0b5acfb23b40500 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 16 Dec 2019 11:16:26 +0100 Subject: [PATCH 2/9] build with older Qt --- libnymea-core/jsonrpc/systemhandler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libnymea-core/jsonrpc/systemhandler.cpp b/libnymea-core/jsonrpc/systemhandler.cpp index b990ec1d..7ff8ad3a 100644 --- a/libnymea-core/jsonrpc/systemhandler.cpp +++ b/libnymea-core/jsonrpc/systemhandler.cpp @@ -252,7 +252,7 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): }); connect(m_platform->systemController(), &PlatformSystemController::timeConfigurationChanged, this, [this](){ QVariantMap params; - params.insert("time", QDateTime::currentDateTime().toSecsSinceEpoch()); + params.insert("time", QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000); params.insert("timeZone", QTimeZone::systemTimeZoneId()); params.insert("automaticTimeAvailable", m_platform->systemController()->automaticTimeAvailable()); params.insert("automaticTime", m_platform->systemController()->automaticTime()); @@ -374,7 +374,7 @@ JsonReply *SystemHandler::GetTime(const QVariantMap ¶ms) const QVariantMap returns; returns.insert("automaticTimeAvailable", m_platform->systemController()->automaticTimeAvailable()); returns.insert("automaticTime", m_platform->systemController()->automaticTime()); - returns.insert("time", QDateTime::currentDateTime().toSecsSinceEpoch()); + returns.insert("time", QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000); returns.insert("timeZone", QTimeZone::systemTimeZoneId()); return createReply(returns); } @@ -392,7 +392,7 @@ JsonReply *SystemHandler::SetTime(const QVariantMap ¶ms) const handled = true; } if (!automaticTime && params.contains("time")) { - QDateTime time = QDateTime::fromSecsSinceEpoch(params.value("time").toUInt()); + QDateTime time = QDateTime::fromMSecsSinceEpoch(params.value("time").toLongLong() * 1000); if (!m_platform->systemController()->setTime(time)) { returns.insert("success", false); return createReply(returns); From 331966c8dd96896b3becde54bc7bf5201ff2d933 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 16 Dec 2019 11:26:32 +0100 Subject: [PATCH 3/9] Bump JSON api version --- nymea.pri | 2 +- tests/auto/api.json | 68 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/nymea.pri b/nymea.pri index 094a6ce7..4d83f986 100644 --- a/nymea.pri +++ b/nymea.pri @@ -3,7 +3,7 @@ NYMEA_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p" # define protocol versions JSON_PROTOCOL_VERSION_MAJOR=4 -JSON_PROTOCOL_VERSION_MINOR=0 +JSON_PROTOCOL_VERSION_MINOR=1 LIBNYMEA_API_VERSION_MAJOR=4 LIBNYMEA_API_VERSION_MINOR=0 LIBNYMEA_API_VERSION_PATCH=0 diff --git a/tests/auto/api.json b/tests/auto/api.json index f78a8b5a..e6c42d70 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1,4 +1,4 @@ -4.0 +4.1 { "enums": { "BasicType": [ @@ -397,7 +397,8 @@ } }, "Configuration.GetAvailableLanguages": { - "description": "DEPRECATED - Use the locale property in the Handshake message instead - Returns a list of locale codes available for the server. i.e. en_US, de_AT", + "deprecated": "Use the locale property in the Handshake message instead.", + "description": "Returns a list of locale codes available for the server. i.e. en_US, de_AT", "params": { }, "returns": { @@ -412,12 +413,12 @@ }, "returns": { "basicConfiguration": { + "d:language": "String", + "d:serverTime": "Uint", + "d:timeZone": "String", "debugServerEnabled": "Bool", - "language": "String", "serverName": "String", - "serverTime": "Uint", - "serverUuid": "Uuid", - "timeZone": "String" + "serverUuid": "Uuid" }, "cloud": { "enabled": "Bool" @@ -454,6 +455,7 @@ } }, "Configuration.GetTimeZones": { + "deprecated": "Use System.GetTimeZones instead.", "description": "Get the list of available timezones.", "params": { }, @@ -482,7 +484,8 @@ } }, "Configuration.SetLanguage": { - "description": "DEPRECATED - Use the locale property in the Handshake message instead - Sets the server language to the given language. See also: \"GetAvailableLanguages\"", + "deprecated": "Use the locale property in the Handshake message instead.", + "description": "Sets the server language to the given language. See also: \"GetAvailableLanguages\"", "params": { "language": "String" }, @@ -527,6 +530,7 @@ } }, "Configuration.SetTimeZone": { + "deprecated": "Use System.SetTimeZone instead.", "description": "Set the time zone of the server. See also: \"GetTimeZones\"", "params": { "timeZone": "String" @@ -1253,11 +1257,12 @@ } }, "System.GetCapabilities": { - "description": "Get the list of capabilites on this system. This allows reading whether things like rebooting or shutting down the system running nymea:core is supported on this host.", + "description": "Get the list of capabilites on this system. The property \"powerManagement\" indicates whether rebooting or shutting down the system running nymea:core is supported on this host. The property \"updateManagement indicates whether system update features are available in this API. The property \"timeManagement\" indicates whether the system time can be configured on this system. Note that GetTime will be available in any case.", "params": { }, "returns": { "powerManagement": "Bool", + "timeManagement": "Bool", "updateManagement": "Bool" } }, @@ -1277,6 +1282,25 @@ "repositories": "$ref:Repositories" } }, + "System.GetTime": { + "description": "Get the system time and configuraton. The \"serverTime\" and \"serverTimezone\" properties give the current server time and time zone. \"automaticTimeAvailable\" indicates whether this system supports automatically setting the clock (e.g. using NTP). \"automaticTime\" will be true if the system is configured to automatically update the clock.", + "params": { + }, + "returns": { + "automaticTime": "Bool", + "automaticTimeAvailable": "Bool", + "time": "Uint", + "timeZone": "String" + } + }, + "System.GetTimeZones": { + "description": "Returns the list of IANA specified time zone IDs which can be used to select a time zone. It is not required to use this method of the client toolkit already provides means to obtain a list of IANA time zone ids.", + "params": { + }, + "returns": { + "timeZones": "StringList" + } + }, "System.GetUpdateStatus": { "description": "Get the current status of the update system. \"busy\" indicates that the system is current busy with an operation regarding updates. This does not necessarily mean an actual update is running. When this is true, update related functions on the client should be marked as busy and no interaction with update components shall be allowed. An example for such a state is when the system queries the server if there are updates available, typically after a call to CheckForUpdates. \"updateRunning\" on the other hand indicates an actual update process is ongoing. The user should be informed about it, the system also might restart at any point while an update is running.", "params": { @@ -1316,6 +1340,17 @@ "success": "Bool" } }, + "System.SetTime": { + "description": "Set the system time configuraton. The system can be configured to update the time automatically by setting \"automaticTime\" to true. This will only work if the \"timeManagement\" capability is available on this system and \"GetTime\" indicates the availability of automatic time settngs. If any of those requirements are not met, this method will return \"false\" in the \"success\" property. In order to manually configure the time, \"automaticTime\" should be set to false and \"time\" should be set. Note that if \"automaticTime\" is set to true and a manual \"time\" is still passed, the system will attempt to configure automatic time updates and only set the manual time if automatic mode fails. A time zone can always be passed optionally to change the system time zone and should be a IANA time zone id.", + "params": { + "o:automaticTime": "Bool", + "o:time": "Uint", + "o:timeZone": "String" + }, + "returns": { + "success": "Bool" + } + }, "System.Shutdown": { "description": "Initiate a shutdown of the system. The return value will indicate whether the procedure has been initiated successfully.", "params": { @@ -1372,12 +1407,12 @@ "description": "Emitted whenever the basic configuration of this server changes.", "params": { "basicConfiguration": { + "d:language": "String", + "d:serverTime": "Uint", + "d:timeZone": "String", "debugServerEnabled": "Bool", - "language": "String", "serverName": "String", - "serverTime": "Uint", - "serverUuid": "Uuid", - "timeZone": "String" + "serverUuid": "Uuid" } } }, @@ -1649,6 +1684,15 @@ "repositoryId": "String" } }, + "System.TimeConfigurationChanged": { + "description": "Emitted whenever the time configuration is changed", + "params": { + "automaticTime": "Bool", + "automaticTimeAvailable": "Bool", + "time": "Uint", + "timeZone": "String" + } + }, "System.UpdateStatusChanged": { "description": "Emitted whenever the update status changes.", "params": { From b6a3a8e0bf4848712fe2e24fafe0c151c285fa27 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 16 Dec 2019 11:35:38 +0100 Subject: [PATCH 4/9] fix typos in api doc --- libnymea-core/jsonrpc/systemhandler.cpp | 10 +++++----- tests/auto/api.json | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libnymea-core/jsonrpc/systemhandler.cpp b/libnymea-core/jsonrpc/systemhandler.cpp index 7ff8ad3a..859d7c07 100644 --- a/libnymea-core/jsonrpc/systemhandler.cpp +++ b/libnymea-core/jsonrpc/systemhandler.cpp @@ -39,10 +39,10 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): // Methods QString description; QVariantMap params; QVariantMap returns; description = "Get the list of capabilites on this system. The property \"powerManagement\" indicates whether " - "rebooting or shutting down the system running nymea:core is supported on this host. The property " - "\"updateManagement indicates whether system update features are available in this API. The " - "property \"timeManagement\" indicates whether the system time can be configured on this system. " - "Note that GetTime will be available in any case."; + "rebooting or shutting down is supported on this system. The property \"updateManagement indicates " + "whether system update features are available in this system. The property \"timeManagement\" " + "indicates whether the system time can be configured on this system. Note that GetTime will be " + "available in any case."; returns.insert("powerManagement", enumValueName(Bool)); returns.insert("updateManagement", enumValueName(Bool)); returns.insert("timeManagement", enumValueName(Bool)); @@ -150,7 +150,7 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): params.clear(); returns.clear(); description = "Returns the list of IANA specified time zone IDs which can be used to select a time zone. It is not " - "required to use this method of the client toolkit already provides means to obtain a list of IANA time " + "required to use this method if the client toolkit already provides means to obtain a list of IANA time " "zone ids."; returns.insert("timeZones", enumValueName(StringList)); registerMethod("GetTimeZones", description, params, returns); diff --git a/tests/auto/api.json b/tests/auto/api.json index e6c42d70..41b81257 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1257,7 +1257,7 @@ } }, "System.GetCapabilities": { - "description": "Get the list of capabilites on this system. The property \"powerManagement\" indicates whether rebooting or shutting down the system running nymea:core is supported on this host. The property \"updateManagement indicates whether system update features are available in this API. The property \"timeManagement\" indicates whether the system time can be configured on this system. Note that GetTime will be available in any case.", + "description": "Get the list of capabilites on this system. The property \"powerManagement\" indicates whether rebooting or shutting down is supported on this system. The property \"updateManagement indicates whether system update features are available in this system. The property \"timeManagement\" indicates whether the system time can be configured on this system. Note that GetTime will be available in any case.", "params": { }, "returns": { @@ -1294,7 +1294,7 @@ } }, "System.GetTimeZones": { - "description": "Returns the list of IANA specified time zone IDs which can be used to select a time zone. It is not required to use this method of the client toolkit already provides means to obtain a list of IANA time zone ids.", + "description": "Returns the list of IANA specified time zone IDs which can be used to select a time zone. It is not required to use this method if the client toolkit already provides means to obtain a list of IANA time zone ids.", "params": { }, "returns": { From 4426f5a61e59050e178ec3907f05766b248f0edf Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 16 Dec 2019 12:07:20 +0100 Subject: [PATCH 5/9] Drop test that won't work any more --- .../configurations/testconfigurations.cpp | 96 ------------------- 1 file changed, 96 deletions(-) diff --git a/tests/auto/configurations/testconfigurations.cpp b/tests/auto/configurations/testconfigurations.cpp index 3bcdb4de..8cf0f552 100644 --- a/tests/auto/configurations/testconfigurations.cpp +++ b/tests/auto/configurations/testconfigurations.cpp @@ -41,7 +41,6 @@ protected slots: private slots: void getConfigurations(); - void testTimeZones(); void testServerName(); void testLanguages(); @@ -81,101 +80,6 @@ void TestConfigurations::getConfigurations() QVERIFY(configurations.contains("webSocketServerConfigurations")); } -void TestConfigurations::testTimeZones() -{ - enableNotifications({"Configuration"}); - - QVariantMap params; QVariant response; QVariantMap configurations; QVariantList configurationChangedNotifications; - - QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); - - QVariantList timeZones = injectAndWait("Configuration.GetTimeZones").toMap().value("params").toMap().value("timeZones").toList(); - QVERIFY(timeZones.count() > 0); - QVERIFY(timeZones.contains("America/Toronto")); - QVERIFY(timeZones.contains("Europe/Vienna")); - QVERIFY(timeZones.contains("Africa/Dakar")); - - // Get current configurations - QVariantMap basicConfigurationMap = loadBasicConfiguration(); - - // Set timezone unchainged - params.clear(); response.clear(); configurations.clear(); - params.insert("timeZone", basicConfigurationMap.value("timeZone").toString()); - response = injectAndWait("Configuration.SetTimeZone", params); - verifyConfigurationError(response); - - // Check notification not emitted - notificationSpy.wait(200); - configurationChangedNotifications = checkNotifications(notificationSpy, "Configuration.BasicConfigurationChanged"); - QVERIFY2(configurationChangedNotifications.count() == 0, "Got Configuration.BasicConfigurationChanged notification but should have not."); - - // Set new timezone (Africa/Dakar) - QString newTimeZone("Africa/Dakar"); - params.clear(); response.clear(); configurations.clear(); notificationSpy.clear(); - params.insert("timeZone", newTimeZone); - response = injectAndWait("Configuration.SetTimeZone", params); - verifyConfigurationError(response); - - notificationSpy.wait(200); - configurationChangedNotifications = checkNotifications(notificationSpy, "Configuration.BasicConfigurationChanged"); - QVERIFY2(configurationChangedNotifications.count() == 1, "Should get only one Configuration.BasicConfigurationChanged notification"); - QVariantMap notificationContent = configurationChangedNotifications.first().toMap().value("params").toMap(); - - qDebug() << notificationContent; - - QVERIFY2(notificationContent.contains("basicConfiguration"), "Notification does not contain basicConfiguration"); - QVariantMap basicConfigurationNotificationMap = notificationContent.value("basicConfiguration").toMap(); - QVERIFY2(basicConfigurationNotificationMap.contains("language"), "Notification does not contain key language"); - QVERIFY2(basicConfigurationNotificationMap.contains("serverName"), "Notification does not contain key serverName"); - QVERIFY2(basicConfigurationNotificationMap.contains("serverTime"), "Notification does not contain key serverTime"); - QVERIFY2(basicConfigurationNotificationMap.contains("serverUuid"), "Notification does not contain key serverUuid"); - QVERIFY2(basicConfigurationNotificationMap.contains("debugServerEnabled"), "Notification does not contain key debugServerEnabled"); - QVERIFY2(basicConfigurationNotificationMap.contains("timeZone"), "Notification does not contain key timeZone"); - QVERIFY2(basicConfigurationNotificationMap.value("timeZone").toString() == newTimeZone, "Notification does not contain the new timeZone"); - - // Get current timezone and time - params.clear(); response.clear(); configurations.clear(); - configurations = injectAndWait("Configuration.GetConfigurations").toMap().value("params").toMap(); - QString currentTimeZone = configurations.value("basicConfiguration").toMap().value("timeZone").toString(); - int currentTime = configurations.value("basicConfiguration").toMap().value("serverTime").toInt(); - qDebug() << currentTimeZone << QDateTime::fromTime_t(currentTime); - - // Set new timezone - params.clear(); response.clear(); configurations.clear(); - params.insert("timeZone", "Moon/Darkside"); - response = injectAndWait("Configuration.SetTimeZone", params); - verifyConfigurationError(response, NymeaConfiguration::ConfigurationErrorInvalidTimeZone); - - // Set new timezone - params.clear(); response.clear(); configurations.clear(); - params.insert("timeZone", "America/Toronto"); - response = injectAndWait("Configuration.SetTimeZone", params); - verifyConfigurationError(response); - - // Check new timezone - params.clear(); response.clear(); configurations.clear(); - configurations = injectAndWait("Configuration.GetConfigurations").toMap().value("params").toMap(); - newTimeZone = configurations.value("basicConfiguration").toMap().value("timeZone").toString(); - int newTime = configurations.value("basicConfiguration").toMap().value("serverTime").toInt(); - qDebug() << newTimeZone << QDateTime::fromTime_t(newTime); - QVERIFY(currentTimeZone != newTimeZone); - - restartServer(); - - // Check loaded timezone - configurations = injectAndWait("Configuration.GetConfigurations").toMap().value("params").toMap(); - QString reloadedTimeZone = configurations.value("basicConfiguration").toMap().value("timeZone").toString(); - QVERIFY(newTimeZone == reloadedTimeZone); - - // Reset the timezone - params.clear(); response.clear(); - params.insert("timeZone", "Europe/Vienna"); - response = injectAndWait("Configuration.SetTimeZone", params); - verifyConfigurationError(response); - - disableNotifications(); -} - void TestConfigurations::testServerName() { enableNotifications({"Configuration"}); From b2960f5f629b35721ced0341e37a1a282927603d Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 16 Dec 2019 12:23:26 +0100 Subject: [PATCH 6/9] fix typo --- libnymea-core/jsonrpc/systemhandler.cpp | 2 +- tests/auto/api.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libnymea-core/jsonrpc/systemhandler.cpp b/libnymea-core/jsonrpc/systemhandler.cpp index 859d7c07..653769cf 100644 --- a/libnymea-core/jsonrpc/systemhandler.cpp +++ b/libnymea-core/jsonrpc/systemhandler.cpp @@ -135,7 +135,7 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): params.clear(); returns.clear(); description = "Set the system time configuraton. The system can be configured to update the time automatically " "by setting \"automaticTime\" to true. This will only work if the \"timeManagement\" capability is " - "available on this system and \"GetTime\" indicates the availability of automatic time settngs. If " + "available on this system and \"GetTime\" indicates the availability of automatic time settings. If " "any of those requirements are not met, this method will return \"false\" in the \"success\" property. " "In order to manually configure the time, \"automaticTime\" should be set to false and \"time\" should " "be set. Note that if \"automaticTime\" is set to true and a manual \"time\" is still passed, the system " diff --git a/tests/auto/api.json b/tests/auto/api.json index 41b81257..10b6c3ec 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1341,7 +1341,7 @@ } }, "System.SetTime": { - "description": "Set the system time configuraton. The system can be configured to update the time automatically by setting \"automaticTime\" to true. This will only work if the \"timeManagement\" capability is available on this system and \"GetTime\" indicates the availability of automatic time settngs. If any of those requirements are not met, this method will return \"false\" in the \"success\" property. In order to manually configure the time, \"automaticTime\" should be set to false and \"time\" should be set. Note that if \"automaticTime\" is set to true and a manual \"time\" is still passed, the system will attempt to configure automatic time updates and only set the manual time if automatic mode fails. A time zone can always be passed optionally to change the system time zone and should be a IANA time zone id.", + "description": "Set the system time configuraton. The system can be configured to update the time automatically by setting \"automaticTime\" to true. This will only work if the \"timeManagement\" capability is available on this system and \"GetTime\" indicates the availability of automatic time settings. If any of those requirements are not met, this method will return \"false\" in the \"success\" property. In order to manually configure the time, \"automaticTime\" should be set to false and \"time\" should be set. Note that if \"automaticTime\" is set to true and a manual \"time\" is still passed, the system will attempt to configure automatic time updates and only set the manual time if automatic mode fails. A time zone can always be passed optionally to change the system time zone and should be a IANA time zone id.", "params": { "o:automaticTime": "Bool", "o:time": "Uint", From e07deaa904f93a2c28d7c9efb6cc7455297b2978 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Thu, 19 Dec 2019 00:26:25 +0100 Subject: [PATCH 7/9] Tighten system/update/zeroconf api versioning a bit --- debian/control | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debian/control b/debian/control index e10207b4..b5029cbf 100644 --- a/debian/control +++ b/debian/control @@ -155,6 +155,9 @@ Multi-Arch: same Depends: ${shlibs:Depends}, ${misc:Depends}, Replaces: libguh1 +Provides: nymea-update-plugin-api-1, + nymea-zeroconf-plugin-api-1, + nymea-system-plugin-api-1 Description: An open source IoT server - core library The nymea daemon is a plugin based IoT (Internet of Things) server. The server works like a translator for devices, things and services and From d579192b4943c40b4ef4c20ccb7e72e733a5b670 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 21 Dec 2019 21:42:42 +0100 Subject: [PATCH 8/9] stabilize test --- tests/auto/timemanager/testtimemanager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/auto/timemanager/testtimemanager.cpp b/tests/auto/timemanager/testtimemanager.cpp index 55c5fcf9..f30886dd 100644 --- a/tests/auto/timemanager/testtimemanager.cpp +++ b/tests/auto/timemanager/testtimemanager.cpp @@ -2171,7 +2171,9 @@ void TestTimeManager::triggerMockEvent1() QCOMPARE(spy.count(), 1); reply->deleteLater(); - eventSpy.wait(200); + if (eventSpy.isEmpty()) { + eventSpy.wait(); + } QVariantList eventTriggerVariants = checkNotifications(eventSpy, "Events.EventTriggered"); QVERIFY2(eventTriggerVariants.count() == 1, "Did not get Events.EventTriggered notification."); QVERIFY2(eventTriggerVariants.first().toMap().value("params").toMap().contains("event"), "Notification Events.EventTriggered does not contain event."); From 114c381e4dcdcf88533817c11fe4e1b920340634 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 28 Jan 2020 10:33:32 +0100 Subject: [PATCH 9/9] fix typo in docs --- libnymea-core/jsonrpc/systemhandler.cpp | 2 +- tests/auto/api.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libnymea-core/jsonrpc/systemhandler.cpp b/libnymea-core/jsonrpc/systemhandler.cpp index 653769cf..eda6312a 100644 --- a/libnymea-core/jsonrpc/systemhandler.cpp +++ b/libnymea-core/jsonrpc/systemhandler.cpp @@ -122,7 +122,7 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): registerMethod("EnableRepository", description, params, returns); params.clear(); returns.clear(); - description = "Get the system time and configuraton. The \"serverTime\" and \"serverTimezone\" properties " + description = "Get the system time and configuraton. The \"time\" and \"timeZone\" properties " "give the current server time and time zone. \"automaticTimeAvailable\" indicates whether " "this system supports automatically setting the clock (e.g. using NTP). \"automaticTime\" will " "be true if the system is configured to automatically update the clock."; diff --git a/tests/auto/api.json b/tests/auto/api.json index 10b6c3ec..91edb27b 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1283,7 +1283,7 @@ } }, "System.GetTime": { - "description": "Get the system time and configuraton. The \"serverTime\" and \"serverTimezone\" properties give the current server time and time zone. \"automaticTimeAvailable\" indicates whether this system supports automatically setting the clock (e.g. using NTP). \"automaticTime\" will be true if the system is configured to automatically update the clock.", + "description": "Get the system time and configuraton. The \"time\" and \"timeZone\" properties give the current server time and time zone. \"automaticTimeAvailable\" indicates whether this system supports automatically setting the clock (e.g. using NTP). \"automaticTime\" will be true if the system is configured to automatically update the clock.", "params": { }, "returns": {