/* ======================================================================== * Copyright (c) 2005-2019 The OPC Foundation, Inc. All rights reserved. * * OPC Foundation MIT License 1.00 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * The complete license agreement can be found here: * http://opcfoundation.org/License/MIT/1.00/ * ======================================================================*/ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography.X509Certificates; using System.Threading; using NUnit.Framework; using Opc.Ua; using Opc.Ua.Gds; using Opc.Ua.Gds.Test; namespace NUnit.Opc.Ua.Gds.Test { /// /// Test GDS Registration and Client Pull. /// [TestFixture, Category("GDSRegistrationAndPull")] public class ClientTest { #region Test Setup /// /// Set up a Global Discovery Server and Client instance and connect the session /// [OneTimeSetUp] protected void OneTimeSetUp() { // work around travis issue by selecting different ports on every run int testPort = 50000 + (((Int32)DateTime.UtcNow.ToFileTimeUtc() / 10000) & 0x1fff); _server = new GlobalDiscoveryTestServer(true); _server.StartServer(true, testPort).Wait(); // load client _gdsClient = new GlobalDiscoveryTestClient(true); _gdsClient.LoadClientConfiguration(testPort).Wait(); // good applications test set _appTestDataGenerator = new ApplicationTestDataGenerator(1); _goodApplicationTestSet = _appTestDataGenerator.ApplicationTestSet(goodApplicationsTestCount, false); _invalidApplicationTestSet = _appTestDataGenerator.ApplicationTestSet(invalidApplicationsTestCount, true); _goodRegistrationOk = false; _invalidRegistrationOk = false; _goodNewKeyPairRequestOk = false; } /// /// Tear down the Global Discovery Server and disconnect the Client /// [OneTimeTearDown] protected void OneTimeTearDown() { _gdsClient.DisconnectClient(); _gdsClient = null; _server.StopServer(); _server = null; Thread.Sleep(1000); } [TearDown] protected void TearDown() { DisconnectGDS(); } #endregion #region Test Methods /// /// Clean the app database from application Uri used during test. /// [Test, Order(10)] public void CleanGoodApplications() { ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { var applicationDataRecords = _gdsClient.GDSClient.FindApplication(application.ApplicationRecord.ApplicationUri); if (applicationDataRecords != null) { foreach (var applicationDataRecord in applicationDataRecords) { _gdsClient.GDSClient.UnregisterApplication(applicationDataRecord.ApplicationId); } } } } /// /// Register the good applications in the database. /// [Test, Order(100)] public void RegisterGoodApplications() { ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { NodeId id = _gdsClient.GDSClient.RegisterApplication(application.ApplicationRecord); Assert.NotNull(id); Assert.IsFalse(id.IsNullNodeId); Assert.That(id.IdType == IdType.Guid || id.IdType == IdType.String); application.ApplicationRecord.ApplicationId = id; } _goodRegistrationOk = true; } [Test, Order(105)] public void RegisterDuplicateGoodApplications() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { ApplicationRecordDataType newRecord = (ApplicationRecordDataType)application.ApplicationRecord.MemberwiseClone(); newRecord.ApplicationId = null; NodeId id = _gdsClient.GDSClient.RegisterApplication(newRecord); Assert.NotNull(id); Assert.IsFalse(id.IsNullNodeId); Assert.That(id.IdType == IdType.Guid || id.IdType == IdType.String); newRecord.ApplicationId = id; var applicationDataRecords = _gdsClient.GDSClient.FindApplication(newRecord.ApplicationUri); Assert.NotNull(applicationDataRecords); bool newIdFound = false; bool registeredIdFound = false; foreach (var applicationDataRecord in applicationDataRecords) { if (applicationDataRecord.ApplicationId == newRecord.ApplicationId) { _gdsClient.GDSClient.UnregisterApplication(id); newIdFound = true; } else if (applicationDataRecord.ApplicationId == application.ApplicationRecord.ApplicationId) { registeredIdFound = true; } } Assert.IsTrue(newIdFound); Assert.IsTrue(registeredIdFound); } } [Test, Order(110)] public void RegisterInvalidApplications() { ConnectGDS(true); foreach (var application in _invalidApplicationTestSet) { Assert.That(() => { NodeId id = _gdsClient.GDSClient.RegisterApplication(application.ApplicationRecord); }, Throws.Exception); } _invalidRegistrationOk = true; } [Test, Order(120)] public void RegisterApplicationAsUser() { AssertIgnoreTestWithoutInvalidRegistration(); ConnectGDS(false); foreach (var application in _invalidApplicationTestSet) { Assert.That(() => { NodeId id = _gdsClient.GDSClient.RegisterApplication(application.ApplicationRecord); }, Throws.Exception); } } [Test, Order(200)] public void UpdateGoodApplications() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { var updatedApplicationRecord = (ApplicationRecordDataType)application.ApplicationRecord.MemberwiseClone(); updatedApplicationRecord.ApplicationUri += "update"; _gdsClient.GDSClient.UpdateApplication(updatedApplicationRecord); var result = _gdsClient.GDSClient.FindApplication(updatedApplicationRecord.ApplicationUri); _gdsClient.GDSClient.UpdateApplication(application.ApplicationRecord); Assert.NotNull(result); Assert.GreaterOrEqual(1, result.Length, "Couldn't find updated application record"); } } [Test, Order(210)] public void UpdateGoodApplicationsWithNewGuid() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { var testApplicationRecord = (ApplicationRecordDataType)application.ApplicationRecord.MemberwiseClone(); testApplicationRecord.ApplicationId = new NodeId(Guid.NewGuid()); Assert.That(() => { _gdsClient.GDSClient.UpdateApplication(testApplicationRecord); }, Throws.Exception); } } [Test, Order(210)] public void UpdateGoodApplicationsWithNewString() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { var testApplicationRecord = (ApplicationRecordDataType)application.ApplicationRecord.MemberwiseClone(); testApplicationRecord.ApplicationId = new NodeId(_appTestDataGenerator.DataGenerator.GetRandomString("en")); Assert.That(() => { _gdsClient.GDSClient.UpdateApplication(testApplicationRecord); }, Throws.Exception); } } [Test, Order(220)] public void UpdateInvalidApplications() { AssertIgnoreTestWithoutInvalidRegistration(); ConnectGDS(true); foreach (var application in _invalidApplicationTestSet) { Assert.That(() => { _gdsClient.GDSClient.UpdateApplication(application.ApplicationRecord); }, Throws.Exception); } } [Test, Order(400)] public void FindGoodApplications() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(false); foreach (var application in _goodApplicationTestSet) { var result = _gdsClient.GDSClient.FindApplication(application.ApplicationRecord.ApplicationUri); Assert.NotNull(result); Assert.GreaterOrEqual(result.Length, 1, "Couldn't find good application"); } } [Test, Order(400)] public void FindInvalidApplications() { AssertIgnoreTestWithoutInvalidRegistration(); ConnectGDS(true); foreach (var application in _invalidApplicationTestSet) { var result = _gdsClient.GDSClient.FindApplication(application.ApplicationRecord.ApplicationUri); if (result != null) { Assert.NotNull(result); Assert.AreEqual(0, result.Length, "Found invalid application on server"); } } } [Test, Order(400)] public void GetGoodApplications() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(false); foreach (var application in _goodApplicationTestSet) { var result = _gdsClient.GDSClient.GetApplication(application.ApplicationRecord.ApplicationId); Assert.NotNull(result); result.ServerCapabilities.Sort(); application.ApplicationRecord.ServerCapabilities.Sort(); Assert.IsTrue(Utils.IsEqual(application.ApplicationRecord, result)); } } [Test, Order(401)] public void GetGoodApplicationsTestApplicationId() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(false); foreach (var application in _goodApplicationTestSet) { var result = _gdsClient.GDSClient.GetApplication(application.ApplicationRecord.ApplicationId); Assert.NotNull(result); Assert.IsTrue(Utils.IsEqual(application.ApplicationRecord.ApplicationId, result.ApplicationId)); } } [Test, Order(401)] public void GetGoodApplicationsTestApplicationNames() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(false); foreach (var application in _goodApplicationTestSet) { var result = _gdsClient.GDSClient.GetApplication(application.ApplicationRecord.ApplicationId); Assert.NotNull(result); Assert.IsTrue(Utils.IsEqual(application.ApplicationRecord.ApplicationNames, result.ApplicationNames)); } } [Test, Order(401)] public void GetGoodApplicationsTestApplicationType() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(false); foreach (var application in _goodApplicationTestSet) { var result = _gdsClient.GDSClient.GetApplication(application.ApplicationRecord.ApplicationId); Assert.NotNull(result); Assert.IsTrue(Utils.IsEqual(application.ApplicationRecord.ApplicationType, result.ApplicationType)); } } [Test, Order(401)] public void GetGoodApplicationsTestApplicationUri() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(false); foreach (var application in _goodApplicationTestSet) { var result = _gdsClient.GDSClient.GetApplication(application.ApplicationRecord.ApplicationId); Assert.NotNull(result); Assert.IsTrue(Utils.IsEqual(application.ApplicationRecord.ApplicationUri, result.ApplicationUri)); } } [Test, Order(401)] public void GetGoodApplicationsTestDiscoveryUrls() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(false); foreach (var application in _goodApplicationTestSet) { var result = _gdsClient.GDSClient.GetApplication(application.ApplicationRecord.ApplicationId); Assert.NotNull(result); Assert.IsTrue(Utils.IsEqual(application.ApplicationRecord.DiscoveryUrls, result.DiscoveryUrls)); } } [Test, Order(401)] public void GetGoodApplicationsTestProductUri() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(false); foreach (var application in _goodApplicationTestSet) { var result = _gdsClient.GDSClient.GetApplication(application.ApplicationRecord.ApplicationId); Assert.NotNull(result); Assert.IsTrue(Utils.IsEqual(application.ApplicationRecord.ProductUri, result.ProductUri)); } } [Test, Order(401)] public void GetGoodApplicationsTestServerCapabilities() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(false); foreach (var application in _goodApplicationTestSet) { var result = _gdsClient.GDSClient.GetApplication(application.ApplicationRecord.ApplicationId); Assert.NotNull(result); result.ServerCapabilities.Sort(); application.ApplicationRecord.ServerCapabilities.Sort(); Assert.IsTrue(Utils.IsEqual(application.ApplicationRecord.ServerCapabilities, result.ServerCapabilities)); } } [Test, Order(400)] public void GetInvalidApplications() { AssertIgnoreTestWithoutInvalidRegistration(); ConnectGDS(true); foreach (var application in _invalidApplicationTestSet) { Assert.That(() => { var result = _gdsClient.GDSClient.GetApplication(application.ApplicationRecord.ApplicationId); }, Throws.Exception); } } [Test, Order(410)] public void QueryAllServers() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(false); // get all servers var allServers = _gdsClient.GDSClient.QueryServers(0, "", "", "", new List()); int totalCount = 0; uint firstID = uint.MaxValue, lastID = 0; Assert.IsNotNull(allServers); foreach (var server in allServers) { var oneServers = _gdsClient.GDSClient.QueryServers(server.RecordId, 1, "", "", "", new List()); Assert.IsNotNull(oneServers); Assert.GreaterOrEqual(oneServers.Count, 1); foreach (var oneServer in oneServers) { Assert.AreEqual(oneServer.RecordId, server.RecordId); } firstID = Math.Min(firstID, server.RecordId); lastID = Math.Max(lastID, server.RecordId); totalCount++; } Assert.GreaterOrEqual(totalCount, goodApplicationsTestCount); Assert.AreEqual(totalCount, allServers.Count); Assert.GreaterOrEqual(lastID, firstID); Assert.GreaterOrEqual(lastID, 1); Assert.GreaterOrEqual(firstID, 1); } [Test, Order(411)] public void QueryAllServersNull() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(false); // get all servers var allServers = _gdsClient.GDSClient.QueryServers(0, null, null, null, null); int totalCount = 0; uint firstID = uint.MaxValue, lastID = 0; Assert.IsNotNull(allServers); foreach (var server in allServers) { var oneServers = _gdsClient.GDSClient.QueryServers(server.RecordId, 1, null, null, null, null); Assert.IsNotNull(oneServers); Assert.GreaterOrEqual(oneServers.Count, 1); foreach (var oneServer in oneServers) { Assert.AreEqual(oneServer.RecordId, server.RecordId); } firstID = Math.Min(firstID, server.RecordId); lastID = Math.Max(lastID, server.RecordId); totalCount++; } Assert.GreaterOrEqual(totalCount, goodApplicationsTestCount); Assert.AreEqual(totalCount, allServers.Count); Assert.GreaterOrEqual(lastID, firstID); Assert.GreaterOrEqual(lastID, 1); Assert.GreaterOrEqual(firstID, 1); } [Test, Order(420)] public void QueryGoodServersBatches() { // repeating queries to get all servers uint nextID = 0; uint iterationCount = Math.Min(10, (uint)(goodApplicationsTestCount / 2)); int serversOnNetwork = 0; int goodServersOnNetwork = GoodServersOnNetworkCount(); while (true) { var iterServers = _gdsClient.GDSClient.QueryServers(nextID, iterationCount, "", "", "", null); Assert.IsNotNull(iterServers); serversOnNetwork += iterServers.Count; if (iterServers.Count == 0) { break; } uint previousID = nextID; nextID = iterServers[iterServers.Count - 1].RecordId + 1; Assert.Greater(nextID, previousID); } Assert.GreaterOrEqual(serversOnNetwork, goodServersOnNetwork); } [Test, Order(430)] public void QueryServersByName() { // search aplications by name const int searchPatternLength = 5; foreach (var application in _goodApplicationTestSet) { var atLeastOneServer = _gdsClient.GDSClient.QueryServers(1, application.ApplicationRecord.ApplicationNames[0].Text, "", "", null); Assert.IsNotNull(atLeastOneServer); if (application.ApplicationRecord.ApplicationType != ApplicationType.Client) { Assert.GreaterOrEqual(atLeastOneServer.Count, 1); } else { Assert.AreEqual(atLeastOneServer.Count, 0); } string searchName = application.ApplicationRecord.ApplicationNames[0].Text.Trim(); if (searchName.Length > searchPatternLength) { searchName = searchName.Substring(0, searchPatternLength) + "%"; } atLeastOneServer = _gdsClient.GDSClient.QueryServers(1, searchName, "", "", null); Assert.IsNotNull(atLeastOneServer); if (application.ApplicationRecord.ApplicationType != ApplicationType.Client) { Assert.GreaterOrEqual(atLeastOneServer.Count, 1); } } } [Test, Order(440)] public void QueryServersByAppUri() { // search aplications by name const int searchPatternLength = 5; foreach (var application in _goodApplicationTestSet) { var atLeastOneServer = _gdsClient.GDSClient.QueryServers(1, null, application.ApplicationRecord.ApplicationUri, null, null); Assert.IsNotNull(atLeastOneServer); if (application.ApplicationRecord.ApplicationType != ApplicationType.Client) { Assert.GreaterOrEqual(atLeastOneServer.Count, 1); } else { Assert.AreEqual(atLeastOneServer.Count, 0); } string searchName = application.ApplicationRecord.ApplicationUri; if (searchName.Length > searchPatternLength) { searchName = searchName.Substring(0, searchPatternLength) + "%"; } atLeastOneServer = _gdsClient.GDSClient.QueryServers(1, null, searchName, null, null); Assert.IsNotNull(atLeastOneServer); if (application.ApplicationRecord.ApplicationType != ApplicationType.Client) { Assert.GreaterOrEqual(atLeastOneServer.Count, 1); } } } [Test, Order(450)] public void QueryServersByProductUri() { // search aplications by name const int searchPatternLength = 5; foreach (var application in _goodApplicationTestSet) { var atLeastOneServer = _gdsClient.GDSClient.QueryServers(1, null, null, application.ApplicationRecord.ProductUri, null); Assert.IsNotNull(atLeastOneServer); if (application.ApplicationRecord.ApplicationType != ApplicationType.Client) { Assert.GreaterOrEqual(atLeastOneServer.Count, 1); } else { Assert.AreEqual(atLeastOneServer.Count, 0); } string searchName = application.ApplicationRecord.ProductUri; if (searchName.Length > searchPatternLength) { searchName = searchName.Substring(0, searchPatternLength) + "%"; } atLeastOneServer = _gdsClient.GDSClient.QueryServers(1, null, null, searchName, null); Assert.IsNotNull(atLeastOneServer); if (application.ApplicationRecord.ApplicationType != ApplicationType.Client) { Assert.GreaterOrEqual(atLeastOneServer.Count, 1); } } } [Test, Order(480)] public void QueryAllApplications() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(false); // get all applications DateTime lastResetCounterTime; uint nextRecordId; var allApplications = _gdsClient.GDSClient.QueryApplications(0, 0, "", "", 0, "", new List(), out lastResetCounterTime, out nextRecordId); int totalCount = 0; Assert.IsNotNull(allApplications); nextRecordId = 0; foreach (var application in allApplications) { var oneApplication = _gdsClient.GDSClient.QueryApplications(nextRecordId, 1, "", "", 0, "", new List(), out lastResetCounterTime, out nextRecordId); Assert.IsNotNull(oneApplication); Assert.GreaterOrEqual(oneApplication.Count, 1); foreach (var oneApp in oneApplication) { //Assert.AreEqual(oneApp., server.RecordId); } totalCount++; } Assert.GreaterOrEqual(totalCount, goodApplicationsTestCount); Assert.AreEqual(totalCount, allApplications.Count); } [Test, Order(500)] public void StartGoodNewKeyPairRequests() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { Assert.Null(application.CertificateRequestId); NodeId requestId = _gdsClient.GDSClient.StartNewKeyPairRequest( application.ApplicationRecord.ApplicationId, application.CertificateGroupId, application.CertificateTypeId, application.Subject, application.DomainNames, application.PrivateKeyFormat, application.PrivateKeyPassword); Assert.NotNull(requestId); application.CertificateRequestId = requestId; } _goodNewKeyPairRequestOk = true; } [Test, Order(501)] public void StartInvalidNewKeyPairRequests() { AssertIgnoreTestWithoutInvalidRegistration(); ConnectGDS(true); foreach (var application in _invalidApplicationTestSet) { Assert.Null(application.CertificateRequestId); Assert.That(() => { NodeId requestId = _gdsClient.GDSClient.StartNewKeyPairRequest( application.ApplicationRecord.ApplicationId, application.CertificateGroupId, application.CertificateTypeId, application.Subject, application.DomainNames, application.PrivateKeyFormat, application.PrivateKeyPassword); }, Throws.Exception); } } [Test, Order(510)] public void FinishGoodNewKeyPairRequests() { AssertIgnoreTestWithoutGoodRegistration(); AssertIgnoreTestWithoutGoodNewKeyPairRequest(); ConnectGDS(true); bool requestBusy; DateTime now = DateTime.UtcNow; do { requestBusy = false; foreach (var application in _goodApplicationTestSet) { if (application.CertificateRequestId != null) { try { byte[] certificate = _gdsClient.GDSClient.FinishRequest( application.ApplicationRecord.ApplicationId, application.CertificateRequestId, out byte[] privateKey, out byte[][] issuerCertificates ); if (certificate != null) { application.CertificateRequestId = null; Assert.NotNull(certificate); Assert.NotNull(privateKey); Assert.NotNull(issuerCertificates); application.Certificate = certificate; application.PrivateKey = privateKey; application.IssuerCertificates = issuerCertificates; X509TestUtils.VerifySignedApplicationCert(application, certificate, issuerCertificates); X509TestUtils.VerifyApplicationCertIntegrity(certificate, privateKey, application.PrivateKeyPassword, application.PrivateKeyFormat, issuerCertificates); } else { requestBusy = true; } } catch (ServiceResultException sre) { if (sre.StatusCode == StatusCodes.BadNothingToDo && now.AddMinutes(5) > DateTime.UtcNow) { requestBusy = true; Thread.Sleep(1000); } else { throw sre; } } } } if (requestBusy) { Thread.Sleep(5000); Console.WriteLine("Waiting for certificate approval"); } } while (requestBusy); } [Test, Order(511)] public void FinishInvalidNewKeyPairRequests() { AssertIgnoreTestWithoutInvalidRegistration(); ConnectGDS(true); foreach (var application in _invalidApplicationTestSet) { Assert.That(() => { byte[] certificate = _gdsClient.GDSClient.FinishRequest( application.ApplicationRecord.ApplicationId, new NodeId(Guid.NewGuid()), out byte[] privateKey, out byte[][] issuerCertificates ); }, Throws.Exception); } } [Test, Order(520)] public void StartGoodSigningRequests() { AssertIgnoreTestWithoutGoodRegistration(); AssertIgnoreTestWithoutGoodNewKeyPairRequest(); ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { Assert.Null(application.CertificateRequestId); X509Certificate2 csrCertificate; if (application.PrivateKeyFormat == "PFX") { csrCertificate = CertificateFactory.CreateCertificateFromPKCS12(application.PrivateKey, application.PrivateKeyPassword); } else { csrCertificate = CertificateFactory.CreateCertificateWithPEMPrivateKey(new X509Certificate2(application.Certificate), application.PrivateKey, application.PrivateKeyPassword); } byte[] certificateRequest = CertificateFactory.CreateSigningRequest(csrCertificate, application.DomainNames); csrCertificate.Dispose(); NodeId requestId = _gdsClient.GDSClient.StartSigningRequest( application.ApplicationRecord.ApplicationId, application.CertificateGroupId, application.CertificateTypeId, certificateRequest); Assert.NotNull(requestId); application.CertificateRequestId = requestId; } } [Test, Order(530)] public void FinishGoodSigningRequests() { AssertIgnoreTestWithoutGoodRegistration(); AssertIgnoreTestWithoutGoodNewKeyPairRequest(); ConnectGDS(true); bool requestBusy; DateTime now = DateTime.UtcNow; do { requestBusy = false; foreach (var application in _goodApplicationTestSet) { if (application.CertificateRequestId != null) { try { var certificate = _gdsClient.GDSClient.FinishRequest( application.ApplicationRecord.ApplicationId, application.CertificateRequestId, out byte[] privateKey, out byte[][] issuerCertificates ); if (certificate != null) { application.CertificateRequestId = null; Assert.Null(privateKey); Assert.NotNull(issuerCertificates); application.Certificate = certificate; application.IssuerCertificates = issuerCertificates; X509TestUtils.VerifySignedApplicationCert(application, certificate, issuerCertificates); X509TestUtils.VerifyApplicationCertIntegrity(certificate, application.PrivateKey, application.PrivateKeyPassword, application.PrivateKeyFormat, issuerCertificates); } else { requestBusy = true; } } catch (ServiceResultException sre) { if (sre.StatusCode == StatusCodes.BadNothingToDo && now.AddMinutes(5) > DateTime.UtcNow) { requestBusy = true; Thread.Sleep(1000); } else { throw sre; } } } } if (requestBusy) { Thread.Sleep(5000); Console.WriteLine("Waiting for certificate approval"); } } while (requestBusy); } [Test, Order(550)] public void StartGoodSigningRequestWithInvalidAppURI() { AssertIgnoreTestWithoutGoodRegistration(); AssertIgnoreTestWithoutGoodNewKeyPairRequest(); ConnectGDS(true); var application = _goodApplicationTestSet[0]; Assert.Null(application.CertificateRequestId); // load csr with invalid app URI byte[] certificateRequest = File.ReadAllBytes("test.csr"); Assert.That(() => { NodeId requestId = _gdsClient.GDSClient.StartSigningRequest( application.ApplicationRecord.ApplicationId, application.CertificateGroupId, application.CertificateTypeId, certificateRequest); }, Throws.Exception); } [Test, Order(600)] public void GetGoodCertificateGroupsNullTests() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(true); Assert.That(() => { _gdsClient.GDSClient.GetCertificateGroups(null); }, Throws.Exception); foreach (var application in _goodApplicationTestSet) { var trustListId = _gdsClient.GDSClient.GetTrustList(application.ApplicationRecord.ApplicationId, null); var trustList = _gdsClient.GDSClient.ReadTrustList(trustListId); Assert.That(() => { _gdsClient.GDSClient.ReadTrustList(null); }, Throws.Exception); var certificateGroups = _gdsClient.GDSClient.GetCertificateGroups(application.ApplicationRecord.ApplicationId); foreach (var certificateGroup in certificateGroups) { Assert.That(() => { _gdsClient.GDSClient.GetTrustList(null, certificateGroup); }, Throws.Exception); } } } [Test, Order(601)] public void GetInvalidCertificateGroupsNullTests() { AssertIgnoreTestWithoutInvalidRegistration(); ConnectGDS(true); Assert.That(() => { _gdsClient.GDSClient.GetCertificateGroups(null); }, Throws.Exception); Assert.That(() => { _gdsClient.GDSClient.GetCertificateGroups(new NodeId(Guid.NewGuid())); }, Throws.Exception); foreach (var application in _invalidApplicationTestSet) { Assert.That(() => { var trustListId = _gdsClient.GDSClient.GetTrustList(application.ApplicationRecord.ApplicationId, null); }, Throws.Exception); Assert.That(() => { var trustListId = _gdsClient.GDSClient.GetTrustList(application.ApplicationRecord.ApplicationId, new NodeId(Guid.NewGuid())); }, Throws.Exception); Assert.That(() => { var certificateGroups = _gdsClient.GDSClient.GetCertificateGroups(application.ApplicationRecord.ApplicationId); }, Throws.Exception); } } [Test, Order(610)] public void GetGoodCertificateGroupsAndTrustLists() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { var certificateGroups = _gdsClient.GDSClient.GetCertificateGroups(application.ApplicationRecord.ApplicationId); foreach (var certificateGroup in certificateGroups) { var trustListId = _gdsClient.GDSClient.GetTrustList(application.ApplicationRecord.ApplicationId, certificateGroup); // Opc.Ua.TrustListDataType var trustList = _gdsClient.GDSClient.ReadTrustList(trustListId); } } } [Test, Order(690)] public void GetGoodCertificateStatus() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { var certificateStatus = _gdsClient.GDSClient.GetCertificateStatus(application.ApplicationRecord.ApplicationId, null, null); } } [Test, Order(691)] public void GetInvalidCertificateStatus() { AssertIgnoreTestWithoutInvalidRegistration(); ConnectGDS(true); foreach (var application in _invalidApplicationTestSet) { Assert.That(() => { var certificateStatus = _gdsClient.GDSClient.GetCertificateStatus(application.ApplicationRecord.ApplicationId, null, null); }, Throws.Exception); } } [Test, Order(900)] public void UnregisterGoodApplications() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { _gdsClient.GDSClient.UnregisterApplication(application.ApplicationRecord.ApplicationId); } } [Test, Order(910)] public void UnregisterInvalidApplications() { ConnectGDS(true); foreach (var application in _invalidApplicationTestSet) { Assert.That(() => { _gdsClient.GDSClient.UnregisterApplication(application.ApplicationRecord.ApplicationId); }, Throws.Exception); } } [Test, Order(915)] public void VerifyUnregisterGoodApplications() { AssertIgnoreTestWithoutGoodRegistration(); ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { var result = _gdsClient.GDSClient.FindApplication(application.ApplicationRecord.ApplicationUri); if (result != null) { Assert.NotNull(result); Assert.AreEqual(0, result.Length, "Found deleted application on server!"); } } } [Test, Order(920)] public void UnregisterUnregisteredGoodApplications() { ConnectGDS(true); foreach (var application in _goodApplicationTestSet) { Assert.That(() => { _gdsClient.GDSClient.UnregisterApplication(application.ApplicationRecord.ApplicationId); }, Throws.Exception); } } #endregion #region Private Methods private void ConnectGDS(bool admin) { _gdsClient.GDSClient.AdminCredentials = admin ? _gdsClient.AdminUser : _gdsClient.AppUser; _gdsClient.GDSClient.Connect(_gdsClient.GDSClient.EndpointUrl).Wait(); } private void DisconnectGDS() { _gdsClient.GDSClient.Disconnect(); } private void AssertIgnoreTestWithoutGoodRegistration() { if (!_goodRegistrationOk) { Assert.Ignore("Test requires good application registrations."); } } private void AssertIgnoreTestWithoutInvalidRegistration() { if (!_invalidRegistrationOk) { Assert.Ignore("Test requires invalid application registration."); } } private void AssertIgnoreTestWithoutGoodNewKeyPairRequest() { if (!_goodNewKeyPairRequestOk) { Assert.Ignore("Test requires good new key pair request."); } } private int GoodServersOnNetworkCount() { return _goodApplicationTestSet.Sum(a => a.ApplicationRecord.DiscoveryUrls.Count); } #endregion #region Private Fields private const int goodApplicationsTestCount = 10; private const int invalidApplicationsTestCount = 10; private const int randomStart = 1; private ApplicationTestDataGenerator _appTestDataGenerator; private GlobalDiscoveryTestServer _server; private GlobalDiscoveryTestClient _gdsClient; private IList _goodApplicationTestSet; private IList _invalidApplicationTestSet; private bool _goodRegistrationOk; private bool _invalidRegistrationOk; private bool _goodNewKeyPairRequestOk; #endregion } }