Add test, fix some issues with loading internal and built-in plugin translations
This commit is contained in:
parent
8ebd1ddc4e
commit
50aa691087
@ -46,7 +46,7 @@ QJsonObject CloudNotifications::metaData() const
|
||||
{
|
||||
QVariantMap pluginMetaData;
|
||||
pluginMetaData.insert("id", "ccc6dbc8-e352-48a1-8e87-3c89a4669fc2");
|
||||
pluginMetaData.insert("name", "cloudNotifications");
|
||||
pluginMetaData.insert("name", "CloudNotifications");
|
||||
pluginMetaData.insert("displayName", tr("Cloud Notifications"));
|
||||
|
||||
QVariantList interfaces;
|
||||
@ -131,6 +131,10 @@ QJsonObject CloudNotifications::metaData() const
|
||||
QVariantList vendors;
|
||||
vendors.append(guhVendor);
|
||||
pluginMetaData.insert("vendors", vendors);
|
||||
|
||||
// Mark this plugin as built-in
|
||||
pluginMetaData.insert("builtIn", true);
|
||||
|
||||
return QJsonObject::fromVariantMap(pluginMetaData);
|
||||
}
|
||||
|
||||
|
||||
@ -75,7 +75,15 @@ JsonRPCServer::JsonRPCServer(const QSslConfiguration &sslConfiguration, QObject
|
||||
QVariantMap params;
|
||||
|
||||
params.clear(); returns.clear();
|
||||
setDescription("Hello", "Upon first connection, nymea will automatically send a welcome message containing information about the setup. If this message is lost for whatever reason (connections with multiple hops might drop this if nymea sends it too early), the exact same message can be retrieved multiple times by calling this Hello method. Note that the contents might change if the system changed its state in the meantime, e.g. initialSetupRequired might turn false if the initial setup has been performed in the meantime.");
|
||||
setDescription("Hello", "Initiates a connection. Use this method to perform an initial handshake of the "
|
||||
"connection. Optionally, a parameter \"locale\" is can be passed to set up the used "
|
||||
"locale for this connection. Strings such as DeviceClass displayNames etc will be "
|
||||
"localized to this locale. If this parameter is omitted, the default system locale "
|
||||
"(depending on the configuration) is used. The reply of this method contains information "
|
||||
"about this core instance such as version information, uuid and its name. The locale value"
|
||||
"indicates the locale used for this connection. Note: This method can be called multiple "
|
||||
"times. The locale used in the last call for this connection will be used. Other values, "
|
||||
"like initialSetupRequired might change if the setup has been performed in the meantime.");
|
||||
params.insert("o:locale", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
setParams("Hello", params);
|
||||
returns.insert("id", JsonTypes::basicTypeToString(JsonTypes::Int));
|
||||
@ -84,6 +92,7 @@ JsonRPCServer::JsonRPCServer(const QSslConfiguration &sslConfiguration, QObject
|
||||
returns.insert("version", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
returns.insert("uuid", JsonTypes::basicTypeToString(JsonTypes::Uuid));
|
||||
returns.insert("language", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
returns.insert("locale", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
returns.insert("protocol version", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
returns.insert("initialSetupRequired", JsonTypes::basicTypeToString(JsonTypes::Bool));
|
||||
returns.insert("authenticationRequired", JsonTypes::basicTypeToString(JsonTypes::Bool));
|
||||
@ -239,7 +248,7 @@ JsonReply *JsonRPCServer::Hello(const QVariantMap ¶ms)
|
||||
|
||||
qCDebug(dcJsonRpc()) << "Client" << clientId << "initiated handshake." << m_clientLocales.value(clientId);
|
||||
|
||||
return createReply(createWelcomeMessage(interface));
|
||||
return createReply(createWelcomeMessage(interface, clientId));
|
||||
}
|
||||
|
||||
JsonReply* JsonRPCServer::Introspect(const QVariantMap ¶ms) const
|
||||
@ -475,7 +484,7 @@ void JsonRPCServer::sendUnauthorizedResponse(TransportInterface *interface, cons
|
||||
interface->sendData(clientId, data);
|
||||
}
|
||||
|
||||
QVariantMap JsonRPCServer::createWelcomeMessage(TransportInterface *interface) const
|
||||
QVariantMap JsonRPCServer::createWelcomeMessage(TransportInterface *interface, const QUuid &clientId) const
|
||||
{
|
||||
QVariantMap handshake;
|
||||
handshake.insert("id", 0);
|
||||
@ -483,7 +492,9 @@ QVariantMap JsonRPCServer::createWelcomeMessage(TransportInterface *interface) c
|
||||
handshake.insert("name", NymeaCore::instance()->configuration()->serverName());
|
||||
handshake.insert("version", NYMEA_VERSION_STRING);
|
||||
handshake.insert("uuid", NymeaCore::instance()->configuration()->serverUuid().toString());
|
||||
handshake.insert("language", NymeaCore::instance()->configuration()->locale().name());
|
||||
// "language" is deprecated
|
||||
handshake.insert("language", m_clientLocales.value(clientId).name());
|
||||
handshake.insert("locale", m_clientLocales.value(clientId).name());
|
||||
handshake.insert("protocol version", JSON_PROTOCOL_VERSION);
|
||||
handshake.insert("initialSetupRequired", (interface->configuration().authenticationEnabled ? NymeaCore::instance()->userManager()->initRequired() : false));
|
||||
handshake.insert("authenticationRequired", interface->configuration().authenticationEnabled);
|
||||
@ -612,14 +623,10 @@ void JsonRPCServer::processJsonPacket(TransportInterface *interface, const QUuid
|
||||
qCDebug(dcJsonRpc()) << "Invoking method" << targetNamespace << method.toLatin1().data();
|
||||
|
||||
if (targetNamespace != "JSONRPC" || method != "Hello") {
|
||||
// Unless this is the Hello message, which allows setting the locale explicity, attach the locale
|
||||
// for this connection
|
||||
// If the client did request a locale in the Hello message, use that locale
|
||||
if (m_clientLocales.contains(clientId)) {
|
||||
params.insert("locale", m_clientLocales.value(clientId));
|
||||
}
|
||||
// Otherwise fall back to the locale set in the configuration.
|
||||
else {
|
||||
params.insert("locale", NymeaCore::instance()->configuration()->locale());
|
||||
}
|
||||
params.insert("locale", m_clientLocales.value(clientId));
|
||||
}
|
||||
|
||||
JsonReply *reply;
|
||||
@ -757,7 +764,10 @@ void JsonRPCServer::clientConnected(const QUuid &clientId)
|
||||
// If authentication is required, notifications are disabled by default. Clients must enable them with a valid token
|
||||
m_clientNotifications.insert(clientId, !interface->configuration().authenticationEnabled);
|
||||
|
||||
interface->sendData(clientId, QJsonDocument::fromVariant(createWelcomeMessage(interface)).toJson(QJsonDocument::Compact));
|
||||
// Initialize the connection locale to the settings default
|
||||
m_clientLocales.insert(clientId, NymeaCore::instance()->configuration()->locale());
|
||||
|
||||
interface->sendData(clientId, QJsonDocument::fromVariant(createWelcomeMessage(interface, clientId)).toJson(QJsonDocument::Compact));
|
||||
}
|
||||
|
||||
void JsonRPCServer::clientDisconnected(const QUuid &clientId)
|
||||
|
||||
@ -77,7 +77,7 @@ private:
|
||||
void sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms = QVariantMap());
|
||||
void sendErrorResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QString &error);
|
||||
void sendUnauthorizedResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QString &error);
|
||||
QVariantMap createWelcomeMessage(TransportInterface *interface) const;
|
||||
QVariantMap createWelcomeMessage(TransportInterface *interface, const QUuid &clientId) const;
|
||||
|
||||
void processJsonPacket(TransportInterface *interface, const QUuid &clientId, const QByteArray &data);
|
||||
|
||||
|
||||
@ -430,6 +430,11 @@ DeviceManager::DeviceError DevicePlugin::setConfigValue(const ParamTypeId ¶m
|
||||
return DeviceManager::DeviceErrorNoError;
|
||||
}
|
||||
|
||||
bool DevicePlugin::isBuiltIn() const
|
||||
{
|
||||
return m_metaData.value("builtIn").toBool();
|
||||
}
|
||||
|
||||
/*! Returns a pointer to the \l{DeviceManager}.
|
||||
When implementing a plugin, use this to find the \l{Device}{Devices} you need.
|
||||
*/
|
||||
@ -501,7 +506,7 @@ void DevicePlugin::loadMetaData()
|
||||
|
||||
// Note: The DevicePlugin has no type class, so we define the json properties here
|
||||
QStringList pluginMandatoryJsonProperties = QStringList() << "id" << "name" << "displayName" << "vendors";
|
||||
QStringList pluginJsonProperties = QStringList() << "id" << "name" << "displayName" << "vendors" << "paramTypes";
|
||||
QStringList pluginJsonProperties = QStringList() << "id" << "name" << "displayName" << "vendors" << "paramTypes" << "builtIn";
|
||||
|
||||
QPair<QStringList, QStringList> verificationResult = verifyFields(pluginJsonProperties, pluginMandatoryJsonProperties, m_metaData);
|
||||
|
||||
|
||||
@ -82,6 +82,8 @@ public:
|
||||
QVariant configValue(const ParamTypeId ¶mTypeId) const;
|
||||
DeviceManager::DeviceError setConfigValue(const ParamTypeId ¶mTypeId, const QVariant &value);
|
||||
|
||||
bool isBuiltIn() const;
|
||||
|
||||
signals:
|
||||
void emitEvent(const Event &event);
|
||||
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &deviceDescriptors);
|
||||
|
||||
@ -137,37 +137,56 @@ void Translator::loadTranslator(DevicePlugin *plugin, const QLocale &locale)
|
||||
}
|
||||
}
|
||||
|
||||
bool loaded = false;
|
||||
// check if there are local translations
|
||||
QTranslator* translator = new QTranslator();
|
||||
QString pluginId = plugin->pluginId().toString().remove(QRegExp("[{}]"));
|
||||
|
||||
bool loaded = false;
|
||||
foreach (const QString &pluginPath, qgetenv("NYMEA_PLUGINS_PATH").split(':')) {
|
||||
if (translator->load(locale, pluginId, "-", QDir(pluginPath + "/translations/").absolutePath(), ".qm")) {
|
||||
qCDebug(dcTranslations()) << "* Loaded translation" << locale.name() << "for plugin" << plugin->pluginName() << "from" << QDir(pluginPath + "/translations/").absolutePath();
|
||||
if (plugin->isBuiltIn()) {
|
||||
if (translator->load(locale, QCoreApplication::instance()->applicationName(), "-", QDir(QCoreApplication::applicationDirPath() + "../../translations/").absolutePath(), ".qm")) {
|
||||
qCDebug(dcTranslations()) << "* Loaded translation" << locale.name() << "for plugin" << plugin->pluginName() << "from" << QDir(QCoreApplication::applicationDirPath() + "../../translations/").absolutePath() + "/" + QCoreApplication::applicationName() + "-[" + locale.name() + "].qm";
|
||||
loaded = true;
|
||||
} else if (translator->load(locale, QCoreApplication::instance()->applicationName(), "-", NymeaSettings::translationsPath(), ".qm")) {
|
||||
qCDebug(dcTranslations()) << "* Loaded translation" << locale.name() << "for plugin" << plugin->pluginName() << "from" << NymeaSettings::translationsPath()+ "/" + QCoreApplication::applicationName() + "-[" + locale.name() + "].qm";
|
||||
loaded = true;
|
||||
break;
|
||||
}
|
||||
foreach (const QString &subdir, QDir(pluginPath).entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||
if (translator->load(locale, pluginId, "-", QDir(pluginPath + "/" + subdir + "/translations/").absolutePath(), ".qm")) {
|
||||
qCDebug(dcTranslations()) << "* Loaded translation" << locale.name() << "for plugin" << plugin->pluginName() << "from" << QDir(pluginPath + "/" + subdir + "/translations/").absolutePath();
|
||||
} else {
|
||||
QString pluginId = plugin->pluginId().toString().remove(QRegExp("[{}]"));
|
||||
|
||||
QStringList searchDirs = QString(qgetenv("NYMEA_PLUGINS_PATH")).split(':');
|
||||
searchDirs << QCoreApplication::applicationDirPath() + "/../lib/nymea/plugins";
|
||||
searchDirs << QCoreApplication::applicationDirPath() + "/../plugins/";
|
||||
searchDirs << QCoreApplication::applicationDirPath() + "/../../../plugins/";
|
||||
searchDirs << QString("%1").arg(NYMEA_PLUGINS_PATH);
|
||||
|
||||
foreach (const QString &pluginPath, searchDirs) {
|
||||
if (translator->load(locale, pluginId, "-", QDir(pluginPath + "/translations/").absolutePath(), ".qm")) {
|
||||
qCDebug(dcTranslations()) << "* Loaded translation" << locale.name() << "for plugin" << plugin->pluginName() << "from" << QDir(pluginPath + "/translations/").absolutePath();
|
||||
loaded = true;
|
||||
break;
|
||||
}
|
||||
foreach (const QString &subdir, QDir(pluginPath).entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||
if (translator->load(locale, pluginId, "-", QDir(pluginPath + "/" + subdir + "/translations/").absolutePath(), ".qm")) {
|
||||
qCDebug(dcTranslations()) << "* Loaded translation" << locale.name() << "for plugin" << plugin->pluginName() << "from" << QDir(pluginPath + "/" + subdir + "/translations/").absolutePath() + "/" + pluginId + "-[" + locale.name() + "].qm";
|
||||
loaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (loaded) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (loaded) {
|
||||
break;
|
||||
|
||||
// otherwise use the system translations
|
||||
if (!loaded && translator->load(locale, pluginId, "-", NymeaSettings::translationsPath(), ".qm")) {
|
||||
qCDebug(dcTranslations()) << "* Load translation" << locale.name() << "for" << plugin->pluginName() << "from" << NymeaSettings::translationsPath() + "/" + pluginId + "-[" + locale.name() + "].qm";
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
if (!loaded && locale.name() != "en_US") {
|
||||
qCWarning(dcTranslations()) << "* Could not load translation" << locale.name() << "for plugin" << plugin->pluginName() << "(" << pluginId << ")";
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise use the system translations
|
||||
if (!loaded && translator->load(locale, pluginId, "-", NymeaSettings::translationsPath(), ".qm")) {
|
||||
qCDebug(dcTranslations()) << "* Load translation" << locale.name() << "for" << plugin->pluginName() << "from" << NymeaSettings::translationsPath();
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
if (!loaded && locale.name() != "en_US")
|
||||
qCWarning(dcTranslations()) << "* Could not load translation" << locale.name() << "for plugin" << plugin->pluginName();
|
||||
|
||||
if (!loaded) {
|
||||
translator = m_translatorContexts.value(plugin->pluginId()).translators.value(QLocale("en_US"));
|
||||
|
||||
12
nymea.pro
12
nymea.pro
@ -23,20 +23,22 @@ test.commands = LD_LIBRARY_PATH=$$top_builddir/libnymea-core:$$top_builddir/libn
|
||||
|
||||
# Translations:
|
||||
# make lupdate to update .ts files
|
||||
TRANSLATIONS += $$files(translations/*.ts, true)
|
||||
TRANSLATIONS += $$files(plugins/mock/translations/*.ts, true)
|
||||
CORE_TRANSLATIONS += $$files($${top_srcdir}/translations/*.ts, true)
|
||||
lupdate.commands = lupdate -recursive -no-obsolete $${top_srcdir} -ts $${CORE_TRANSLATIONS};
|
||||
PLUGIN_TRANSLATIONS += $$files($${top_srcdir}/plugins/mock/translations/*.ts, true)
|
||||
lupdate.commands += lupdate -recursive -no-obsolete $${top_builddir}/plugins/mock/ -ts $${PLUGIN_TRANSLATIONS};
|
||||
lupdate.depends = FORCE
|
||||
lupdate.commands = lupdate -recursive -no-obsolete $$_FILE_;
|
||||
TRANSLATIONS = $${CORE_TRANSLATIONS} $${PLUGIN_TRANSLATIONS}
|
||||
|
||||
# make lrelease to compile .ts to .qm
|
||||
lrelease.depends = FORCE
|
||||
lrelease.commands = lrelease $$_FILE_; \
|
||||
rsync -a $$top_srcdir/translations/*.qm $$top_builddir/translations/;
|
||||
rsync -a $$top_srcdir/translations/*.qm $$top_builddir/translations/; \
|
||||
rsync -a $$top_srcdir/plugins/mock/translations/*.qm $$top_builddir/plugins/mock/translations/;
|
||||
first.depends = $(first) lrelease
|
||||
|
||||
# Install translation files
|
||||
translations.path = /usr/share/nymea/translations
|
||||
translations.files = $$[QT_SOURCE_TREE]/translations/*.qm
|
||||
translations.depends = lrelease
|
||||
INSTALLS += translations
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@ include(../nymea.pri)
|
||||
TEMPLATE = lib
|
||||
CONFIG += plugin
|
||||
|
||||
QT += network bluetooth
|
||||
QT += network
|
||||
|
||||
INCLUDEPATH += $$top_srcdir/libnymea
|
||||
LIBS += -L../../libnymea -lnymea
|
||||
|
||||
@ -146,7 +146,7 @@ int main(int argc, char *argv[])
|
||||
// check if there are local translations
|
||||
if (!translator.load(QLocale::system(), application.applicationName(), "-", QDir(QCoreApplication::applicationDirPath() + "../../translations/").absolutePath(), ".qm"))
|
||||
if (!translator.load(QLocale::system(), application.applicationName(), "-", NymeaSettings::translationsPath(), ".qm"))
|
||||
qWarning(dcApplication()) << "Could not find nymead translations for" << QLocale::system().name() << endl << (QDir(QCoreApplication::applicationDirPath() + "../../translations/").absolutePath()) << endl << NymeaSettings::translationsPath();
|
||||
qWarning(dcTranslations()) << "Could not find nymead translations for" << QLocale::system().name() << endl << (QDir(QCoreApplication::applicationDirPath() + "../../translations/").absolutePath()) << endl << NymeaSettings::translationsPath();
|
||||
|
||||
|
||||
|
||||
|
||||
@ -35,6 +35,8 @@ private slots:
|
||||
|
||||
void testHandshake();
|
||||
|
||||
void testHandshakeLocale();
|
||||
|
||||
void testInitialSetup();
|
||||
|
||||
void testRevokeToken();
|
||||
@ -131,7 +133,9 @@ void TestJSONRPC::initTestCase()
|
||||
{
|
||||
NymeaTestBase::initTestCase();
|
||||
QLoggingCategory::setFilterRules("*.debug=false\n"
|
||||
"JsonRpc*.debug=true");
|
||||
// "JsonRpc*.debug=true\n"
|
||||
"Translations.debug=true\n"
|
||||
"Tests.debug=true");
|
||||
}
|
||||
|
||||
void TestJSONRPC::testHandshake()
|
||||
@ -170,6 +174,42 @@ void TestJSONRPC::testHandshake()
|
||||
QCOMPARE(handShake.value("params").toMap().value("version").toString(), nymeaVersionString);
|
||||
}
|
||||
|
||||
void TestJSONRPC::testHandshakeLocale()
|
||||
{
|
||||
// first test if the handshake message is auto-sent upon connecting
|
||||
QSignalSpy spy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
||||
|
||||
// Test withouth locale data
|
||||
QVariantMap handShake = injectAndWait("JSONRPC.Hello").toMap();
|
||||
QCOMPARE(handShake.value("params").toMap().value("locale").toString(), QString("en_US"));
|
||||
|
||||
QVariantMap supportedDevices = injectAndWait("Devices.GetSupportedDevices").toMap();
|
||||
bool found = false;
|
||||
foreach (const QVariant &dcMap, supportedDevices.value("params").toMap().value("deviceClasses").toList()) {
|
||||
if (dcMap.toMap().value("id").toUuid() == mockDeviceAutoClassId) {
|
||||
QCOMPARE(dcMap.toMap().value("displayName").toString(), QString("Mock Device (Auto created)"));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
QVERIFY(found);
|
||||
|
||||
// And now with locale info
|
||||
QVariantMap params;
|
||||
params.insert("locale", "de_DE");
|
||||
handShake = injectAndWait("JSONRPC.Hello", params).toMap();
|
||||
QCOMPARE(handShake.value("params").toMap().value("locale").toString(), QString("de_DE"));
|
||||
|
||||
supportedDevices = injectAndWait("Devices.GetSupportedDevices").toMap();
|
||||
found = false;
|
||||
foreach (const QVariant &dcMap, supportedDevices.value("params").toMap().value("deviceClasses").toList()) {
|
||||
if (dcMap.toMap().value("id").toUuid() == mockDeviceAutoClassId) {
|
||||
QCOMPARE(dcMap.toMap().value("displayName").toString(), QString("Mock Gerät (Automatisch erzeugt)"));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
QVERIFY(found);
|
||||
}
|
||||
|
||||
void TestJSONRPC::testInitialSetup()
|
||||
{
|
||||
foreach (const QString &user, NymeaCore::instance()->userManager()->users()) {
|
||||
|
||||
Reference in New Issue
Block a user