diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-12-10 03:03:01 +0100 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-12-10 03:03:02 +0100 |
commit | 701d1876209473c4c6e916f0c677b36829560cb5 (patch) | |
tree | a2e4d17e8a69042540cb90326f31a6ddde5d6a97 /tests | |
parent | f1ab55285840068cf38fba6fdea667578dad7c5b (diff) | |
parent | 957d17b42b24e558fbee3f4f503712d18edf4953 (diff) |
Merge remote-tracking branch 'origin/5.15' into dev
Change-Id: Iaeed3b0e4f701994c2d2876886e148b4f732230c
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/auto.pro | 3 | ||||
-rw-r--r-- | tests/auto/x509/tst_x509.cpp | 274 | ||||
-rw-r--r-- | tests/auto/x509/x509.pro | 8 | ||||
-rw-r--r-- | tests/manual/gds/gds.pro | 8 | ||||
-rw-r--r-- | tests/manual/gds/tst_gds.cpp | 329 | ||||
-rw-r--r-- | tests/manual/manual.pro | 3 | ||||
-rw-r--r-- | tests/tests.pro | 3 |
7 files changed, 625 insertions, 3 deletions
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 9d8b7db..82a44df 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,10 +1,11 @@ TEMPLATE = subdirs SUBDIRS += qopcuaclient connection clientSetupInCpp security -QT_FOR_CONFIG += opcua-private +QT_FOR_CONFIG += opcua-private core-private # only build declarative tests if at least one backend was built qtHaveModule(qmltest):qtConfig(open62541)|qtConfig(uacpp) { SUBDIRS += declarative } +qtConfig(ssl):!darwin:!winrt: SUBDIRS += x509 diff --git a/tests/auto/x509/tst_x509.cpp b/tests/auto/x509/tst_x509.cpp new file mode 100644 index 0000000..d00c3d9 --- /dev/null +++ b/tests/auto/x509/tst_x509.cpp @@ -0,0 +1,274 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt OPC UA module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtOpcUa/QOpcUaProvider> +#include <QtOpcUa/QOpcUaKeyPair> + +#include <QtCore/QCoreApplication> +#include <QtCore/QScopedPointer> +#include <QOpcUaX509CertificateSigningRequest> +#include <QOpcUaX509ExtensionSubjectAlternativeName> +#include <QOpcUaX509ExtensionBasicConstraints> +#include <QOpcUaX509ExtensionKeyUsage> +#include <QOpcUaX509ExtensionExtendedKeyUsage> + +#include <QtTest/QSignalSpy> +#include <QtTest/QtTest> + +#define defineDataMethod(name) void name()\ +{\ + QTest::addColumn<QString>("backend");\ + for (auto backend : m_backends) {\ + const QString rowName = QString("%1").arg(backend); \ + QTest::newRow(rowName.toLatin1().constData()) << backend ; \ + }\ +} + +class Tst_QOpcUaSecurity: public QObject +{ + Q_OBJECT + +public: + Tst_QOpcUaSecurity(); + +private slots: + void initTestCase(); + void cleanupTestCase(); + + defineDataMethod(keyPairs_data) + void keyPairs(); + + defineDataMethod(certificateSigningRequest_data) + void certificateSigningRequest(); + +private: + QStringList m_backends; + QOpcUaProvider m_opcUa; +}; + +QByteArray textifyCertificateRequest(const QByteArray &data) +{ + QProcess p; + p.start("openssl", QStringList {"req", "-text", "-noout"}); + p.waitForStarted(); + p.write(data); + p.closeWriteChannel(); + p.waitForFinished(); + return p.readAllStandardOutput(); +} + +QByteArray textifyCertificate(const QByteArray &data) +{ + QProcess p; + p.start("openssl", QStringList {"x509", "-text", "-noout"}); + p.waitForStarted(); + p.write(data); + p.closeWriteChannel(); + p.waitForFinished(); + return p.readAllStandardOutput(); +} + +QByteArray asn1dump(const QByteArray &data) +{ + QProcess p; + p.start("openssl", QStringList {"asn1parse", "-inform","PEM"}); + p.waitForStarted(); + p.write(data); + p.closeWriteChannel(); + p.waitForFinished(); + return p.readAllStandardOutput(); +} + +Tst_QOpcUaSecurity::Tst_QOpcUaSecurity() +{ + m_backends = QOpcUaProvider::availableBackends(); +} + +void Tst_QOpcUaSecurity::initTestCase() +{ +} + +void Tst_QOpcUaSecurity::keyPairs() +{ + QFETCH(QString, backend); + + QOpcUaKeyPair key; + QOpcUaKeyPair loadedKey; + QByteArray byteArray; + + QVERIFY(key.hasPrivateKey() == false); + + // Generate key + key.generateRsaKey(QOpcUaKeyPair::RsaKeyStrength::Bits1024); + QVERIFY(key.hasPrivateKey() == true); + + // Export public key + byteArray = key.publicKeyToByteArray(); + QVERIFY(byteArray.startsWith("-----BEGIN PUBLIC KEY-----\n")); + QVERIFY(byteArray.endsWith("-----END PUBLIC KEY-----\n")); + + // Load public key + QVERIFY(loadedKey.loadFromPemData(byteArray)); + QVERIFY(loadedKey.hasPrivateKey() == false); + + // Check unencrypted PEM export + byteArray = key.privateKeyToByteArray(QOpcUaKeyPair::Cipher::Unencrypted, QString()); + QVERIFY(byteArray.startsWith("-----BEGIN PRIVATE KEY-----\n")); + QVERIFY(byteArray.endsWith("-----END PRIVATE KEY-----\n")); + + // Load private key from PEM data + QSignalSpy passwordSpy(&loadedKey, SIGNAL(passphraseNeeded(QString&,int,bool))); + + QVERIFY(loadedKey.loadFromPemData(byteArray)); + QVERIFY(loadedKey.hasPrivateKey() == true); + QCOMPARE(passwordSpy.count(), 0); + QCOMPARE(loadedKey.privateKeyToByteArray(QOpcUaKeyPair::Cipher::Unencrypted, QString()), byteArray); + + // Check encrypted PEM export + byteArray = key.privateKeyToByteArray(QOpcUaKeyPair::Cipher::Aes128Cbc, QString("password")); + QVERIFY(byteArray.startsWith("-----BEGIN ENCRYPTED PRIVATE KEY-----\n")); + QVERIFY(byteArray.endsWith("-----END ENCRYPTED PRIVATE KEY-----\n")); + QCOMPARE(passwordSpy.count(), 0); + + // Setup password callback + QString passphraseToReturn; + connect(&loadedKey, &QOpcUaKeyPair::passphraseNeeded, this, [&passphraseToReturn](QString &passphrase, int maximumLength, bool writeOperation){ + Q_UNUSED(maximumLength); + qDebug() << "Requested a passphrase for" << (writeOperation ? "write":"read") << "operation"; + passphrase = passphraseToReturn; + }); + + // Load key with wrong password + qDebug() << "Trying to decrypt with wrong password; will cause an error"; + passphraseToReturn = "WrongPassword"; + QVERIFY(!loadedKey.loadFromPemData(byteArray)); + QCOMPARE(passwordSpy.count(), 1); + QVERIFY(loadedKey.hasPrivateKey() == false); + + // Load key with right password + qDebug() << "Trying to decrypt with right password; will cause no error"; + passphraseToReturn = "password"; + QVERIFY(loadedKey.loadFromPemData(byteArray)); + QCOMPARE(passwordSpy.count(), 2); + QCOMPARE(loadedKey.privateKeyToByteArray(QOpcUaKeyPair::Cipher::Unencrypted, QString()), + key.privateKeyToByteArray(QOpcUaKeyPair::Cipher::Unencrypted, QString())); + QVERIFY(loadedKey.hasPrivateKey() == true); +} + +void Tst_QOpcUaSecurity::certificateSigningRequest() +{ + QFETCH(QString, backend); + + QOpcUaKeyPair key; + + // Generate key + key.generateRsaKey(QOpcUaKeyPair::RsaKeyStrength::Bits1024); + QVERIFY(key.hasPrivateKey() == true); + + QOpcUaX509CertificateSigningRequest csr; + + QOpcUaX509DistinguishedName dn; + dn.setEntry(QOpcUaX509DistinguishedName::Type::CommonName, "QtOpcUaViewer"); + dn.setEntry(QOpcUaX509DistinguishedName::Type::CountryName, "DE"); + dn.setEntry(QOpcUaX509DistinguishedName::Type::LocalityName, "Berlin"); + dn.setEntry(QOpcUaX509DistinguishedName::Type::StateOrProvinceName, "Berlin"); + dn.setEntry(QOpcUaX509DistinguishedName::Type::OrganizationName, "The Qt Company"); + csr.setSubject(dn); + + QOpcUaX509ExtensionSubjectAlternativeName *san = new QOpcUaX509ExtensionSubjectAlternativeName; + san->addEntry(QOpcUaX509ExtensionSubjectAlternativeName::Type::DNS, "foo.com"); + san->addEntry(QOpcUaX509ExtensionSubjectAlternativeName::Type::DNS, "bla.com"); + san->addEntry(QOpcUaX509ExtensionSubjectAlternativeName::Type::URI, "urn:foo.com:The%20Qt%20Company:QtOpcUaViewer"); + san->setCritical(true); + csr.addExtension(san); + + QOpcUaX509ExtensionBasicConstraints *bc = new QOpcUaX509ExtensionBasicConstraints; + bc->setCa(false); + bc->setCritical(true); + csr.addExtension(bc); + + QOpcUaX509ExtensionKeyUsage *ku = new QOpcUaX509ExtensionKeyUsage; + ku->setCritical(true); + ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::DigitalSignature); + ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::NonRepudiation); + ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::KeyEncipherment); + ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::DataEncipherment); + ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::CertificateSigning); + csr.addExtension(ku); + + QOpcUaX509ExtensionExtendedKeyUsage *eku = new QOpcUaX509ExtensionExtendedKeyUsage; + eku->setCritical(true); + eku->setKeyUsage(QOpcUaX509ExtensionExtendedKeyUsage::KeyUsage::EmailProtection); + csr.addExtension(eku); + + QByteArray csrData = csr.createRequest(key); + qDebug() << csrData; + QVERIFY(csrData.startsWith("-----BEGIN CERTIFICATE REQUEST-----\n")); + QVERIFY(csrData.endsWith("\n-----END CERTIFICATE REQUEST-----\n")); + qDebug().noquote() << textifyCertificateRequest(csrData); + qDebug().noquote() << asn1dump(csrData); + + QByteArray certData = csr.createSelfSignedCertificate(key); + qDebug() << certData; + QVERIFY(certData.startsWith("-----BEGIN CERTIFICATE-----\n")); + QVERIFY(certData.endsWith("\n-----END CERTIFICATE-----\n")); + qDebug().noquote() << textifyCertificate(certData); + qDebug().noquote() << asn1dump(certData); +} + +void Tst_QOpcUaSecurity::cleanupTestCase() +{ +} + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + QTEST_SET_MAIN_SOURCE_PATH + + // run tests for all available backends + QStringList availableBackends = QOpcUaProvider::availableBackends(); + if (availableBackends.empty()) { + qDebug("No OPCUA backends found, skipping tests."); + return EXIT_SUCCESS; + } + + Tst_QOpcUaSecurity tc; + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_x509.moc" + diff --git a/tests/auto/x509/x509.pro b/tests/auto/x509/x509.pro new file mode 100644 index 0000000..b1f1fc1 --- /dev/null +++ b/tests/auto/x509/x509.pro @@ -0,0 +1,8 @@ +TARGET = tst_x509 + +QT += testlib opcua network +QT -= gui +CONFIG += testcase + +SOURCES += \ + tst_x509.cpp diff --git a/tests/manual/gds/gds.pro b/tests/manual/gds/gds.pro new file mode 100644 index 0000000..525595f --- /dev/null +++ b/tests/manual/gds/gds.pro @@ -0,0 +1,8 @@ +TARGET = tst_gds + +QT += testlib opcua network +QT -= gui +CONFIG += testcase + +SOURCES += \ + tst_gds.cpp diff --git a/tests/manual/gds/tst_gds.cpp b/tests/manual/gds/tst_gds.cpp new file mode 100644 index 0000000..9e57238 --- /dev/null +++ b/tests/manual/gds/tst_gds.cpp @@ -0,0 +1,329 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt OPC UA module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtOpcUa/QOpcUaProvider> +#include <QtOpcUa/QOpcUaGdsClient> +#include <QtOpcUa/QOpcUaApplicationIdentity> +#include <QtOpcUa/QOpcUaPkiConfiguration> +#include <QtOpcUa/QOpcUaAuthenticationInformation> +#include <QtOpcUa/QOpcUaEndpointDescription> +#include <QtOpcUa/QOpcUaApplicationRecordDataType> +#include <QtOpcUa/QOpcUaClient> +#include <QtOpcUa/QOpcUaX509DistinguishedName> + +#include <QtCore/QCoreApplication> +#include <QtCore/QScopedPointer> +#include <QHostInfo> + +#include <QtTest/QSignalSpy> +#include <QtTest/QtTest> + +#define defineDataMethod(name) void name()\ +{\ + QTest::addColumn<QString>("backend");\ + for (auto backend : m_backends) {\ + const QString rowName = QString("%1").arg(backend); \ + QTest::newRow(rowName.toLatin1().constData()) << backend ; \ + QVERIFY(!backend.isEmpty()); \ + }\ +} + +static QOpcUaPkiConfiguration getPkiConfig() +{ + QOpcUaPkiConfiguration pkiConfig; + const QString pkiDir = QCoreApplication::applicationDirPath() + "/pki"; + + pkiConfig.setClientCertificateFile(pkiDir + "/own/certs/application.der"); + pkiConfig.setPrivateKeyFile(pkiDir + "/own/private/application.pem"); + pkiConfig.setTrustListDirectory(pkiDir + "/trusted/certs"); + pkiConfig.setRevocationListDirectory(pkiDir + "/trusted/crl"); + pkiConfig.setIssuerListDirectory(pkiDir + "/issuers/certs"); + pkiConfig.setIssuerRevocationListDirectory(pkiDir + "/issuers/crl"); + return pkiConfig; +} + +static QOpcUaApplicationIdentity getAppIdentity() +{ + QOpcUaApplicationIdentity identity; + + const QString applicationUri = QStringLiteral("urn:%1:%2:%3") + .arg(QHostInfo::localHostName()) + .arg(QCoreApplication::organizationName()) + .arg(QCoreApplication::applicationName()); + const QString productUri = QStringLiteral("urn:%1:%2") + .arg(QCoreApplication::organizationName()) + .arg(QCoreApplication::applicationName()); + + identity.setProductUri(productUri); + identity.setApplicationUri(applicationUri); + identity.setApplicationName(QCoreApplication::applicationName()); + identity.setApplicationType(QOpcUaApplicationDescription::Client); + return identity; +} + +static bool removeSettingsFile() +{ + QSettings settings; + QFile file(settings.fileName()); + if (file.exists()) + return file.remove(); + return true; +} + +static void provideCredentials(QOpcUaAuthenticationInformation &authInfo) +{ + qDebug() << "Authentication credentials provided"; + authInfo.setUsernameAuthentication("root", "secret"); +} + +static void commonGdsClientSetup(QOpcUaGdsClient &gc, const QString &backend, const QOpcUaEndpointDescription endpoint) +{ + QObject::connect(&gc, &QOpcUaGdsClient::authenticationRequired, provideCredentials); + + gc.setBackend(backend); + gc.setEndpoint(endpoint); + gc.setApplicationIdentity(getAppIdentity()); + gc.setPkiConfiguration(getPkiConfig()); + + QOpcUaApplicationRecordDataType ar = gc.applicationRecord(); + ar.setApplicationNames(QVector<QOpcUaLocalizedText>{QOpcUaLocalizedText("en", gc.applicationIdentity().applicationName())}); + ar.setApplicationType(gc.applicationIdentity().applicationType()); + ar.setApplicationUri(gc.applicationIdentity().applicationUri()); + ar.setProductUri(gc.applicationIdentity().productUri()); + ar.setDiscoveryUrls(QVector<QString>{QLatin1String("opc.tcp://localhost")}); + gc.setApplicationRecord(ar); + + QOpcUaX509DistinguishedName dn; + dn.setEntry(QOpcUaX509DistinguishedName::Type::CountryName, QLatin1String("DE")); + dn.setEntry(QOpcUaX509DistinguishedName::Type::LocalityName, QLatin1String("Berlin")); + dn.setEntry(QOpcUaX509DistinguishedName::Type::StateOrProvinceName, QLatin1String("Berlin")); + dn.setEntry(QOpcUaX509DistinguishedName::Type::OrganizationName, QLatin1String("The Qt Company")); + gc.setCertificateSigningRequestPresets(dn, QLatin1String("foo.com")); +} + +// The tests have are depending on each other and have to be executed in order. + +class Tst_QOpcUaGds: public QObject +{ + Q_OBJECT + +public: + Tst_QOpcUaGds(); + +private slots: + void initTestCase(); + void cleanupTestCase(); + + defineDataMethod(registerApplication_data) + void registerApplication(); + defineDataMethod(reuseApplicationId_data) + void reuseApplicationId(); + defineDataMethod(reuseRegisteredUri_data) + void reuseRegisteredUri(); + defineDataMethod(serverForgotRegistration_data) + void serverForgotRegistration(); +private: + QStringList m_backends; + QOpcUaEndpointDescription m_endpoint; +}; + +Tst_QOpcUaGds::Tst_QOpcUaGds() +{ + m_backends = QOpcUaProvider::availableBackends(); +} + +void Tst_QOpcUaGds::initTestCase() +{ + QOpcUaEndpointDescription endpoint; + QOpcUaProvider provider; + + QScopedPointer<QOpcUaClient> client(provider.createClient("open62541")); + QVERIFY(!client.isNull()); + QSignalSpy endpointSpy(client.data(), &QOpcUaClient::endpointsRequestFinished); + client->requestEndpoints(QUrl("opc.tcp://172.17.0.1:48060")); + endpointSpy.wait(2000); + QCOMPARE(endpointSpy.size(), 1); + + const QVector<QOpcUaEndpointDescription> desc = endpointSpy.at(0).at(0).value<QVector<QOpcUaEndpointDescription>>(); + QVERIFY(desc.size() > 0); + + for (const auto &i : qAsConst(desc)) { + if (i.securityPolicy().endsWith("#Basic256Sha256") + && i.securityMode() == QOpcUaEndpointDescription::MessageSecurityMode::SignAndEncrypt) + m_endpoint = i; + } + + QVERIFY(m_endpoint.securityPolicy().endsWith("#Basic256Sha256")); +} + +void Tst_QOpcUaGds::registerApplication() +{ + QFETCH(QString, backend); + if (backend == "open62541") + QSKIP("Skipping open62541"); + + QVERIFY(removeSettingsFile()); + + QOpcUaGdsClient gc; + commonGdsClientSetup(gc, backend, m_endpoint); + + QSignalSpy registeredSpy(&gc, &QOpcUaGdsClient::applicationRegistered); + QSignalSpy certificateGroupsSpy(&gc, &QOpcUaGdsClient::certificateGroupsReceived); + QSignalSpy certificateStatusSpy(&gc, &QOpcUaGdsClient::certificateUpdateRequired); + QSignalSpy certificateUpdatedSpy(&gc, &QOpcUaGdsClient::certificateUpdated); + QSignalSpy trustListUpdatedSpy(&gc, &QOpcUaGdsClient::trustListUpdated); + + gc.start(); + + QVERIFY(certificateGroupsSpy.wait()); + QVERIFY(!certificateGroupsSpy.at(0).at(0).value<QStringList>().isEmpty()); + QVERIFY(registeredSpy.wait()); + + if (certificateStatusSpy.isEmpty()) + certificateStatusSpy.wait(); + + if (certificateUpdatedSpy.isEmpty()) + certificateUpdatedSpy.wait(); + + if (trustListUpdatedSpy.isEmpty()) + trustListUpdatedSpy.wait(); + + QVERIFY(!certificateStatusSpy.isEmpty()); + QVERIFY(!certificateUpdatedSpy.isEmpty()); + QVERIFY(!trustListUpdatedSpy.isEmpty()); +} + +void Tst_QOpcUaGds::reuseApplicationId() +{ + QFETCH(QString, backend); + if (backend == "open62541") + QSKIP("Skipping open62541"); + + // Keep settings file in order to reuse the existing registration + + QOpcUaGdsClient gc; + commonGdsClientSetup(gc, backend, m_endpoint); + + QSignalSpy registeredSpy(&gc, &QOpcUaGdsClient::applicationRegistered); + QSignalSpy certificateGroupsSpy(&gc, &QOpcUaGdsClient::certificateGroupsReceived); + + gc.start(); + + QVERIFY(certificateGroupsSpy.wait()); + QVERIFY(!certificateGroupsSpy.at(0).at(0).value<QStringList>().isEmpty()); + QVERIFY(registeredSpy.wait()); +} + +void Tst_QOpcUaGds::reuseRegisteredUri() +{ + // This test assumes that a registratin at the server is still present. + // It will remove the information locally and has to reuse the + // registration from the server. + + QFETCH(QString, backend); + if (backend == "open62541") + QSKIP("Skipping open62541"); + + // Remove the registration data locally; the server will keep it. + QSettings settings("Unknown Organization", "tst_gds"); + + QString applicationId = settings.value(QLatin1String("gds/applicationId")).toString(); + settings.remove(QLatin1String("gds/applicationId")); + settings.sync(); + + QVERIFY(removeSettingsFile()); + + QOpcUaGdsClient gc; + commonGdsClientSetup(gc, backend, m_endpoint); + + QSignalSpy registeredSpy(&gc, &QOpcUaGdsClient::applicationRegistered); + QSignalSpy certificateGroupsSpy(&gc, &QOpcUaGdsClient::certificateGroupsReceived); + + gc.start(); + + QVERIFY(certificateGroupsSpy.wait()); + QVERIFY(!certificateGroupsSpy.at(0).at(0).value<QStringList>().isEmpty()); + QVERIFY(registeredSpy.wait()); + QVERIFY(gc.applicationId().size() > 10); + if (!applicationId.isEmpty()) + QVERIFY(gc.applicationId() == applicationId); +} + +void Tst_QOpcUaGds::serverForgotRegistration() +{ + QFETCH(QString, backend); + if (backend == "open62541") + QSKIP("Skipping open62541"); + + // Setting an invalid application ID simulates a previous registration which has been + // forgotten by the server + QSettings settings("Unknown Organization", "tst_gds"); + settings.setValue(QLatin1String("gds/applicationId"), "ns=42;i=1111111"); + settings.sync(); + + QOpcUaGdsClient gc; + commonGdsClientSetup(gc, backend, m_endpoint); + + QSignalSpy registeredSpy(&gc, &QOpcUaGdsClient::applicationRegistered); + QSignalSpy certificateGroupsSpy(&gc, &QOpcUaGdsClient::certificateGroupsReceived); + + gc.start(); + + QVERIFY(certificateGroupsSpy.wait()); + QVERIFY(!certificateGroupsSpy.at(0).at(0).value<QStringList>().isEmpty()); + QVERIFY(registeredSpy.wait()); +} + +void Tst_QOpcUaGds::cleanupTestCase() +{ +} + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + QTEST_SET_MAIN_SOURCE_PATH + + if (QOpcUaProvider::availableBackends().empty()) { + qDebug("No OPCUA backends found, skipping tests."); + return EXIT_SUCCESS; + } + + Tst_QOpcUaGds tc; + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_gds.moc" diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index 3ee3e86..6007738 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -1,3 +1,6 @@ TEMPLATE = subdirs SUBDIRS += eventsubscription + +QT_FOR_CONFIG += opcua-private core-private +qtConfig(ssl):!darwin:!winrt: SUBDIRS += gds diff --git a/tests/tests.pro b/tests/tests.pro index e7b0667..5719b55 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -1,6 +1,5 @@ TEMPLATE = subdirs -SUBDIRS += auto \ - manual +SUBDIRS += auto QT_FOR_CONFIG += opcua-private |