From c54e28940353f55632099ef3c4ac9da626ce65fc Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 3 May 2014 17:22:44 +0200 Subject: [PATCH] added a mechanism to bump the version added a test that checks for JSONRPC api changes and enforces a version bump --- guh.pri | 10 + server/guhcore.cpp | 3 + server/jsonrpc/jsonrpcserver.cpp | 2 +- server/jsonrpc/jsontypes.cpp | 2 + tests/auto/api.json | 377 +++++++++++++++++++++++++++++++ tests/auto/auto.pro | 1 + tests/auto/testjsonrpc.cpp | 51 +++++ 7 files changed, 445 insertions(+), 1 deletion(-) create mode 100644 tests/auto/api.json diff --git a/guh.pri b/guh.pri index 5934c89b..44159321 100644 --- a/guh.pri +++ b/guh.pri @@ -1,6 +1,16 @@ +guh_version_major = 0 +guh_version_minor = 0 +guh_version_patch = 1 + coverage { message("Building coverage.") QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage -O0 LIBS += -lgcov QMAKE_LFLAGS += -fprofile-arcs } + +message("fooooooooo $${guh_version_major} $${MYVAR}") +DEFINES += GUH_VERSION_MAJOR=$$guh_version_major +DEFINES += GUH_VERSION_MINOR=$$guh_version_minor +DEFINES += GUH_VERSION_PATCH=$$guh_version_patch +DEFINES += GUH_VERSION_STRING=\\\"$${guh_version_major}.$${guh_version_minor}.$${guh_version_patch}\\\" diff --git a/server/guhcore.cpp b/server/guhcore.cpp index 5fac6ece..66e52c64 100644 --- a/server/guhcore.cpp +++ b/server/guhcore.cpp @@ -70,6 +70,9 @@ RuleEngine *GuhCore::ruleEngine() const GuhCore::GuhCore(QObject *parent) : QObject(parent) { + qDebug() << "*****************************************"; + qDebug() << "* GUH version:" << GUH_VERSION_STRING << "starting up. *"; + qDebug() << "*****************************************"; qDebug() << "*****************************************"; qDebug() << "* Creating Device Manager *"; diff --git a/server/jsonrpc/jsonrpcserver.cpp b/server/jsonrpc/jsonrpcserver.cpp index 44352415..2f56f852 100644 --- a/server/jsonrpc/jsonrpcserver.cpp +++ b/server/jsonrpc/jsonrpcserver.cpp @@ -116,7 +116,7 @@ JsonReply* JsonRPCServer::Version(const QVariantMap ¶ms) const Q_UNUSED(params) QVariantMap data; - data.insert("version", "0.0.0"); + data.insert("version", GUH_VERSION_STRING); return createReply(data); } diff --git a/server/jsonrpc/jsontypes.cpp b/server/jsonrpc/jsontypes.cpp index 22f93c77..dec6933d 100644 --- a/server/jsonrpc/jsontypes.cpp +++ b/server/jsonrpc/jsontypes.cpp @@ -136,6 +136,7 @@ void JsonTypes::init() s_device.insert("deviceClassId", "uuid"); s_device.insert("name", "string"); s_device.insert("params", QVariantList() << paramRef()); + s_device.insert("setupComplete", "bool"); // DeviceDescription s_deviceDescriptor.insert("id", "uuid"); @@ -346,6 +347,7 @@ QVariantMap JsonTypes::packDevice(Device *device) params.append(packParam(param)); } variant.insert("params", params); + variant.insert("setupComplete", device->setupComplete()); return variant; } diff --git a/tests/auto/api.json b/tests/auto/api.json new file mode 100644 index 00000000..559d2e55 --- /dev/null +++ b/tests/auto/api.json @@ -0,0 +1,377 @@ +0.0.1 +{ + "methods": { + "Actions.ExecuteAction": { + "description": "Execute a single action.", + "params": { + "actionTypeId": "uuid", + "deviceId": "uuid", + "o:params": [ + "$ref:Param" + ] + }, + "returns": { + "errorMessage": "string", + "success": "bool" + } + }, + "Devices.AddConfiguredDevice": { + "description": "Add a configured device. Use deviceDescriptorId or deviceParams, depending on the createMethod of the device class.", + "params": { + "deviceClassId": "uuid", + "o:deviceDescriptorId": "uuid", + "o:deviceParams": [ + "$ref:Param" + ] + }, + "returns": { + "errorMessage": "string", + "o:deviceId": "uuid", + "success": "bool" + } + }, + "Devices.GetActionTypes": { + "description": "Get action types for a specified deviceClassId.", + "params": { + "deviceClassId": "uuid" + }, + "returns": { + "actionTypes": [ + "$ref:ActionType" + ] + } + }, + "Devices.GetConfiguredDevices": { + "description": "Returns a list of configured devices.", + "params": { + }, + "returns": { + "devices": [ + "$ref:Device" + ] + } + }, + "Devices.GetDiscoveredDevices": { + "description": "Performs a device discovery and returns the results. This function may take a while to return.", + "params": { + "deviceClassId": "uuid", + "o:discoveryParams": [ + "$ref:Param" + ] + }, + "returns": { + "errorMessage": "string", + "o:deviceDescriptors": [ + "$ref:DeviceDescriptor" + ], + "success": "bool" + } + }, + "Devices.GetEventTypes": { + "description": "Get event types for a specified deviceClassId.", + "params": { + "deviceClassId": "uuid" + }, + "returns": { + "eventTypes": [ + "$ref:EventType" + ] + } + }, + "Devices.GetPlugins": { + "description": "Returns a list of loaded plugins.", + "params": { + }, + "returns": { + "plugins": [ + "$ref:Plugin" + ] + } + }, + "Devices.GetStateTypes": { + "description": "Get state types for a specified deviceClassId.", + "params": { + "deviceClassId": "uuid" + }, + "returns": { + "stateTypes": [ + "$ref:StateType" + ] + } + }, + "Devices.GetStateValue": { + "description": "Get the value of the given device and the given stateType", + "params": { + "deviceId": "uuid", + "stateTypeId": "uuid" + }, + "returns": { + "errorMessage": "string", + "o:value": "variant", + "success": "bool" + } + }, + "Devices.GetSupportedDevices": { + "description": "Returns a list of supported Device classes, optionally filtered by vendorId.", + "params": { + "o:vendorId": "uuid" + }, + "returns": { + "deviceClasses": [ + "$ref:DeviceClass" + ] + } + }, + "Devices.GetSupportedVendors": { + "description": "Returns a list of supported Vendors.", + "params": { + }, + "returns": { + "vendors": [ + "$ref:Vendor" + ] + } + }, + "Devices.RemoveConfiguredDevice": { + "description": "Remove a device from the system.", + "params": { + "deviceId": "uuid" + }, + "returns": { + "errorMessage": "string", + "success": "bool" + } + }, + "Devices.SetPluginConfiguration": { + "description": "Set a plugin's params.", + "params": { + "pluginId": "uuid", + "pluginParams": [ + "$ref:ParamType" + ] + }, + "returns": { + } + }, + "JSONRPC.Introspect": { + "description": "Introspect this API.", + "params": { + }, + "returns": { + "methods": "object", + "types": "object" + } + }, + "JSONRPC.SetNotificationStatus": { + "description": "Enable/Disable notifications for this connections.", + "params": { + "enabled": "bool" + }, + "returns": { + "enabled": "bool", + "errorMessage": "string", + "success": "bool" + } + }, + "JSONRPC.Version": { + "description": "Version of this Guh/JSONRPC interface.", + "params": { + }, + "returns": { + "version": "string" + } + }, + "Rules.AddRule": { + "description": "Add a rule", + "params": { + "actions": [ + "$ref:Action" + ], + "eventDescriptor": "$ref:EventDescriptor" + }, + "returns": { + "errorMessage": "string", + "success": "bool" + } + }, + "Rules.GetRules": { + "description": "Get all configured rules", + "params": { + }, + "returns": { + "rules": [ + "$ref:Rule" + ] + } + }, + "Rules.RemoveRule": { + "description": "Remove a rule", + "params": { + "ruleId": "uuid" + }, + "returns": { + } + } + }, + "notifications": { + "Devices.StateChanged": { + "description": "Emitted whenever a State of a device changes.", + "params": { + "deviceId": "uuid", + "stateTypeId": "uuid", + "variant": "value" + } + } + }, + "types": { + "Action": { + "actionTypeId": "uuid", + "deviceId": "uuid", + "o:params": [ + "$ref:Param" + ] + }, + "ActionType": { + "id": "uuid", + "name": "string", + "params": [ + "$ref:ParamType" + ] + }, + "BasicType": [ + "uuid", + "string", + "integer", + "double", + "bool" + ], + "CreateMethodType": [ + "CreateMethodUser", + "CreateMethodAuto", + "CreateMethodDiscovery" + ], + "Device": { + "deviceClassId": "uuid", + "id": "uuid", + "name": "string", + "params": [ + "$ref:Param" + ], + "setupComplete": "bool" + }, + "DeviceClass": { + "actions": [ + "$ref:ActionType" + ], + "createMethod": "$ref:CreateMethodType", + "events": [ + "$ref:EventType" + ], + "id": "uuid", + "name": "string", + "params": [ + "$ref:ParamType" + ], + "setupMethod": "$ref:SetupMethodType", + "states": [ + "$ref:StateType" + ], + "vendorId": "uuid" + }, + "DeviceDescriptor": { + "description": "string", + "id": "uuid", + "title": "string" + }, + "Event": { + "deviceId": "uuid", + "eventTypeId": "uuid", + "o:params": [ + "$ref:Param" + ] + }, + "EventDescriptor": { + "deviceId": "uuid", + "eventTypeId": "uuid", + "o:paramDescriptors": [ + "$ref:ParamDescriptor" + ] + }, + "EventType": { + "id": "uuid", + "name": "string", + "params": [ + "$ref:ParamType" + ] + }, + "OperandType": [ + "OperandTypeEquals", + "OperandTypeNotEquals", + "OperandTypeLess", + "OperandTypeGreater", + "OperandTypeLessThan", + "OperandTypeGreaterThan" + ], + "Param": { + "name": "string", + "value": "$ref:BasicType" + }, + "ParamDescriptor": { + "name": "string", + "operand": "$ref:OperandType", + "value": "$ref:BasicType" + }, + "ParamType": { + "name": "string", + "o:defaultValue": "variant", + "o:maxValue": "variant", + "o:minValue": "variant", + "type": "$ref:BasicType" + }, + "Plugin": { + "id": "uuid", + "name": "string", + "params": [ + "$ref:ParamType" + ] + }, + "Rule": { + "actions": [ + "$ref:Action" + ], + "eventDescriptors": [ + "$ref:EventDescriptor" + ], + "id": "uuid", + "ruleType": "$ref:RuleType", + "states": [ + "$ref:State" + ] + }, + "RuleType": [ + "RuleTypeMatchAll", + "RuleTypeMatchAny" + ], + "SetupMethodType": [ + "SetupMethodJustAdd", + "SetupMethodDisplayPin", + "SetupMethodEnterPin", + "SetupMethodPushButton" + ], + "State": { + "deviceId": "uuid", + "stateTypeId": "uuid", + "value": "variant" + }, + "StateType": { + "defaultValue": "variant", + "id": "uuid", + "name": "string", + "type": "$ref:BasicType" + }, + "Vendor": { + "id": "uuid", + "name": "string" + } + } +} diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 764954d9..9ba84496 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -4,6 +4,7 @@ TARGET = guhtests QT += testlib network CONFIG += testcase c++11 DEFINES += TESTING_ENABLED +DEFINES += TESTS_SOURCE_DIR=\\\"$$top_srcdir/tests/auto/\\\" INCLUDEPATH += $$top_srcdir/server/ $$top_srcdir/server/jsonrpc $$top_srcdir/libguh $$top_srcdir/tests/auto/ LIBS += -L$$top_builddir/libguh/ -lguh diff --git a/tests/auto/testjsonrpc.cpp b/tests/auto/testjsonrpc.cpp index d417e5f2..4beb0f8a 100644 --- a/tests/auto/testjsonrpc.cpp +++ b/tests/auto/testjsonrpc.cpp @@ -26,6 +26,7 @@ #include #include #include +#include Q_IMPORT_PLUGIN(DevicePluginMock) @@ -83,6 +84,8 @@ private slots: void getRules(); + void apiChangeBumpsVersion(); + private: QVariant injectAndWait(const QString &method, const QVariantMap ¶ms); QStringList extractRefs(const QVariant &variant); @@ -601,5 +604,53 @@ void TestJSONRPC::getRules() qDebug() << "got rules response" << response; } +void TestJSONRPC::apiChangeBumpsVersion() +{ + QString oldFilePath = QString(TESTS_SOURCE_DIR) + "/api.json"; + QString newFilePath = QString(TESTS_SOURCE_DIR) + "/api.json.new"; + + QVariant response = injectAndWait("JSONRPC.Version", QVariantMap()); + QByteArray newVersion = response.toMap().value("params").toMap().value("version").toByteArray(); + + response = injectAndWait("JSONRPC.Introspect", QVariantMap()); + QJsonDocument jsonDoc = QJsonDocument::fromVariant(response.toMap().value("params")); + QByteArray newApi = jsonDoc.toJson(); + + + QFile oldApiFile(oldFilePath); + QVERIFY(oldApiFile.exists() && oldApiFile.open(QIODevice::ReadOnly)); + + QByteArray oldVersion = oldApiFile.readLine().trimmed(); + QByteArray oldApi = oldApiFile.readAll(); + + qDebug() << "version" << oldVersion << newVersion; + + if (oldVersion == newVersion && oldApi == newApi) { + // All fine. no changes + return; + } + + if (oldVersion == newVersion && oldApi != newApi) { + QVERIFY2(false, "JSONRPC API has changed but version is still the same. You need to bump the API version."); + } + + QFile newApiFile(newFilePath); + QVERIFY(newApiFile.open(QIODevice::ReadWrite)); + if (newApiFile.size() > 0) { + newApiFile.resize(0); + } + + newApiFile.write(newVersion + '\n'); + newApiFile.write(newApi); + newApiFile.flush(); + + QProcess p; + p.execute("diff", QStringList() << "-u" << oldFilePath << newFilePath); + p.waitForFinished(); + qDebug() << p.readAll(); + + QVERIFY2(false, QString("JSONRPC API has changed. Update %1.").arg(oldFilePath).toLatin1().data()); +} + QTEST_MAIN(TestJSONRPC) #include "testjsonrpc.moc"