From 622c1c4ce997f18bd8dccd27524348145c3488a9 Mon Sep 17 00:00:00 2001 From: mvxxx Date: Fri, 23 Apr 2021 15:01:25 +0100 Subject: [PATCH 1/7] Added getting build version from config files --- .../ExecutionContext/BaseExecutionContext.cs | 162 +++++++++++++++++- 1 file changed, 160 insertions(+), 2 deletions(-) diff --git a/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs b/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs index 89e680a1f..8357a4400 100644 --- a/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs +++ b/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs @@ -2,10 +2,15 @@ // Licensed under the MIT license. using System; +using System.Collections.Generic; using System.Diagnostics; +using System.IO; +using System.Linq; using System.Net; using System.Net.Sockets; using System.Reflection; +using System.Text.RegularExpressions; +using System.Xml.Linq; using Microsoft.Extensions.Hosting; namespace Microsoft.Omex.Extensions.Abstractions.ExecutionContext @@ -28,6 +33,7 @@ public class BaseExecutionContext : IExecutionContext internal const string ApplicationNameVariableName = "Fabric_ApplicationName"; internal const string NodeNameVariableName = "Fabric_NodeName"; internal const string NodeIPOrFQDNVariableName = "Fabric_NodeIPOrFQDN"; + internal const string FarbicFolderApplication = "Fabric_Folder_Application"; /// /// Create instance of execution context @@ -36,10 +42,10 @@ public class BaseExecutionContext : IExecutionContext public BaseExecutionContext(IHostEnvironment? hostEnvironment = null) { MachineName = GetMachineName(); - BuildVersion = GetBuildVersion(); + BuildVersion = GetBuildVersionFromServiceManifest() ?? DefaultEmptyValue; ClusterIpAddress = GetIpAddress(MachineName); - + RegionName = GetVariable(RegionNameVariableName) ?? DefaultEmptyValue; DeploymentSlice = GetVariable(SliceNameVariableName) ?? DefaultEmptyValue; @@ -137,6 +143,158 @@ protected static string GetBuildVersion() : DefaultEmptyValue; } + /// + /// Get build version from the current running service's manifest file + /// + /// Service manifest name defined in ApplicationManifest.xml + /// + public static string? GetBuildVersionFromServiceManifest(string serviceManifestName) + { + string? serviceManifestPath = GetServiceManifestPath(serviceManifestName); + if (serviceManifestPath == null) + { + return null; + } + + return XElement.Load(serviceManifestPath).Attribute("Version")?.Value; + } + + /// + /// Get build version from the current running service's manifest file + /// + /// + public static string? GetBuildVersionFromServiceManifest() + { + string? applicationDir = GetVariable(FarbicFolderApplication); + string? serviceName = GetVariable(ServiceNameVariableName); + string? applicationManifest = GetApplicationManifestPath(); + + if (applicationDir == null || serviceName == null || applicationManifest == null) + { + return null; + } + + // Firstly we load all entries from Application Manifest + IEnumerable descendants = XDocument + .Load(applicationManifest) + .Descendants(); + + // Query all service specific manifest names + IEnumerable manifestNames = descendants + .Where(entry => entry.Name.LocalName == "ServiceManifestRef") + .Select(entry => entry.Attribute("ServiceManifestName")?.Value) + .Where(entry => entry != null) + .Select(entry => entry!); // we know at this point that there are not nulls. + + // Query all services and corresponding types from Application Manifest + IEnumerable<(string serviceName, string serviceTypeName)> serviceMetaInfo = QueryServicesNamesWithTypes(descendants); + + // Query all service types and corresponding build versions from service manifest files + IEnumerable<(string serviceTypeName, string buildVersion)> manifestMetaInfo = QueryServicesTypesWithVersion(manifestNames); + + // Match our service with corresponding build version + try + { + string targetServiceType = serviceMetaInfo.Single(entry => entry.serviceName == serviceName.Split('/').Last()) + .serviceTypeName; + return manifestMetaInfo.Single(entry => entry.serviceTypeName == targetServiceType).buildVersion; + } + catch (Exception) + { + // Target service not found + return null; + } + } + + internal static IEnumerable<(string serviceTypeName, string buildVersion)> QueryServicesTypesWithVersion(IEnumerable manifestNames) + { + return manifestNames + .Select(manifestFilename => + { + string? manifestFilePath = GetServiceManifestPath(manifestFilename); + if (manifestFilePath == null) + { + return (serviceTypeName: null, buildVersion: null); + } + + IEnumerable manifestDescendants = XDocument.Load(manifestFilePath).Descendants(); + IEnumerable serviceManifestEntries = manifestDescendants + .Where(entry => entry.Name.LocalName == "ServiceManifest"); + + if (serviceManifestEntries.Count() != 1) + { + return (serviceTypeName: null, buildVersion: null); + } + + string? buildVersion = serviceManifestEntries.Single().Attribute("Version")?.Value; + + IEnumerable serviceTypeNames = manifestDescendants + .Where(entry => entry.Name.LocalName is "StatelessServiceType" or "StatefulServiceType") + .Select(entry => entry.Attribute("ServiceTypeName")?.Value); + + if (serviceTypeNames.Count() != 1) + { + return (serviceTypeName: null, buildVersion: null); + } + + return (serviceTypeName: serviceTypeNames.Single(), buildVersion); + }) + .Where(entry => entry.serviceTypeName != null && entry.buildVersion != null) + .Select(entry => (serviceTypeName: entry.serviceTypeName!, buildVersion: entry.buildVersion!)); + } + + internal static IEnumerable<(string serviceName, string serviceTypeName)> QueryServicesNamesWithTypes(IEnumerable descendants) + { + return descendants + .Where(entry => entry.Name.LocalName == "Service") + .Select(entry => + { + string? serviceName = entry.Attribute("Name")?.Value; + IEnumerable serviceDescendants = entry + .Descendants().Where(entry => entry.Name.LocalName is "StatelessService" or "StatefulService"); + + if (serviceDescendants.Count() != 1) + { + return (null, null); + } + XElement head = serviceDescendants.Single(); + return (serviceName, serviceTypeName: head.Attribute("ServiceTypeName")?.Value); + }) + .Where(entry => entry.serviceName != null && entry.serviceTypeName != null) + .Select(entry => (serviceName: entry.serviceName!, serviceTypeName: entry.serviceTypeName!)); // we know at this point that there are not nulls. + } + + internal static string? GetApplicationManifestPath() + { + Regex regex = new(@"(ApplicationManifest\..*\.xml)$"); + string[] files = Directory + .EnumerateFiles(@"C:\\SfDevCluster\", "*.*", SearchOption.AllDirectories) + .Where(path => regex.IsMatch(path)) + .ToArray(); + + return files.Length != 1 ? null : files.Single(); + } + + internal static string? GetServiceManifestPath(string serviceManifestName) + { + string? applicationDir = GetVariable(FarbicFolderApplication); + + if (applicationDir == null) + { + return null; + } + + string serviceProperName = serviceManifestName.Replace(@"\", @"\\").Replace(".", @"\."); + string regexExp = string.Format(@"(.*{0}.*\.Manifest\..*\.xml)$", serviceProperName); + Regex regex = new(regexExp); + + string[] manifests = Directory.GetFiles(applicationDir).Where( + path => regex.IsMatch(path) + ).ToArray(); + + return manifests.Length != 1 ? null : manifests.Single(); + } + /// /// Default empty value /// From 0b1d9362f441b5d2dfdfb4dfe4f599fc9cd777ed Mon Sep 17 00:00:00 2001 From: mvxxx Date: Fri, 23 Apr 2021 15:06:40 +0100 Subject: [PATCH 2/7] make methods protected --- .../Abstractions/ExecutionContext/BaseExecutionContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs b/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs index 8357a4400..783cc27fc 100644 --- a/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs +++ b/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs @@ -148,7 +148,7 @@ protected static string GetBuildVersion() /// /// Service manifest name defined in ApplicationManifest.xml /// - public static string? GetBuildVersionFromServiceManifest(string serviceManifestName) + protected static string? GetBuildVersionFromServiceManifest(string serviceManifestName) { string? serviceManifestPath = GetServiceManifestPath(serviceManifestName); if (serviceManifestPath == null) @@ -163,7 +163,7 @@ protected static string GetBuildVersion() /// Get build version from the current running service's manifest file /// /// - public static string? GetBuildVersionFromServiceManifest() + protected static string? GetBuildVersionFromServiceManifest() { string? applicationDir = GetVariable(FarbicFolderApplication); string? serviceName = GetVariable(ServiceNameVariableName); From 6d4fe83959279e36e10dd2ccf662cd3d7796698f Mon Sep 17 00:00:00 2001 From: mvxxx Date: Fri, 23 Apr 2021 15:15:30 +0100 Subject: [PATCH 3/7] Docs extended --- .../Abstractions/ExecutionContext/BaseExecutionContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs b/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs index 783cc27fc..7fb2826bb 100644 --- a/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs +++ b/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs @@ -147,7 +147,7 @@ protected static string GetBuildVersion() /// Get build version from the current running service's manifest file /// /// Service manifest name defined in ApplicationManifest.xml - /// + /// Build version if found, otherwise null protected static string? GetBuildVersionFromServiceManifest(string serviceManifestName) { string? serviceManifestPath = GetServiceManifestPath(serviceManifestName); @@ -162,7 +162,7 @@ protected static string GetBuildVersion() /// /// Get build version from the current running service's manifest file /// - /// + /// Build version if found, otherwise null protected static string? GetBuildVersionFromServiceManifest() { string? applicationDir = GetVariable(FarbicFolderApplication); From ae3586b49e266ae67e337fff88a6dba422660df5 Mon Sep 17 00:00:00 2001 From: mvxxx Date: Thu, 29 Apr 2021 12:39:16 +0100 Subject: [PATCH 4/7] refactor --- .../ExecutionContext/BaseExecutionContext.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs b/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs index 7fb2826bb..45ccc032b 100644 --- a/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs +++ b/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs @@ -151,12 +151,8 @@ protected static string GetBuildVersion() protected static string? GetBuildVersionFromServiceManifest(string serviceManifestName) { string? serviceManifestPath = GetServiceManifestPath(serviceManifestName); - if (serviceManifestPath == null) - { - return null; - } - - return XElement.Load(serviceManifestPath).Attribute("Version")?.Value; + return serviceManifestPath == null ? null : + XElement.Load(serviceManifestPath).Attribute("Version")?.Value; } /// @@ -195,9 +191,12 @@ protected static string GetBuildVersion() // Match our service with corresponding build version try { - string targetServiceType = serviceMetaInfo.Single(entry => entry.serviceName == serviceName.Split('/').Last()) - .serviceTypeName; - return manifestMetaInfo.Single(entry => entry.serviceTypeName == targetServiceType).buildVersion; + string targetServiceType = serviceMetaInfo + .Single(entry => entry.serviceName == serviceName.Split('/').Last()) + .serviceTypeName; + return manifestMetaInfo + .Single(entry => entry.serviceTypeName == targetServiceType) + .buildVersion; } catch (Exception) { From 9abcb8142a20d97eca001c1b8a0c0745f0520d60 Mon Sep 17 00:00:00 2001 From: mvxxx Date: Thu, 29 Apr 2021 12:55:30 +0100 Subject: [PATCH 5/7] version --- .../Abstractions/Microsoft.Omex.Extensions.Abstractions.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Extensions/Abstractions/Microsoft.Omex.Extensions.Abstractions.csproj b/src/Extensions/Abstractions/Microsoft.Omex.Extensions.Abstractions.csproj index 7651e0f42..9056dff1b 100644 --- a/src/Extensions/Abstractions/Microsoft.Omex.Extensions.Abstractions.csproj +++ b/src/Extensions/Abstractions/Microsoft.Omex.Extensions.Abstractions.csproj @@ -6,6 +6,7 @@ + From ab644a0dbddc3cebc1f57e2fef3eaacf75994c7f Mon Sep 17 00:00:00 2001 From: mvxxx Date: Fri, 30 Apr 2021 16:14:43 +0100 Subject: [PATCH 6/7] update build version --- .../ExecutionContext/BaseExecutionContext.cs | 130 +----------------- 1 file changed, 5 insertions(+), 125 deletions(-) diff --git a/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs b/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs index 45ccc032b..318467d46 100644 --- a/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs +++ b/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs @@ -146,147 +146,27 @@ protected static string GetBuildVersion() /// /// Get build version from the current running service's manifest file /// - /// Service manifest name defined in ApplicationManifest.xml /// Build version if found, otherwise null - protected static string? GetBuildVersionFromServiceManifest(string serviceManifestName) + protected static string? GetBuildVersionFromServiceManifest() { - string? serviceManifestPath = GetServiceManifestPath(serviceManifestName); + string? serviceManifestPath = GetServiceManifestPath(); return serviceManifestPath == null ? null : XElement.Load(serviceManifestPath).Attribute("Version")?.Value; } - /// - /// Get build version from the current running service's manifest file - /// - /// Build version if found, otherwise null - protected static string? GetBuildVersionFromServiceManifest() - { - string? applicationDir = GetVariable(FarbicFolderApplication); - string? serviceName = GetVariable(ServiceNameVariableName); - string? applicationManifest = GetApplicationManifestPath(); - - if (applicationDir == null || serviceName == null || applicationManifest == null) - { - return null; - } - - // Firstly we load all entries from Application Manifest - IEnumerable descendants = XDocument - .Load(applicationManifest) - .Descendants(); - - // Query all service specific manifest names - IEnumerable manifestNames = descendants - .Where(entry => entry.Name.LocalName == "ServiceManifestRef") - .Select(entry => entry.Attribute("ServiceManifestName")?.Value) - .Where(entry => entry != null) - .Select(entry => entry!); // we know at this point that there are not nulls. - // Query all services and corresponding types from Application Manifest - IEnumerable<(string serviceName, string serviceTypeName)> serviceMetaInfo = QueryServicesNamesWithTypes(descendants); - - // Query all service types and corresponding build versions from service manifest files - IEnumerable<(string serviceTypeName, string buildVersion)> manifestMetaInfo = QueryServicesTypesWithVersion(manifestNames); - - // Match our service with corresponding build version - try - { - string targetServiceType = serviceMetaInfo - .Single(entry => entry.serviceName == serviceName.Split('/').Last()) - .serviceTypeName; - return manifestMetaInfo - .Single(entry => entry.serviceTypeName == targetServiceType) - .buildVersion; - } - catch (Exception) - { - // Target service not found - return null; - } - } - - internal static IEnumerable<(string serviceTypeName, string buildVersion)> QueryServicesTypesWithVersion(IEnumerable manifestNames) - { - return manifestNames - .Select(manifestFilename => - { - string? manifestFilePath = GetServiceManifestPath(manifestFilename); - if (manifestFilePath == null) - { - return (serviceTypeName: null, buildVersion: null); - } - - IEnumerable manifestDescendants = XDocument.Load(manifestFilePath).Descendants(); - IEnumerable serviceManifestEntries = manifestDescendants - .Where(entry => entry.Name.LocalName == "ServiceManifest"); - - if (serviceManifestEntries.Count() != 1) - { - return (serviceTypeName: null, buildVersion: null); - } - - string? buildVersion = serviceManifestEntries.Single().Attribute("Version")?.Value; - - IEnumerable serviceTypeNames = manifestDescendants - .Where(entry => entry.Name.LocalName is "StatelessServiceType" or "StatefulServiceType") - .Select(entry => entry.Attribute("ServiceTypeName")?.Value); - - if (serviceTypeNames.Count() != 1) - { - return (serviceTypeName: null, buildVersion: null); - } - - return (serviceTypeName: serviceTypeNames.Single(), buildVersion); - }) - .Where(entry => entry.serviceTypeName != null && entry.buildVersion != null) - .Select(entry => (serviceTypeName: entry.serviceTypeName!, buildVersion: entry.buildVersion!)); - } - - internal static IEnumerable<(string serviceName, string serviceTypeName)> QueryServicesNamesWithTypes(IEnumerable descendants) - { - return descendants - .Where(entry => entry.Name.LocalName == "Service") - .Select(entry => - { - string? serviceName = entry.Attribute("Name")?.Value; - IEnumerable serviceDescendants = entry - .Descendants().Where(entry => entry.Name.LocalName is "StatelessService" or "StatefulService"); - - if (serviceDescendants.Count() != 1) - { - return (null, null); - } - XElement head = serviceDescendants.Single(); - return (serviceName, serviceTypeName: head.Attribute("ServiceTypeName")?.Value); - }) - .Where(entry => entry.serviceName != null && entry.serviceTypeName != null) - .Select(entry => (serviceName: entry.serviceName!, serviceTypeName: entry.serviceTypeName!)); // we know at this point that there are not nulls. - } - - internal static string? GetApplicationManifestPath() - { - Regex regex = new(@"(ApplicationManifest\..*\.xml)$"); - string[] files = Directory - .EnumerateFiles(@"C:\\SfDevCluster\", "*.*", SearchOption.AllDirectories) - .Where(path => regex.IsMatch(path)) - .ToArray(); - - return files.Length != 1 ? null : files.Single(); - } - - internal static string? GetServiceManifestPath(string serviceManifestName) + private static string? GetServiceManifestPath() { string? applicationDir = GetVariable(FarbicFolderApplication); + string serviceManifestName = GetVariable("Fabric_ServicePackageName")!; - if (applicationDir == null) + if (applicationDir == null || serviceManifestName == null) { return null; } - string serviceProperName = serviceManifestName.Replace(@"\", @"\\").Replace(".", @"\."); string regexExp = string.Format(@"(.*{0}.*\.Manifest\..*\.xml)$", serviceProperName); Regex regex = new(regexExp); - string[] manifests = Directory.GetFiles(applicationDir).Where( path => regex.IsMatch(path) ).ToArray(); From 3c66f931135f37f4a5474279f88b54ec521116ec Mon Sep 17 00:00:00 2001 From: mvxxx Date: Fri, 30 Apr 2021 16:29:23 +0100 Subject: [PATCH 7/7] Added tests && exposed variable --- .../ExecutionContext/BaseExecutionContext.cs | 12 ++++++++---- .../ExecutionContext/IExecutionContext.cs | 5 +++++ .../ExecutionContext/BaseExecutionContextTests.cs | 4 ++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs b/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs index 318467d46..126ae8e9d 100644 --- a/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs +++ b/src/Extensions/Abstractions/ExecutionContext/BaseExecutionContext.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; @@ -30,6 +29,7 @@ public class BaseExecutionContext : IExecutionContext // defined by Service Fabric https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-environment-variables-reference internal const string ServiceNameVariableName = "Fabric_ServiceName"; + internal const string ServicePackageVariableName = "Fabric_ServicePackageName"; internal const string ApplicationNameVariableName = "Fabric_ApplicationName"; internal const string NodeNameVariableName = "Fabric_NodeName"; internal const string NodeIPOrFQDNVariableName = "Fabric_NodeIPOrFQDN"; @@ -42,6 +42,7 @@ public class BaseExecutionContext : IExecutionContext public BaseExecutionContext(IHostEnvironment? hostEnvironment = null) { MachineName = GetMachineName(); + ServicePackageName = GetVariable(ServicePackageVariableName) ?? DefaultEmptyValue; BuildVersion = GetBuildVersionFromServiceManifest() ?? DefaultEmptyValue; ClusterIpAddress = GetIpAddress(MachineName); @@ -115,6 +116,9 @@ public BaseExecutionContext(IHostEnvironment? hostEnvironment = null) /// public bool IsPrivateDeployment { get; protected set; } + /// + public string ServicePackageName { get; protected set; } + /// /// Get environment variable value /// @@ -147,7 +151,7 @@ protected static string GetBuildVersion() /// Get build version from the current running service's manifest file /// /// Build version if found, otherwise null - protected static string? GetBuildVersionFromServiceManifest() + protected string? GetBuildVersionFromServiceManifest() { string? serviceManifestPath = GetServiceManifestPath(); return serviceManifestPath == null ? null : @@ -155,10 +159,10 @@ protected static string GetBuildVersion() } - private static string? GetServiceManifestPath() + private string? GetServiceManifestPath() { string? applicationDir = GetVariable(FarbicFolderApplication); - string serviceManifestName = GetVariable("Fabric_ServicePackageName")!; + string? serviceManifestName = ServicePackageName; if (applicationDir == null || serviceManifestName == null) { diff --git a/src/Extensions/Abstractions/ExecutionContext/IExecutionContext.cs b/src/Extensions/Abstractions/ExecutionContext/IExecutionContext.cs index cad66ee27..cf6b6f47a 100644 --- a/src/Extensions/Abstractions/ExecutionContext/IExecutionContext.cs +++ b/src/Extensions/Abstractions/ExecutionContext/IExecutionContext.cs @@ -67,5 +67,10 @@ public interface IExecutionContext /// The service name /// string ServiceName { get; } + + /// + /// The service package name + /// + string ServicePackageName { get; } } } diff --git a/tests/Extensions/Abstractions.UnitTests/ExecutionContext/BaseExecutionContextTests.cs b/tests/Extensions/Abstractions.UnitTests/ExecutionContext/BaseExecutionContextTests.cs index 35b54aabb..61e0f83b5 100644 --- a/tests/Extensions/Abstractions.UnitTests/ExecutionContext/BaseExecutionContextTests.cs +++ b/tests/Extensions/Abstractions.UnitTests/ExecutionContext/BaseExecutionContextTests.cs @@ -24,9 +24,12 @@ public void Constructor_InitializesPropertiesProperly(string enviroment, bool is string applicationName = "SomeApplicationName"; string serviceName = "SomeServiceName"; string nodeName = "SomeNodeName"; + string packageName = "SomePackageName"; + IPAddress nodeIPOrFQDN = IPAddress.Parse("192.0.0.1"); Environment.SetEnvironmentVariable(BaseExecutionContext.ClusterNameVariableName, clusterName); + Environment.SetEnvironmentVariable(BaseExecutionContext.ServicePackageVariableName, packageName); Environment.SetEnvironmentVariable(BaseExecutionContext.RegionNameVariableName, regionName); Environment.SetEnvironmentVariable(BaseExecutionContext.SliceNameVariableName, sliceName); Environment.SetEnvironmentVariable(BaseExecutionContext.ApplicationNameVariableName, applicationName); @@ -42,6 +45,7 @@ public void Constructor_InitializesPropertiesProperly(string enviroment, bool is Assert.AreEqual(clusterName, info.Cluster); Assert.AreEqual(regionName, info.RegionName); Assert.AreEqual(sliceName, info.DeploymentSlice); + Assert.AreEqual(packageName, info.ServicePackageName); Assert.AreEqual(enviroment, info.EnvironmentName); Assert.AreEqual(isPrivate, info.IsPrivateDeployment);