From eeedadcdfe814a01ad41b722d84cb30c4b1483e0 Mon Sep 17 00:00:00 2001 From: Mayank Bansal Date: Mon, 18 Dec 2017 21:07:48 +0530 Subject: [PATCH 1/5] C++ UWP Reflection based discovery --- .../TestCase.cs | 6 ++-- .../common/System/PlatformFile.cs | 23 +++++++++++++++ .../netstandard1.0/System/PlatformFile.cs | 23 +++++++++++++++ .../uap10.0/System/PlatformFile.cs | 29 +++++++++++++++++++ .../Hosting/DefaultTestHostManager.cs | 18 ++++++++++-- 5 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformFile.cs create mode 100644 src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformFile.cs create mode 100644 src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformFile.cs diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs index 786af5c29a..26d8f9606c 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs @@ -7,11 +7,13 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel using System.IO; using System.Runtime.Serialization; - using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; using System.Globalization; using System.Collections.Generic; using System.Linq; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; + using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; + /// /// Stores information about a test case. /// @@ -221,7 +223,7 @@ private Guid GetTestId() // For example in the database adapter case this is not a file path. string source = this.Source; - if (File.Exists(source)) + if (PlatformFile.Exists(source)) { source = Path.GetFileName(source); } diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformFile.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformFile.cs new file mode 100644 index 0000000000..b3052a52a8 --- /dev/null +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformFile.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions +{ + using System.IO; + + /// + /// File Abstraction + /// + public static class PlatformFile + { + /// + /// Checks if give file exists on disk + /// + /// input filePath + /// True if file Exists + public static bool Exists(string filePath) + { + return File.Exists(filePath); + } + } +} diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformFile.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformFile.cs new file mode 100644 index 0000000000..972736d2ab --- /dev/null +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformFile.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions +{ + using System; + + /// + /// File Abstraction + /// + public static class PlatformFile + { + /// + /// Checks if give file exists on disk + /// + /// input filePath + /// True if file Exists + public static bool Exists(string filePath) + { + throw new NotImplementedException(filePath); + } + } +} diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformFile.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformFile.cs new file mode 100644 index 0000000000..bb3d7a586a --- /dev/null +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformFile.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions +{ + using System.IO; + + /// + /// File Abstraction + /// + public static class PlatformFile + { + /// + /// Checks if give file exists on disk + /// + /// input filePath + /// True if file Exists + public static bool Exists(string filePath) + { + // Appxrecipe gets renamed vs.appxrecipe, which test platform is unaware of, so if queried for appxrecipe, return true + if (filePath.EndsWith(".appxrecipe", System.StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + return File.Exists(filePath); + } + } +} diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs index 6c3594af21..ede9d27d15 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs @@ -13,6 +13,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting using System.Text; using System.Threading; using System.Threading.Tasks; + using System.Xml; using Microsoft.TestPlatform.TestHostProvider.Hosting; using Microsoft.TestPlatform.TestHostProvider.Resources; using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Extensions; @@ -203,8 +204,21 @@ public IEnumerable GetTestPlatformExtensions(IEnumerable sources /// public IEnumerable GetTestSources(IEnumerable sources) { - // We do not have scenario where full CLR tests are deployed to remote machine, so no need to udpate sources - return sources; + List actualSources = new List(); + + // We are doing this specifically for UWP, should we extract it out to some other utility? + // Why? Lets say if we have to do same for someother source extension, would we just add another if check? + var uwpSources = sources.Where(source => source.EndsWith(".appxrecipe", StringComparison.OrdinalIgnoreCase)); + + foreach (var uwpSource in uwpSources) + { + XmlDocument xmlDocument = new XmlDocument(); + xmlDocument.Load(XmlReader.Create(new StringReader(File.ReadAllText(uwpSource, Encoding.UTF8)), XmlRunSettingsUtilities.ReaderSettings)); + + actualSources.Add(Path.Combine(Path.GetDirectoryName(uwpSource), xmlDocument.GetElementsByTagName("PackagePath").Cast().Where(node => node.InnerText.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)).FirstOrDefault().InnerText)); + } + + return actualSources.Concat(sources.Except(uwpSources)); } /// From 4a40e8cfbe58d94bce43ed8a234f09c444539a65 Mon Sep 17 00:00:00 2001 From: Mayank Bansal Date: Tue, 19 Dec 2017 19:07:39 +0530 Subject: [PATCH 2/5] Read Exe path from AppxManifest --- .../Hosting/AppxManifestFile.cs | 27 ++++++++++++++++ .../Hosting/DefaultTestHostManager.cs | 31 ++++++++++++++----- 2 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 src/Microsoft.TestPlatform.TestHostProvider/Hosting/AppxManifestFile.cs diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/AppxManifestFile.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/AppxManifestFile.cs new file mode 100644 index 0000000000..be8da4e4d0 --- /dev/null +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/AppxManifestFile.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.TestPlatform.DesktopTestHostRuntimeProvider +{ + using System.Xml.Linq; + + /// Wrapper for an appxmanifest file. + internal static class AppxManifestFile + { + /// Gets the app's exe name. + /// + /// AppxManifest filePath + /// + /// ExecutableName + public static string GetApplicationExecutableName(string filePath) + { + var doc = XDocument.Load(filePath); + var ns = doc.Root.Name.Namespace; + + return doc.Element(ns + "Package"). + Element(ns + "Applications"). + Element(ns + "Application"). + Attribute("Executable").Value; + } + } +} diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs index ede9d27d15..4a97db6d4c 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs @@ -13,12 +13,13 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting using System.Text; using System.Threading; using System.Threading.Tasks; - using System.Xml; + using System.Xml.Linq; using Microsoft.TestPlatform.TestHostProvider.Hosting; using Microsoft.TestPlatform.TestHostProvider.Resources; using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Extensions; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Helpers; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Helpers.Interfaces; + using Microsoft.VisualStudio.TestPlatform.DesktopTestHostRuntimeProvider; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Host; @@ -204,21 +205,22 @@ public IEnumerable GetTestPlatformExtensions(IEnumerable sources /// public IEnumerable GetTestSources(IEnumerable sources) { - List actualSources = new List(); - // We are doing this specifically for UWP, should we extract it out to some other utility? // Why? Lets say if we have to do same for someother source extension, would we just add another if check? var uwpSources = sources.Where(source => source.EndsWith(".appxrecipe", StringComparison.OrdinalIgnoreCase)); - foreach (var uwpSource in uwpSources) + if (uwpSources.Any()) { - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.Load(XmlReader.Create(new StringReader(File.ReadAllText(uwpSource, Encoding.UTF8)), XmlRunSettingsUtilities.ReaderSettings)); + List actualSources = new List(); + foreach (var uwpSource in uwpSources) + { + actualSources.Add(Path.Combine(Path.GetDirectoryName(uwpSource), this.GetUwpSources(uwpSource))); + } - actualSources.Add(Path.Combine(Path.GetDirectoryName(uwpSource), xmlDocument.GetElementsByTagName("PackagePath").Cast().Where(node => node.InnerText.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)).FirstOrDefault().InnerText)); + return actualSources; } - return actualSources.Concat(sources.Except(uwpSources)); + return sources; } /// @@ -394,5 +396,18 @@ private bool LaunchHost(TestProcessStartInfo testHostStartInfo, CancellationToke this.OnHostLaunched(new HostProviderEventArgs("Test Runtime launched", 0, this.testHostProcess.Id)); return this.testHostProcess != null; } + + private string GetUwpSources(string uwpSource) + { + var doc = XDocument.Load(uwpSource); + var ns = doc.Root.Name.Namespace; + + string appxManifestPath = doc.Element(ns + "Project"). + Element(ns + "ItemGroup"). + Element(ns + "AppXManifest"). + Attribute("Include").Value; + + return AppxManifestFile.GetApplicationExecutableName(appxManifestPath); + } } } \ No newline at end of file From e235f59e7447d4d98d6aedf9891fb4cd9b51520b Mon Sep 17 00:00:00 2001 From: Mayank Bansal Date: Wed, 20 Dec 2017 13:48:27 +0530 Subject: [PATCH 3/5] Adding test --- .../Hosting/AppxManifestFile.cs | 18 +- .../Hosting/DefaultTestHostManager.cs | 5 + .../Hosting/DefaultTestHostManagerTests.cs | 10 + .../TestAssets/UWPTestAssets/AppxManifest.xml | 75 +++++++ .../UnitTestApp8.build.appxrecipe | 209 ++++++++++++++++++ 5 files changed, 311 insertions(+), 6 deletions(-) create mode 100644 test/TestAssets/UWPTestAssets/AppxManifest.xml create mode 100644 test/TestAssets/UWPTestAssets/UnitTestApp8.build.appxrecipe diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/AppxManifestFile.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/AppxManifestFile.cs index be8da4e4d0..74e2716f0d 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/AppxManifestFile.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/AppxManifestFile.cs @@ -4,6 +4,7 @@ namespace Microsoft.VisualStudio.TestPlatform.DesktopTestHostRuntimeProvider { using System.Xml.Linq; + using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; /// Wrapper for an appxmanifest file. internal static class AppxManifestFile @@ -15,13 +16,18 @@ internal static class AppxManifestFile /// ExecutableName public static string GetApplicationExecutableName(string filePath) { - var doc = XDocument.Load(filePath); - var ns = doc.Root.Name.Namespace; + if (PlatformFile.Exists(filePath)) + { + var doc = XDocument.Load(filePath); + var ns = doc.Root.Name.Namespace; - return doc.Element(ns + "Package"). - Element(ns + "Applications"). - Element(ns + "Application"). - Attribute("Executable").Value; + return doc.Element(ns + "Package"). + Element(ns + "Applications"). + Element(ns + "Application"). + Attribute("Executable").Value; + } + + return null; } } } diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs index 4a97db6d4c..4871e2d707 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs @@ -407,6 +407,11 @@ private string GetUwpSources(string uwpSource) Element(ns + "AppXManifest"). Attribute("Include").Value; + if (!Path.IsPathRooted(appxManifestPath)) + { + appxManifestPath = Path.Combine(Path.GetDirectoryName(uwpSource), appxManifestPath); + } + return AppxManifestFile.GetApplicationExecutableName(appxManifestPath); } } diff --git a/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DefaultTestHostManagerTests.cs b/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DefaultTestHostManagerTests.cs index 71ca028046..abba3a0aa8 100644 --- a/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DefaultTestHostManagerTests.cs +++ b/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DefaultTestHostManagerTests.cs @@ -8,6 +8,7 @@ namespace TestPlatform.TestHostProvider.UnitTests.Hosting using System.Diagnostics; using System.IO; using System.Linq; + using System.Reflection; using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Extensions; @@ -378,6 +379,15 @@ public void LaunchTestHostShouldUseCustomHostIfSet() Assert.AreEqual(currentProcess.Id, this.testHostId); } + [TestMethod] + public void GetTestSourcesShouldReturnAppropriateSourceIfAppxRecipeIsProvided() + { + var sourcePath = Path.Combine(Path.GetDirectoryName(typeof(TestableTestHostManager).GetTypeInfo().Assembly.GetAssemblyLocation()), @"..\..\..\..\TestAssets\UWPTestAssets\UnitTestApp8.build.appxrecipe"); + IEnumerable sources = this.testHostManager.GetTestSources(new List { sourcePath }); + Assert.IsTrue(sources.Any()); + Assert.IsTrue(sources.FirstOrDefault().EndsWith(".exe", StringComparison.OrdinalIgnoreCase)); + } + [TestMethod] public async Task ErrorMessageShouldBeReadAsynchronously() { diff --git a/test/TestAssets/UWPTestAssets/AppxManifest.xml b/test/TestAssets/UWPTestAssets/AppxManifest.xml new file mode 100644 index 0000000000..f8a4d2a5d4 --- /dev/null +++ b/test/TestAssets/UWPTestAssets/AppxManifest.xml @@ -0,0 +1,75 @@ + + + + + + + UnitTestApp8 + maban + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + CLRHost.dll + + + + + + CppUnitTestFramework_Executor_WindowsPhone.dll + + + + + + + + vstest_executionengine_platformbridge.dll + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/TestAssets/UWPTestAssets/UnitTestApp8.build.appxrecipe b/test/TestAssets/UWPTestAssets/UnitTestApp8.build.appxrecipe new file mode 100644 index 0000000000..1eda172016 --- /dev/null +++ b/test/TestAssets/UWPTestAssets/UnitTestApp8.build.appxrecipe @@ -0,0 +1,209 @@ + + + + MABAN-PC + maban + UAP + 10.0 + Windows 10.0 + Release|Win32 + x86 + e7a3d303-9783-498c-9285-7474e1e66396 + CN=maban + C:\Users\maban\source\repos\UnitTestApp8\UnitTestApp8\Release\ + CopyToDevice + + false + false + C:\Program Files %28x86%29\Windows Kits\10\ + C:\Users\maban\source\repos\UnitTestApp8\Release\UnitTestApp8\AppX + + + + AppxManifest.xml + true + + + + + Assets\LockScreenLogo.scale-200.png + + + Assets\SplashScreen.scale-200.png + true + + + Assets\Square150x150Logo.scale-200.png + true + + + Assets\Square44x44Logo.scale-200.png + true + + + Assets\Square44x44Logo.targetsize-24_altform-unplated.png + true + + + Assets\StoreLogo.png + true + + + Assets\Wide310x150Logo.scale-200.png + true + + + clrcompression.dll + + + CppUnitTestFramework_Executor_WindowsPhone.dll + + + CppUnitTestFramework_Executor_WindowsPhone.winmd + + + e7a3d303-9783-498c-9285-7474e1e66396.dll + + + e7a3d303-9783-498c-9285-7474e1e66396.exe + + + e7a3d303-9783-498c-9285-7474e1e66396.pdb + + + Microsoft.VisualStudio.TestPlatform.TestExecutor.WinRTCore.winmd + + + Microsoft.VisualStudio.TestTools.CppUnitTestFramework.dll + + + resources.pri + true + + + UnitTestApp8.exe + + + UnitTestApp8.pdb + + + UnitTestApp8.winmd + + + vstest.executionengine.WindowsPhone.dll + + + vstest_executionengine_platformbridge.dll + + + vstest_executionengine_platformbridge.winmd + + + _Resources\0.rsrc + + + _Resources\1.rsrc + + + _Resources\2.rsrc + + + _Resources\3.rsrc + + + _Resources\4.rsrc + + + _Resources\5.rsrc + + + _Resources\6.rsrc + + + _Resources\7.rsrc + + + _Resources\8.rsrc + + + _Resources\9.rsrc + + + _Resources\index.txt + + + + + Microsoft.VCLibs.140.00 + 14.0.25426.0 + ARM + Name = Microsoft.VCLibs.140.00, MinVersion = 14.0.25426.0, Publisher = %27CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US%27 + C:\Program Files %28x86%29\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.VCLibs\14.0\.\AppX\Retail\ARM\Microsoft.VCLibs.ARM.14.00.appx + + + + Microsoft.VCLibs.140.00 + 14.0.25426.0 + x64 + Name = Microsoft.VCLibs.140.00, MinVersion = 14.0.25426.0, Publisher = %27CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US%27 + C:\Program Files %28x86%29\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.VCLibs\14.0\.\AppX\Retail\x64\Microsoft.VCLibs.x64.14.00.appx + + + + Microsoft.VCLibs.140.00 + 14.0.25426.0 + x86 + Name = Microsoft.VCLibs.140.00, MinVersion = 14.0.25426.0, Publisher = %27CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US%27 + C:\Program Files %28x86%29\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.VCLibs\14.0\.\AppX\Retail\x86\Microsoft.VCLibs.x86.14.00.appx + + + + Microsoft.NET.Native.Framework.1.3 + 1.3.24201.0 + ARM + Name = Microsoft.NET.Native.Framework.1.3, MinVersion = 1.3.24201.0, Publisher = %27CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US%27 + C:\Program Files %28x86%29\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.NET.Native.Framework.1.3\1.3\.\arm\ret\Native\Microsoft.NET.Native.Framework.1.3.appx + + + + Microsoft.NET.Native.Framework.1.3 + 1.3.24201.0 + x64 + Name = Microsoft.NET.Native.Framework.1.3, MinVersion = 1.3.24201.0, Publisher = %27CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US%27 + C:\Program Files %28x86%29\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.NET.Native.Framework.1.3\1.3\.\x64\ret\Native\Microsoft.NET.Native.Framework.1.3.appx + + + + Microsoft.NET.Native.Framework.1.3 + 1.3.24201.0 + x86 + Name = Microsoft.NET.Native.Framework.1.3, MinVersion = 1.3.24201.0, Publisher = %27CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US%27 + C:\Program Files %28x86%29\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.NET.Native.Framework.1.3\1.3\.\x86\ret\Native\Microsoft.NET.Native.Framework.1.3.appx + + + + Microsoft.NET.Native.Runtime.1.4 + 1.4.24201.0 + ARM + Name = Microsoft.NET.Native.Runtime.1.4, MinVersion = 1.4.24201.0, Publisher = %27CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US%27 + C:\Program Files %28x86%29\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.NET.Native.Runtime.1.4\1.4\.\AppX\ARM\Microsoft.NET.Native.Runtime.1.4.appx + + + + Microsoft.NET.Native.Runtime.1.4 + 1.4.24201.0 + x64 + Name = Microsoft.NET.Native.Runtime.1.4, MinVersion = 1.4.24201.0, Publisher = %27CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US%27 + C:\Program Files %28x86%29\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.NET.Native.Runtime.1.4\1.4\.\AppX\x64\Microsoft.NET.Native.Runtime.1.4.appx + + + + Microsoft.NET.Native.Runtime.1.4 + 1.4.24201.0 + x86 + Name = Microsoft.NET.Native.Runtime.1.4, MinVersion = 1.4.24201.0, Publisher = %27CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US%27 + C:\Program Files %28x86%29\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.NET.Native.Runtime.1.4\1.4\.\AppX\x86\Microsoft.NET.Native.Runtime.1.4.appx + + + + From e1314d57bba898379464175d4ec6ca56749cf954 Mon Sep 17 00:00:00 2001 From: Mayank Bansal Date: Wed, 20 Dec 2017 20:58:07 +0530 Subject: [PATCH 4/5] Changing TestCase ID generation logic Please see comment in TestCase .cs file --- .../TestCase.cs | 11 ++++++----- .../System/PlatformPath.cs} | 17 ++++++++++++----- .../System/PlatformPath.cs} | 8 ++++---- .../System/{PlatformFile.cs => PlatformPath.cs} | 17 +++++++++-------- .../Hosting/AppxManifestFile.cs | 4 ++-- .../Hosting/DefaultTestHostManagerTests.cs | 9 +++++++++ 6 files changed, 42 insertions(+), 24 deletions(-) rename src/Microsoft.TestPlatform.PlatformAbstractions/{netstandard1.0/System/PlatformFile.cs => common/System/PlatformPath.cs} (56%) rename src/Microsoft.TestPlatform.PlatformAbstractions/{common/System/PlatformFile.cs => netstandard1.0/System/PlatformPath.cs} (69%) rename src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/{PlatformFile.cs => PlatformPath.cs} (55%) diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs index 26d8f9606c..7a129bbcf6 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs @@ -223,12 +223,13 @@ private Guid GetTestId() // For example in the database adapter case this is not a file path. string source = this.Source; - if (PlatformFile.Exists(source)) - { - source = Path.GetFileName(source); - } + // As discussed with team, we found no scenario for netcore, & fullclr where the Source is not present where the ID is generated, + // which means we would always use FileName to generated ID. In cases where somehow Source Path contained garbage character the API Path.GetFileName() + // In such cases we are simply returning original input. + // For UWP where source during discovery, & during execution can be on different machine, in such case we should always use Path.GetFileName() + PlatformPath.TryGetFileName(source, out string fileName); - string testcaseFullName = this.ExecutorUri + source + this.FullyQualifiedName; + string testcaseFullName = this.ExecutorUri + fileName + this.FullyQualifiedName; return EqtHash.GuidFromString(testcaseFullName); } diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformFile.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformPath.cs similarity index 56% rename from src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformFile.cs rename to src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformPath.cs index 972736d2ab..fb4630beea 100644 --- a/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformFile.cs +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformPath.cs @@ -3,21 +3,28 @@ namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions { - using System; + using System.IO; /// /// File Abstraction /// - public static class PlatformFile + public static class PlatformPath { /// /// Checks if give file exists on disk /// /// input filePath - /// True if file Exists - public static bool Exists(string filePath) + /// output fileName + public static void TryGetFileName(string filePath, out string fileName) { - throw new NotImplementedException(filePath); + try + { + fileName = Path.GetFileName(filePath); + } + catch + { + fileName = filePath; + } } } } diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformFile.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformPath.cs similarity index 69% rename from src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformFile.cs rename to src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformPath.cs index b3052a52a8..0071a2e5e0 100644 --- a/src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformFile.cs +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformPath.cs @@ -8,16 +8,16 @@ namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions /// /// File Abstraction /// - public static class PlatformFile + public static class PlatformPath { /// /// Checks if give file exists on disk /// /// input filePath - /// True if file Exists - public static bool Exists(string filePath) + /// output fileName + public static void TryGetFileName(string filePath, out string fileName) { - return File.Exists(filePath); + throw new FileNotFoundException(); } } } diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformFile.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformPath.cs similarity index 55% rename from src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformFile.cs rename to src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformPath.cs index bb3d7a586a..fb4630beea 100644 --- a/src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformFile.cs +++ b/src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformPath.cs @@ -8,22 +8,23 @@ namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions /// /// File Abstraction /// - public static class PlatformFile + public static class PlatformPath { /// /// Checks if give file exists on disk /// /// input filePath - /// True if file Exists - public static bool Exists(string filePath) + /// output fileName + public static void TryGetFileName(string filePath, out string fileName) { - // Appxrecipe gets renamed vs.appxrecipe, which test platform is unaware of, so if queried for appxrecipe, return true - if (filePath.EndsWith(".appxrecipe", System.StringComparison.OrdinalIgnoreCase)) + try { - return true; + fileName = Path.GetFileName(filePath); + } + catch + { + fileName = filePath; } - - return File.Exists(filePath); } } } diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/AppxManifestFile.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/AppxManifestFile.cs index 74e2716f0d..3ac67e6db8 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/AppxManifestFile.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/AppxManifestFile.cs @@ -3,8 +3,8 @@ namespace Microsoft.VisualStudio.TestPlatform.DesktopTestHostRuntimeProvider { + using System.IO; using System.Xml.Linq; - using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; /// Wrapper for an appxmanifest file. internal static class AppxManifestFile @@ -16,7 +16,7 @@ internal static class AppxManifestFile /// ExecutableName public static string GetApplicationExecutableName(string filePath) { - if (PlatformFile.Exists(filePath)) + if (File.Exists(filePath)) { var doc = XDocument.Load(filePath); var ns = doc.Root.Name.Namespace; diff --git a/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DefaultTestHostManagerTests.cs b/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DefaultTestHostManagerTests.cs index abba3a0aa8..82c4a7b1e3 100644 --- a/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DefaultTestHostManagerTests.cs +++ b/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DefaultTestHostManagerTests.cs @@ -15,6 +15,7 @@ namespace TestPlatform.TestHostProvider.UnitTests.Hosting using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Helpers; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Helpers.Interfaces; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting; + using Microsoft.VisualStudio.TestPlatform.DesktopTestHostRuntimeProvider; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Host; @@ -388,6 +389,14 @@ public void GetTestSourcesShouldReturnAppropriateSourceIfAppxRecipeIsProvided() Assert.IsTrue(sources.FirstOrDefault().EndsWith(".exe", StringComparison.OrdinalIgnoreCase)); } + [TestMethod] + public void AppxManifestFileShouldReturnAppropriateSourceIfAppxManifestIsProvided() + { + var appxManifestPath = Path.Combine(Path.GetDirectoryName(typeof(TestableTestHostManager).GetTypeInfo().Assembly.GetAssemblyLocation()), @"..\..\..\..\TestAssets\UWPTestAssets\AppxManifest.xml"); + string source = AppxManifestFile.GetApplicationExecutableName(appxManifestPath); + Assert.AreEqual("UnitTestApp8.exe", source); + } + [TestMethod] public async Task ErrorMessageShouldBeReadAsynchronously() { From 5b95e63093fdf7c849df8261fd4f2a34c8b9b6d0 Mon Sep 17 00:00:00 2001 From: Mayank Bansal Date: Thu, 21 Dec 2017 18:10:33 +0530 Subject: [PATCH 5/5] Remove extra code from platform abstraction --- .../TestCase.cs | 18 +++++++---- .../common/System/PlatformPath.cs | 30 ------------------- .../netstandard1.0/System/PlatformPath.cs | 23 -------------- .../uap10.0/System/PlatformPath.cs | 30 ------------------- 4 files changed, 13 insertions(+), 88 deletions(-) delete mode 100644 src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformPath.cs delete mode 100644 src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformPath.cs delete mode 100644 src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformPath.cs diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs index 7a129bbcf6..6eab3923eb 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs @@ -223,13 +223,21 @@ private Guid GetTestId() // For example in the database adapter case this is not a file path. string source = this.Source; - // As discussed with team, we found no scenario for netcore, & fullclr where the Source is not present where the ID is generated, - // which means we would always use FileName to generated ID. In cases where somehow Source Path contained garbage character the API Path.GetFileName() - // In such cases we are simply returning original input. + // As discussed with team, we found no scenario for netcore, & fullclr where the Source is not present where ID is generated, + // which means we would always use FileName to generate ID. In cases where somehow Source Path contained garbage character the API Path.GetFileName() + // we are simply returning original input. // For UWP where source during discovery, & during execution can be on different machine, in such case we should always use Path.GetFileName() - PlatformPath.TryGetFileName(source, out string fileName); + try + { + // If source name is malformed, GetFileName API will throw exception, so use same input malformed string to generate ID + source = Path.GetFileName(source); + } + catch + { + // do nothing + } - string testcaseFullName = this.ExecutorUri + fileName + this.FullyQualifiedName; + string testcaseFullName = this.ExecutorUri + source + this.FullyQualifiedName; return EqtHash.GuidFromString(testcaseFullName); } diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformPath.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformPath.cs deleted file mode 100644 index fb4630beea..0000000000 --- a/src/Microsoft.TestPlatform.PlatformAbstractions/common/System/PlatformPath.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions -{ - using System.IO; - - /// - /// File Abstraction - /// - public static class PlatformPath - { - /// - /// Checks if give file exists on disk - /// - /// input filePath - /// output fileName - public static void TryGetFileName(string filePath, out string fileName) - { - try - { - fileName = Path.GetFileName(filePath); - } - catch - { - fileName = filePath; - } - } - } -} diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformPath.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformPath.cs deleted file mode 100644 index 0071a2e5e0..0000000000 --- a/src/Microsoft.TestPlatform.PlatformAbstractions/netstandard1.0/System/PlatformPath.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions -{ - using System.IO; - - /// - /// File Abstraction - /// - public static class PlatformPath - { - /// - /// Checks if give file exists on disk - /// - /// input filePath - /// output fileName - public static void TryGetFileName(string filePath, out string fileName) - { - throw new FileNotFoundException(); - } - } -} diff --git a/src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformPath.cs b/src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformPath.cs deleted file mode 100644 index fb4630beea..0000000000 --- a/src/Microsoft.TestPlatform.PlatformAbstractions/uap10.0/System/PlatformPath.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions -{ - using System.IO; - - /// - /// File Abstraction - /// - public static class PlatformPath - { - /// - /// Checks if give file exists on disk - /// - /// input filePath - /// output fileName - public static void TryGetFileName(string filePath, out string fileName) - { - try - { - fileName = Path.GetFileName(filePath); - } - catch - { - fileName = filePath; - } - } - } -}