diff --git a/.github/workflows/AzureDevOps.yml b/.github/workflows/AzureDevOps.yml new file mode 100644 index 0000000000..43b7bfde40 --- /dev/null +++ b/.github/workflows/AzureDevOps.yml @@ -0,0 +1,25 @@ +name: Sync issue to Azure DevOps work item + +on: + issues: + types: + [labeled] #, opened, edited, deleted, closed, reopened, labeled, unlabeled, assigned + +jobs: + updateAzDO: + if: github.event.label.name == 'sprint' + runs-on: ubuntu-latest + steps: + - uses: pavelhorak/github-actions-issue-to-work-item@master + env: + ado_token: "${{ secrets.ADO_PERSONAL_ACCESS_TOKEN }}" + github_token: "${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}" + ado_organization: "${{ secrets.ADO_ORGANIZATION }}" + ado_project: "${{ secrets.ADO_PROJECT }}" + ado_area_path: "${{ secrets.ADO_AREA_PATH }}" + ado_iteration_path: ${{ secrets.ADO_ITERATION_PATH }}" # this doesn't work: "@CurrentIteration('[DevDiv]\\.NET DevExp Prague')" + ado_wit: "User Story" + ado_new_state: "Committed" + ado_active_state: "In Progress" + ado_close_state: "Completed" + ado_bypassrules: false diff --git a/.gitignore b/.gitignore index 9523d94f87..845632e36a 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ build*.log build*.wrn build*.err *.binlog +*.svclog # MSTest test Results [Tt]est[Rr]esult*/ diff --git a/NuGet.config b/NuGet.config index e369b7fa35..449aa3d8e0 100644 --- a/NuGet.config +++ b/NuGet.config @@ -13,10 +13,9 @@ - - - - + + + diff --git a/README.md b/README.md index 949ff88427..a7f543766c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The Visual Studio Test Platform is an open and extensible test platform that ena The Test Platform currently ships as part Visual Studio 2017, and in the .NET Core Tools Preview 3. ### Build status -[![Build Status](https://dev.azure.com/vstestplatform/TestPlatform/_apis/build/status/TestPlatform.CI?branchName=master)](https://dev.azure.com/vstestplatform/TestPlatform/_build/latest?definitionId=9&branchName=master) +[![Build Status](https://dev.azure.com/dnceng/public/_apis/build/status/Microsoft/vstest/microsoft.vstest.ci?branchName=master)](https://dev.azure.com/dnceng/public/_build/latest?definitionId=935&branchName=master) ### Contributing There are many ways to contribute to VSTest diff --git a/TestPlatform.sln b/TestPlatform.sln index 26a8b21bb6..321f401295 100644 --- a/TestPlatform.sln +++ b/TestPlatform.sln @@ -15,7 +15,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "datacollector", "src\dataco EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.Build", "src\Microsoft.TestPlatform.Build\Microsoft.TestPlatform.Build.csproj", "{6F5EC38C-4A11-40D3-827C-F607B90BEFF0}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Logger", "Logger", "{5E7F18A8-F843-4C8A-AB02-4C7D9205C6CF}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Loggers", "Loggers", "{5E7F18A8-F843-4C8A-AB02-4C7D9205C6CF}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.Client", "src\Microsoft.TestPlatform.Client\Microsoft.TestPlatform.Client.csproj", "{E19B5128-3469-492E-82E1-725631C4A68C}" EndProject @@ -41,10 +41,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "vstest.console", "src\vstes EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Integration", "Integration", "{46250E12-4CF1-4051-B4A7-80C8C06E0068}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Logger", "Logger", "{020E15EA-731F-4667-95AF-226671E0C3AE}" - ProjectSection(SolutionItems) = preProject - test\Microsoft.TestPlatform.AcceptanceTests\TestResults.html = test\Microsoft.TestPlatform.AcceptanceTests\TestResults.html - EndProjectSection +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Loggers", "Loggers", "{020E15EA-731F-4667-95AF-226671E0C3AE}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Performance", "Performance", "{595BE9C1-E10F-4E50-938A-E6C248D3F950}" EndProject @@ -68,6 +65,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "vstest.console.UnitTests", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.Extensions.TrxLogger.UnitTests", "test\Microsoft.TestPlatform.Extensions.TrxLogger.UnitTests\Microsoft.TestPlatform.Extensions.TrxLogger.UnitTests.csproj", "{BFF7714C-E5A3-4EEB-B04B-5FA47F29AD03}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "perf", "perf", "{0D4DF78D-7E5F-4516-B19F-E6AA71A1DBF4}" + ProjectSection(SolutionItems) = preProject + scripts\perf\perf.ps1 = scripts\perf\perf.ps1 + scripts\perf\perfconfig.csv = scripts\perf\perfconfig.csv + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{DED1590A-ED25-413B-8590-006A4DD5B2FD}" + ProjectSection(SolutionItems) = preProject + scripts\build\TestPlatform.Dependencies.props = scripts\build\TestPlatform.Dependencies.props + scripts\build\TestPlatform.Localization.targets = scripts\build\TestPlatform.Localization.targets + scripts\build\TestPlatform.Settings.targets = scripts\build\TestPlatform.Settings.targets + scripts\build\TestPlatform.targets = scripts\build\TestPlatform.targets + EndProjectSection +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{EE49F5DC-5835-4AE3-B3BA-8BDE0AD56330}" ProjectSection(SolutionItems) = preProject scripts\build.ps1 = scripts\build.ps1 @@ -76,6 +87,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{EE49 scripts\stylecop.test.ruleset = scripts\stylecop.test.ruleset scripts\test.ps1 = scripts\test.ps1 scripts\verify-sign.ps1 = scripts\verify-sign.ps1 + scripts\verify-nupkgs.ps1 = scripts\verify-nupkgs.ps1 + scripts\PortableToFullPdb.ps1 = scripts\PortableToFullPdb.ps1 + scripts\vsts-prebuild.ps1 = scripts\vsts-prebuild.ps1 + scripts\write-release-notes.ps1 = scripts\write-release-notes.ps1 + scripts\build.sh = scripts\build.sh + scripts\test.sh = scripts\test.sh EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E344E0A2-7715-4C7F-BAF7-D64EA94CB19B}" @@ -103,14 +120,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "datacollector.PlatformTests EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platform", "Platform", "{7D4082EA-7AC9-4DFB-98E8-C5E08BDC0EC3}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{DED1590A-ED25-413B-8590-006A4DD5B2FD}" - ProjectSection(SolutionItems) = preProject - scripts\build\TestPlatform.Dependencies.props = scripts\build\TestPlatform.Dependencies.props - scripts\build\TestPlatform.Localization.targets = scripts\build\TestPlatform.Localization.targets - scripts\build\TestPlatform.Settings.targets = scripts\build\TestPlatform.Settings.targets - scripts\build\TestPlatform.targets = scripts\build\TestPlatform.targets - EndProjectSection -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "package", "src\package\package\package.csproj", "{E141A226-CC0A-4F26-BD17-4AE427D81C3B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platform", "Platform", "{376C19DE-31E2-4FF6-88FC-0D0D6233C999}" @@ -135,20 +144,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataCollectors", "DataColle EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.Extensions.EventLogCollector.UnitTests", "test\DataCollectors\Microsoft.TestPlatform.Extensions.EventLogCollector.UnitTests\Microsoft.TestPlatform.Extensions.EventLogCollector.UnitTests.csproj", "{21DB138B-85B7-479E-91FE-01E0F972EC56}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "perf", "perf", "{0D4DF78D-7E5F-4516-B19F-E6AA71A1DBF4}" - ProjectSection(SolutionItems) = preProject - scripts\perf\perf.ps1 = scripts\perf\perf.ps1 - scripts\perf\perfconfig.csv = scripts\perf\perfconfig.csv - EndProjectSection -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "vstest.console.PlatformTests", "test\vstest.console.PlatformTests\vstest.console.PlatformTests.csproj", "{8C068694-23A2-47A2-A0DD-DB82D0AF0142}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.Common.PlatformTests", "test\Microsoft.TestPlatform.Common.PlatformTests\Microsoft.TestPlatform.Common.PlatformTests.csproj", "{24C7683D-2607-4901-B8EB-83A57E49E93D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.TraceDataCollector", "src\DataCollectors\TraceDataCollector\Microsoft.VisualStudio.TraceDataCollector.csproj", "{32BD96BD-16FB-43F0-B952-E7EEDB6DD813}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.TraceDataCollector.UnitTests", "test\DataCollectors\TraceDataCollector.UnitTests\Microsoft.TestPlatform.TraceDataCollector.UnitTests.csproj", "{A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SettingsMigrator", "src\SettingsMigrator\SettingsMigrator.csproj", "{69F5FF81-5615-4F06-B83C-FCF979BB84CA}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SettingsMigrator.UnitTests", "test\SettingsMigrator.UnitTests\SettingsMigrator.UnitTests.csproj", "{E7D4921C-F12D-4E1C-85AC-8B7F91C59B0E}" @@ -159,7 +158,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.Exte EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.collector", "test\coverlet.collector\coverlet.collector.csproj", "{074F5BD6-DC05-460B-B78F-044D125FD787}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests", "test\Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests\Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests.csproj", "{DCD0C39E-C78C-4A44-B0BD-7325254A2E97}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.AdapterUtilities.UnitTests", "test\Microsoft.TestPlatform.AdapterUtilities.UnitTests\Microsoft.TestPlatform.AdapterUtilities.UnitTests.csproj", "{DCD0C39E-C78C-4A44-B0BD-7325254A2E97}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.AdapterUtilities", "src\Microsoft.TestPlatform.AdapterUtilities\Microsoft.TestPlatform.AdapterUtilities.csproj", "{2DE99835-A3A3-4922-82AD-6D10D284816D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -699,30 +700,6 @@ Global {24C7683D-2607-4901-B8EB-83A57E49E93D}.Release|x64.Build.0 = Release|Any CPU {24C7683D-2607-4901-B8EB-83A57E49E93D}.Release|x86.ActiveCfg = Release|Any CPU {24C7683D-2607-4901-B8EB-83A57E49E93D}.Release|x86.Build.0 = Release|Any CPU - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813}.Debug|Any CPU.Build.0 = Debug|Any CPU - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813}.Debug|x64.ActiveCfg = Debug|Any CPU - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813}.Debug|x64.Build.0 = Debug|Any CPU - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813}.Debug|x86.ActiveCfg = Debug|Any CPU - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813}.Debug|x86.Build.0 = Debug|Any CPU - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813}.Release|Any CPU.ActiveCfg = Release|Any CPU - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813}.Release|Any CPU.Build.0 = Release|Any CPU - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813}.Release|x64.ActiveCfg = Release|Any CPU - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813}.Release|x64.Build.0 = Release|Any CPU - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813}.Release|x86.ActiveCfg = Release|Any CPU - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813}.Release|x86.Build.0 = Release|Any CPU - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}.Debug|x64.ActiveCfg = Debug|Any CPU - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}.Debug|x64.Build.0 = Debug|Any CPU - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}.Debug|x86.ActiveCfg = Debug|Any CPU - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}.Debug|x86.Build.0 = Debug|Any CPU - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}.Release|Any CPU.Build.0 = Release|Any CPU - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}.Release|x64.ActiveCfg = Release|Any CPU - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}.Release|x64.Build.0 = Release|Any CPU - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}.Release|x86.ActiveCfg = Release|Any CPU - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3}.Release|x86.Build.0 = Release|Any CPU {69F5FF81-5615-4F06-B83C-FCF979BB84CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {69F5FF81-5615-4F06-B83C-FCF979BB84CA}.Debug|Any CPU.Build.0 = Debug|Any CPU {69F5FF81-5615-4F06-B83C-FCF979BB84CA}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -795,22 +772,34 @@ Global {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Release|x64.Build.0 = Release|Any CPU {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Release|x86.ActiveCfg = Release|Any CPU {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Release|x86.Build.0 = Release|Any CPU + {2DE99835-A3A3-4922-82AD-6D10D284816D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2DE99835-A3A3-4922-82AD-6D10D284816D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2DE99835-A3A3-4922-82AD-6D10D284816D}.Debug|x64.ActiveCfg = Debug|Any CPU + {2DE99835-A3A3-4922-82AD-6D10D284816D}.Debug|x64.Build.0 = Debug|Any CPU + {2DE99835-A3A3-4922-82AD-6D10D284816D}.Debug|x86.ActiveCfg = Debug|Any CPU + {2DE99835-A3A3-4922-82AD-6D10D284816D}.Debug|x86.Build.0 = Debug|Any CPU + {2DE99835-A3A3-4922-82AD-6D10D284816D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2DE99835-A3A3-4922-82AD-6D10D284816D}.Release|Any CPU.Build.0 = Release|Any CPU + {2DE99835-A3A3-4922-82AD-6D10D284816D}.Release|x64.ActiveCfg = Release|Any CPU + {2DE99835-A3A3-4922-82AD-6D10D284816D}.Release|x64.Build.0 = Release|Any CPU + {2DE99835-A3A3-4922-82AD-6D10D284816D}.Release|x86.ActiveCfg = Release|Any CPU + {2DE99835-A3A3-4922-82AD-6D10D284816D}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {50C00046-0DA3-4B5C-9F6F-7BE1145E156A} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} - {01409D95-A5F1-4EBE-94B1-909D5D2D0DC3} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} + {50C00046-0DA3-4B5C-9F6F-7BE1145E156A} = {7D4082EA-7AC9-4DFB-98E8-C5E08BDC0EC3} + {01409D95-A5F1-4EBE-94B1-909D5D2D0DC3} = {376C19DE-31E2-4FF6-88FC-0D0D6233C999} {2C7CE1F8-E73E-4987-8023-B5A0EBAC86E8} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} {6F5EC38C-4A11-40D3-827C-F607B90BEFF0} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} {5E7F18A8-F843-4C8A-AB02-4C7D9205C6CF} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} {E19B5128-3469-492E-82E1-725631C4A68C} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} - {68ADC720-316E-4895-9F8E-C3CCADD262BE} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} - {1621415E-7723-4F46-A589-4C4620C0751A} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} - {987898D9-724E-4324-BF91-77B1A6DBE8F1} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} - {FD63F778-3938-45D2-900B-51EC770F70E5} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} - {61F7F446-9EF3-4768-B33A-4D75F60E1059} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} + {68ADC720-316E-4895-9F8E-C3CCADD262BE} = {7D4082EA-7AC9-4DFB-98E8-C5E08BDC0EC3} + {1621415E-7723-4F46-A589-4C4620C0751A} = {7D4082EA-7AC9-4DFB-98E8-C5E08BDC0EC3} + {987898D9-724E-4324-BF91-77B1A6DBE8F1} = {7D4082EA-7AC9-4DFB-98E8-C5E08BDC0EC3} + {FD63F778-3938-45D2-900B-51EC770F70E5} = {7D4082EA-7AC9-4DFB-98E8-C5E08BDC0EC3} + {61F7F446-9EF3-4768-B33A-4D75F60E1059} = {7D4082EA-7AC9-4DFB-98E8-C5E08BDC0EC3} {D5296435-3A3F-4B1A-81D1-434EC9E97DEF} = {5E7F18A8-F843-4C8A-AB02-4C7D9205C6CF} {790B8030-00C2-4121-B125-EDC4CE329BA3} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} {27DFBD04-64B2-4F1B-82B2-006620CCA6F8} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} @@ -820,12 +809,12 @@ Global {020E15EA-731F-4667-95AF-226671E0C3AE} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} {595BE9C1-E10F-4E50-938A-E6C248D3F950} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} {0D59BA81-6279-4650-AEBB-4EA735C28A1A} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} - {DE730F17-7D5C-4D9D-B479-025024BF4F1D} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} - {E062FFD6-DEB1-4DB4-8B6E-ADBF04129545} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} - {F582949D-8B92-47BD-9DD7-9F2BFCCC290C} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} - {376A7588-50DF-46CD-955B-0309F491D830} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} + {DE730F17-7D5C-4D9D-B479-025024BF4F1D} = {376C19DE-31E2-4FF6-88FC-0D0D6233C999} + {E062FFD6-DEB1-4DB4-8B6E-ADBF04129545} = {376C19DE-31E2-4FF6-88FC-0D0D6233C999} + {F582949D-8B92-47BD-9DD7-9F2BFCCC290C} = {376C19DE-31E2-4FF6-88FC-0D0D6233C999} + {376A7588-50DF-46CD-955B-0309F491D830} = {376C19DE-31E2-4FF6-88FC-0D0D6233C999} {5DF3CF65-3E11-4639-964D-7BEB4109DCF9} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} - {D3E8A13B-92EE-45A8-BB24-40EC3CC9DB34} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} + {D3E8A13B-92EE-45A8-BB24-40EC3CC9DB34} = {376C19DE-31E2-4FF6-88FC-0D0D6233C999} {9EFCEFB5-253E-4DE2-8A70-821D7B8189DF} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} {3A8080FB-9C93-45B9-8EB5-828DDC31FDF0} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} {BFF7714C-E5A3-4EEB-B04B-5FA47F29AD03} = {020E15EA-731F-4667-95AF-226671E0C3AE} @@ -847,7 +836,7 @@ Global {7B48115A-B766-4B55-93A8-C08A42C37710} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} {FBF74C8F-695C-4967-84AC-358EEFB1376D} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} {11ECCB8B-6958-42A7-BD58-88C09CB149B2} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} - {76D4BB7E-D981-42D5-BE96-6FAD8DEF9A4A} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} + {76D4BB7E-D981-42D5-BE96-6FAD8DEF9A4A} = {B705537C-B82C-4A30-AFA5-6244D9A7DAEB} {488675EC-C8BB-40E0-AD4F-91F623D548B3} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} {B705537C-B82C-4A30-AFA5-6244D9A7DAEB} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} {65A25D6E-C9CC-4F45-8925-04087AC82634} = {B705537C-B82C-4A30-AFA5-6244D9A7DAEB} @@ -856,14 +845,13 @@ Global {0D4DF78D-7E5F-4516-B19F-E6AA71A1DBF4} = {EE49F5DC-5835-4AE3-B3BA-8BDE0AD56330} {8C068694-23A2-47A2-A0DD-DB82D0AF0142} = {376C19DE-31E2-4FF6-88FC-0D0D6233C999} {24C7683D-2607-4901-B8EB-83A57E49E93D} = {376C19DE-31E2-4FF6-88FC-0D0D6233C999} - {32BD96BD-16FB-43F0-B952-E7EEDB6DD813} = {B705537C-B82C-4A30-AFA5-6244D9A7DAEB} - {A7E2261B-B2E6-4CBF-983F-E3A3FF8E52E3} = {D9A30E32-D466-4EC5-B4F2-62E17562279B} {69F5FF81-5615-4F06-B83C-FCF979BB84CA} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959} {E7D4921C-F12D-4E1C-85AC-8B7F91C59B0E} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} {236A71E3-01DA-4679-9DFF-16A8E079ACFF} = {5E7F18A8-F843-4C8A-AB02-4C7D9205C6CF} {41248B96-6E15-4E5E-A78F-859897676814} = {020E15EA-731F-4667-95AF-226671E0C3AE} - {074F5BD6-DC05-460B-B78F-044D125FD787} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} + {074F5BD6-DC05-460B-B78F-044D125FD787} = {D9A30E32-D466-4EC5-B4F2-62E17562279B} {DCD0C39E-C78C-4A44-B0BD-7325254A2E97} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} + {2DE99835-A3A3-4922-82AD-6D10D284816D} = {7D4082EA-7AC9-4DFB-98E8-C5E08BDC0EC3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0541B30C-FF51-4E28-B172-83F5F3934BCD} diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b8b5333e1d..e59f2b8b75 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -33,6 +33,13 @@ jobs: modifyEnvironment: false failOnStandardError: true + - task: PublishTestResults@2 + displayName: 'Publish Test Results **\*.trx' + inputs: + testResultsFormat: VSTest + testResultsFiles: '**\*.trx' + condition: succeededOrFailed() + - task: PublishPipelineArtifact@1 inputs: targetPath: '$(Build.SourcesDirectory)\artifacts' @@ -124,16 +131,25 @@ jobs: steps: - script: ./build.sh -c $(buildConfiguration) displayName: 'Build' + - script: ./test.sh -c $(buildConfiguration) -p Unit displayName: 'Unit tests' + - task: DownloadPipelineArtifact@2 inputs: buildType: 'current' artifactName: 'testArtifacts' targetPath: '$(Build.SourcesDirectory)/artifacts' + - script: ./tools/dotnet-linux/dotnet build -c $(buildConfiguration) ./test/TestAssets/TestAssets.sln displayName: 'Build test assets' + - script: ./test.sh -c $(buildConfiguration) -p Acceptance displayName: 'Acceptance tests' - - + + - task: PublishTestResults@2 + displayName: 'Publish Test Results **/*.trx' + inputs: + testResultsFormat: VSTest + testResultsFiles: '**/*.trx' + condition: succeededOrFailed() \ No newline at end of file diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 0ac3fbcb4b..bcc7c5c8a9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,25 +3,25 @@ - + https://github.com/dotnet/arcade - 1ceac96c54fcf33eb745649c4e7b8d7507a9b730 + 620462dd065490620c03a80cea8e251004f6bf21 - + https://github.com/dotnet/arcade - 1ceac96c54fcf33eb745649c4e7b8d7507a9b730 + 620462dd065490620c03a80cea8e251004f6bf21 - + https://github.com/dotnet/arcade - 1ceac96c54fcf33eb745649c4e7b8d7507a9b730 + 620462dd065490620c03a80cea8e251004f6bf21 - + https://github.com/dotnet/arcade - 1ceac96c54fcf33eb745649c4e7b8d7507a9b730 + 620462dd065490620c03a80cea8e251004f6bf21 - + https://github.com/dotnet/arcade - 1ceac96c54fcf33eb745649c4e7b8d7507a9b730 + 620462dd065490620c03a80cea8e251004f6bf21 https://github.com/dotnet/arcade-services @@ -36,7 +36,7 @@ - + https://github.com/dotnet/symreader-converter c5ba7c88f92e2dde156c324a8c8edc04d9fa4fe0 diff --git a/eng/Versions.props b/eng/Versions.props index e708d770fc..9c7b7e66bd 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -60,8 +60,8 @@ 2.4.1 2.0.3 2.4.1 - 2.2.0-beta.20570.10 - 1.0.0-beta.20570.10 + 2.2.0-beta.21072.7 + 1.0.0-beta.21072.7 1.22.0 1.1.2 2.0.0 @@ -73,7 +73,7 @@ 1.7.0 1.1.0-beta.19556.4 1.0.0-beta2-19554-01 - 1.0.0-beta.20570.10 + 1.0.0-beta.21072.7 1.0.0-beta.20055.1 + .NETFramework + v4.5.1 + + + + + + + + + + + + + diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/ManagedNameMessages.Designer.cs b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/Resources.Designer.cs similarity index 57% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/ManagedNameMessages.Designer.cs rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/Resources.Designer.cs index 266ad299d1..19827c698e 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/ManagedNameMessages.Designer.cs +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/Resources.Designer.cs @@ -1,118 +1,135 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Resources { - using System; +namespace Microsoft.TestPlatform.AdapterUtilities.Resources +{ using System.Reflection; /// /// A strongly-typed resource class, for looking up localized strings, etc. /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class ManagedNameMessages { - + internal class Resources + { + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal ManagedNameMessages() { + + internal Resources() + { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.VisualStudio.TestPlatform.ObjectModel.Resources.ManagedNameMessages", typeof(ManagedNameMessages).GetTypeInfo().Assembly); + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if (object.ReferenceEquals(resourceMan, null)) + { +#if NET20 || NET35 + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.TestPlatform.AdapterUtilities.Resources.Resources", typeof(Resources).Assembly); +#else + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.TestPlatform.AdapterUtilities.Resources.Resources", typeof(Resources).GetTypeInfo().Assembly); +#endif resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { + internal static global::System.Globalization.CultureInfo Culture + { + get + { return resourceCulture; } - set { + set + { resourceCulture = value; } } - + /// /// Looks up a localized string similar to ManagedName is incomplete. /// - internal static string ErrorIncompleteManagedName { - get { + internal static string ErrorIncompleteManagedName + { + get + { return ResourceManager.GetString("ErrorIncompleteManagedName", resourceCulture); } } - + /// /// Looks up a localized string similar to Method arity must be numeric. /// - internal static string ErrorMethodArityMustBeNumeric { - get { + internal static string ErrorMethodArityMustBeNumeric + { + get + { return ResourceManager.GetString("ErrorMethodArityMustBeNumeric", resourceCulture); } } - + /// /// Looks up a localized string similar to Method '{0}' not found on type '{1}'. /// - internal static string ErrorMethodNotFound { - get { + internal static string ErrorMethodNotFound + { + get + { return ResourceManager.GetString("ErrorMethodNotFound", resourceCulture); } } - + /// /// Looks up a localized string similar to Type '{0}' not found. /// - internal static string ErrorTypeNotFound { - get { + internal static string ErrorTypeNotFound + { + get + { return ResourceManager.GetString("ErrorTypeNotFound", resourceCulture); } } - + /// /// Looks up a localized string similar to Unexpected characters after the end of the ManagedName (pos: {0}). /// - internal static string ErrorUnexpectedCharactersAtEnd { - get { + internal static string ErrorUnexpectedCharactersAtEnd + { + get + { return ResourceManager.GetString("ErrorUnexpectedCharactersAtEnd", resourceCulture); } } - + /// /// Looks up a localized string similar to Whitespace is not valid in a ManagedName (pos: {0}). /// - internal static string ErrorWhitespaceNotValid { - get { + internal static string ErrorWhitespaceNotValid + { + get + { return ResourceManager.GetString("ErrorWhitespaceNotValid", resourceCulture); } } + + /// + /// Looks up a localized string similar to '{0}.{1}' is not implemented on this platform!. + /// + internal static string MethodNotImplementedOnPlatform + { + get + { + return ResourceManager.GetString("MethodNotImplementedOnPlatform", resourceCulture); + } + } } } diff --git a/src/DataCollectors/TraceDataCollector/Resources/Resources.resx b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/Resources.resx similarity index 81% rename from src/DataCollectors/TraceDataCollector/Resources/Resources.resx rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/Resources.resx index bec54d6610..da81725acf 100644 --- a/src/DataCollectors/TraceDataCollector/Resources/Resources.resx +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/Resources.resx @@ -117,22 +117,32 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Failed to create directory: {0} with error:{1} + + ManagedName is incomplete - - Failed to initialize code coverage datacollector with error: {0} + + Method arity must be numeric - - Running event not received from CodeCoverage.exe. Check eventlogs for failure reason. + + Method '{0}' not found on type '{1}' + {0} is the method name, {1} is the full type name. - - Cannot find CodeCoverage.exe at {0} + + Type '{0}' not found + {0} is the full type name. - - Failed to receive running event from CodeCoverage.exe in {0} seconds, This may occur due to machine slowness, please set environment variable {1} to increase timeout. + + Unexpected characters after the end of the ManagedName (pos: {0}) + {0} is the position of unexpected characters - - No code coverage data available. Code coverage is currently supported only on Windows. + + Whitespace is not valid in a ManagedName (pos: {0}) + {0} is the position of invalid whitespace + + + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.cs.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.cs.xlf similarity index 72% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.cs.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.cs.xlf index 22dd7bfd1a..77e0cf29b0 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.cs.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.cs.xlf @@ -1,10 +1,10 @@  - + ManagedName is incomplete - PlněKvalifikovanýNázev je neúplný. + Název ManagedName není úplný. @@ -24,14 +24,21 @@ Unexpected characters after the end of the ManagedName (pos: {0}) - Neočekávané znaky na konci položky PlněKvalifikovanýNázev (pos: {0}) + Neočekávané znaky na konci položky ManagedName (pozice: {0}) {0} is the position of unexpected characters Whitespace is not valid in a ManagedName (pos: {0}) - V položce PlněKvalifikovanýNázev není povolena mezera (pos: {0}). + V ManagedName se nepovoluje mezera (pozice: {0}). {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + Metoda {0}.{1} není na této platformě implementována. + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.de.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.de.xlf similarity index 72% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.de.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.de.xlf index 173142e423..cc3be8f402 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.de.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.de.xlf @@ -1,10 +1,10 @@  - + ManagedName is incomplete - ManagedName ist unvollständig. + ManagedName unvollständig @@ -24,14 +24,21 @@ Unexpected characters after the end of the ManagedName (pos: {0}) - Nach dem Ende von ManagedName (Pos: {0}) wurden unerwartete Zeichen gefunden. + Unerwartetes Zeichen nach dem Ende von ManagedName (Position: {0}). {0} is the position of unexpected characters Whitespace is not valid in a ManagedName (pos: {0}) - Leerzeichen sind in einem ManagedName (Pos: {0}) unzulässig. + Leerzeichen sind in einem ManagedName unzulässig (Position: {0}). {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + "{0}.{1}" ist auf dieser Plattform nicht implementiert! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.es.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.es.xlf similarity index 74% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.es.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.es.xlf index 61a0a28563..111e6b9dd4 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.es.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.es.xlf @@ -1,10 +1,10 @@  - + ManagedName is incomplete - ManagedName está incompleto + ManagedName está incompleto. @@ -24,14 +24,21 @@ Unexpected characters after the end of the ManagedName (pos: {0}) - Caracteres inesperados después del final de ManagedName (pos: {0}) + Caracteres inesperados después del final de ManagedName (posición: {0}) {0} is the position of unexpected characters Whitespace is not valid in a ManagedName (pos: {0}) - El espacio en blanco no es válido en un elemento ManagedName (pos: {0}) + El espacio en blanco no es válido en un elemento ManagedName (posición: {0}) {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + "{0}.{1}" no se ha implementado en esta plataforma. + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.fr.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.fr.xlf similarity index 77% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.fr.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.fr.xlf index 7f48d41414..13be1b762b 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.fr.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.fr.xlf @@ -1,6 +1,6 @@  - + ManagedName is incomplete @@ -24,14 +24,21 @@ Unexpected characters after the end of the ManagedName (pos: {0}) - Caractères inattendus après la fin du ManagedName (pos : {0}) + Caractères inattendus après la fin de ManagedName (pos. : {0}) {0} is the position of unexpected characters Whitespace is not valid in a ManagedName (pos: {0}) - Les espaces blancs ne sont pas valides dans un ManagedName (pos : {0}) + Les espaces blancs ne sont pas valides dans un ManagedName (pos. : {0}) {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' n'est pas implémenté sur cette plateforme ! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.it.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.it.xlf similarity index 82% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.it.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.it.xlf index cd33cbb7ea..1602378445 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.it.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.it.xlf @@ -1,6 +1,6 @@  - + ManagedName is incomplete @@ -32,6 +32,13 @@ Gli spazi vuoti non sono validi in un elemento ManagedName (pos.: {0}) {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' non è implementato in questa piattaforma. + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.ja.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.ja.xlf similarity index 72% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.ja.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.ja.xlf index 804c2891ba..2bc25ce3ae 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.ja.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.ja.xlf @@ -1,10 +1,10 @@  - + ManagedName is incomplete - ManagedName が不完全です。 + ManagedName が不完全です @@ -24,14 +24,21 @@ Unexpected characters after the end of the ManagedName (pos: {0}) - ManagedName (pos: {0}) の末尾の後ろに予期しない文字があります + ManagedName の末尾の後ろに予期しない文字があります (位置: {0}) {0} is the position of unexpected characters Whitespace is not valid in a ManagedName (pos: {0}) - ManagedName (pos: {0}) では空白は無効です + ManagedName では空白は無効です (位置: {0}) {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' はこのプラットフォームに実装されていません。 + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.ko.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.ko.xlf similarity index 78% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.ko.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.ko.xlf index f10f8d5bd8..2ef4e1cdc3 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.ko.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.ko.xlf @@ -1,10 +1,10 @@  - + ManagedName is incomplete - ManagedName이 불완전합니다. + ManagedName이 불완전함 @@ -32,6 +32,13 @@ ManagedName에서 공백은 유효하지 않습니다(pos: {0}). {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}'이(가)이 플랫폼에서 구현되지 않았습니다. + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.pl.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.pl.xlf similarity index 76% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.pl.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.pl.xlf index 33f316fc55..9f40119244 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.pl.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.pl.xlf @@ -1,10 +1,10 @@  - + ManagedName is incomplete - Wartość ManagedName jest niepełna + Wartość ManagedName jest niekompletna @@ -24,7 +24,7 @@ Unexpected characters after the end of the ManagedName (pos: {0}) - Nieoczekiwane znaki za końcem wartości ManagedName (pozycja: {0}) + Nieoczekiwane znaki po zakończeniu wartości ManagedName (pozycja: {0}) {0} is the position of unexpected characters @@ -32,6 +32,13 @@ Biały znak jest niedozwolony w wartości ManagedName (pozycja: {0}) {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + Element „{0}.{1}” nie jest zaimplementowany na tej platformie. + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.pt-BR.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.pt-BR.xlf similarity index 71% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.pt-BR.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.pt-BR.xlf index 0fa9a17b35..6e08e8348c 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.pt-BR.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.pt-BR.xlf @@ -1,10 +1,10 @@  - + ManagedName is incomplete - ManagedName está incompleto + O ManagedName está incompleto @@ -24,14 +24,21 @@ Unexpected characters after the end of the ManagedName (pos: {0}) - Caracteres inesperados após o fnal de ManagedName (pos: {0}) + Caracteres inesperados após o final de ManagedName (posição: {0}) {0} is the position of unexpected characters Whitespace is not valid in a ManagedName (pos: {0}) - Espaço em branco não é válido em um ManagedName (pos: {0}) + O espaço em branco não é válido em um ManagedName (posição: {0}) {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' não está implementado nesta plataforma. + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.ru.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.ru.xlf similarity index 71% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.ru.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.ru.xlf index 542202b6a2..98ab3c94da 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.ru.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.ru.xlf @@ -1,10 +1,10 @@  - + ManagedName is incomplete - ManagedName (Полное имя) содержит не все данные + ManagedName является неполным. @@ -24,14 +24,21 @@ Unexpected characters after the end of the ManagedName (pos: {0}) - Непредусмотренные символы после ManagedName (Полного имени), позиция: {0} + Неожиданные символы после окончания ManagedName (позиция: {0}). {0} is the position of unexpected characters Whitespace is not valid in a ManagedName (pos: {0}) - Пробел в ManagedName (Полном имени) недопустим, позиция: {0} + Пробел в ManagedName (позиция: {0}) не допускается. {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' bu platformda uygulanmıyor! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.tr.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.tr.xlf similarity index 70% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.tr.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.tr.xlf index 393b2edd77..fb6cc464b2 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.tr.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.tr.xlf @@ -1,10 +1,10 @@  - + ManagedName is incomplete - ManagedName eksik + ManagedName tamamlanmadı @@ -24,14 +24,21 @@ Unexpected characters after the end of the ManagedName (pos: {0}) - ManagedName’den sonra beklenmeyen karakterler (konum: {0}) + ManagedName'den sonra beklenmeyen karakterler var (konum: {0}) {0} is the position of unexpected characters Whitespace is not valid in a ManagedName (pos: {0}) - ManagedName’de boşluk geçersizdir (konum: {0}) + ManagedName'de boşluk geçersiz (konum: {0}) {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' bu platformda uygulanmıyor! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.xlf similarity index 74% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.xlf index 6b76894923..232d95bf2d 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.xlf @@ -1,6 +1,6 @@  - + ManagedName is incomplete @@ -26,6 +26,13 @@ Whitespace is not valid in a ManagedName (pos: {0}) {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.zh-Hans.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.zh-Hans.xlf similarity index 73% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.zh-Hans.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.zh-Hans.xlf index 2ed7fcaeab..2a3e79c29d 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.zh-Hans.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.zh-Hans.xlf @@ -1,6 +1,6 @@  - + ManagedName is incomplete @@ -24,14 +24,21 @@ Unexpected characters after the end of the ManagedName (pos: {0}) - ManagedName (pos: {0}) 末尾后有不需要的字符 + ManagedName 末尾后面有不需要的字符(位置: {0}) {0} is the position of unexpected characters Whitespace is not valid in a ManagedName (pos: {0}) - ManagedName (pos: {0}) 中空白无效 + ManagedName 中空白无效(位置: {0}) {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + 未在此平台上实现 "{0}.{1}"! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.zh-Hant.xlf b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.zh-Hant.xlf similarity index 73% rename from src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.zh-Hant.xlf rename to src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.zh-Hant.xlf index b3dcdd91cd..b722fc446f 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/ManagedNameMessages.zh-Hant.xlf +++ b/src/Microsoft.TestPlatform.AdapterUtilities/Resources/xlf/Resources.zh-Hant.xlf @@ -1,6 +1,6 @@  - + ManagedName is incomplete @@ -24,14 +24,21 @@ Unexpected characters after the end of the ManagedName (pos: {0}) - ManagedName (pos: {0}) 的結尾出現未預期的字元 + ManagedName 的結尾後出現非預期的字元 (位置: {0}) {0} is the position of unexpected characters Whitespace is not valid in a ManagedName (pos: {0}) - 空白字元在 ManagedName (pos: {0}) 中無效 + 空白字元在 ManagedName 中無效 (位置: {0}) {0} is the position of invalid whitespace + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' 未在此平台上實作! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Client/DesignMode/DesignModeClient.cs b/src/Microsoft.TestPlatform.Client/DesignMode/DesignModeClient.cs index 565cf31578..31812dacfa 100644 --- a/src/Microsoft.TestPlatform.Client/DesignMode/DesignModeClient.cs +++ b/src/Microsoft.TestPlatform.Client/DesignMode/DesignModeClient.cs @@ -9,6 +9,8 @@ namespace Microsoft.VisualStudio.TestPlatform.Client.DesignMode using System.Net; using System.Threading; using System.Threading.Tasks; + + using Microsoft.VisualStudio.TestPlatform.Client; using Microsoft.VisualStudio.TestPlatform.Client.TestRunAttachmentsProcessing; using Microsoft.VisualStudio.TestPlatform.Client.RequestHelper; using Microsoft.VisualStudio.TestPlatform.Common.Logging; @@ -17,11 +19,14 @@ namespace Microsoft.VisualStudio.TestPlatform.Client.DesignMode using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers; + using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Payloads; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; + using CommunicationUtilitiesResources = CommunicationUtilities.Resources.Resources; /// @@ -32,7 +37,7 @@ public class DesignModeClient : IDesignModeClient private readonly ICommunicationManager communicationManager; private readonly IDataSerializer dataSerializer; - private ProtocolConfig protocolConfig = Constants.DefaultProtocolConfig; + private ProtocolConfig protocolConfig = ObjectModel.Constants.DefaultProtocolConfig; private IEnvironment platformEnvironment; private TestSessionMessageLogger testSessionMessageLogger; private object lockObject = new object(); @@ -170,6 +175,20 @@ private void ProcessRequests(ITestRequestManager testRequestManager) break; } + case MessageType.StartTestSession: + { + var testSessionPayload = this.communicationManager.DeserializePayload(message); + this.StartTestSession(testSessionPayload, testRequestManager); + break; + } + + case MessageType.StopTestSession: + { + var testSessionInfo = this.communicationManager.DeserializePayload(message); + this.StopTestSession(testSessionInfo); + break; + } + case MessageType.StartDiscovery: { var discoveryPayload = this.dataSerializer.DeserializePayload(message); @@ -183,7 +202,7 @@ private void ProcessRequests(ITestRequestManager testRequestManager) var testRunPayload = this.communicationManager.DeserializePayload( message); - this.StartTestRun(testRunPayload, testRequestManager, skipTestHostLaunch: true); + this.StartTestRun(testRunPayload, testRequestManager, shouldLaunchTesthost: true); break; } @@ -193,7 +212,7 @@ private void ProcessRequests(ITestRequestManager testRequestManager) var testRunPayload = this.communicationManager.DeserializePayload( message); - this.StartTestRun(testRunPayload, testRequestManager, skipTestHostLaunch: false); + this.StartTestRun(testRunPayload, testRequestManager, shouldLaunchTesthost: false); break; } @@ -322,7 +341,7 @@ public bool AttachDebuggerToProcess(int pid, CancellationToken cancellationToken // If an attach request is issued but there is no support for attaching on the other // side of the communication channel, we simply return and let the caller know the // request failed. - if (this.protocolConfig.Version < Constants.MinimumProtocolVersionWithDebugSupport) + if (this.protocolConfig.Version < ObjectModel.Constants.MinimumProtocolVersionWithDebugSupport) { return false; } @@ -408,7 +427,7 @@ public void TestRunMessageHandler(object sender, TestRunMessageEventArgs e) } } - private void StartTestRun(TestRunRequestPayload testRunPayload, ITestRequestManager testRequestManager, bool skipTestHostLaunch) + private void StartTestRun(TestRunRequestPayload testRunPayload, ITestRequestManager testRequestManager, bool shouldLaunchTesthost) { Task.Run( () => @@ -417,8 +436,15 @@ private void StartTestRun(TestRunRequestPayload testRunPayload, ITestRequestMana { testRequestManager.ResetOptions(); - var customLauncher = skipTestHostLaunch ? - DesignModeTestHostLauncherFactory.GetCustomHostLauncherForTestRun(this, testRunPayload) : null; + // We must avoid re-launching the test host if the test run payload already + // contains test session info. Test session info being present is an indicative + // of an already running test host spawned by a start test session call. + var customLauncher = + shouldLaunchTesthost && testRunPayload.TestSessionInfo == null + ? DesignModeTestHostLauncherFactory.GetCustomHostLauncherForTestRun( + this, + testRunPayload.DebuggingEnabled) + : null; testRequestManager.RunTests(testRunPayload, customLauncher, new DesignModeTestEventsRegistrar(this), this.protocolConfig); } @@ -497,6 +523,53 @@ private void StartTestRunAttachmentsProcessing(TestRunAttachmentsProcessingPaylo }); } + private void StartTestSession(StartTestSessionPayload payload, ITestRequestManager requestManager) + { + Task.Run(() => + { + var eventsHandler = new TestSessionEventsHandler(this.communicationManager); + + try + { + var customLauncher = payload.HasCustomHostLauncher + ? DesignModeTestHostLauncherFactory.GetCustomHostLauncherForTestRun(this, payload.IsDebuggingEnabled) + : null; + + requestManager.ResetOptions(); + requestManager.StartTestSession(payload, customLauncher, eventsHandler, this.protocolConfig); + } + catch (Exception ex) + { + EqtTrace.Error("DesignModeClient: Exception in StartTestSession: " + ex); + + eventsHandler.HandleLogMessage(TestMessageLevel.Error, ex.ToString()); + eventsHandler.HandleStartTestSessionComplete(null); + } + }); + } + + private void StopTestSession(TestSessionInfo testSessionInfo) + { + Task.Run(() => + { + var eventsHandler = new TestSessionEventsHandler(this.communicationManager); + + try + { + var stopped = TestSessionPool.Instance.KillSession(testSessionInfo); + + eventsHandler.HandleStopTestSessionComplete(testSessionInfo, stopped); + } + catch (Exception ex) + { + EqtTrace.Error("DesignModeClient: Exception in StopTestSession: " + ex); + + eventsHandler.HandleLogMessage(TestMessageLevel.Error, ex.ToString()); + eventsHandler.HandleStopTestSessionComplete(testSessionInfo, false); + } + }); + } + #region IDisposable Support private bool disposedValue = false; // To detect redundant calls diff --git a/src/Microsoft.TestPlatform.Client/DesignMode/DesignModeTestHostLauncherFactory.cs b/src/Microsoft.TestPlatform.Client/DesignMode/DesignModeTestHostLauncherFactory.cs index 8edec80450..5b92bc54ba 100644 --- a/src/Microsoft.TestPlatform.Client/DesignMode/DesignModeTestHostLauncherFactory.cs +++ b/src/Microsoft.TestPlatform.Client/DesignMode/DesignModeTestHostLauncherFactory.cs @@ -14,11 +14,11 @@ public static class DesignModeTestHostLauncherFactory private static ITestHostLauncher defaultLauncher; private static ITestHostLauncher debugLauncher; - public static ITestHostLauncher GetCustomHostLauncherForTestRun(IDesignModeClient designModeClient, TestRunRequestPayload testRunRequestPayload) + public static ITestHostLauncher GetCustomHostLauncherForTestRun(IDesignModeClient designModeClient, bool debuggingEnabled) { ITestHostLauncher testHostLauncher = null; - if (!testRunRequestPayload.DebuggingEnabled) + if (!debuggingEnabled) { testHostLauncher = defaultLauncher = defaultLauncher ?? new DesignModeTestHostLauncher(designModeClient); } diff --git a/src/Microsoft.TestPlatform.Client/RequestHelper/ITestRequestManager.cs b/src/Microsoft.TestPlatform.Client/RequestHelper/ITestRequestManager.cs index 0a0e68e301..714e1df9cb 100644 --- a/src/Microsoft.TestPlatform.Client/RequestHelper/ITestRequestManager.cs +++ b/src/Microsoft.TestPlatform.Client/RequestHelper/ITestRequestManager.cs @@ -5,69 +5,105 @@ namespace Microsoft.VisualStudio.TestPlatform.Client.RequestHelper { using System; using System.Collections.Generic; - + using Microsoft.VisualStudio.TestPlatform.Client; using Microsoft.VisualStudio.TestPlatform.Common.Interfaces; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Payloads; /// - /// Defines the contract that command line + /// Defines the contract for running various requests. /// public interface ITestRequestManager : IDisposable { /// - /// Initializes the extensions while probing additional paths + /// Initializes the extensions while probing additional paths. /// - /// Paths to Additional extensions - /// Skip extension filtering by name (if true) - void InitializeExtensions(IEnumerable pathToAdditionalExtensions, bool skipExtensionFilters); + /// + /// Paths to additional extensions. + /// Skip extension filtering by name if true. + void InitializeExtensions( + IEnumerable pathToAdditionalExtensions, + bool skipExtensionFilters); /// - /// Resets Vstest.console.exe Options + /// Resets vstest.console.exe options. /// void ResetOptions(); /// - /// Discover Tests given a list of sources, runsettings + /// Discovers tests given a list of sources and some run settings. + /// + /// + /// Discovery payload. + /// Discovery events registrar. + /// Protocol related information. + void DiscoverTests( + DiscoveryRequestPayload discoveryPayload, + ITestDiscoveryEventsRegistrar disoveryEventsRegistrar, + ProtocolConfig protocolConfig); + + /// + /// Runs tests given a list of sources and some run settings. /// - /// Discovery payload - /// Discovery events registrar - registers and unregisters discovery events - /// Protocol related information - void DiscoverTests(DiscoveryRequestPayload discoveryPayload, ITestDiscoveryEventsRegistrar disoveryEventsRegistrar, ProtocolConfig protocolConfig); + /// + /// Test run request payload. + /// Custom test host launcher for the run. + /// Run events registrar. + /// Protocol related information. + void RunTests( + TestRunRequestPayload testRunRequestPayLoad, + ITestHostLauncher customTestHostLauncher, + ITestRunEventsRegistrar testRunEventsRegistrar, + ProtocolConfig protocolConfig); /// - /// Run Tests with given a test of sources + /// Processes test run attachments. /// - /// Test Run Request payload - /// Custom testHostLauncher for the run - /// RunEvents registrar - /// Protocol related information - void RunTests(TestRunRequestPayload testRunRequestPayLoad, ITestHostLauncher customTestHostLauncher, ITestRunEventsRegistrar testRunEventsRegistrar, ProtocolConfig protocolConfig); + /// + /// + /// Test run attachments processing payload. + /// + /// + /// Test run attachments processing events handler. + /// + /// Protocol related information. + void ProcessTestRunAttachments( + TestRunAttachmentsProcessingPayload testRunAttachmentsProcessingPayload, + ITestRunAttachmentsProcessingEventsHandler testRunAttachmentsProcessingEventsHandler, + ProtocolConfig protocolConfig); /// - /// Processes test run attachments + /// Starts a test session. /// - /// Test run attachments processing payload - /// Test run attachments processing events handler - void ProcessTestRunAttachments(TestRunAttachmentsProcessingPayload testRunAttachmentsProcessingPayload, ITestRunAttachmentsProcessingEventsHandler testRunAttachmentsProcessingEventsHandler, ProtocolConfig protocolConfig); + /// + /// The start test session payload. + /// The custom test host launcher. + /// The events handler. + /// Protocol related information. + void StartTestSession( + StartTestSessionPayload payload, + ITestHostLauncher testHostLauncher, + ITestSessionEventsHandler eventsHandler, + ProtocolConfig protocolConfig); /// - /// Cancel the current TestRun request + /// Cancel the current test run request. /// void CancelTestRun(); /// - /// Abort the current TestRun + /// Abort the current test run. /// void AbortTestRun(); /// - /// Cancels the current discovery request + /// Cancels the current discovery request. /// void CancelDiscovery(); /// - /// Cancels the current test run attachments processing request + /// Cancels the current test run attachments processing request. /// void CancelTestRunAttachmentsProcessing(); } diff --git a/src/Microsoft.TestPlatform.Client/TestPlatform.cs b/src/Microsoft.TestPlatform.Client/TestPlatform.cs index 8a24a51a4f..1f2915f065 100644 --- a/src/Microsoft.TestPlatform.Client/TestPlatform.cs +++ b/src/Microsoft.TestPlatform.Client/TestPlatform.cs @@ -29,7 +29,7 @@ namespace Microsoft.VisualStudio.TestPlatform.Client using ClientResources = Resources.Resources; /// - /// Implementation for TestPlatform + /// Implementation for TestPlatform. /// internal class TestPlatform : ITestPlatform { @@ -39,32 +39,34 @@ internal class TestPlatform : ITestPlatform static TestPlatform() { - // TODO This is not the right away to force initialization of default extensions. Test runtime providers - // require this today. They're getting initialized even before test adapter paths are provided, which is - // incorrect. + // TODO: This is not the right way to force initialization of default extensions. + // Test runtime providers require this today. They're getting initialized even before + // test adapter paths are provided, which is incorrect. AddExtensionAssembliesFromExtensionDirectory(); } /// /// Initializes a new instance of the class. /// - public TestPlatform() : this(new TestEngine(), new FileHelper(), TestRuntimeProviderManager.Instance) + public TestPlatform() + : this( + new TestEngine(), + new FileHelper(), + TestRuntimeProviderManager.Instance) { } /// /// Initializes a new instance of the class. /// - /// - /// The test engine. - /// - /// - /// The file helper. - /// - /// - /// The data. - /// - protected TestPlatform(ITestEngine testEngine, IFileHelper filehelper, TestRuntimeProviderManager testHostProviderManager) + /// + /// The test engine. + /// The file helper. + /// The data. + protected TestPlatform( + ITestEngine testEngine, + IFileHelper filehelper, + TestRuntimeProviderManager testHostProviderManager) { this.TestEngine = testEngine; this.fileHelper = filehelper; @@ -72,36 +74,32 @@ protected TestPlatform(ITestEngine testEngine, IFileHelper filehelper, TestRunti } /// - /// Gets or sets Test Engine instance + /// Gets or sets the test engine instance. /// private ITestEngine TestEngine { get; set; } - /// - /// The create discovery request. - /// - /// Request data. - /// The discovery criteria. - /// Test platform options. - /// The . - /// Throws if parameter is null. - public IDiscoveryRequest CreateDiscoveryRequest(IRequestData requestData, DiscoveryCriteria discoveryCriteria, TestPlatformOptions options) + /// + public IDiscoveryRequest CreateDiscoveryRequest( + IRequestData requestData, + DiscoveryCriteria discoveryCriteria, + TestPlatformOptions options) { if (discoveryCriteria == null) { throw new ArgumentNullException(nameof(discoveryCriteria)); } - // Update cache with Extension Folder's files + // Update cache with Extension folder's files. this.AddExtensionAssemblies(discoveryCriteria.RunSettings); // Update extension assemblies from source when design mode is false. var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(discoveryCriteria.RunSettings); - if (runConfiguration.DesignMode == false) + if (!runConfiguration.DesignMode) { this.AddExtensionAssembliesFromSource(discoveryCriteria.Sources); } - // Initialize loggers + // Initialize loggers. var loggerManager = this.TestEngine.GetLoggerManager(requestData); loggerManager.Initialize(discoveryCriteria.RunSettings); @@ -116,15 +114,11 @@ public IDiscoveryRequest CreateDiscoveryRequest(IRequestData requestData, Discov return new DiscoveryRequest(requestData, discoveryCriteria, discoveryManager, loggerManager); } - /// - /// The create test run request. - /// - /// Request data. - /// The test run criteria. - /// Test platform options. - /// The . - /// Throws if parameter is null. - public ITestRunRequest CreateTestRunRequest(IRequestData requestData, TestRunCriteria testRunCriteria, TestPlatformOptions options) + /// + public ITestRunRequest CreateTestRunRequest( + IRequestData requestData, + TestRunCriteria testRunCriteria, + TestPlatformOptions options) { if (testRunCriteria == null) { @@ -141,7 +135,7 @@ public ITestRunRequest CreateTestRunRequest(IRequestData requestData, TestRunCri this.AddExtensionAssembliesFromSource(testRunCriteria); } - // Initialize loggers + // Initialize loggers. var loggerManager = this.TestEngine.GetLoggerManager(requestData); loggerManager.Initialize(testRunCriteria.TestRunSettings); @@ -150,6 +144,7 @@ public ITestRunRequest CreateTestRunRequest(IRequestData requestData, TestRunCri testHostManager.Initialize(TestSessionMessageLogger.Instance, testRunCriteria.TestRunSettings); + // NOTE: The custom launcher should not be set when we have test session info available. if (testRunCriteria.TestHostLauncher != null) { testHostManager.SetCustomLauncher(testRunCriteria.TestHostLauncher); @@ -161,6 +156,60 @@ public ITestRunRequest CreateTestRunRequest(IRequestData requestData, TestRunCri return new TestRunRequest(requestData, testRunCriteria, executionManager, loggerManager); } + /// + public void StartTestSession( + IRequestData requestData, + StartTestSessionCriteria testSessionCriteria, + ITestSessionEventsHandler eventsHandler) + { + if (testSessionCriteria == null) + { + throw new ArgumentNullException(nameof(testSessionCriteria)); + } + + this.AddExtensionAssemblies(testSessionCriteria.RunSettings); + + var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(testSessionCriteria.RunSettings); + + // Update extension assemblies from source when design mode is false. + // + // TODO (copoiena): Is it possible for this code to run if we're not in design mode ? + // An use case for this would be when running tests with "dotnet test". Usually there's + // a build involved then. + if (!runConfiguration.DesignMode) + { + return; + } + + // Initialize loggers. + var loggerManager = this.TestEngine.GetLoggerManager(requestData); + loggerManager.Initialize(testSessionCriteria.RunSettings); + + var testHostManager = this.testHostProviderManager.GetTestHostManagerByRunConfiguration(testSessionCriteria.RunSettings); + ThrowExceptionIfTestHostManagerIsNull(testHostManager, testSessionCriteria.RunSettings); + + testHostManager.Initialize(TestSessionMessageLogger.Instance, testSessionCriteria.RunSettings); + + if (testSessionCriteria.TestHostLauncher != null) + { + testHostManager.SetCustomLauncher(testSessionCriteria.TestHostLauncher); + } + + var testSessionManager = this.TestEngine.GetTestSessionManager(requestData, testHostManager, testSessionCriteria); + if (testSessionManager == null) + { + // The test session manager is null because the combination of runsettings and + // sources tells us we should run in-process (i.e. in vstest.console). Because + // of this no session will be created because there's no testhost to be launched. + // Expecting a subsequent call to execute tests with the same set of parameters. + eventsHandler.HandleStartTestSessionComplete(null); + return; + } + + testSessionManager.Initialize(false); + testSessionManager.StartSession(testSessionCriteria, eventsHandler); + } + /// /// The dispose. /// @@ -169,25 +218,23 @@ public void Dispose() throw new NotImplementedException(); } - /// - /// The update extensions. - /// - /// The path to additional extensions. - /// Skips filtering by name (if true). - public void UpdateExtensions(IEnumerable pathToAdditionalExtensions, bool skipExtensionFilters) + /// + public void UpdateExtensions( + IEnumerable pathToAdditionalExtensions, + bool skipExtensionFilters) { this.TestEngine.GetExtensionManager().UseAdditionalExtensions(pathToAdditionalExtensions, skipExtensionFilters); } - /// - /// Clears the cached extensions - /// + /// public void ClearExtensions() { this.TestEngine.GetExtensionManager().ClearExtensions(); } - private void ThrowExceptionIfTestHostManagerIsNull(ITestRuntimeProvider testHostManager, string settingXml) + private void ThrowExceptionIfTestHostManagerIsNull( + ITestRuntimeProvider testHostManager, + string settingXml) { if (testHostManager == null) { @@ -197,11 +244,11 @@ private void ThrowExceptionIfTestHostManagerIsNull(ITestRuntimeProvider testHost } /// - /// Update the test adapter paths provided through run settings to be used by the test service + /// Updates the test adapter paths provided through run settings to be used by the test + /// service. /// - /// - /// The run Settings. - /// + /// + /// The run settings. private void AddExtensionAssemblies(string runSettings) { IEnumerable customTestAdaptersPaths = RunSettingsUtilities.GetTestAdaptersPaths(runSettings); @@ -221,11 +268,14 @@ private void AddExtensionAssemblies(string runSettings) continue; } - var extensionAssemblies = new List(this.fileHelper.EnumerateFiles(adapterPath, SearchOption.AllDirectories, - TestPlatformConstants.TestAdapterEndsWithPattern, - TestPlatformConstants.TestLoggerEndsWithPattern, - TestPlatformConstants.DataCollectorEndsWithPattern, - TestPlatformConstants.RunTimeEndsWithPattern)); + var extensionAssemblies = new List( + this.fileHelper.EnumerateFiles( + adapterPath, + SearchOption.AllDirectories, + TestPlatformConstants.TestAdapterEndsWithPattern, + TestPlatformConstants.TestLoggerEndsWithPattern, + TestPlatformConstants.DataCollectorEndsWithPattern, + TestPlatformConstants.RunTimeEndsWithPattern)); if (extensionAssemblies.Count > 0) { @@ -236,17 +286,16 @@ private void AddExtensionAssemblies(string runSettings) } /// - /// Update the extension assemblies from source directory + /// Updates the extension assemblies from source directory. /// - /// - /// The test Run Criteria. - /// + /// + /// The test run criteria. private void AddExtensionAssembliesFromSource(TestRunCriteria testRunCriteria) { IEnumerable sources = testRunCriteria.Sources; if (testRunCriteria.HasSpecificTests) { - // If the test execution is with a test filter, group them by sources + // If the test execution is with a test filter, group them by sources. sources = testRunCriteria.Tests.Select(tc => tc.Source).Distinct(); } @@ -254,20 +303,26 @@ private void AddExtensionAssembliesFromSource(TestRunCriteria testRunCriteria) } /// - /// Update the test logger paths from source directory + /// Updates the test logger paths from source directory. /// - /// + /// + /// The list of sources. private void AddExtensionAssembliesFromSource(IEnumerable sources) { - // Currently we support discovering loggers only from Source directory + // Currently we support discovering loggers only from Source directory. var loggersToUpdate = new List(); foreach (var source in sources) { var sourceDirectory = Path.GetDirectoryName(source); - if (!string.IsNullOrEmpty(sourceDirectory) && this.fileHelper.DirectoryExists(sourceDirectory)) + if (!string.IsNullOrEmpty(sourceDirectory) + && this.fileHelper.DirectoryExists(sourceDirectory)) { - loggersToUpdate.AddRange(this.fileHelper.EnumerateFiles(sourceDirectory, SearchOption.TopDirectoryOnly, TestPlatformConstants.TestLoggerEndsWithPattern)); + loggersToUpdate.AddRange( + this.fileHelper.EnumerateFiles( + sourceDirectory, + SearchOption.TopDirectoryOnly, + TestPlatformConstants.TestLoggerEndsWithPattern)); } } @@ -278,16 +333,26 @@ private void AddExtensionAssembliesFromSource(IEnumerable sources) } /// - /// Find all test platform extensions from the `.\Extensions` directory. This is used to load the inbox extensions like - /// Trx logger and legacy test extensions like mstest v1, mstest c++ etc.. + /// Finds all test platform extensions from the `.\Extensions` directory. This is used to + /// load the inbox extensions like TrxLogger and legacy test extensions like MSTest v1, + /// MSTest C++, etc.. /// private static void AddExtensionAssembliesFromExtensionDirectory() { var fileHelper = new FileHelper(); - var extensionsFolder = Path.Combine(Path.GetDirectoryName(typeof(TestPlatform).GetTypeInfo().Assembly.GetAssemblyLocation()), "Extensions"); + var extensionsFolder = Path.Combine( + Path.GetDirectoryName( + typeof(TestPlatform).GetTypeInfo().Assembly.GetAssemblyLocation()), + "Extensions"); + if (fileHelper.DirectoryExists(extensionsFolder)) { - var defaultExtensionPaths = fileHelper.EnumerateFiles(extensionsFolder, SearchOption.TopDirectoryOnly, ".dll", ".exe"); + var defaultExtensionPaths = fileHelper.EnumerateFiles( + extensionsFolder, + SearchOption.TopDirectoryOnly, + ".dll", + ".exe"); + TestPluginCache.Instance.DefaultExtensionPaths = defaultExtensionPaths; } } diff --git a/src/Microsoft.TestPlatform.Client/TestSession/TestSessionEventsHandler.cs b/src/Microsoft.TestPlatform.Client/TestSession/TestSessionEventsHandler.cs new file mode 100644 index 0000000000..d5eaa5e6cc --- /dev/null +++ b/src/Microsoft.TestPlatform.Client/TestSession/TestSessionEventsHandler.cs @@ -0,0 +1,72 @@ +// 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.Client +{ + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Payloads; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; + + /// + /// Defines the way in which test session events should be handled. + /// + internal class TestSessionEventsHandler : ITestSessionEventsHandler + { + private readonly ICommunicationManager communicationManager; + + /// + /// Creates an instance of the current class. + /// + /// + /// + /// The communication manager used for passing messages around. + /// + public TestSessionEventsHandler(ICommunicationManager communicationManager) + { + this.communicationManager = communicationManager; + } + + /// + public void HandleStartTestSessionComplete(TestSessionInfo testSessionInfo) + { + var ackPayload = new StartTestSessionAckPayload() + { + TestSessionInfo = testSessionInfo + }; + + this.communicationManager.SendMessage(MessageType.StartTestSessionCallback, ackPayload); + } + + /// + public void HandleStopTestSessionComplete(TestSessionInfo testSessionInfo, bool stopped) + { + var ackPayload = new StopTestSessionAckPayload() + { + TestSessionInfo = testSessionInfo, + IsStopped = stopped + }; + + this.communicationManager.SendMessage(MessageType.StopTestSessionCallback, ackPayload); + } + + /// + public void HandleLogMessage(TestMessageLevel level, string message) + { + var messagePayload = new TestMessagePayload() + { + MessageLevel = level, + Message = message + }; + + this.communicationManager.SendMessage(MessageType.TestMessage, messagePayload); + } + + /// + public void HandleRawMessage(string rawMessage) + { + // No-op. + } + } +} diff --git a/src/Microsoft.TestPlatform.Common/DataCollection/AfterTestRunEndResult.cs b/src/Microsoft.TestPlatform.Common/DataCollection/AfterTestRunEndResult.cs new file mode 100644 index 0000000000..1c65bb13d6 --- /dev/null +++ b/src/Microsoft.TestPlatform.Common/DataCollection/AfterTestRunEndResult.cs @@ -0,0 +1,38 @@ +// 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.Common.DataCollection +{ + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Runtime.Serialization; + + /// + /// Payload object that is used to exchange data between datacollector process and runner process. + /// + [DataContract] + public class AfterTestRunEndResult + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The collection of attachment sets. + /// + /// + /// The metrics. + /// + public AfterTestRunEndResult(Collection attachmentSets, IDictionary metrics) + { + this.AttachmentSets = attachmentSets; + this.Metrics = metrics; + } + + [DataMember] + public Collection AttachmentSets { get; private set; } + + [DataMember] + public IDictionary Metrics { get; private set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Common/DataCollection/DataCollectionManager.cs b/src/Microsoft.TestPlatform.Common/DataCollection/DataCollectionManager.cs index fe3d2aa44c..401782efd3 100644 --- a/src/Microsoft.TestPlatform.Common/DataCollection/DataCollectionManager.cs +++ b/src/Microsoft.TestPlatform.Common/DataCollection/DataCollectionManager.cs @@ -8,12 +8,12 @@ namespace Microsoft.VisualStudio.TestPlatform.Common.DataCollector using System.Collections.ObjectModel; using System.Globalization; using System.Linq; - using Microsoft.VisualStudio.TestPlatform.Common.DataCollector.Interfaces; using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework; using Microsoft.VisualStudio.TestPlatform.Common.Logging; using Microsoft.VisualStudio.TestPlatform.Common.Utilities; using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; @@ -61,13 +61,18 @@ internal class DataCollectionManager : IDataCollectionManager /// private DataCollectorExtensionManager dataCollectorExtensionManager; + /// + /// Request data + /// + private IDataCollectionTelemetryManager dataCollectionTelemetryManager; + /// /// Initializes a new instance of the class. /// /// /// The message Sink. /// - internal DataCollectionManager(IMessageSink messageSink) : this(new DataCollectionAttachmentManager(), messageSink) + internal DataCollectionManager(IMessageSink messageSink, IRequestData requestData) : this(new DataCollectionAttachmentManager(), messageSink, new DataCollectionTelemetryManager(requestData)) { } @@ -83,13 +88,14 @@ internal DataCollectionManager(IMessageSink messageSink) : this(new DataCollecti /// /// The constructor is not public because the factory method should be used to get instances of this class. /// - protected DataCollectionManager(IDataCollectionAttachmentManager datacollectionAttachmentManager, IMessageSink messageSink) + protected DataCollectionManager(IDataCollectionAttachmentManager datacollectionAttachmentManager, IMessageSink messageSink, IDataCollectionTelemetryManager dataCollectionTelemetryManager) { this.attachmentManager = datacollectionAttachmentManager; this.messageSink = messageSink; this.events = new TestPlatformDataCollectionEvents(); this.dataCollectorExtensionManager = null; this.RunDataCollectors = new Dictionary(); + this.dataCollectionTelemetryManager = dataCollectionTelemetryManager; } /// @@ -128,7 +134,7 @@ private DataCollectorExtensionManager DataCollectorExtensionManager /// /// The . /// - public static DataCollectionManager Create(IMessageSink messageSink) + public static DataCollectionManager Create(IMessageSink messageSink, IRequestData requestData) { if (Instance == null) { @@ -136,7 +142,7 @@ public static DataCollectionManager Create(IMessageSink messageSink) { if (Instance == null) { - Instance = new DataCollectionManager(messageSink); + Instance = new DataCollectionManager(messageSink, requestData); } } } @@ -673,6 +679,8 @@ private void AddCollectorEnvironmentVariables( dataCollectionWrapper.Logger.LogError(this.dataCollectionEnvironmentContext.SessionDataCollectionContext, message); } } + + dataCollectionTelemetryManager.RecordEnvironmentVariableConflict(dataCollectionWrapper, namevaluepair.Key, namevaluepair.Value, alreadyRequestedVariable.Value); } else { @@ -685,6 +693,8 @@ private void AddCollectorEnvironmentVariables( dataCollectorEnvironmentVariables.Add( namevaluepair.Key, new DataCollectionEnvironmentVariable(namevaluepair, collectorFriendlyName)); + + dataCollectionTelemetryManager.RecordEnvironmentVariableAddition(dataCollectionWrapper, namevaluepair.Key, namevaluepair.Value); } } } diff --git a/src/Microsoft.TestPlatform.Common/DataCollection/DataCollectionTelemetryManager.cs b/src/Microsoft.TestPlatform.Common/DataCollection/DataCollectionTelemetryManager.cs new file mode 100644 index 0000000000..9396a17dc0 --- /dev/null +++ b/src/Microsoft.TestPlatform.Common/DataCollection/DataCollectionTelemetryManager.cs @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.VisualStudio.TestPlatform.Common.DataCollector.Interfaces; +using Microsoft.VisualStudio.TestPlatform.Common.Telemetry; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; +using System; +using System.Linq; + +namespace Microsoft.VisualStudio.TestPlatform.Common.DataCollector +{ + /// + /// Stores and provides telemetry information for data collection. + /// + internal class DataCollectionTelemetryManager : IDataCollectionTelemetryManager + { + private const string CorProfilerVariable = "COR_PROFILER"; + private const string CoreClrProfilerVariable = "CORECLR_PROFILER"; + private const string ClrIeInstrumentationMethodConfigurationPrefix32Variable = "MicrosoftInstrumentationEngine_ConfigPath32_"; + private const string ClrIeInstrumentationMethodConfigurationPrefix64Variable = "MicrosoftInstrumentationEngine_ConfigPath64_"; + + private static readonly Guid ClrIeProfilerGuid = Guid.Parse("{324f817a-7420-4e6d-b3c1-143fbed6d855}"); + private const string OverwrittenProfilerName = "overwritten"; + + private readonly IRequestData requestData; + + internal DataCollectionTelemetryManager(IRequestData requestData) + { + this.requestData = requestData; + } + + /// + public void RecordEnvironmentVariableAddition(DataCollectorInformation dataCollectorInformation, string name, string value) + { + RecordProfilerMetricForNewVariable(CorProfilerVariable, TelemetryDataConstants.DataCollectorsCorProfiler, dataCollectorInformation, name, value); + RecordProfilerMetricForNewVariable(CoreClrProfilerVariable, TelemetryDataConstants.DataCollectorsCoreClrProfiler, dataCollectorInformation, name, value); + } + + /// + public void RecordEnvironmentVariableConflict(DataCollectorInformation dataCollectorInformation, string name, string value, string existingValue) + { + RecordProfilerMetricForConflictedVariable(CorProfilerVariable, TelemetryDataConstants.DataCollectorsCorProfiler, dataCollectorInformation, name, value, existingValue); + RecordProfilerMetricForConflictedVariable(CoreClrProfilerVariable, TelemetryDataConstants.DataCollectorsCoreClrProfiler, dataCollectorInformation, name, value, existingValue); + } + + private void RecordProfilerMetricForNewVariable(string profilerVariable, string telemetryPrefix, DataCollectorInformation dataCollectorInformation, string name, string value) + { + if (!string.Equals(profilerVariable, name, StringComparison.Ordinal)) + { + return; + } + + requestData.MetricsCollection.Add(GetTelemetryKey(telemetryPrefix, dataCollectorInformation), GetProfilerGuid(value).ToString()); + } + + private void RecordProfilerMetricForConflictedVariable(string profilerVariable, string telemetryPrefix, DataCollectorInformation dataCollectorInformation, string name, string value, string existingValue) + { + // If data collector is requesting same profiler record it same as new + if (string.Equals(value, existingValue, StringComparison.OrdinalIgnoreCase)) + { + RecordProfilerMetricForNewVariable(profilerVariable, telemetryPrefix, dataCollectorInformation, name, value); + return; + } + + if (!string.Equals(profilerVariable, name, StringComparison.Ordinal)) + { + return; + } + + var existingProfilerGuid = GetProfilerGuid(existingValue); + + if (ClrIeProfilerGuid == existingProfilerGuid) + { + if (dataCollectorInformation.TestExecutionEnvironmentVariables != null && + dataCollectorInformation.TestExecutionEnvironmentVariables.Any(pair => pair.Key.StartsWith(ClrIeInstrumentationMethodConfigurationPrefix32Variable)) && + dataCollectorInformation.TestExecutionEnvironmentVariables.Any(pair => pair.Key.StartsWith(ClrIeInstrumentationMethodConfigurationPrefix64Variable))) + { + requestData.MetricsCollection.Add(GetTelemetryKey(telemetryPrefix, dataCollectorInformation), ClrIeProfilerGuid.ToString()); + return; + } + } + + requestData.MetricsCollection.Add(GetTelemetryKey(telemetryPrefix, dataCollectorInformation), $"{existingProfilerGuid}({OverwrittenProfilerName}:{GetProfilerGuid(value)})"); + } + + private static Guid GetProfilerGuid(string profilerGuid) + { + Guid guid; + if (Guid.TryParse(profilerGuid, out guid)) + { + return guid; + } + + return Guid.Empty; + } + + private static string GetTelemetryKey(string telemetryPrefix, DataCollectorInformation dataCollectorInformation) + { + return string.Format("{0}.{1}", telemetryPrefix, dataCollectorInformation.DataCollectorConfig?.TypeUri?.ToString()); + } + } +} diff --git a/src/Microsoft.TestPlatform.Common/DataCollection/Interfaces/IDataCollectionTelemetryManager.cs b/src/Microsoft.TestPlatform.Common/DataCollection/Interfaces/IDataCollectionTelemetryManager.cs new file mode 100644 index 0000000000..9bc3550914 --- /dev/null +++ b/src/Microsoft.TestPlatform.Common/DataCollection/Interfaces/IDataCollectionTelemetryManager.cs @@ -0,0 +1,42 @@ +// 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.Common.DataCollector.Interfaces +{ + /// + /// The IDataCollectionTelemetryManager Interface. + /// + internal interface IDataCollectionTelemetryManager + { + /// + /// Record telemetry regarding environment variable added. + /// + /// + /// Data collector information which requested environment variable. + /// + /// + /// Environment variable name. + /// + /// + /// Environment variable value. + /// + void RecordEnvironmentVariableAddition(DataCollectorInformation dataCollectorInformation, string name, string value); + + /// + /// Record telemetry regarding environment variable is conflicting. + /// + /// + /// Data collector information which requested environment variable. + /// + /// + /// Environment variable name. + /// + /// + /// Environment variable value. + /// + /// + /// Environment variable value that was requested previously. + /// + void RecordEnvironmentVariableConflict(DataCollectorInformation dataCollectorInformation, string name, string value, string existingValue); + } +} diff --git a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginDiscoverer.cs b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginDiscoverer.cs index 3d845df33a..f08f565394 100644 --- a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginDiscoverer.cs +++ b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginDiscoverer.cs @@ -18,6 +18,7 @@ namespace Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; using CommonResources = Resources.Resources; + using Microsoft.VisualStudio.TestPlatform.Common.Utilities; /// /// Discovers test extensions in a directory. @@ -108,8 +109,6 @@ private void AddKnownExtensions(ref IEnumerable extensionPaths) /// /// Test plugins collection to add to. /// - [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We would like to continue discovering all plugins even if some dll in Extensions folder is not able to be load properly")] private void GetTestExtensionsFromFiles( string[] files, Dictionary pluginInfos) where TPluginInfo : TestPluginInformation @@ -167,13 +166,10 @@ private void GetTestExtensionsFromAssembly(Assembly ass Type extension = typeof(TExtension); try - { - var customAttribute = CustomAttributeExtensions.GetCustomAttribute(assembly, typeof(TypesToLoadAttribute)) as TypesToLoadAttribute; - if (customAttribute != null) - { - types = customAttribute.Types; - } - else + { + types = TypesToLoadUtilities.GetTypesToLoad(assembly); + + if (!types.Any()) { types = assembly.GetTypes().Where(type => type.GetTypeInfo().IsClass && !type.GetTypeInfo().IsAbstract); } diff --git a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginManager.cs b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginManager.cs index ae780aa7a3..b322d75fd7 100644 --- a/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginManager.cs +++ b/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginManager.cs @@ -5,7 +5,6 @@ namespace Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework { using System; using System.Collections.Generic; - using System.Diagnostics; using System.Reflection; using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.Utilities; diff --git a/src/Microsoft.TestPlatform.Common/Friends.cs b/src/Microsoft.TestPlatform.Common/Friends.cs index e767fb98ad..fb645969e2 100644 --- a/src/Microsoft.TestPlatform.Common/Friends.cs +++ b/src/Microsoft.TestPlatform.Common/Friends.cs @@ -24,5 +24,5 @@ [assembly: InternalsVisibleTo("Microsoft.TestPlatform.Client.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] [assembly: InternalsVisibleTo("Microsoft.TestPlatform.Extensions.BlameDataCollector.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] [assembly: InternalsVisibleTo("Microsoft.TestPlatform.TestUtilities, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] - +[assembly: InternalsVisibleTo("Microsoft.TestPlatform.AcceptanceTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] #endregion \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Common/Interfaces/Engine/ClientProtocol/IProxyTestSessionManager.cs b/src/Microsoft.TestPlatform.Common/Interfaces/Engine/ClientProtocol/IProxyTestSessionManager.cs new file mode 100644 index 0000000000..415974639d --- /dev/null +++ b/src/Microsoft.TestPlatform.Common/Interfaces/Engine/ClientProtocol/IProxyTestSessionManager.cs @@ -0,0 +1,38 @@ +// 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.ObjectModel.Engine +{ + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; + + /// + /// Orchestrates test session related functionality for the engine communicating with the + /// client. + /// + public interface IProxyTestSessionManager + { + /// + /// Initialize the proxy. + /// + /// + /// Skip default adapters flag. + void Initialize(bool skipDefaultAdapters); + + /// + /// Starts the test session based on the test session criteria. + /// + /// + /// The test session criteria. + /// + /// Event handler for handling events fired during test session management operations. + /// + void StartSession( + StartTestSessionCriteria criteria, + ITestSessionEventsHandler eventsHandler); + + /// + /// Stops the test session. + /// + void StopSession(); + } +} diff --git a/src/Microsoft.TestPlatform.Common/Interfaces/Engine/ClientProtocol/ITestEngine.cs b/src/Microsoft.TestPlatform.Common/Interfaces/Engine/ClientProtocol/ITestEngine.cs index 431c7c3ef1..03f2e222fb 100644 --- a/src/Microsoft.TestPlatform.Common/Interfaces/Engine/ClientProtocol/ITestEngine.cs +++ b/src/Microsoft.TestPlatform.Common/Interfaces/Engine/ClientProtocol/ITestEngine.cs @@ -12,37 +12,76 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine public interface ITestEngine { /// - /// Fetches the DiscoveryManager for this engine. This manager would provide all functionality required for discovery. + /// Fetches the DiscoveryManager for this engine. This manager would provide all + /// functionality required for discovery. /// - /// The Request Data for providing discovery services and data. + /// + /// + /// The request data for providing discovery services and data. + /// /// Test host manager for the current test discovery. - /// The discovery Criteria. - /// - /// ITestDiscoveryManager object that can do discovery - /// - IProxyDiscoveryManager GetDiscoveryManager(IRequestData requestData, ITestRuntimeProvider testHostManager, DiscoveryCriteria discoveryCriteria); + /// The discovery criteria. + /// + /// An IProxyDiscoveryManager object that can do discovery. + IProxyDiscoveryManager GetDiscoveryManager( + IRequestData requestData, + ITestRuntimeProvider testHostManager, + DiscoveryCriteria discoveryCriteria); /// - /// Fetches the ExecutionManager for this engine. This manager would provide all functionality required for execution. + /// Fetches the ExecutionManager for this engine. This manager would provide all + /// functionality required for execution. /// - /// The request data for providing common execution services and data - /// Test host manager for current test run. - /// TestRunCriteria of the current test run - /// ITestExecutionManager object that can do execution - IProxyExecutionManager GetExecutionManager(IRequestData requestData, ITestRuntimeProvider testHostManager, TestRunCriteria testRunCriteria); + /// + /// + /// The request data for providing common execution services and data. + /// + /// Test host manager for the current test run. + /// Test run criteria of the current test run. + /// + /// An IProxyExecutionManager object that can do execution. + IProxyExecutionManager GetExecutionManager( + IRequestData requestData, + ITestRuntimeProvider testHostManager, + TestRunCriteria testRunCriteria); + + /// + /// Fetches the TestSessionManager for this engine. This manager would provide all + /// functionality required for test session management. + /// + /// + /// + /// The request data for providing test session services and data. + /// + /// Test host manager for the current test session. + /// + /// Test session criteria of the current test session. + /// + /// + /// An IProxyTestSessionManager object that can manage test sessions. + IProxyTestSessionManager GetTestSessionManager( + IRequestData requestData, + ITestRuntimeProvider testHostManager, + StartTestSessionCriteria testSessionCriteria); /// /// Fetches the extension manager for this engine. This manager would provide extensibility /// features that this engine supports. /// - /// ITestExtensionManager object that helps with extensibility + /// + /// An ITestExtensionManager object that helps with extensibility. ITestExtensionManager GetExtensionManager(); /// - /// Fetches the logger manager for this engine. This manager will provide logger extensibility features that this engine supports. + /// Fetches the logger manager for this engine. This manager will provide logger + /// extensibility features that this engine supports. /// - /// The request data for providing common execution services and data - /// ITestLoggerManager object that helps with logger extensibility. + /// + /// + /// The request data for providing common execution services and data. + /// + /// + /// An ITestLoggerManager object that helps with logger extensibility. ITestLoggerManager GetLoggerManager(IRequestData requestData); } } diff --git a/src/Microsoft.TestPlatform.Common/RequestData.cs b/src/Microsoft.TestPlatform.Common/RequestData.cs index 14f2ae0033..128bc3fc5f 100644 --- a/src/Microsoft.TestPlatform.Common/RequestData.cs +++ b/src/Microsoft.TestPlatform.Common/RequestData.cs @@ -4,7 +4,7 @@ namespace Microsoft.VisualStudio.TestPlatform.Common { using System; - + using Microsoft.VisualStudio.TestPlatform.Common.Telemetry; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; /// @@ -23,6 +23,15 @@ public class RequestData : IRequestData /// private ProtocolConfig protocolConfig; + /// + /// The default constructor for request data. + /// + public RequestData() + { + this.MetricsCollection = new NoOpMetricsCollection(); + this.IsTelemetryOptedIn = false; + } + /// /// Gets or sets the metrics collection. /// diff --git a/src/Microsoft.TestPlatform.Common/Telemetry/TelemetryDataConstants.cs b/src/Microsoft.TestPlatform.Common/Telemetry/TelemetryDataConstants.cs index be35c610c2..0b1ca41424 100644 --- a/src/Microsoft.TestPlatform.Common/Telemetry/TelemetryDataConstants.cs +++ b/src/Microsoft.TestPlatform.Common/Telemetry/TelemetryDataConstants.cs @@ -26,6 +26,10 @@ public static class TelemetryDataConstants public static string DataCollectorsEnabled = "VS.TestRun.DataCollectorsEnabled"; + internal const string DataCollectorsCorProfiler = "VS.TestPlatform.DataCollector.CorProfiler"; + + internal const string DataCollectorsCoreClrProfiler = "VS.TestPlatform.DataCollector.CoreClrProfiler"; + public static string RunState = "VS.TestRun.RunState"; public static string NumberOfSourcesSentForRun = "VS.TestRun.NumberOfSources"; @@ -68,6 +72,8 @@ public static class TelemetryDataConstants public static string ParallelEnabledDuringDiscovery = "VS.TestDiscovery.ParallelEnabled"; + public static string ParallelEnabledDuringStartTestSession = "VS.StartTestSession.ParallelEnabled"; + // All the times are in sec public static string TimeTakenInSecForDiscovery = "VS.TestDiscovery.TotalTimeTakenInSec"; @@ -104,5 +110,7 @@ public static class TelemetryDataConstants public static string TestExecutionCompleteEvent = "vs/testplatform/testrunsession"; public static string TestAttachmentsProcessingCompleteEvent = "vs/testplatform/testattachmentsprocessingsession"; + + public static string StartTestSessionCompleteEvent = "vs/testplatform/starttestsession"; } } diff --git a/src/Microsoft.TestPlatform.Common/Utilities/TypesToLoadUtilities.cs b/src/Microsoft.TestPlatform.Common/Utilities/TypesToLoadUtilities.cs new file mode 100644 index 0000000000..22f568f399 --- /dev/null +++ b/src/Microsoft.TestPlatform.Common/Utilities/TypesToLoadUtilities.cs @@ -0,0 +1,42 @@ +// 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.Common.Utilities +{ + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; + + using System; + using System.Collections.Generic; + using System.Reflection; + using System.Linq; + + internal static class TypesToLoadUtilities + { + public const string TypesToLoadAttributeFullName = "Microsoft.VisualStudio.TestPlatform.TestExtensionTypesAttribute"; + + internal static IEnumerable GetTypesToLoad(Assembly assembly) + { + ValidateArg.NotNull(assembly, nameof(assembly)); + + var typesToLoad = assembly + .GetCustomAttributes(TypesToLoadAttributeFullName) + .SelectMany(i => GetTypesToLoad(i)); + + return typesToLoad; + } + + private static IEnumerable GetTypesToLoad(Attribute attribute) + { + if (attribute == null) + return Enumerable.Empty(); + + var type = attribute.GetType(); + var typesProperty = type.GetProperty("Types"); + if(typesProperty == null) + return Enumerable.Empty(); + + return typesProperty.GetValue(attribute) as Type[]; + } + } +} diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestHandler.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestHandler.cs index ee319c2744..7add8c6308 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestHandler.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestHandler.cs @@ -16,11 +16,13 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollect using Microsoft.VisualStudio.TestPlatform.Common.DataCollector; using Microsoft.VisualStudio.TestPlatform.Common.DataCollector.Interfaces; using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework; + using Microsoft.VisualStudio.TestPlatform.Common.Telemetry; using Microsoft.VisualStudio.TestPlatform.Common.Utilities; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection.Interfaces; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers; @@ -49,6 +51,8 @@ internal class DataCollectionRequestHandler : IDataCollectionRequestHandler, IDi private IFileHelper fileHelper; + private IRequestData requestData; + /// /// Use to cancel data collection test case events monitoring if test run is canceled. /// @@ -60,14 +64,18 @@ internal class DataCollectionRequestHandler : IDataCollectionRequestHandler, IDi /// /// The message sink. /// - protected DataCollectionRequestHandler(IMessageSink messageSink) + /// + /// The request data. + /// + protected DataCollectionRequestHandler(IMessageSink messageSink, IRequestData requestData) : this( new SocketCommunicationManager(), messageSink, - DataCollectionManager.Create(messageSink), + DataCollectionManager.Create(messageSink, requestData), new DataCollectionTestCaseEventHandler(), JsonDataSerializer.Instance, - new FileHelper()) + new FileHelper(), + requestData) { this.messageSink = messageSink; } @@ -93,13 +101,17 @@ protected DataCollectionRequestHandler(IMessageSink messageSink) /// /// File Helper /// + /// + /// Request data + /// protected DataCollectionRequestHandler( ICommunicationManager communicationManager, IMessageSink messageSink, IDataCollectionManager dataCollectionManager, IDataCollectionTestCaseEventHandler dataCollectionTestCaseEventHandler, IDataSerializer dataSerializer, - IFileHelper fileHelper) + IFileHelper fileHelper, + IRequestData requestData) { this.communicationManager = communicationManager; this.messageSink = messageSink; @@ -108,6 +120,7 @@ protected DataCollectionRequestHandler( this.dataCollectionTestCaseEventHandler = dataCollectionTestCaseEventHandler; this.cancellationTokenSource = new CancellationTokenSource(); this.fileHelper = fileHelper; + this.requestData = requestData; } /// @@ -139,13 +152,16 @@ public static DataCollectionRequestHandler Create( { if (Instance == null) { + var requestData = new RequestData(); + Instance = new DataCollectionRequestHandler( communicationManager, messageSink, - DataCollectionManager.Create(messageSink), + DataCollectionManager.Create(messageSink, requestData), new DataCollectionTestCaseEventHandler(), JsonDataSerializer.Instance, - new FileHelper()); + new FileHelper(), + requestData); } } } @@ -295,6 +311,7 @@ private void HandleBeforeTestRunStart(Message message) { // Initialize datacollectors and get environment variables. var payload = this.dataSerializer.DeserializePayload(message); + this.UpdateRequestData(payload.IsTelemetryOptedIn); this.AddExtensionAssemblies(payload); var envVariables = this.dataCollectionManager.InitializeDataCollectors(payload.SettingsXml); @@ -372,17 +389,27 @@ private void HandleAfterTestRunEnd(Message message) } var attachmentsets = this.dataCollectionManager.SessionEnded(isCancelled); + var afterTestRunEndResult = new AfterTestRunEndResult(attachmentsets, this.requestData.MetricsCollection.Metrics); // Dispose all datacollectors before sending attachments to vstest.console process. // As datacollector process exits itself on parent process(vstest.console) exits. this.dataCollectionManager?.Dispose(); - this.communicationManager.SendMessage(MessageType.AfterTestRunEndResult, attachmentsets); + this.communicationManager.SendMessage(MessageType.AfterTestRunEndResult, afterTestRunEndResult); EqtTrace.Info("DataCollectionRequestHandler.ProcessRequests : Session End message received from server. Closing the connection."); this.Close(); EqtTrace.Info("DataCollectionRequestHandler.ProcessRequests : DataCollection completed"); } + + private void UpdateRequestData(bool isTelemetryOptedIn) + { + if (isTelemetryOptedIn != this.requestData.IsTelemetryOptedIn) + { + this.requestData.MetricsCollection = isTelemetryOptedIn ? (IMetricsCollection)new MetricsCollection() : new NoOpMetricsCollection(); + this.requestData.IsTelemetryOptedIn = isTelemetryOptedIn; + } + } } } \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestSender.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestSender.cs index 0da7ea32d2..f51e3b7d5d 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestSender.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestSender.cs @@ -4,7 +4,6 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection { using System.Collections.Generic; - using System.Collections.ObjectModel; using System.Globalization; using System.Net; @@ -108,7 +107,7 @@ public void SendTestHostLaunched(TestHostLaunchedPayload testHostLaunchedPayload } /// - public BeforeTestRunStartResult SendBeforeTestRunStartAndGetResult(string settingsXml, IEnumerable sources, ITestMessageEventHandler runEventsHandler) + public BeforeTestRunStartResult SendBeforeTestRunStartAndGetResult(string settingsXml, IEnumerable sources, bool isTelemetryOptedIn, ITestMessageEventHandler runEventsHandler) { var isDataCollectionStarted = false; BeforeTestRunStartResult result = null; @@ -121,7 +120,8 @@ public BeforeTestRunStartResult SendBeforeTestRunStartAndGetResult(string settin var payload = new BeforeTestRunStartPayload { SettingsXml = settingsXml, - Sources = sources + Sources = sources, + IsTelemetryOptedIn = isTelemetryOptedIn }; this.communicationManager.SendMessage(MessageType.BeforeTestRunStart, payload); @@ -151,10 +151,10 @@ public BeforeTestRunStartResult SendBeforeTestRunStartAndGetResult(string settin } /// - public Collection SendAfterTestRunEndAndGetResult(ITestMessageEventHandler runEventsHandler, bool isCancelled) + public AfterTestRunEndResult SendAfterTestRunEndAndGetResult(ITestMessageEventHandler runEventsHandler, bool isCancelled) { var isDataCollectionComplete = false; - Collection attachmentSets = null; + AfterTestRunEndResult result = null; if (EqtTrace.IsVerboseEnabled) { @@ -181,12 +181,12 @@ public Collection SendAfterTestRunEndAndGetResult(ITestMessageEve } else if (message.MessageType == MessageType.AfterTestRunEndResult) { - attachmentSets = this.dataSerializer.DeserializePayload>(message); + result = this.dataSerializer.DeserializePayload(message); isDataCollectionComplete = true; } } - return attachmentSets; + return result; } private void LogDataCollectorMessage(DataCollectionMessageEventArgs dataCollectionMessageEventArgs, ITestMessageEventHandler requestHandler) diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/IDataCollectionRequestSender.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/IDataCollectionRequestSender.cs index 4e70e5ea41..5dd36660b1 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/IDataCollectionRequestSender.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/IDataCollectionRequestSender.cs @@ -4,11 +4,9 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection.Interfaces { using System.Collections.Generic; - using System.Collections.ObjectModel; using Microsoft.VisualStudio.TestPlatform.Common.DataCollection; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; - using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; /// @@ -51,13 +49,16 @@ internal interface IDataCollectionRequestSender /// /// Test run sources /// + /// + /// Telemetry opted in flag. + /// /// /// Test message event handler for handling messages. /// /// /// BeforeTestRunStartResult containing environment variables /// - BeforeTestRunStartResult SendBeforeTestRunStartAndGetResult(string settingXml, IEnumerable sources, ITestMessageEventHandler runEventsHandler); + BeforeTestRunStartResult SendBeforeTestRunStartAndGetResult(string settingXml, IEnumerable sources, bool isTelemetryOptedIn, ITestMessageEventHandler runEventsHandler); /// /// Sends the AfterTestRunEnd event and waits for result @@ -69,8 +70,8 @@ internal interface IDataCollectionRequestSender /// The value to specify whether the test run is canceled or not. /// /// - /// DataCollector attachments + /// AfterTestRunEndResult containing dataCollector attachments and metrics /// - Collection SendAfterTestRunEndAndGetResult(ITestMessageEventHandler runEventsHandler, bool isCancelled); + AfterTestRunEndResult SendAfterTestRunEndAndGetResult(ITestMessageEventHandler runEventsHandler, bool isCancelled); } } \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs index 5eea4ca571..db7e58a08f 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs @@ -229,6 +229,7 @@ private JsonSerializer GetPayloadSerializer(int? version) return payloadSerializer; case 2: case 4: + case 5: return payloadSerializer2; default: throw new NotSupportedException($"Protocol version {version} is not supported. " + diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/BeforeTestRunStartPayload.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/BeforeTestRunStartPayload.cs index c6150547fd..a8872140fe 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/BeforeTestRunStartPayload.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/BeforeTestRunStartPayload.cs @@ -19,5 +19,10 @@ public class BeforeTestRunStartPayload /// Gets or sets list of test sources. /// public IEnumerable Sources { get; set; } + + /// + /// Gets or sets a value indicating whether telemetry is enabled. + /// + public bool IsTelemetryOptedIn { get; set; } } } diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs index 76cfeec873..0a92bbc38b 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs @@ -193,6 +193,26 @@ public static class MessageType /// public const string DataCollectionMessage = "DataCollection.SendMessage"; + /// + /// StartTestSession message. + /// + public const string StartTestSession = "TestSession.StartTestSession"; + + /// + /// StartTestSession callback message. + /// + public const string StartTestSessionCallback = "TestSession.StartTestSessionCallback"; + + /// + /// StopTestSession message. + /// + public const string StopTestSession = "TestSession.StopTestSession"; + + /// + /// StopTestSession callback message. + /// + public const string StopTestSessionCallback = "TestSession.StopTestSessionCallback"; + #region DataCollector messages /// diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs index e0896ab338..df3bc35603 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs @@ -52,8 +52,9 @@ public class TestRequestSender : ITestRequestSender // that implies host is using version 1. private int protocolVersion = 1; - // Also check TestRequestHandler. - private int highestSupportedVersion = 4; + // Must be in sync with the highest supported version in + // src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs file. + private int highestSupportedVersion = 5; private TestHostConnectionInfo connectionInfo; @@ -733,4 +734,4 @@ private void SetCommunicationEndPoint() } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/Resources.resx b/src/Microsoft.TestPlatform.CoreUtilities/Resources/Resources.resx index 27a397f0d5..ba520ac0b1 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/Resources.resx +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/Resources.resx @@ -165,10 +165,4 @@ Error getting process name. - - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.cs.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.cs.xlf index 47832fc031..d3fcf4893f 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.cs.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.cs.xlf @@ -160,13 +160,6 @@ Hostitele {0} nešlo najít. Ujistěte se, jestli je {0} nainstalovaný na počítači a dostupný v cestě určené proměnnou prostředí PATH. - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.de.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.de.xlf index 7540c20d89..e56739c937 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.de.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.de.xlf @@ -160,13 +160,6 @@ Der Host "{0}" wurde nicht gefunden. Stellen Sie sicher, dass "{0}" auf dem Computer installiert und in der PATH-Umgebungsvariablen verfügbar ist. - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.es.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.es.xlf index f0b6d9d623..b428568d5f 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.es.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.es.xlf @@ -160,13 +160,6 @@ No se pudo encontrar el host "{0}". Asegúrese de que "{0}" está instalado en el equipo y está disponible en la variable de entorno PATH. - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.fr.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.fr.xlf index ca8c35a132..776258dfeb 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.fr.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.fr.xlf @@ -160,13 +160,6 @@ L'hôte '{0}' est introuvable. Vérifiez que '{0}' est installé sur la machine et qu'il est disponible dans la variable d'environnement PATH. - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.it.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.it.xlf index 406e82c52f..2a67405108 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.it.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.it.xlf @@ -160,13 +160,6 @@ L'host '{0}' non è stato trovato. Assicurarsi che '{0}' sia installato nel computer e che sia disponibile nella variabile di ambiente PATH. - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ja.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ja.xlf index bb418fbaac..f7540bc847 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ja.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ja.xlf @@ -160,13 +160,6 @@ '{0}' ホストが見つかりませんでした。'{0}' がコンピューターにインストールされており、PATH 環境変数で使用できることを確認してください。 - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ko.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ko.xlf index 7a0d780acc..045f1456c0 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ko.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ko.xlf @@ -160,13 +160,6 @@ ‘{0}’ 호스트를 찾을 수 없습니다. ‘{0}’이(가) 컴퓨터에 설치되어 있고 PATH 환경 변수에서 사용할 수 있는지 확인하세요. - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pl.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pl.xlf index d6c0d233a4..1a4f72c7c4 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pl.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pl.xlf @@ -160,13 +160,6 @@ Nie można znaleźć hosta „{0}”. Upewnij się, że element „{0}” jest zainstalowany na maszynie i jest dostępny w zmiennej środowiskowej PATH. - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pt-BR.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pt-BR.xlf index 01c4d89016..c1ca953991 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pt-BR.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pt-BR.xlf @@ -160,13 +160,6 @@ Não foi possível encontrar o host '{0}'. Verifique se o '{0}' está instalado no computador e está disponível na variável de ambiente PATH. - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ru.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ru.xlf index 009f2c3f84..439e58c02c 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ru.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ru.xlf @@ -160,13 +160,6 @@ Не удалось найти хост "{0}". Убедитесь, что "{0}" установлен на компьютере и доступен в переменной среды PATH. - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.tr.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.tr.xlf index ac138ce520..e137c740bd 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.tr.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.tr.xlf @@ -160,13 +160,6 @@ '{0}' konağı bulunamadı. '{0}' konağının makinede yüklü olduğundan ve PATH ortam değişkeninde bulunduğundan emin olun. - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.xlf index f557a28547..615147279b 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.xlf @@ -67,13 +67,6 @@ Could not find {0}. Make sure that the dotnet is installed on the machine. - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hans.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hans.xlf index 32b1ad3e48..4d75b26690 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hans.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hans.xlf @@ -1,6 +1,6 @@  - +
119 @@ -160,13 +160,6 @@ 找不到“{0}”主机。请确保计算机上已安装“{0}”且位于 PATH 环境变量中。 - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hant.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hant.xlf index 3cf3379924..c46a781603 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hant.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hant.xlf @@ -1,6 +1,6 @@  - +
119 @@ -160,13 +160,6 @@ 找不到 '{0}' 主機。請確認 '{0}' 已安裝在機器上,而且可在 PATH 環境變數中使用。 - - '{0}.{1}' is not implemented on this platform! - '{0}.{1}' is not implemented on this platform! - '{className}.{methodName}' is not implemented on this platform! - -Example: 'System.Reflection.MethodBase' is not implemented on this platform! - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Tracing/Interfaces/ITestPlatformEventSource.cs b/src/Microsoft.TestPlatform.CoreUtilities/Tracing/Interfaces/ITestPlatformEventSource.cs index 7f88ccbf83..767d09cf83 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Tracing/Interfaces/ITestPlatformEventSource.cs +++ b/src/Microsoft.TestPlatform.CoreUtilities/Tracing/Interfaces/ITestPlatformEventSource.cs @@ -218,5 +218,45 @@ public interface ITestPlatformEventSource /// Mark the completion of translation layer test run attachments processing request. ///
void TranslationLayerTestRunAttachmentsProcessingStop(); + + /// + /// The start of the test session start request. + /// + void StartTestSessionStart(); + + /// + /// The end of the test session start request. + /// + void StartTestSessionStop(); + + /// + /// Mark the start of a translation layer start test session request. + /// + void TranslationLayerStartTestSessionStart(); + + /// + /// Mark the end of a translation layer start test session request. + /// + void TranslationLayerStartTestSessionStop(); + + /// + /// The start of the test session stop request. + /// + void StopTestSessionStart(); + + /// + /// The end of the test session stop request. + /// + void StopTestSessionStop(); + + /// + /// Mark the start of a translation layer stop test session request. + /// + void TranslationLayerStopTestSessionStart(); + + /// + /// Mark the end of a translation layer stop test session request. + /// + void TranslationLayerStopTestSessionStop(); } } diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Tracing/TestPlatformEventSource.cs b/src/Microsoft.TestPlatform.CoreUtilities/Tracing/TestPlatformEventSource.cs index 7db7ffe6e4..3ad391be38 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Tracing/TestPlatformEventSource.cs +++ b/src/Microsoft.TestPlatform.CoreUtilities/Tracing/TestPlatformEventSource.cs @@ -282,6 +282,62 @@ public void TranslationLayerTestRunAttachmentsProcessingStop() { this.WriteEvent(TestPlatformInstrumentationEvents.TranslationLayerTestRunAttachmentsProcessingStopEventId); } + + /// + [Event(TestPlatformInstrumentationEvents.StartTestSessionStartEventId)] + public void StartTestSessionStart() + { + this.WriteEvent(TestPlatformInstrumentationEvents.StartTestSessionStartEventId); + } + + /// + [Event(TestPlatformInstrumentationEvents.StartTestSessionStopEventId)] + public void StartTestSessionStop() + { + this.WriteEvent(TestPlatformInstrumentationEvents.StartTestSessionStopEventId); + } + + /// + [Event(TestPlatformInstrumentationEvents.TranslationLayerStartTestSessionStartEventId)] + public void TranslationLayerStartTestSessionStart() + { + this.WriteEvent(TestPlatformInstrumentationEvents.TranslationLayerStartTestSessionStartEventId); + } + + /// + [Event(TestPlatformInstrumentationEvents.TranslationLayerStartTestSessionStopEventId)] + public void TranslationLayerStartTestSessionStop() + { + this.WriteEvent(TestPlatformInstrumentationEvents.TranslationLayerStartTestSessionStopEventId); + } + + /// + [Event(TestPlatformInstrumentationEvents.StopTestSessionStartEventId)] + public void StopTestSessionStart() + { + this.WriteEvent(TestPlatformInstrumentationEvents.StopTestSessionStartEventId); + } + + /// + [Event(TestPlatformInstrumentationEvents.StopTestSessionStopEventId)] + public void StopTestSessionStop() + { + this.WriteEvent(TestPlatformInstrumentationEvents.StopTestSessionStopEventId); + } + + /// + [Event(TestPlatformInstrumentationEvents.TranslationLayerStopTestSessionStartEventId)] + public void TranslationLayerStopTestSessionStart() + { + this.WriteEvent(TestPlatformInstrumentationEvents.TranslationLayerStopTestSessionStartEventId); + } + + /// + [Event(TestPlatformInstrumentationEvents.TranslationLayerStopTestSessionStopEventId)] + public void TranslationLayerStopTestSessionStop() + { + this.WriteEvent(TestPlatformInstrumentationEvents.TranslationLayerStopTestSessionStopEventId); + } } } diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Tracing/TestPlatformInstrumentationEvents.cs b/src/Microsoft.TestPlatform.CoreUtilities/Tracing/TestPlatformInstrumentationEvents.cs index 1aa2311048..51e8fec9ba 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Tracing/TestPlatformInstrumentationEvents.cs +++ b/src/Microsoft.TestPlatform.CoreUtilities/Tracing/TestPlatformInstrumentationEvents.cs @@ -187,5 +187,45 @@ internal class TestPlatformInstrumentationEvents /// Events fired on session attachments processing complete in translation layer. ///
public const int TranslationLayerTestRunAttachmentsProcessingStopEventId = 0x45; + + /// + /// The start test session start event id. + /// + public const int StartTestSessionStartEventId = 0x46; + + /// + /// The start test session stop event id. + /// + public const int StartTestSessionStopEventId = 0x47; + + /// + /// The translation layer start test session start event id. + /// + public const int TranslationLayerStartTestSessionStartEventId = 0x48; + + /// + /// The translation layer start test session stop event id. + /// + public const int TranslationLayerStartTestSessionStopEventId = 0x49; + + /// + /// The stop test session start event id. + /// + public const int StopTestSessionStartEventId = 0x4A; + + /// + /// The stop test session stop event id. + /// + public const int StopTestSessionStopEventId = 0x4B; + + /// + /// The translation layer stop test session start event id. + /// + public const int TranslationLayerStopTestSessionStartEventId = 0x4C; + + /// + /// The translation layer stop test session stop event id. + /// + public const int TranslationLayerStopTestSessionStopEventId = 0x4D; } } \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs index 07158a8106..7623603154 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs @@ -23,8 +23,9 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client /// /// Orchestrates discovery operations for the engine communicating with the client. /// - public class ProxyDiscoveryManager : ProxyOperationManager, IProxyDiscoveryManager, ITestDiscoveryEventsHandler2 + public class ProxyDiscoveryManager : IProxyDiscoveryManager, IBaseProxy, ITestDiscoveryEventsHandler2 { + private ProxyOperationManager proxyOperationManager; private readonly ITestRuntimeProvider testHostManager; private IDataSerializer dataSerializer; private bool isCommunicationEstablished; @@ -38,72 +39,82 @@ public class ProxyDiscoveryManager : ProxyOperationManager, IProxyDiscoveryManag /// /// Initializes a new instance of the class. /// - /// The Request Data for providing discovery services and data. + /// + /// + /// The request data for providing discovery services and data. + /// /// Test request sender instance. /// Test host manager instance. - public ProxyDiscoveryManager(IRequestData requestData, ITestRequestSender testRequestSender, ITestRuntimeProvider testHostManager) - : this(requestData, testRequestSender, testHostManager, JsonDataSerializer.Instance, new FileHelper()) + public ProxyDiscoveryManager( + IRequestData requestData, + ITestRequestSender testRequestSender, + ITestRuntimeProvider testHostManager) + : this( + requestData, + testRequestSender, + testHostManager, + JsonDataSerializer.Instance, + new FileHelper()) { this.testHostManager = testHostManager; } /// /// Initializes a new instance of the class. - /// Constructor with Dependency injection. Used for unit testing. /// - /// - /// - /// The request Sender. - /// - /// - /// Test host Manager instance + /// + /// + /// Constructor with dependency injection. Used for unit testing. + /// + /// + /// + /// The request data for providing discovery services and data. /// - /// - internal ProxyDiscoveryManager(IRequestData requestData, + /// The request sender. + /// Test host manager instance. + /// The data serializer. + /// The file helper. + internal ProxyDiscoveryManager( + IRequestData requestData, ITestRequestSender requestSender, ITestRuntimeProvider testHostManager, IDataSerializer dataSerializer, IFileHelper fileHelper) - : base(requestData, requestSender, testHostManager) { this.dataSerializer = dataSerializer; this.testHostManager = testHostManager; this.isCommunicationEstablished = false; this.requestData = requestData; this.fileHelper = fileHelper; + + // Create a new proxy operation manager. + this.proxyOperationManager = new ProxyOperationManager(requestData, requestSender, testHostManager, this); } #endregion #region IProxyDiscoveryManager implementation. - /// - /// Ensure that the discovery component of engine is ready for discovery usually by loading extensions. - /// Skip default adapters flag. - /// + /// public void Initialize(bool skipDefaultAdapters) { this.skipDefaultAdapters = skipDefaultAdapters; } - /// - /// Discovers tests - /// - /// Settings, parameters for the discovery request - /// EventHandler for handling discovery events from Engine + /// public void DiscoverTests(DiscoveryCriteria discoveryCriteria, ITestDiscoveryEventsHandler2 eventHandler) { this.baseTestDiscoveryEventsHandler = eventHandler; try { - this.isCommunicationEstablished = this.SetupChannel(discoveryCriteria.Sources, discoveryCriteria.RunSettings); + this.isCommunicationEstablished = this.proxyOperationManager.SetupChannel(discoveryCriteria.Sources, discoveryCriteria.RunSettings); if (this.isCommunicationEstablished) { this.InitializeExtensions(discoveryCriteria.Sources); discoveryCriteria.UpdateDiscoveryCriteria(testHostManager); - this.RequestSender.DiscoverTests(discoveryCriteria, this); + this.proxyOperationManager.RequestSender.DiscoverTests(discoveryCriteria, this); } } catch (Exception exception) @@ -139,10 +150,16 @@ public void DiscoverTests(DiscoveryCriteria discoveryCriteria, ITestDiscoveryEve public void Abort() { // Cancel fast, try to stop testhost deployment/launch - this.CancellationTokenSource.Cancel(); + this.proxyOperationManager.CancellationTokenSource.Cancel(); this.Close(); } + /// + public void Close() + { + this.proxyOperationManager.Close(); + } + /// public void HandleDiscoveryComplete(DiscoveryCompleteEventArgs discoveryCompleteEventArgs, IEnumerable lastChunk) { @@ -175,6 +192,17 @@ public void HandleLogMessage(TestMessageLevel level, string message) #endregion + #region IBaseProxy implementation. + /// + public virtual TestProcessStartInfo UpdateTestProcessStartInfo(TestProcessStartInfo testProcessStartInfo) + { + // Update Telemetry Opt in status because by default in Test Host Telemetry is opted out + var telemetryOptedIn = this.proxyOperationManager.RequestData.IsTelemetryOptedIn ? "true" : "false"; + testProcessStartInfo.Arguments += " --telemetryoptedin " + telemetryOptedIn; + return testProcessStartInfo; + } + #endregion + private void InitializeExtensions(IEnumerable sources) { var extensions = TestPluginCache.Instance.GetExtensionPaths(TestPlatformConstants.TestAdapterEndsWithPattern, this.skipDefaultAdapters); @@ -192,7 +220,7 @@ private void InitializeExtensions(IEnumerable sources) // Only send this if needed. if (platformExtensions.Any()) { - this.RequestSender.InitializeDiscovery(platformExtensions); + this.proxyOperationManager.RequestSender.InitializeDiscovery(platformExtensions); } } diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs index ba157953ef..b16d5ef3e9 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs @@ -6,8 +6,8 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client using System; using System.Collections.Generic; using System.Collections.ObjectModel; - using System.Globalization; using System.Linq; + using System.Threading; using Microsoft.VisualStudio.TestPlatform.Common; using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework; @@ -15,6 +15,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine; @@ -27,71 +28,121 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client /// /// Orchestrates test execution operations for the engine communicating with the client. /// - internal class ProxyExecutionManager : ProxyOperationManager, IProxyExecutionManager, ITestRunEventsHandler2 + internal class ProxyExecutionManager : IProxyExecutionManager, IBaseProxy, ITestRunEventsHandler2 { private readonly ITestRuntimeProvider testHostManager; - private IDataSerializer dataSerializer; + private readonly IFileHelper fileHelper; + private bool isCommunicationEstablished; + private bool skipDefaultAdapters; + private IDataSerializer dataSerializer; private IRequestData requestData; private ITestRunEventsHandler baseTestRunEventsHandler; - private bool skipDefaultAdapters; - private readonly IFileHelper fileHelper; + private TestSessionInfo testSessionInfo = null; + private bool debugEnabledForTestSession = false; /// public bool IsInitialized { get; private set; } = false; + /// + /// Gets or sets the cancellation token source. + /// + public CancellationTokenSource CancellationTokenSource + { + get { return this.ProxyOperationManager.CancellationTokenSource; } + set { this.ProxyOperationManager.CancellationTokenSource = value; } + } + + protected ProxyOperationManager ProxyOperationManager { get; set; } #region Constructors /// /// Initializes a new instance of the class. /// - /// The Request Data for providing services and data for Run. + /// + /// The test session info. + /// + /// A flag indicating if debugging should be enabled or not. + /// + public ProxyExecutionManager(TestSessionInfo testSessionInfo, bool debugEnabledForTestSession) + { + // Filling in test session info and proxy information. + this.testSessionInfo = testSessionInfo; + this.ProxyOperationManager = TestSessionPool.Instance.TakeProxy(this.testSessionInfo); + // This should be set to enable debugging when we have test session info available. + this.debugEnabledForTestSession = debugEnabledForTestSession; + + this.testHostManager = this.ProxyOperationManager.TestHostManager; + this.dataSerializer = JsonDataSerializer.Instance; + this.isCommunicationEstablished = false; + this.requestData = this.ProxyOperationManager.RequestData; + this.fileHelper = new FileHelper(); + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// The request data for providing services and data for run. + /// /// Test request sender instance. /// Test host manager for this proxy. - public ProxyExecutionManager(IRequestData requestData, ITestRequestSender requestSender, ITestRuntimeProvider testHostManager) : - this(requestData, requestSender, testHostManager, JsonDataSerializer.Instance, new FileHelper()) + public ProxyExecutionManager( + IRequestData requestData, + ITestRequestSender requestSender, + ITestRuntimeProvider testHostManager) : + this( + requestData, + requestSender, + testHostManager, + JsonDataSerializer.Instance, + new FileHelper()) { } /// /// Initializes a new instance of the class. - /// Constructor with Dependency injection. Used for unit testing. /// - /// The Request Data for Common services and data for Run. - /// Request Sender instance - /// Test host manager instance - /// - internal ProxyExecutionManager(IRequestData requestData, ITestRequestSender requestSender, - ITestRuntimeProvider testHostManager, IDataSerializer dataSerializer, IFileHelper fileHelper) - : base(requestData, requestSender, testHostManager) + /// + /// + /// Constructor with dependency injection. Used for unit testing. + /// + /// + /// The request data for common services and data for run. + /// Request sender instance. + /// Test host manager instance. + /// Data serializer instance. + /// File helper instance. + internal ProxyExecutionManager( + IRequestData requestData, + ITestRequestSender requestSender, + ITestRuntimeProvider testHostManager, + IDataSerializer dataSerializer, + IFileHelper fileHelper) { this.testHostManager = testHostManager; this.dataSerializer = dataSerializer; this.isCommunicationEstablished = false; this.requestData = requestData; this.fileHelper = fileHelper; + + // Create a new proxy operation manager. + this.ProxyOperationManager = new ProxyOperationManager(requestData, requestSender, testHostManager, this); } #endregion #region IProxyExecutionManager implementation. - /// - /// Ensure that the Execution component of engine is ready for execution usually by loading extensions. - /// Skip default adapters flag. - /// + /// public virtual void Initialize(bool skipDefaultAdapters) { this.skipDefaultAdapters = skipDefaultAdapters; this.IsInitialized = true; } - /// - /// Starts the test run - /// - /// The settings/options for the test run. - /// EventHandler for handling execution events from Engine. - /// The process id of the runner executing tests. + /// public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsHandler eventHandler) { this.baseTestRunEventsHandler = eventHandler; @@ -103,19 +154,24 @@ public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsH EqtTrace.Verbose("ProxyExecutionManager: Test host is always Lazy initialize."); } - var testSources = new List(testRunCriteria.HasSpecificSources ? testRunCriteria.Sources : - // If the test execution is with a test filter, group them by sources - testRunCriteria.Tests.GroupBy(tc => tc.Source).Select(g => g.Key)); + var testSources = new List( + testRunCriteria.HasSpecificSources + ? testRunCriteria.Sources + // If the test execution is with a test filter, group them by sources. + : testRunCriteria.Tests.GroupBy(tc => tc.Source).Select(g => g.Key)); - this.isCommunicationEstablished = this.SetupChannel(testSources, testRunCriteria.TestRunSettings); + this.isCommunicationEstablished = this.ProxyOperationManager.SetupChannel( + testSources, + testRunCriteria.TestRunSettings); if (this.isCommunicationEstablished) { - this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested(); + this.ProxyOperationManager.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested(); this.InitializeExtensions(testSources); - // This code should be in sync with InProcessProxyExecutionManager.StartTestRun executionContext + // This code should be in sync with InProcessProxyExecutionManager.StartTestRun + // execution context. var executionContext = new TestExecutionContext( testRunCriteria.FrequencyOfRunStatsChangeEvent, testRunCriteria.RunStatsChangeEventTimeout, @@ -124,22 +180,37 @@ public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsH isDataCollectionEnabled: false, areTestCaseLevelEventsRequired: false, hasTestRun: true, - isDebug: (testRunCriteria.TestHostLauncher != null && testRunCriteria.TestHostLauncher.IsDebug), + // Debugging should happen if there's a custom test host launcher present + // and is in debugging mode, or if the debugging is enabled in case the + // test session info is present. + isDebug: + (testRunCriteria.TestHostLauncher != null && testRunCriteria.TestHostLauncher.IsDebug) + || this.debugEnabledForTestSession, testCaseFilter: testRunCriteria.TestCaseFilter, filterOptions: testRunCriteria.FilterOptions); // This is workaround for the bug https://github.com/Microsoft/vstest/issues/970 - var runsettings = this.RemoveNodesFromRunsettingsIfRequired(testRunCriteria.TestRunSettings, (testMessageLevel, message) => { this.LogMessage(testMessageLevel, message); }); + var runsettings = this.ProxyOperationManager.RemoveNodesFromRunsettingsIfRequired( + testRunCriteria.TestRunSettings, + (testMessageLevel, message) => { this.LogMessage(testMessageLevel, message); }); if (testRunCriteria.HasSpecificSources) { - var runRequest = testRunCriteria.CreateTestRunCriteriaForSources(testHostManager, runsettings, executionContext, testSources); - this.RequestSender.StartTestRun(runRequest, this); + var runRequest = testRunCriteria.CreateTestRunCriteriaForSources( + testHostManager, + runsettings, + executionContext, + testSources); + this.ProxyOperationManager.RequestSender.StartTestRun(runRequest, this); } else { - var runRequest = testRunCriteria.CreateTestRunCriteriaForTests(testHostManager, runsettings, executionContext, testSources); - this.RequestSender.StartTestRun(runRequest, this); + var runRequest = testRunCriteria.CreateTestRunCriteriaForTests( + testHostManager, + runsettings, + executionContext, + testSources); + this.ProxyOperationManager.RequestSender.StartTestRun(runRequest, this); } } } @@ -148,17 +219,24 @@ public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsH EqtTrace.Error("ProxyExecutionManager.StartTestRun: Failed to start test run: {0}", exception); // Log error message to design mode and CLI. - // TestPlatformException is expected exception, log only the message - // For other exceptions, log the stacktrace as well + // TestPlatformException is expected exception, log only the message. + // For other exceptions, log the stacktrace as well. var errorMessage = exception is TestPlatformException ? exception.Message : exception.ToString(); - var testMessagePayload = new TestMessagePayload { MessageLevel = TestMessageLevel.Error, Message = errorMessage }; + var testMessagePayload = new TestMessagePayload() + { + MessageLevel = TestMessageLevel.Error, + Message = errorMessage + }; this.HandleRawMessage(this.dataSerializer.SerializePayload(MessageType.TestMessage, testMessagePayload)); this.LogMessage(TestMessageLevel.Error, errorMessage); - // Send a run complete to caller. Similar logic is also used in ParallelProxyExecutionManager.StartTestRunOnConcurrentManager - // Aborted is `true`: in case of parallel run (or non shared host), an aborted message ensures another execution manager - // created to replace the current one. This will help if the current execution manager is aborted due to irreparable error - // and the test host is lost as well. + // Send a run complete to caller. Similar logic is also used in + // ParallelProxyExecutionManager.StartTestRunOnConcurrentManager. + // + // Aborted is `true`: in case of parallel run (or non shared host), an aborted + // message ensures another execution manager created to replace the current one. + // This will help if the current execution manager is aborted due to irreparable + // error and the test host is lost as well. var completeArgs = new TestRunCompleteEventArgs(null, false, true, null, new Collection(), TimeSpan.Zero); var testRunCompletePayload = new TestRunCompletePayload { TestRunCompleteArgs = completeArgs }; this.HandleRawMessage(this.dataSerializer.SerializePayload(MessageType.ExecutionComplete, testRunCompletePayload)); @@ -168,62 +246,68 @@ public virtual int StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsH return 0; } - /// - /// Cancels the test run. - /// - /// EventHandler for handling execution events from Engine. + /// public virtual void Cancel(ITestRunEventsHandler eventHandler) { - // Just in case ExecuteAsync isn't called yet, set the eventhandler + // Just in case ExecuteAsync isn't called yet, set the eventhandler. if (this.baseTestRunEventsHandler == null) { this.baseTestRunEventsHandler = eventHandler; } - // Cancel fast, try to stop testhost deployment/launch - this.CancellationTokenSource.Cancel(); + // Cancel fast, try to stop testhost deployment/launch. + this.ProxyOperationManager.CancellationTokenSource.Cancel(); if (this.isCommunicationEstablished) { - this.RequestSender.SendTestRunCancel(); + this.ProxyOperationManager.RequestSender.SendTestRunCancel(); } } /// - public virtual int LaunchProcessWithDebuggerAttached(TestProcessStartInfo testProcessStartInfo) - { - return this.baseTestRunEventsHandler.LaunchProcessWithDebuggerAttached(testProcessStartInfo); - } - - /// - public bool AttachDebuggerToProcess(int pid) - { - return ((ITestRunEventsHandler2)this.baseTestRunEventsHandler).AttachDebuggerToProcess(pid); - } - - /// - /// Aborts the test run. - /// - /// EventHandler for handling execution events from Engine. public void Abort(ITestRunEventsHandler eventHandler) { - // Just in case ExecuteAsync isn't called yet, set the eventhandler + // Just in case ExecuteAsync isn't called yet, set the eventhandler. if (this.baseTestRunEventsHandler == null) { this.baseTestRunEventsHandler = eventHandler; } - // Cancel fast, try to stop testhost deployment/launch - this.CancellationTokenSource.Cancel(); + // Cancel fast, try to stop testhost deployment/launch. + this.ProxyOperationManager.CancellationTokenSource.Cancel(); if (this.isCommunicationEstablished) { - this.RequestSender.SendTestRunAbort(); + this.ProxyOperationManager.RequestSender.SendTestRunAbort(); } } + /// + public void Close() + { + this.ProxyOperationManager.Close(); + } + + /// + public virtual int LaunchProcessWithDebuggerAttached(TestProcessStartInfo testProcessStartInfo) + { + return this.baseTestRunEventsHandler.LaunchProcessWithDebuggerAttached(testProcessStartInfo); + } + + /// + public bool AttachDebuggerToProcess(int pid) + { + return ((ITestRunEventsHandler2)this.baseTestRunEventsHandler).AttachDebuggerToProcess(pid); + } + /// public void HandleTestRunComplete(TestRunCompleteEventArgs testRunCompleteArgs, TestRunChangedEventArgs lastChunkArgs, ICollection runContextAttachments, ICollection executorUris) { + if (this.testSessionInfo != null) + { + // TODO (copoiena): Is returning the proxy to the pool here enough ? + TestSessionPool.Instance.ReturnProxy(this.testSessionInfo, this.ProxyOperationManager.Id); + } + this.baseTestRunEventsHandler.HandleTestRunComplete(testRunCompleteArgs, lastChunkArgs, runContextAttachments, executorUris); } @@ -246,6 +330,7 @@ public void HandleRawMessage(string rawMessage) this.baseTestRunEventsHandler.HandleRawMessage(rawMessage); } + /// public void HandleLogMessage(TestMessageLevel level, string message) { this.baseTestRunEventsHandler.HandleLogMessage(level, message); @@ -253,14 +338,41 @@ public void HandleLogMessage(TestMessageLevel level, string message) #endregion + #region IBaseProxy implementation. + /// + public virtual TestProcessStartInfo UpdateTestProcessStartInfo(TestProcessStartInfo testProcessStartInfo) + { + // Update Telemetry Opt in status because by default in Test Host Telemetry is opted out + var telemetryOptedIn = this.ProxyOperationManager.RequestData.IsTelemetryOptedIn ? "true" : "false"; + testProcessStartInfo.Arguments += " --telemetryoptedin " + telemetryOptedIn; + return testProcessStartInfo; + } + #endregion + + /// + /// Ensures that the engine is ready for test operations. Usually includes starting up the + /// test host process. + /// + /// + /// List of test sources. + /// Run settings to be used. + /// + /// + /// Returns true if the communication is established b/w runner and host, false otherwise. + /// + public virtual bool SetupChannel(IEnumerable sources, string runSettings) + { + return this.ProxyOperationManager.SetupChannel(sources, runSettings); + } + private void LogMessage(TestMessageLevel testMessageLevel, string message) { - // Log to vs ide test output + // Log to vs ide test output. var testMessagePayload = new TestMessagePayload { MessageLevel = testMessageLevel, Message = message }; var rawMessage = this.dataSerializer.SerializePayload(MessageType.TestMessage, testMessagePayload); this.HandleRawMessage(rawMessage); - // Log to vstest.console + // Log to vstest.console. this.HandleLogMessage(testMessageLevel, message); } @@ -268,7 +380,7 @@ private void InitializeExtensions(IEnumerable sources) { var extensions = TestPluginCache.Instance.GetExtensionPaths(TestPlatformConstants.TestAdapterEndsWithPattern, this.skipDefaultAdapters); - // Filter out non existing extensions + // Filter out non existing extensions. var nonExistingExtensions = extensions.Where(extension => !this.fileHelper.Exists(extension)); if (nonExistingExtensions.Any()) { @@ -281,7 +393,7 @@ private void InitializeExtensions(IEnumerable sources) // Only send this if needed. if (platformExtensions.Any()) { - this.RequestSender.InitializeExecution(platformExtensions); + this.ProxyOperationManager.RequestSender.InitializeExecution(platformExtensions); } } } diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManagerWithDataCollection.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManagerWithDataCollection.cs index 179a6df370..8aad17856d 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManagerWithDataCollection.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManagerWithDataCollection.cs @@ -38,8 +38,15 @@ internal class ProxyExecutionManagerWithDataCollection : ProxyExecutionManager /// /// The request data for providing execution services and data. /// - public ProxyExecutionManagerWithDataCollection(IRequestData requestData, ITestRequestSender requestSender, ITestRuntimeProvider testHostManager, IProxyDataCollectionManager proxyDataCollectionManager) - : base(requestData, requestSender, testHostManager) + public ProxyExecutionManagerWithDataCollection( + IRequestData requestData, + ITestRequestSender requestSender, + ITestRuntimeProvider testHostManager, + IProxyDataCollectionManager proxyDataCollectionManager) + : base( + requestData, + requestSender, + testHostManager) { this.ProxyDataCollectionManager = proxyDataCollectionManager; this.DataCollectionRunEventsHandler = new DataCollectionRunEventsHandler(); @@ -160,7 +167,7 @@ public override int LaunchProcessWithDebuggerAttached(TestProcessStartInfo testP } /// - protected override TestProcessStartInfo UpdateTestProcessStartInfo(TestProcessStartInfo testProcessStartInfo) + public override TestProcessStartInfo UpdateTestProcessStartInfo(TestProcessStartInfo testProcessStartInfo) { if (testProcessStartInfo.EnvironmentVariables == null) { diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs index aa0c7a40a0..81e83f2e7d 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs @@ -10,7 +10,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client using System.Linq; using System.Reflection; using System.Threading; - using CoreUtilities.Helpers; + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; using Microsoft.VisualStudio.TestPlatform.Common.Utilities; using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Extensions; @@ -22,189 +22,284 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; using Microsoft.VisualStudio.TestPlatform.Utilities; - using CrossPlatEngineResources = Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Resources.Resources; - using CommunicationUtilitiesResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; - using CoreUtilitiesConstants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; + using CoreUtilities.Helpers; + + using CrossPlatEngineResources = Resources.Resources; + using CommunicationUtilitiesResources = CommunicationUtilities.Resources.Resources; + using CoreUtilitiesConstants = CoreUtilities.Constants; /// /// Base class for any operations that the client needs to drive through the engine. /// - public abstract class ProxyOperationManager + public class ProxyOperationManager { - private readonly ITestRuntimeProvider testHostManager; - private readonly IProcessHelper processHelper; private readonly string versionCheckPropertyName = "IsVersionCheckRequired"; private readonly string makeRunsettingsCompatiblePropertyName = "MakeRunsettingsCompatible"; + private readonly Guid id = Guid.NewGuid(); + private readonly ManualResetEventSlim testHostExited = new ManualResetEventSlim(false); + private readonly IProcessHelper processHelper; + + private IBaseProxy baseProxy; private bool versionCheckRequired = true; private bool makeRunsettingsCompatible; private bool makeRunsettingsCompatibleSet; - private readonly ManualResetEventSlim testHostExited = new ManualResetEventSlim(false); - - private int testHostProcessId; private bool initialized; - private string testHostProcessStdError; private bool testHostLaunched; - private IRequestData requestData; + private int testHostProcessId; + private string testHostProcessStdError; #region Constructors + /// + /// Initializes a new instance of the class. + /// + /// + /// Request data instance. + /// Request sender instance. + /// Test host manager instance. + public ProxyOperationManager( + IRequestData requestData, + ITestRequestSender requestSender, + ITestRuntimeProvider testHostManager) + : this( + requestData, + requestSender, + testHostManager, + null) + { } /// /// Initializes a new instance of the class. /// - /// - /// Request Sender instance. + /// + /// Request data instance. + /// Request sender instance. /// Test host manager instance. - protected ProxyOperationManager(IRequestData requestData, ITestRequestSender requestSender, ITestRuntimeProvider testHostManager) + /// The base proxy. + public ProxyOperationManager( + IRequestData requestData, + ITestRequestSender requestSender, + ITestRuntimeProvider testHostManager, + IBaseProxy baseProxy) { + this.RequestData = requestData; this.RequestSender = requestSender; - this.CancellationTokenSource = new CancellationTokenSource(); - this.testHostManager = testHostManager; - this.processHelper = new ProcessHelper(); + this.TestHostManager = testHostManager; + this.baseProxy = baseProxy; + this.initialized = false; this.testHostLaunched = false; this.testHostProcessId = -1; - this.requestData = requestData; + this.processHelper = new ProcessHelper(); + this.CancellationTokenSource = new CancellationTokenSource(); } #endregion #region Properties + /// + /// Gets or sets the request data. + /// + public IRequestData RequestData { get; set; } /// /// Gets or sets the server for communication. /// - protected ITestRequestSender RequestSender { get; set; } + public ITestRequestSender RequestSender { get; set; } /// - /// Gets or sets the cancellation token source. + /// Gets or sets the test host manager. + /// + public ITestRuntimeProvider TestHostManager { get; set; } + + /// + /// Gets the proxy operation manager id. /// - protected CancellationTokenSource CancellationTokenSource { get; set; } + public Guid Id { get { return this.id; } } + /// + /// Gets or sets the cancellation token source. + /// + public CancellationTokenSource CancellationTokenSource { get; set; } #endregion #region IProxyOperationManager implementation. - /// - /// Ensure that the engine is ready for test operations. - /// Usually includes starting up the test host process. + /// Initializes the proxy. /// - /// - /// List of test sources. - /// - /// + /// + /// + /// Flag indicating if we should skip the default adapters initialization. /// + public virtual void Initialize(bool skipDefaultAdapters) + { + // No-op. + } + + /// + /// Ensures that the engine is ready for test operations. Usually includes starting up the + /// test host process. + /// + /// + /// List of test sources. + /// Run settings to be used. + /// The events handler. + /// /// - /// Returns true if Communication is established b/w runner and host + /// Returns true if the communication is established b/w runner and host, false otherwise. + /// + public virtual bool SetupChannel( + IEnumerable sources, + string runSettings, + ITestMessageEventHandler eventHandler) + { + return this.SetupChannel(sources, runSettings); + } + + /// + /// Ensures that the engine is ready for test operations. Usually includes starting up the + /// test host process. + /// + /// + /// List of test sources. + /// Run settings to be used. + /// + /// + /// Returns true if the communication is established b/w runner and host, false otherwise. /// public virtual bool SetupChannel(IEnumerable sources, string runSettings) { this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested(); - var connTimeout = EnvironmentHelper.GetConnectionTimeout(); - if (!this.initialized) + if (this.initialized) { - this.testHostProcessStdError = string.Empty; - TestHostConnectionInfo testHostConnectionInfo = this.testHostManager.GetTestHostConnectionInfo(); - - var portNumber = 0; - - if (testHostConnectionInfo.Role == ConnectionRole.Client) - { - portNumber = this.RequestSender.InitializeCommunication(); - testHostConnectionInfo.Endpoint += portNumber; - } + return true; + } - var processId = this.processHelper.GetCurrentProcessId(); - var connectionInfo = new TestRunnerConnectionInfo { Port = portNumber, ConnectionInfo = testHostConnectionInfo, RunnerProcessId = processId, LogFile = this.GetTimestampedLogFile(EqtTrace.LogFile), TraceLevel = (int)EqtTrace.TraceLevel }; + var connTimeout = EnvironmentHelper.GetConnectionTimeout(); - // Subscribe to TestHost Event - this.testHostManager.HostLaunched += this.TestHostManagerHostLaunched; - this.testHostManager.HostExited += this.TestHostManagerHostExited; + this.testHostProcessStdError = string.Empty; + TestHostConnectionInfo testHostConnectionInfo = this.TestHostManager.GetTestHostConnectionInfo(); + + var portNumber = 0; + if (testHostConnectionInfo.Role == ConnectionRole.Client) + { + portNumber = this.RequestSender.InitializeCommunication(); + testHostConnectionInfo.Endpoint += portNumber; + } - // Get envVars from run settings - var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettings); + var processId = this.processHelper.GetCurrentProcessId(); + var connectionInfo = new TestRunnerConnectionInfo() + { + Port = portNumber, + ConnectionInfo = testHostConnectionInfo, + RunnerProcessId = processId, + LogFile = this.GetTimestampedLogFile(EqtTrace.LogFile), + TraceLevel = (int)EqtTrace.TraceLevel + }; + + // Subscribe to test host events. + this.TestHostManager.HostLaunched += this.TestHostManagerHostLaunched; + this.TestHostManager.HostExited += this.TestHostManagerHostExited; + + // Get environment variables from run settings. + var envVars = InferRunSettingsHelper.GetEnvironmentVariables(runSettings); + + // Get the test process start info. + var testHostStartInfo = this.UpdateTestProcessStartInfo( + this.TestHostManager.GetTestHostProcessStartInfo( + sources, + envVars, + connectionInfo)); + try + { + // Launch the test host. + var hostLaunchedTask = this.TestHostManager.LaunchTestHostAsync( + testHostStartInfo, + this.CancellationTokenSource.Token); + this.testHostLaunched = hostLaunchedTask.Result; - // Get the test process start info - var testHostStartInfo = this.UpdateTestProcessStartInfo(this.testHostManager.GetTestHostProcessStartInfo(sources, envVars, connectionInfo)); - try - { - // Launch the test host. - var hostLaunchedTask = this.testHostManager.LaunchTestHostAsync(testHostStartInfo, this.CancellationTokenSource.Token); - this.testHostLaunched = hostLaunchedTask.Result; - - if (this.testHostLaunched && testHostConnectionInfo.Role == ConnectionRole.Host) - { - // If test runtime is service host, try to poll for connection as client - this.RequestSender.InitializeCommunication(); - } - } - catch (Exception ex) + if (this.testHostLaunched && testHostConnectionInfo.Role == ConnectionRole.Host) { - EqtTrace.Error("ProxyOperationManager: Failed to launch testhost :{0}", ex); - - this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested(); - throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, CrossPlatEngineResources.FailedToLaunchTestHost, ex.ToString())); + // If test runtime is service host, try to poll for connection as client. + this.RequestSender.InitializeCommunication(); } + } + catch (Exception ex) + { + EqtTrace.Error("ProxyOperationManager: Failed to launch testhost :{0}", ex); - // Warn the user that execution will wait for debugger attach. - var hostDebugEnabled = Environment.GetEnvironmentVariable("VSTEST_HOST_DEBUG"); - var nativeHostDebugEnabled = Environment.GetEnvironmentVariable("VSTEST_HOST_NATIVE_DEBUG"); + this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested(); + throw new TestPlatformException(string.Format( + CultureInfo.CurrentUICulture, + CrossPlatEngineResources.FailedToLaunchTestHost, + ex.ToString())); + } - if (!string.IsNullOrEmpty(hostDebugEnabled) && hostDebugEnabled.Equals("1", StringComparison.Ordinal) || - new PlatformEnvironment().OperatingSystem.Equals(PlatformOperatingSystem.Windows) && - !string.IsNullOrEmpty(nativeHostDebugEnabled) && nativeHostDebugEnabled.Equals("1", StringComparison.Ordinal)) - { - ConsoleOutput.Instance.WriteLine(CrossPlatEngineResources.HostDebuggerWarning, OutputLevel.Warning); - ConsoleOutput.Instance.WriteLine( - string.Format("Process Id: {0}, Name: {1}", this.testHostProcessId, this.processHelper.GetProcessName(this.testHostProcessId)), - OutputLevel.Information); + // Warn the user that execution will wait for debugger attach. + var hostDebugEnabled = Environment.GetEnvironmentVariable("VSTEST_HOST_DEBUG"); + var nativeHostDebugEnabled = Environment.GetEnvironmentVariable("VSTEST_HOST_NATIVE_DEBUG"); - // Increase connection timeout when debugging is enabled. - connTimeout *= 5; - } - - // If TestHost does not launch then throw exception - // If Testhost launches, wait for connection. - if (!this.testHostLaunched || - !this.RequestSender.WaitForRequestHandlerConnection(connTimeout * 1000, this.CancellationTokenSource.Token)) - { - EqtTrace.Verbose($"Test host failed to start Test host launched:{testHostLaunched} test host exited: {testHostExited.IsSet}"); - // Throw a test platform exception with the appropriate message if user requested cancellation - this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested(); + if (!string.IsNullOrEmpty(hostDebugEnabled) && hostDebugEnabled.Equals("1", StringComparison.Ordinal) || + new PlatformEnvironment().OperatingSystem.Equals(PlatformOperatingSystem.Windows) && + !string.IsNullOrEmpty(nativeHostDebugEnabled) && nativeHostDebugEnabled.Equals("1", StringComparison.Ordinal)) + { + ConsoleOutput.Instance.WriteLine( + CrossPlatEngineResources.HostDebuggerWarning, + OutputLevel.Warning); + + ConsoleOutput.Instance.WriteLine( + string.Format( + "Process Id: {0}, Name: {1}", + this.testHostProcessId, + this.processHelper.GetProcessName(this.testHostProcessId)), + OutputLevel.Information); + + // Increase connection timeout when debugging is enabled. + connTimeout *= 5; + } - // Throw a test platform exception along with the error messages from the test if the test host exited unexpectedly - // before communication was established - this.ThrowOnTestHostExited(this.testHostExited.IsSet); + // If test host does not launch then throw exception, otherwise wait for connection. + if (!this.testHostLaunched || + !this.RequestSender.WaitForRequestHandlerConnection( + connTimeout * 1000, + this.CancellationTokenSource.Token)) + { + EqtTrace.Verbose($"Test host failed to start Test host launched:{testHostLaunched} test host exited: {testHostExited.IsSet}"); + // Throw a test platform exception with the appropriate message if user requested cancellation. + this.CancellationTokenSource.Token.ThrowTestPlatformExceptionIfCancellationRequested(); - // Throw a test platform exception stating the connection to test could not be established even after waiting - // for the configure timeout period - this.ThrowExceptionOnConnectionFailure(connTimeout); - } + // Throw a test platform exception along with the error messages from the test if the test host exited unexpectedly + // before communication was established. + this.ThrowOnTestHostExited(this.testHostExited.IsSet); - // Handling special case for dotnet core projects with older test hosts - // Older test hosts are not aware of protocol version check - // Hence we should not be sending VersionCheck message to these test hosts - this.CompatIssueWithVersionCheckAndRunsettings(); + // Throw a test platform exception stating the connection to test could not be established even after waiting + // for the configure timeout period. + this.ThrowExceptionOnConnectionFailure(connTimeout); + } - if (this.versionCheckRequired) - { - this.RequestSender.CheckVersionWithTestHost(); - } + // Handling special case for dotnet core projects with older test hosts. + // Older test hosts are not aware of protocol version check, hence we should not be + // sending VersionCheck message to these test hosts. + this.CompatIssueWithVersionCheckAndRunsettings(); - this.initialized = true; + if (this.versionCheckRequired) + { + this.RequestSender.CheckVersionWithTestHost(); } + this.initialized = true; + return true; } /// - /// Closes the channel, terminate test host process. + /// Closes the channel and terminates the test host process. /// public virtual void Close() { try { - // do not send message if host did not launch + // Do not send message if the host did not launch. if (this.testHostLaunched) { this.RequestSender.EndSession(); @@ -228,55 +323,50 @@ public virtual void Close() EqtTrace.Warning("ProxyOperationManager: Timed out waiting for test host to exit. Will terminate process."); - // please clean up test host. - this.testHostManager.CleanTestHostAsync(CancellationToken.None).Wait(); + // Please clean up test host. + this.TestHostManager.CleanTestHostAsync(CancellationToken.None).Wait(); - this.testHostManager.HostExited -= this.TestHostManagerHostExited; - this.testHostManager.HostLaunched -= this.TestHostManagerHostLaunched; + this.TestHostManager.HostExited -= this.TestHostManagerHostExited; + this.TestHostManager.HostLaunched -= this.TestHostManagerHostLaunched; } } #endregion /// - /// This method is exposed to enable derived classes to modify TestProcessStartInfo. E.g. DataCollection need additional environment variables to be passed, etc. + /// This method is exposed to enable derived classes to modify + /// . For example, data collectors need additional + /// environment variables to be passed. /// - /// - /// The sources. - /// + /// + /// The test process start info. + /// /// /// The . /// - protected virtual TestProcessStartInfo UpdateTestProcessStartInfo(TestProcessStartInfo testProcessStartInfo) + public virtual TestProcessStartInfo UpdateTestProcessStartInfo(TestProcessStartInfo testProcessStartInfo) { - // Update Telemetry Opt in status because by default in Test Host Telemetry is opted out - var telemetryOptedIn = this.requestData.IsTelemetryOptedIn ? "true" : "false"; - testProcessStartInfo.Arguments += " --telemetryoptedin " + telemetryOptedIn; - return testProcessStartInfo; - } - - protected string GetTimestampedLogFile(string logFile) - { - if (string.IsNullOrWhiteSpace(logFile)) + if (this.baseProxy == null) { - return null; + // Update Telemetry Opt in status because by default in Test Host Telemetry is opted out + var telemetryOptedIn = this.RequestData.IsTelemetryOptedIn ? "true" : "false"; + testProcessStartInfo.Arguments += " --telemetryoptedin " + telemetryOptedIn; + return testProcessStartInfo; } - return Path.ChangeExtension( - logFile, - string.Format( - "host.{0}_{1}{2}", - DateTime.Now.ToString("yy-MM-dd_HH-mm-ss_fffff"), - new PlatformEnvironment().GetCurrentManagedThreadId(), - Path.GetExtension(logFile))).AddDoubleQuote(); + return this.baseProxy.UpdateTestProcessStartInfo(testProcessStartInfo); } /// - /// This function will remove the unknown runsettings node from runsettings for old testhost who throws exception for unknown node. + /// This function will remove the unknown run settings nodes from the run settings strings. + /// This is necessary because older test hosts may throw exceptions when encountering + /// unknown nodes. /// - /// runsettings string - /// runsetting after removing un-required nodes - protected string RemoveNodesFromRunsettingsIfRequired(string runsettingsXml, Action logMessage) + /// + /// Run settings string. + /// + /// The run settings after removing non-required nodes. + public string RemoveNodesFromRunsettingsIfRequired(string runsettingsXml, Action logMessage) { var updatedRunSettingsXml = runsettingsXml; if (!this.makeRunsettingsCompatibleSet) @@ -293,20 +383,36 @@ protected string RemoveNodesFromRunsettingsIfRequired(string runsettingsXml, Act return updatedRunSettingsXml; } + private string GetTimestampedLogFile(string logFile) + { + if (string.IsNullOrWhiteSpace(logFile)) + { + return null; + } + + return Path.ChangeExtension( + logFile, + string.Format( + "host.{0}_{1}{2}", + DateTime.Now.ToString("yy-MM-dd_HH-mm-ss_fffff"), + new PlatformEnvironment().GetCurrentManagedThreadId(), + Path.GetExtension(logFile))).AddDoubleQuote(); + } + private void CompatIssueWithVersionCheckAndRunsettings() { - var properties = this.testHostManager.GetType().GetRuntimeProperties(); + var properties = this.TestHostManager.GetType().GetRuntimeProperties(); var versionCheckProperty = properties.FirstOrDefault(p => string.Equals(p.Name, versionCheckPropertyName, StringComparison.OrdinalIgnoreCase)); if (versionCheckProperty != null) { - this.versionCheckRequired = (bool)versionCheckProperty.GetValue(this.testHostManager); + this.versionCheckRequired = (bool)versionCheckProperty.GetValue(this.TestHostManager); } var makeRunsettingsCompatibleProperty = properties.FirstOrDefault(p => string.Equals(p.Name, makeRunsettingsCompatiblePropertyName, StringComparison.OrdinalIgnoreCase)); if (makeRunsettingsCompatibleProperty != null) { - this.makeRunsettingsCompatible = (bool)makeRunsettingsCompatibleProperty.GetValue(this.testHostManager); + this.makeRunsettingsCompatible = (bool)makeRunsettingsCompatibleProperty.GetValue(this.TestHostManager); this.makeRunsettingsCompatibleSet = true; } } @@ -322,11 +428,11 @@ private void TestHostManagerHostExited(object sender, HostProviderEventArgs e) EqtTrace.Verbose("CrossPlatEngine.TestHostManagerHostExited: calling on client process exit callback."); this.testHostProcessStdError = e.Data; - // this needs to be set before we call the OnClientProcess exit - // because the OnClientProcess will short-circuit WaitForRequestHandlerConnection in SetupChannel - // that then continues to throw an exception and checks if the testhost process exited - // if not it reports timeout, if we don't set this before OnClientProcessExit we will report timeout - // even though we exited the test host before even attempting the connect + // This needs to be set before we call the OnClientProcess exit because the + // OnClientProcess will short-circuit WaitForRequestHandlerConnection in SetupChannel + // that then continues to throw an exception and checks if the test host process exited. + // If not it reports timeout, if we don't set this before OnClientProcessExit we will + // report timeout even though we exited the test host before even attempting the connect. this.testHostExited.Set(); this.RequestSender.OnClientProcessExit(this.testHostProcessStdError); } @@ -335,8 +441,8 @@ private void ThrowOnTestHostExited(bool testHostExited) { if (testHostExited) { - // we might consider passing standard output here in case standard error is not available because some - // errors don't end up in the standard error output + // We might consider passing standard output here in case standard error is not + // available because some errors don't end up in the standard error output. throw new TestPlatformException(string.Format(CrossPlatEngineResources.TestHostExitedWithError, this.testHostProcessStdError)); } } @@ -346,7 +452,7 @@ private void ThrowExceptionOnConnectionFailure(int connTimeout) // Failed to launch testhost process. var errorMsg = CrossPlatEngineResources.InitializationFailed; - // Testhost launched but Timeout occurred due to machine slowness. + // Testhost launched but timeout occurred due to machine slowness. if (this.testHostLaunched) { errorMsg = string.Format( @@ -360,7 +466,7 @@ private void ThrowExceptionOnConnectionFailure(int connTimeout) // After testhost process launched failed with error. if (!string.IsNullOrWhiteSpace(this.testHostProcessStdError)) { - // Testhost failed with error + // Testhost failed with error. errorMsg = string.Format(CrossPlatEngineResources.TestHostExitedWithError, this.testHostProcessStdError); } diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManagerWithDataCollection.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManagerWithDataCollection.cs new file mode 100644 index 0000000000..67b8b07c4c --- /dev/null +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManagerWithDataCollection.cs @@ -0,0 +1,146 @@ +// 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.CrossPlatEngine.Client +{ + using System; + using System.Collections.Generic; + + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; + using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection.Interfaces; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Host; + + /// + /// The proxy operation manager with data collection. + /// + public class ProxyOperationManagerWithDataCollection : ProxyOperationManager + { + private IDictionary dataCollectionEnvironmentVariables; + private IRequestData requestData; + private int dataCollectionPort; + + /// + /// Initializes a new instance of the + /// class. + /// + /// + /// The request data. + /// The request sender. + /// The test host manager. + /// The data collection proxy. + public ProxyOperationManagerWithDataCollection( + IRequestData requestData, + ITestRequestSender requestSender, + ITestRuntimeProvider testHostManager, + IProxyDataCollectionManager proxyDataCollectionManager) + : base( + requestData, + requestSender, + testHostManager) + { + this.ProxyDataCollectionManager = proxyDataCollectionManager; + this.DataCollectionRunEventsHandler = new DataCollectionRunEventsHandler(); + this.requestData = requestData; + this.dataCollectionEnvironmentVariables = new Dictionary(); + + testHostManager.HostLaunched += this.TestHostLaunchedHandler; + } + + /// + public override void Initialize(bool skipDefaultAdapters) + { + this.ProxyDataCollectionManager.Initialize(); + + try + { + var dataCollectionParameters = this.ProxyDataCollectionManager.BeforeTestRunStart( + resetDataCollectors: true, + isRunStartingNow: true, + runEventsHandler: this.DataCollectionRunEventsHandler); + + if (dataCollectionParameters != null) + { + this.dataCollectionEnvironmentVariables = dataCollectionParameters.EnvironmentVariables; + this.dataCollectionPort = dataCollectionParameters.DataCollectionEventsPort; + } + } + catch (Exception) + { + // On failure in calling BeforeTestRunStart, call AfterTestRunEnd to end the data + // collection process. + this.ProxyDataCollectionManager.AfterTestRunEnd( + isCanceled: true, + runEventsHandler: this.DataCollectionRunEventsHandler); + throw; + } + + base.Initialize(skipDefaultAdapters); + } + + /// + public override TestProcessStartInfo UpdateTestProcessStartInfo(TestProcessStartInfo testProcessStartInfo) + { + if (testProcessStartInfo.EnvironmentVariables == null) + { + testProcessStartInfo.EnvironmentVariables = this.dataCollectionEnvironmentVariables; + } + else + { + foreach (var kvp in this.dataCollectionEnvironmentVariables) + { + testProcessStartInfo.EnvironmentVariables[kvp.Key] = kvp.Value; + } + } + + // Update telemetry opt in status because by default test host telemetry is opted out. + var telemetryOptedIn = this.requestData.IsTelemetryOptedIn ? "true" : "false"; + testProcessStartInfo.Arguments += " --datacollectionport " + this.dataCollectionPort + + " --telemetryoptedin " + telemetryOptedIn; + + return testProcessStartInfo; + } + + /// + public override bool SetupChannel( + IEnumerable sources, + string runSettings, + ITestMessageEventHandler eventHandler) + { + // Log all the messages that are reported while initializing the DataCollectionClient. + if (this.DataCollectionRunEventsHandler.Messages.Count > 0) + { + foreach (var message in this.DataCollectionRunEventsHandler.Messages) + { + eventHandler.HandleLogMessage(message.Item1, message.Item2); + } + + this.DataCollectionRunEventsHandler.Messages.Clear(); + } + + return base.SetupChannel(sources, runSettings); + } + + /// + /// Gets the data collection run events handler. + /// + internal DataCollectionRunEventsHandler DataCollectionRunEventsHandler + { + get; private set; + } + + /// + /// Gets the proxy data collection manager. + /// + internal IProxyDataCollectionManager ProxyDataCollectionManager + { + get; private set; + } + + private void TestHostLaunchedHandler(object sender, HostProviderEventArgs e) + { + this.ProxyDataCollectionManager.TestHostLaunched(e.ProcessId); + } + } +} diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/ProxyDataCollectionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/ProxyDataCollectionManager.cs index 282ceb5bf5..999e57309e 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/ProxyDataCollectionManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/ProxyDataCollectionManager.cs @@ -29,6 +29,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection using CrossPlatEngineResources = Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Resources.Resources; using CommunicationUtilitiesResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; using CoreUtilitiesConstants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; + using Microsoft.VisualStudio.TestPlatform.Common.DataCollection; /// /// Managed datacollector interaction from runner process. @@ -147,15 +148,24 @@ internal ProxyDataCollectionManager(IRequestData requestData, string settingsXml /// public Collection AfterTestRunEnd(bool isCanceled, ITestMessageEventHandler runEventsHandler) { - Collection attachmentSet = null; + AfterTestRunEndResult afterTestRunEnd = null; this.InvokeDataCollectionServiceAction( - () => - { - EqtTrace.Info("ProxyDataCollectionManager.AfterTestRunEnd: Get attachment set for datacollector processId: {0} port: {1}", dataCollectionProcessId, dataCollectionPort); - attachmentSet = this.dataCollectionRequestSender.SendAfterTestRunEndAndGetResult(runEventsHandler, isCanceled); - }, - runEventsHandler); - return attachmentSet; + () => + { + EqtTrace.Info("ProxyDataCollectionManager.AfterTestRunEnd: Get attachment set for datacollector processId: {0} port: {1}", dataCollectionProcessId, dataCollectionPort); + afterTestRunEnd = this.dataCollectionRequestSender.SendAfterTestRunEndAndGetResult(runEventsHandler, isCanceled); + }, + runEventsHandler); + + if (requestData.IsTelemetryOptedIn && afterTestRunEnd?.Metrics != null) + { + foreach (var metric in afterTestRunEnd.Metrics) + { + requestData.MetricsCollection.Add(metric.Key, metric.Value); + } + } + + return afterTestRunEnd?.AttachmentSets; } /// @@ -186,7 +196,7 @@ public DataCollectionParameters BeforeTestRunStart( () => { EqtTrace.Info("ProxyDataCollectionManager.BeforeTestRunStart: Get environment variable and port for datacollector processId: {0} port: {1}", this.dataCollectionProcessId, this.dataCollectionPort); - var result = this.dataCollectionRequestSender.SendBeforeTestRunStartAndGetResult(this.SettingsXml, this.Sources, runEventsHandler); + var result = this.dataCollectionRequestSender.SendBeforeTestRunStartAndGetResult(this.SettingsXml, this.Sources, this.requestData.IsTelemetryOptedIn, runEventsHandler); environmentVariables = result.EnvironmentVariables; dataCollectionEventsPort = result.DataCollectionEventsPort; diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs index 89809c139e..50137fe787 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs @@ -24,9 +24,10 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities public class TestRequestHandler : ITestRequestHandler { private int protocolVersion = 1; - - // Also check TestRequestSender. - private int highestSupportedVersion = 4; + + // Must be in sync with the highest supported version in + // src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs file. + private int highestSupportedVersion = 5; private readonly IDataSerializer dataSerializer; private ITestHostManagerFactory testHostManagerFactory; diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Microsoft.TestPlatform.CrossPlatEngine.csproj b/src/Microsoft.TestPlatform.CrossPlatEngine/Microsoft.TestPlatform.CrossPlatEngine.csproj index f350f7fd32..72e7d1f777 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Microsoft.TestPlatform.CrossPlatEngine.csproj +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Microsoft.TestPlatform.CrossPlatEngine.csproj @@ -21,7 +21,7 @@ - + true diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.Designer.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.Designer.cs index 683eb49355..8ee4d46c5c 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.Designer.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.Designer.cs @@ -11,8 +11,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Resources { using System; using System.Reflection; - - + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -205,6 +204,15 @@ internal static string LaunchDebugProcessNotAllowedForANonDebugRun { } } + /// + /// Looks up a localized string similar to Could not find an available proxy to deque.. + /// + internal static string NoAvailableProxyForDeque { + get { + return ResourceManager.GetString("NoAvailableProxyForDeque", resourceCulture); + } + } + /// /// Looks up a localized string similar to Could not find {0}. Make sure that the dotnet is installed on the machine.. /// @@ -232,6 +240,15 @@ internal static string NonExistingExtensions { } } + /// + /// Looks up a localized string similar to Proxy with id {0} is not managed by the current session manager.. + /// + internal static string NoSuchProxyId { + get { + return ResourceManager.GetString("NoSuchProxyId", resourceCulture); + } + } + /// /// Looks up a localized string similar to No test matches the given testcase filter `{0}` in {1}. /// @@ -259,6 +276,15 @@ internal static string OldTestHostIsGettingUsed { } } + /// + /// Looks up a localized string similar to Proxy with id {0} is already available and cannot be re-enqueued.. + /// + internal static string ProxyIsAlreadyAvailable { + get { + return ResourceManager.GetString("ProxyIsAlreadyAvailable", resourceCulture); + } + } + /// /// Looks up a localized string similar to , . /// diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.resx b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.resx index 4ef18b3697..802bf4805b 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.resx +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/Resources.resx @@ -204,4 +204,13 @@ {0} Access denied while trying to create "TestResults" folder in mentioned location. You are getting this exception because you are running vstest.console.exe from a folder which requires having write access. To solve the issue: please run vstest.console.exe from a folder where you have write privileges. + + Could not find an available proxy to deque. + + + Proxy with id {0} is not managed by the current session manager. + + + Proxy with id {0} is already available and cannot be re-enqueued. + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.cs.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.cs.xlf index b1003dc39a..f82d76a3e7 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.cs.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.cs.xlf @@ -217,6 +217,21 @@ {0} Při pokusu o vytvoření složky TestResults v uvedeném umístění došlo k odepření přístupu. Tato výjimka se vyvolala, protože spouštíte vstest.console.exe ze složky, která vyžaduje, abyste měli přístup pro zápis. Pokud chcete problém vyřešit, spusťte prosím vstest.console.exe ze složky, ve které máte oprávnění k zápisu. + + Could not find an available proxy to deque. + Nepovedlo se najít dostupný proxy server, který se má odebrat z fronty. + + + + Proxy with id {0} is not managed by the current session manager. + Aktuální správce relace nespravuje proxy s ID {0}. + + + + Proxy with id {0} is already available and cannot be re-enqueued. + Proxy s ID {0} je už k dispozici a nedá se znovu zařadit do fronty. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.de.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.de.xlf index 6d380d102c..fa9a4ee1bc 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.de.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.de.xlf @@ -217,6 +217,21 @@ {0} Beim Erstellen des Ordners "TestResults" am angegebenen Speicherort wurde der Zugriff verweigert. Sie erhalten diese Ausnahme, weil Sie "vstest.console.exe" in einem Ordner ausführen, für den Schreibzugriff erforderlich ist. So beheben Sie das Problem: Führen Sie "vstest.console.exe" in einem Ordner aus, für den Sie Schreibberechtigungen besitzen. + + Could not find an available proxy to deque. + Es wurde kein verfügbarer Proxy für die Deque gefunden. + + + + Proxy with id {0} is not managed by the current session manager. + Der Proxy mit der ID {0} wird nicht vom aktuellen Sitzungs-Manager verwaltet. + + + + Proxy with id {0} is already available and cannot be re-enqueued. + Der Proxy mit der ID {0} ist bereits verfügbar und kann nicht erneut in die Warteschlange eingereiht werden. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.es.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.es.xlf index b7610805b3..87e1f13a4e 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.es.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.es.xlf @@ -217,6 +217,21 @@ {0} Se denegó el acceso al intentar crear la carpeta "TestResults" en la ubicación mencionada. Está recibiendo esta excepción porque está ejecutando vstest.console.exe desde una carpeta que requiere acceso de escritura. Para solucionar la incidencia: ejecute vstest.console.exe desde una carpeta en la que tenga privilegios de escritura. + + Could not find an available proxy to deque. + No se encontró ningún proxy disponible para quitar de la cola. + + + + Proxy with id {0} is not managed by the current session manager. + El administrador de la sesión actual no administra el proxy con el identificador {0}. + + + + Proxy with id {0} is already available and cannot be re-enqueued. + El proxy con el identificador {0} ya está disponible y no se puede volver a poner en cola. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.fr.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.fr.xlf index 82a010bfab..81c3bb53d1 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.fr.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.fr.xlf @@ -217,6 +217,21 @@ {0} Accès refusé durant la tentative de création du dossier "TestResults" à l'emplacement indiqué. Vous obtenez cette exception, car vous exécutez vstest.console.exe à partir d'un dossier qui nécessite un accès en écriture. Pour résoudre le problème, exécutez vstest.console.exe à partir d'un dossier sur lequel vous disposez de privilèges d'accès en écriture. + + Could not find an available proxy to deque. + Impossible de localiser un proxy disponible à dépiler. + + + + Proxy with id {0} is not managed by the current session manager. + Le proxy ayant l'ID {0} n'est pas géré par le gestionnaire de session actuel. + + + + Proxy with id {0} is already available and cannot be re-enqueued. + Le proxy ayant l'ID {0} est déjà disponible et ne peut pas être empilé à nouveau. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.it.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.it.xlf index 1df6136b0f..21bfaa9c17 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.it.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.it.xlf @@ -217,6 +217,21 @@ {0} Accesso negato durante il tentativo di creare la cartella "TestResults" nel percorso indicato. Si riceve questa eccezione perché si esegue vstest.console.exe da una cartella per cui è necessario l'accesso in scrittura. Per risolvere il problema, eseguire vstest.console.exe da una cartella per cui si hanno privilegi di scrittura. + + Could not find an available proxy to deque. + Non è stato possibile trovare un proxy disponibile da rimuovere dalla coda. + + + + Proxy with id {0} is not managed by the current session manager. + Il proxy con ID {0} non è gestito dallo strumento di gestione sessioni corrente. + + + + Proxy with id {0} is already available and cannot be re-enqueued. + Il proxy con ID {0} è già disponibile e non può essere riaccodato. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ja.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ja.xlf index 133ec5d7fb..0eb80ccaa0 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ja.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ja.xlf @@ -217,6 +217,21 @@ {0} 記載した場所に "TestResults" フォルダーを作成しようとしたときにアクセスが拒否されました。書き込みアクセスを必要とするフォルダーから vstest.console.exe を実行しているため、この例外が発生しています。この問題を解決するには、書き込み特権のあるフォルダーから vstest.console.exe を実行してください。 + + Could not find an available proxy to deque. + デキューするために使用できるプロキシが見つかりませんでした。 + + + + Proxy with id {0} is not managed by the current session manager. + ID が {0} のプロキシは、現在のセッション マネージャーで管理されません。 + + + + Proxy with id {0} is already available and cannot be re-enqueued. + ID が {0} のプロキシは、既に使用可能になっているため、再度エンキューすることはできません。 + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ko.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ko.xlf index e7fcac9dde..92958896e9 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ko.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ko.xlf @@ -217,6 +217,21 @@ {0} "TestResults" 폴더를 언급된 위치에 만드는 동안 액세스가 거부되었습니다. 쓰기 권한이 필요한 폴더에서 vstest.console.exe를 실행하고 있으므로 이 예외가 발생했습니다. 이 문제를 해결하려면 쓰기 권한이 있는 폴더에서 vstest.console.exe를 실행하세요. + + Could not find an available proxy to deque. + 큐에서 제거하기 위해 사용할 수 있는 프록시를 찾을 수 없습니다. + + + + Proxy with id {0} is not managed by the current session manager. + ID가 {0}인 프록시가 현재 세션 관리자에서 관리되지 않습니다. + + + + Proxy with id {0} is already available and cannot be re-enqueued. + ID가 {0}인 프록시를 이미 사용할 수 있으며 큐에 다시 넣을 수 없습니다. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pl.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pl.xlf index 872c937c60..793a78d4e8 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pl.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pl.xlf @@ -217,6 +217,21 @@ {0} Odmowa dostępu podczas próby utworzenia folderu „TestResults” w określonej lokalizacji. Widzisz ten wyjątek, ponieważ program vstest.console.exe został uruchomiony z folderu wymagającego dostępu do zapisu. Aby rozwiązać ten problem: uruchom program vstest.console.exe z folderu, w którym masz uprawnienia do zapisu. + + Could not find an available proxy to deque. + Nie można było znaleźć dostępnego serwera proxy do umieszczenia w kolejce dwukierunkowej. + + + + Proxy with id {0} is not managed by the current session manager. + Serwer proxy o identyfikatorze {0} nie jest zarządzany przez bieżącego menedżera sesji. + + + + Proxy with id {0} is already available and cannot be re-enqueued. + Serwer proxy o identyfikatorze {0} jest już dostępny i nie można go ponownie umieścić w kolejce. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pt-BR.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pt-BR.xlf index 3fd80a0374..63502df5bb 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pt-BR.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.pt-BR.xlf @@ -217,6 +217,21 @@ {0} Acesso negado ao tentar criar a pasta "TestResults" no local mencionado. Você está recebendo esta exceção porque está executando o vstest.console.exe em uma pasta que requer acesso para gravação. Para resolver o problema: execute vstest.console.exe em uma pasta na qual você tenha privilégios de gravação. + + Could not find an available proxy to deque. + Não foi possível encontrar um proxy disponível para deque. + + + + Proxy with id {0} is not managed by the current session manager. + O proxy com a ID {0} não é gerenciado pelo gerenciador de sessão atual. + + + + Proxy with id {0} is already available and cannot be re-enqueued. + O proxy com a ID {0} já está disponível e não pode ser enfileirado novamente. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ru.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ru.xlf index 4327825219..37a6f933f6 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ru.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.ru.xlf @@ -217,6 +217,21 @@ {0} Отказано в доступе при попытке создания папки "TestResults" в указанном расположении. Это исключение возникло, так как вы запускаете файл vstest.console.exe из папки, для которой требуется доступ на запись. Чтобы устранить эту проблему, запустите vstest.console.exe из папки, для которой у вас есть разрешения на запись. + + Could not find an available proxy to deque. + Не удалось найти доступный прокси-сервер для двусторонней очереди. + + + + Proxy with id {0} is not managed by the current session manager. + Прокси-сервер с идентификатором {0} не управляется текущим диспетчером сеансов. + + + + Proxy with id {0} is already available and cannot be re-enqueued. + Прокси-сервер с идентификатором {0} уже доступен и не может быть повторно поставлен в очередь. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.tr.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.tr.xlf index e232d989cd..442955eaec 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.tr.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.tr.xlf @@ -217,6 +217,21 @@ {0} Belirtilen konumda "TestResults" klasörü oluşturulmaya çalışılırken erişim engellendi. Yazma erişimi gerektiren bir klasörden vstest.console.exe çalıştırdığınız için bu özel durumu aldınız. Sorunu çözmek için lütfen yazma ayrıcalıklarına sahip olduğunuz bir klasörden vstest.console.exe dosyasını çalıştırın. + + Could not find an available proxy to deque. + İki uçtan erişimli kuyruğa yönelik kullanılabilir ara sunucu bulunamadı. + + + + Proxy with id {0} is not managed by the current session manager. + {0} kimliğine sahip ara sunucu, geçerli oturum yöneticisi tarafından yönetilmiyor. + + + + Proxy with id {0} is already available and cannot be re-enqueued. + {0} kimliğine sahip ara sunucu zaten var ve yeniden kuyruğa alınamaz. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.xlf index 7c88354463..a5998be2f6 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.xlf @@ -128,6 +128,21 @@ {0} Access denied while trying to create "TestResults" folder in mentioned location. You are getting this exception because you are running vstest.console.exe from a folder which requires having write access. To solve the issue: please run vstest.console.exe from a folder where you have write privileges. For more information, please look at the error message: + + Could not find an available proxy to deque. + Could not find an available proxy to deque. + + + + Proxy with id {0} is not managed by the current session manager. + Proxy with id {0} is not managed by the current session manager. + + + + Proxy with id {0} is already available and cannot be re-enqueued. + Proxy with id {0} is already available and cannot be re-enqueued. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hans.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hans.xlf index 9404756105..dc8c5a7f29 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hans.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hans.xlf @@ -1,6 +1,6 @@  - +
228 @@ -217,6 +217,21 @@ {0} 尝试在所述位置创建 "TestResults" 文件夹时,访问被拒。你收到此异常是因为你正在从需要具有写入权限的文件夹运行 vstest.console.exe。若要解决此问题,请从你具有写入权限的文件夹运行 vstest.console.exe。 + + Could not find an available proxy to deque. + 找不到用于取消排队的可用代理。 + + + + Proxy with id {0} is not managed by the current session manager. + ID 为 {0} 的代理不受当前会话管理器管理。 + + + + Proxy with id {0} is already available and cannot be re-enqueued. + ID 为 {0} 的代理已可用,无法重新排队。 + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hant.xlf b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hant.xlf index da689cb08e..15881061f1 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hant.xlf +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Resources/xlf/Resources.zh-Hant.xlf @@ -1,6 +1,6 @@  - +
228 @@ -217,6 +217,21 @@ {0} 當嘗試在提及的位置上建立 "TestResults" 資料夾時存取被拒。因為您正從需要寫入存取權的資料夾執行 vstest.console.exe,所以收到此例外狀況。若要解決此問題: 請從您有權寫入的資料夾執行 vstest.console.exe。 + + Could not find an available proxy to deque. + 找不到任何要排除於佇列外的 Proxy。 + + + + Proxy with id {0} is not managed by the current session manager. + 識別碼為 {0} 的 Proxy 並非由目前的工作階段管理員所管理。 + + + + Proxy with id {0} is already available and cannot be re-enqueued. + 識別碼為 {0} 的 Proxy 已可供使用,但無法重新加入佇列。 + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs index 0f9f6e8118..82efbca0be 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs @@ -27,7 +27,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine using Microsoft.VisualStudio.TestPlatform.Utilities; /// - /// Cross Platform test engine entry point for the client. + /// Cross platform test engine entry point for the client. /// public class TestEngine : ITestEngine { @@ -43,7 +43,9 @@ public class TestEngine : ITestEngine { } - protected TestEngine(TestRuntimeProviderManager testHostProviderManager, IProcessHelper processHelper) + protected TestEngine( + TestRuntimeProviderManager testHostProviderManager, + IProcessHelper processHelper) { this.testHostProviderManager = testHostProviderManager; this.processHelper = processHelper; @@ -51,33 +53,28 @@ protected TestEngine(TestRuntimeProviderManager testHostProviderManager, IProces #region ITestEngine implementation - /// - /// Fetches the DiscoveryManager for this engine. This manager would provide all functionality required for discovery. - /// - /// - /// The request data for providing discovery services and data. - /// - /// - /// Test host manager - /// - /// - /// The discovery Criteria. - /// - /// - /// ITestDiscoveryManager object that can do discovery - /// - public IProxyDiscoveryManager GetDiscoveryManager(IRequestData requestData, ITestRuntimeProvider testHostManager, DiscoveryCriteria discoveryCriteria) + /// + public IProxyDiscoveryManager GetDiscoveryManager( + IRequestData requestData, + ITestRuntimeProvider testHostManager, + DiscoveryCriteria discoveryCriteria) { - var parallelLevel = this.VerifyParallelSettingAndCalculateParallelLevel(discoveryCriteria.Sources.Count(), discoveryCriteria.RunSettings); + var parallelLevel = this.VerifyParallelSettingAndCalculateParallelLevel( + discoveryCriteria.Sources.Count(), + discoveryCriteria.RunSettings); - // Collecting IsParallel Enabled - requestData.MetricsCollection.Add(TelemetryDataConstants.ParallelEnabledDuringDiscovery, parallelLevel > 1 ? "True" : "False"); + // Collecting IsParallel enabled. + requestData.MetricsCollection.Add( + TelemetryDataConstants.ParallelEnabledDuringDiscovery, + parallelLevel > 1 ? "True" : "False"); if (this.ShouldRunInNoIsolation(discoveryCriteria.RunSettings, parallelLevel > 1, false)) { var isTelemetryOptedIn = requestData.IsTelemetryOptedIn; var newRequestData = this.GetRequestData(isTelemetryOptedIn); - return new InProcessProxyDiscoveryManager(testHostManager, new TestHostManagerFactory(newRequestData)); + return new InProcessProxyDiscoveryManager( + testHostManager, + new TestHostManagerFactory(newRequestData)); } Func proxyDiscoveryManagerCreator = () => @@ -85,44 +82,82 @@ public IProxyDiscoveryManager GetDiscoveryManager(IRequestData requestData, ITes var hostManager = this.testHostProviderManager.GetTestHostManagerByRunConfiguration(discoveryCriteria.RunSettings); hostManager?.Initialize(TestSessionMessageLogger.Instance, discoveryCriteria.RunSettings); - return new ProxyDiscoveryManager(requestData, new TestRequestSender(requestData.ProtocolConfig, hostManager), hostManager); + return new ProxyDiscoveryManager( + requestData, + new TestRequestSender(requestData.ProtocolConfig, hostManager), + hostManager); }; - return !testHostManager.Shared ? new ParallelProxyDiscoveryManager(requestData, proxyDiscoveryManagerCreator, parallelLevel, sharedHosts: testHostManager.Shared) : proxyDiscoveryManagerCreator(); + return testHostManager.Shared + ? proxyDiscoveryManagerCreator() + : new ParallelProxyDiscoveryManager( + requestData, + proxyDiscoveryManagerCreator, + parallelLevel, + sharedHosts: testHostManager.Shared); } - /// - /// Fetches the ExecutionManager for this engine. This manager would provide all functionality required for execution. - /// - /// The request data for providing execution services and data - /// Test host manager. - /// Test run criterion. - /// - /// ITestExecutionManager object that can do execution - /// - public IProxyExecutionManager GetExecutionManager(IRequestData requestData, ITestRuntimeProvider testHostManager, TestRunCriteria testRunCriteria) + /// + public IProxyExecutionManager GetExecutionManager( + IRequestData requestData, + ITestRuntimeProvider testHostManager, + TestRunCriteria testRunCriteria) { var distinctSources = GetDistinctNumberOfSources(testRunCriteria); - var parallelLevel = this.VerifyParallelSettingAndCalculateParallelLevel(distinctSources, testRunCriteria.TestRunSettings); + var parallelLevel = this.VerifyParallelSettingAndCalculateParallelLevel( + distinctSources, + testRunCriteria.TestRunSettings); - // Collecting IsParallel Enabled - requestData.MetricsCollection.Add(TelemetryDataConstants.ParallelEnabledDuringExecution, parallelLevel > 1 ? "True" : "False"); + // Collecting IsParallel enabled. + requestData.MetricsCollection.Add( + TelemetryDataConstants.ParallelEnabledDuringExecution, + parallelLevel > 1 ? "True" : "False"); var isDataCollectorEnabled = XmlRunSettingsUtilities.IsDataCollectionEnabled(testRunCriteria.TestRunSettings); - var isInProcDataCollectorEnabled = XmlRunSettingsUtilities.IsInProcDataCollectionEnabled(testRunCriteria.TestRunSettings); - if (this.ShouldRunInNoIsolation(testRunCriteria.TestRunSettings, parallelLevel > 1, isDataCollectorEnabled || isInProcDataCollectorEnabled)) + if (this.ShouldRunInNoIsolation( + testRunCriteria.TestRunSettings, + parallelLevel > 1, + isDataCollectorEnabled || isInProcDataCollectorEnabled)) { var isTelemetryOptedIn = requestData.IsTelemetryOptedIn; var newRequestData = this.GetRequestData(isTelemetryOptedIn); - return new InProcessProxyExecutionManager(testHostManager, new TestHostManagerFactory(newRequestData)); + return new InProcessProxyExecutionManager( + testHostManager, + new TestHostManagerFactory(newRequestData)); } - // SetupChannel ProxyExecutionManager with data collection if data collectors are specififed in run settings. + // SetupChannel ProxyExecutionManager with data collection if data collectors are + // specififed in run settings. Func proxyExecutionManagerCreator = () => { - // Create a new HostManager, to be associated with individual ProxyExecutionManager(&POM) + if (testRunCriteria.TestSessionInfo != null) + { + try + { + // In case we have an active test session, data collection needs were + // already taken care of when first creating the session. As a consequence + // we always return this proxy instead of choosing between the vanilla + // execution proxy and the one with data collection enabled. + return new ProxyExecutionManager( + testRunCriteria.TestSessionInfo, + testRunCriteria.DebugEnabledForTestSession); + } + catch (InvalidOperationException ex) + { + // If the proxy creation process based on test session info failed, then + // we'll proceed with the normal creation process as if no test session + // info was passed in in the first place. + // + // WARNING: This should not normally happen and it raises questions + // regarding the test session pool operation and consistency. + EqtTrace.Warning("ProxyExecutionManager failed: {0}", ex.ToString()); + } + } + + // Create a new host manager, to be associated with individual + // ProxyExecutionManager(&POM) var hostManager = this.testHostProviderManager.GetTestHostManagerByRunConfiguration(testRunCriteria.TestRunSettings); hostManager?.Initialize(TestSessionMessageLogger.Instance, testRunCriteria.TestRunSettings); @@ -133,35 +168,97 @@ public IProxyExecutionManager GetExecutionManager(IRequestData requestData, ITes var requestSender = new TestRequestSender(requestData.ProtocolConfig, hostManager); - return isDataCollectorEnabled ? new ProxyExecutionManagerWithDataCollection(requestData, requestSender, hostManager, new ProxyDataCollectionManager(requestData, testRunCriteria.TestRunSettings, GetSourcesFromTestRunCriteria(testRunCriteria))) - : new ProxyExecutionManager(requestData, requestSender, hostManager); + return isDataCollectorEnabled + ? new ProxyExecutionManagerWithDataCollection( + requestData, + requestSender, + hostManager, + new ProxyDataCollectionManager( + requestData, + testRunCriteria.TestRunSettings, + GetSourcesFromTestRunCriteria(testRunCriteria))) + : new ProxyExecutionManager( + requestData, + requestSender, + hostManager); }; // parallelLevel = 1 for desktop should go via else route. - if (parallelLevel > 1 || !testHostManager.Shared) + return (parallelLevel > 1 || !testHostManager.Shared) + ? new ParallelProxyExecutionManager( + requestData, + proxyExecutionManagerCreator, + parallelLevel, + sharedHosts: testHostManager.Shared) + : proxyExecutionManagerCreator(); + } + + /// + public IProxyTestSessionManager GetTestSessionManager( + IRequestData requestData, + ITestRuntimeProvider testHostManager, + StartTestSessionCriteria testSessionCriteria) + { + var parallelLevel = this.VerifyParallelSettingAndCalculateParallelLevel( + testSessionCriteria.Sources.Count, + testSessionCriteria.RunSettings); + + requestData.MetricsCollection.Add( + TelemetryDataConstants.ParallelEnabledDuringStartTestSession, + parallelLevel > 1 ? "True" : "False"); + + var isDataCollectorEnabled = XmlRunSettingsUtilities.IsDataCollectionEnabled(testSessionCriteria.RunSettings); + var isInProcDataCollectorEnabled = XmlRunSettingsUtilities.IsInProcDataCollectionEnabled(testSessionCriteria.RunSettings); + + if (this.ShouldRunInNoIsolation( + testSessionCriteria.RunSettings, + parallelLevel > 1, + isDataCollectorEnabled || isInProcDataCollectorEnabled)) { - return new ParallelProxyExecutionManager(requestData, proxyExecutionManagerCreator, parallelLevel, sharedHosts: testHostManager.Shared); + // This condition is the equivalent of the in-process proxy execution manager case. + // In this case all tests will be run in the vstest.console process, so there's no + // test host to be started. As a consequence there'll be no session info. + return null; } - else + + Func proxyCreator = () => { - return proxyExecutionManagerCreator(); - } + var hostManager = this.testHostProviderManager.GetTestHostManagerByRunConfiguration(testSessionCriteria.RunSettings); + hostManager?.Initialize(TestSessionMessageLogger.Instance, testSessionCriteria.RunSettings); + + if (testSessionCriteria.TestHostLauncher != null) + { + hostManager.SetCustomLauncher(testSessionCriteria.TestHostLauncher); + } + + var requestSender = new TestRequestSender(requestData.ProtocolConfig, hostManager); + + return isDataCollectorEnabled + ? new ProxyOperationManagerWithDataCollection( + requestData, + requestSender, + hostManager, + new ProxyDataCollectionManager( + requestData, + testSessionCriteria.RunSettings, + testSessionCriteria.Sources)) + : new ProxyOperationManager( + requestData, + requestSender, + hostManager); + }; + + return new ProxyTestSessionManager(parallelLevel, proxyCreator); } - /// - /// Fetches the extension manager for this engine. This manager would provide extensibility features that this engine supports. - /// - /// ITestExtensionManager object that helps with extensibility + /// public ITestExtensionManager GetExtensionManager() { - return this.testExtensionManager ?? (this.testExtensionManager = new TestExtensionManager()); + return this.testExtensionManager + ?? (this.testExtensionManager = new TestExtensionManager()); } - /// - /// Fetches the logger manager for this engine. This manager will provide logger extensibility features that this engine supports. - /// - /// The request data for providing common execution services and data - /// ITestLoggerManager object that helps with logger extensibility. + /// public ITestLoggerManager GetLoggerManager(IRequestData requestData) { return new TestLoggerManager( @@ -174,7 +271,8 @@ public ITestLoggerManager GetLoggerManager(IRequestData requestData) private static int GetDistinctNumberOfSources(TestRunCriteria testRunCriteria) { - // No point in creating more processes if number of sources is less than what user configured for + // No point in creating more processes if number of sources is less than what the user + // configured for. int numSources = 1; if (testRunCriteria.HasSpecificTests) { @@ -190,48 +288,56 @@ private static int GetDistinctNumberOfSources(TestRunCriteria testRunCriteria) } /// - /// Verifies Parallel Setting and returns parallel level to use based on the run criteria + /// Verifies parallel setting and returns parallel level to use based on the run criteria. /// - /// - /// The source Count. - /// - /// - /// The run Settings. - /// - /// - /// Parallel Level to use - /// - private int VerifyParallelSettingAndCalculateParallelLevel(int sourceCount, string runSettings) + /// + /// The source count. + /// The run settings. + /// + /// The parallel level to use. + private int VerifyParallelSettingAndCalculateParallelLevel( + int sourceCount, + string runSettings) { - // Default is 1 + // Default is 1. int parallelLevelToUse = 1; try { - // Check the User Parallel Setting + // Check the user parallel setting. int userParallelSetting = RunSettingsUtilities.GetMaxCpuCount(runSettings); - parallelLevelToUse = userParallelSetting == 0 ? Environment.ProcessorCount : userParallelSetting; + parallelLevelToUse = userParallelSetting == 0 + ? Environment.ProcessorCount + : userParallelSetting; var enableParallel = parallelLevelToUse > 1; - EqtTrace.Verbose("TestEngine: Initializing Parallel Execution as MaxCpuCount is set to: {0}", parallelLevelToUse); + EqtTrace.Verbose( + "TestEngine: Initializing Parallel Execution as MaxCpuCount is set to: {0}", + parallelLevelToUse); - // Verify if the number of Sources is less than user setting of parallel - // we should use number of sources as the parallel level, if sources count is less than parallel level + // Verify if the number of sources is less than user setting of parallel. + // We should use number of sources as the parallel level, if sources count is less + // than parallel level. if (enableParallel) { parallelLevelToUse = Math.Min(sourceCount, parallelLevelToUse); - // If only one source, no need to use parallel service client + // If only one source, no need to use parallel service client. enableParallel = parallelLevelToUse > 1; if (EqtTrace.IsInfoEnabled) { - EqtTrace.Verbose("TestEngine: ParallelExecution set to '{0}' as the parallel level is adjusted to '{1}' based on number of sources", enableParallel, parallelLevelToUse); + EqtTrace.Verbose( + "TestEngine: ParallelExecution set to '{0}' as the parallel level is adjusted to '{1}' based on number of sources", + enableParallel, + parallelLevelToUse); } } } catch (Exception ex) { - EqtTrace.Error("TestEngine: Error occurred while initializing ParallelExecution: {0}", ex); + EqtTrace.Error( + "TestEngine: Error occurred while initializing ParallelExecution: {0}", + ex); EqtTrace.Warning("TestEngine: Defaulting to Sequential Execution"); parallelLevelToUse = 1; @@ -240,7 +346,10 @@ private int VerifyParallelSettingAndCalculateParallelLevel(int sourceCount, stri return parallelLevelToUse; } - private bool ShouldRunInNoIsolation(string runsettings, bool isParallelEnabled, bool isDataCollectorEnabled) + private bool ShouldRunInNoIsolation( + string runsettings, + bool isParallelEnabled, + bool isDataCollectorEnabled) { var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runsettings); @@ -261,7 +370,7 @@ private bool ShouldRunInNoIsolation(string runsettings, bool isParallelEnabled, var currentProcessPath = this.processHelper.GetCurrentProcessFileName(); - // If running with the dotnet executable, then don't run in InProcess + // If running with the dotnet executable, then don't run in in process. if (currentProcessPath.EndsWith("dotnet", StringComparison.OrdinalIgnoreCase) || currentProcessPath.EndsWith("dotnet.exe", StringComparison.OrdinalIgnoreCase)) { @@ -269,12 +378,12 @@ private bool ShouldRunInNoIsolation(string runsettings, bool isParallelEnabled, } // Return true if - // 1) Not running in parallel - // 2) Data collector is not enabled - // 3) Target framework is x86 or anyCpu - // 4) DisableAppDomain is false - // 5) Not running in design mode - // 6) target framework is NETFramework (Desktop test) + // 1) Not running in parallel; + // 2) Data collector is not enabled; + // 3) Target framework is x86 or anyCpu; + // 4) DisableAppDomain is false; + // 5) Not running in design mode; + // 6) target framework is NETFramework (Desktop test); if (!isParallelEnabled && !isDataCollectorEnabled && (runConfiguration.TargetPlatform == Architecture.X86 || runConfiguration.TargetPlatform == Architecture.AnyCPU) && @@ -293,28 +402,33 @@ private bool ShouldRunInNoIsolation(string runsettings, bool isParallelEnabled, } /// - /// Get Request Data on basis of Telemetry OptedIn or not + /// Get request data on basis of telemetry opted in or not. /// - /// - /// + /// + /// A flag indicating if telemetry is opted in. + /// + /// The request data. private IRequestData GetRequestData(bool isTelemetryOptedIn) { return new RequestData - { - MetricsCollection = isTelemetryOptedIn - ? (IMetricsCollection)new MetricsCollection() - : new NoOpMetricsCollection(), - IsTelemetryOptedIn = isTelemetryOptedIn - }; + { + MetricsCollection = isTelemetryOptedIn + ? (IMetricsCollection)new MetricsCollection() + : new NoOpMetricsCollection(), + IsTelemetryOptedIn = isTelemetryOptedIn + }; } /// - /// Gets test sources from test run criteria + /// Gets test sources from test run criteria. /// - /// test sources + /// + /// The test sources. private IEnumerable GetSourcesFromTestRunCriteria(TestRunCriteria testRunCriteria) { - return testRunCriteria.HasSpecificTests ? TestSourcesUtility.GetSources(testRunCriteria.Tests) : testRunCriteria.Sources; + return testRunCriteria.HasSpecificTests + ? TestSourcesUtility.GetSources(testRunCriteria.Tests) + : testRunCriteria.Sources; } } } diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/TestSession/ProxyTestSessionManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/TestSession/ProxyTestSessionManager.cs new file mode 100644 index 0000000000..1d072944fc --- /dev/null +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/TestSession/ProxyTestSessionManager.cs @@ -0,0 +1,218 @@ +// 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.CrossPlatEngine +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Threading.Tasks; + + using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Engine; + + using CrossPlatResources = Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Resources.Resources; + + /// + /// Orchestrates test session operations for the engine communicating with the client. + /// + public class ProxyTestSessionManager : IProxyTestSessionManager + { + private readonly object lockObject = new object(); + private int parallelLevel; + private bool skipDefaultAdapters; + private Func proxyCreator; + private Queue availableProxyQueue; + private IDictionary proxyMap; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The parallel level. + /// The proxy creator. + public ProxyTestSessionManager(int parallelLevel, Func proxyCreator) + { + this.parallelLevel = parallelLevel; + this.proxyCreator = proxyCreator; + + this.availableProxyQueue = new Queue(); + this.proxyMap = new Dictionary(); + } + + /// + public void Initialize(bool skipDefaultAdapters) + { + this.skipDefaultAdapters = skipDefaultAdapters; + } + + /// + public void StartSession( + StartTestSessionCriteria criteria, + ITestSessionEventsHandler eventsHandler) + { + var testSessionInfo = new TestSessionInfo(); + Task[] taskList = new Task[this.parallelLevel]; + + // Create all the proxies in parallel, one task per proxy. + for (int i = 0; i < this.parallelLevel; ++i) + { + taskList[i] = Task.Factory.StartNew(() => + { + // Create the proxy. + var operationManagerProxy = this.CreateProxy(); + + // Initialize the proxy. + operationManagerProxy.Initialize(this.skipDefaultAdapters); + + // Start the test host associated to the proxy. + operationManagerProxy.SetupChannel( + criteria.Sources, + criteria.RunSettings, + eventsHandler); + }); + } + + // Wait for proxy creation to be over. + Task.WaitAll(taskList); + + // Make the session available. + TestSessionPool.Instance.AddSession(testSessionInfo, this); + + // Let the caller know the session has been created. + eventsHandler.HandleStartTestSessionComplete(testSessionInfo); + } + + /// + public void StopSession() + { + // TODO (copoiena): Do nothing for now because in the current implementation the + // testhosts are disposed of right after the test run is done. However, when we'll + // decide to re-use the testhosts for discovery & execution we'll perform some + // changes for keeping them alive indefinetely, so the responsability for killing + // testhosts will be with the users of the vstest.console wrapper. Then we'll need + // to be able to dispose of the testhosts here. + + // foreach (var kvp in this.proxyMap) + // { + // } + } + + /// + /// Dequeues a proxy to be used either by discovery or execution. + /// + /// + /// The dequeued proxy. + public ProxyOperationManager DequeueProxy() + { + ProxyOperationManagerContainer proxyContainer = null; + + lock (this.lockObject) + { + // No proxy available means the caller will have to create its own proxy. + if (this.availableProxyQueue.Count == 0) + { + throw new InvalidOperationException( + string.Format( + CultureInfo.CurrentUICulture, + CrossPlatResources.NoAvailableProxyForDeque)); + } + + // Get the proxy id from the available queue. + var proxyId = this.availableProxyQueue.Dequeue(); + + // Get the actual proxy. + proxyContainer = this.proxyMap[proxyId]; + + // Mark the proxy as unavailable. + proxyContainer.IsAvailable = false; + } + + return proxyContainer.Proxy; + } + + /// + /// Enqueues a proxy back once discovery or executions is done with it. + /// + /// + /// The id of the proxy to be re-enqueued. + public void EnqueueProxy(Guid proxyId) + { + lock (this.lockObject) + { + // Check if the proxy exists. + if (!this.proxyMap.ContainsKey(proxyId)) + { + throw new ArgumentException( + string.Format( + CultureInfo.CurrentUICulture, + CrossPlatResources.NoSuchProxyId, + proxyId)); + } + + // Get the actual proxy. + var proxyContainer = this.proxyMap[proxyId]; + if (proxyContainer.IsAvailable) + { + throw new InvalidOperationException( + string.Format( + CultureInfo.CurrentUICulture, + CrossPlatResources.ProxyIsAlreadyAvailable, + proxyId)); + } + + // Mark the proxy as available. + proxyContainer.IsAvailable = true; + + // Re-enqueue the proxy in the available queue. + this.availableProxyQueue.Enqueue(proxyId); + } + } + + private ProxyOperationManager CreateProxy() + { + // Invoke the proxy creator. + var proxy = this.proxyCreator(); + + lock (this.lockObject) + { + // Add the proxy to the map. + this.proxyMap.Add(proxy.Id, new ProxyOperationManagerContainer(proxy, available: true)); + + // Enqueue the proxy id in the available queue. + this.availableProxyQueue.Enqueue(proxy.Id); + } + + return proxy; + } + } + + /// + /// Defines a container encapsulating the proxy and its corresponding state info. + /// + internal class ProxyOperationManagerContainer + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The proxy. + /// A flag indicating if the proxy is available to do work. + public ProxyOperationManagerContainer(ProxyOperationManager proxy, bool available) + { + this.Proxy = proxy; + this.IsAvailable = available; + } + + /// + /// Gets or sets the proxy. + /// + public ProxyOperationManager Proxy { get; set; } + + /// + /// Gets or sets a flag indicating if the proxy is available to do work. + /// + public bool IsAvailable { get; set; } + } +} diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/TestSession/TestSessionPool.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/TestSession/TestSessionPool.cs new file mode 100644 index 0000000000..5110552b50 --- /dev/null +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/TestSession/TestSessionPool.cs @@ -0,0 +1,167 @@ +// 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.CrossPlatEngine +{ + using System; + using System.Collections.Generic; + + using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; + + /// + /// Represents the test session pool. + /// + public class TestSessionPool + { + private static object instanceLockObject = new object(); + private static volatile TestSessionPool instance; + + private object lockObject = new object(); + private Dictionary sessionPool; + + /// + /// Initializes a new instance of the class. + /// + private TestSessionPool() + { + this.sessionPool = new Dictionary(); + } + + /// + /// Gets the test session pool instance. + /// + /// + /// Thread-safe singleton pattern. + public static TestSessionPool Instance + { + get + { + if (instance == null) + { + lock (instanceLockObject) + { + if (instance == null) + { + instance = new TestSessionPool(); + } + } + } + + return instance; + } + } + + /// + /// Adds a session to the pool. + /// + /// + /// The test session info object. + /// The proxy manager object. + /// + /// True if the operation succeeded, false otherwise. + public bool AddSession( + TestSessionInfo testSessionInfo, + ProxyTestSessionManager proxyManager) + { + lock (this.lockObject) + { + // Check if the session info already exists. + if (this.sessionPool.ContainsKey(testSessionInfo)) + { + return false; + } + + // Adds an association between session info and proxy manager to the pool. + this.sessionPool.Add(testSessionInfo, proxyManager); + return true; + } + } + + /// + /// Kills and removes a session from the pool. + /// + /// + /// The test session info object. + /// + /// True if the operation succeeded, false otherwise. + public bool KillSession(TestSessionInfo testSessionInfo) + { + // TODO (copoiena): What happens if some request is running for the current session ? + // Should we stop the request as well ? Probably yes. + ProxyTestSessionManager proxyManager = null; + + lock (this.lockObject) + { + // Check if the session info exists. + if (!this.sessionPool.ContainsKey(testSessionInfo)) + { + return false; + } + + // Remove the session from the pool. + proxyManager = this.sessionPool[testSessionInfo]; + this.sessionPool.Remove(testSessionInfo); + } + + // Kill the session. + proxyManager.StopSession(); + return true; + } + + /// + /// Gets a reference to the proxy object from the session pool. + /// + /// + /// The test session info object. + /// + /// The proxy object. + public ProxyOperationManager TakeProxy(TestSessionInfo testSessionInfo) + { + ProxyTestSessionManager sessionManager = null; + lock (this.lockObject) + { + // Gets the session manager reference from the pool. + sessionManager = this.sessionPool[testSessionInfo]; + } + + // Deque an actual proxy to do work. + // + // This can potentially throw, but let the caller handle this as it must recover from + // this error by creating its own proxy. + return sessionManager.DequeueProxy(); + } + + /// + /// Returns the proxy object to the session pool. + /// + /// + /// The test session info object. + /// The proxy id to be returned. + public void ReturnProxy(TestSessionInfo testSessionInfo, Guid proxyId) + { + ProxyTestSessionManager sessionManager = null; + lock (this.lockObject) + { + // Gets the session manager reference from the pool. + sessionManager = this.sessionPool[testSessionInfo]; + } + + try + { + // Try re-enqueueing the specified proxy. + sessionManager.EnqueueProxy(proxyId); + } + catch (InvalidOperationException ex) + { + // If we are unable to re-enqueue the proxy we just eat up the exception here as + // it is safe to proceed. + // + // WARNING: This should not normally happen and it raises questions regarding the + // test session pool operation and consistency. + EqtTrace.Warning("TestSessionPool.ReturnProxy failed: {0}", ex.ToString()); + } + } + } +} diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Microsoft.TestPlatform.Extensions.BlameDataCollector.csproj b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Microsoft.TestPlatform.Extensions.BlameDataCollector.csproj index 11a26e7f56..5ac9c65b5d 100644 --- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Microsoft.TestPlatform.Extensions.BlameDataCollector.csproj +++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Microsoft.TestPlatform.Extensions.BlameDataCollector.csproj @@ -16,12 +16,15 @@ true + + + - - + + @@ -31,9 +34,7 @@ - - 0.2.0-preview.20419.2 - + diff --git a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Properties/AssemblyInfo.cs b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Properties/AssemblyInfo.cs index 68809aec87..dc8cee6a54 100644 --- a/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Properties/AssemblyInfo.cs +++ b/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/Properties/AssemblyInfo.cs @@ -3,8 +3,9 @@ using System.Reflection; using System.Runtime.InteropServices; + using Microsoft.TestPlatform.Extensions.BlameDataCollector; -using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; +using Microsoft.VisualStudio.TestPlatform; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -14,7 +15,6 @@ [assembly: AssemblyCopyright(" Microsoft Corporation. All rights reserved.")] [assembly: AssemblyProduct("Microsoft.TestPlatform.Extensions.BlameDataCollector")] [assembly: AssemblyTrademark("")] -[assembly: TypesToLoad(typeof(BlameLogger), typeof(BlameCollector))] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from @@ -23,3 +23,5 @@ // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("716373d6-9162-4ac6-9ae7-b5a3a4286808")] + +[assembly: TestExtensionTypes(typeof(BlameLogger), typeof(BlameCollector))] \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Extensions.HtmlLogger/Microsoft.TestPlatform.Extensions.HtmlLogger.csproj b/src/Microsoft.TestPlatform.Extensions.HtmlLogger/Microsoft.TestPlatform.Extensions.HtmlLogger.csproj index 9025a0d8c1..e4c3045ff6 100644 --- a/src/Microsoft.TestPlatform.Extensions.HtmlLogger/Microsoft.TestPlatform.Extensions.HtmlLogger.csproj +++ b/src/Microsoft.TestPlatform.Extensions.HtmlLogger/Microsoft.TestPlatform.Extensions.HtmlLogger.csproj @@ -21,8 +21,11 @@ - - + + + + + diff --git a/src/Microsoft.TestPlatform.Extensions.HtmlLogger/Properties/AssemblyInfo.cs b/src/Microsoft.TestPlatform.Extensions.HtmlLogger/Properties/AssemblyInfo.cs index bc64c4ba85..8ea41b1b09 100644 --- a/src/Microsoft.TestPlatform.Extensions.HtmlLogger/Properties/AssemblyInfo.cs +++ b/src/Microsoft.TestPlatform.Extensions.HtmlLogger/Properties/AssemblyInfo.cs @@ -3,8 +3,9 @@ using System.Reflection; using System.Runtime.InteropServices; + +using Microsoft.VisualStudio.TestPlatform; using Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger; -using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -14,7 +15,6 @@ [assembly: AssemblyCopyright(" Microsoft Corporation. All rights reserved.")] [assembly: AssemblyProduct("Microsoft.TestPlatform.Extensions.HtmlLogger")] [assembly: AssemblyTrademark("")] -[assembly: TypesToLoad(typeof(HtmlLogger))] // Setting ComVisible to false makes the types in this assembly not visible @@ -23,5 +23,6 @@ [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM. - [assembly: Guid("1f26e9c7-5018-4091-a22a-89280f2f98a9")] + +[assembly: TestExtensionTypes(typeof(HtmlLogger))] \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Interfaces/ITestElement.cs b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Interfaces/ITestElement.cs index 92d7db22f4..39121ae3e0 100644 --- a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Interfaces/ITestElement.cs +++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Interfaces/ITestElement.cs @@ -16,6 +16,7 @@ internal interface ITestElement TestExecId ParentExecutionId { get; set; } TestListCategoryId CategoryId { get; set; } TestCategoryItemCollection TestCategories { get; } + WorkItemCollection WorkItems { get; set; } TestType TestType { get; } } } diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Microsoft.TestPlatform.Extensions.TrxLogger.csproj b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Microsoft.TestPlatform.Extensions.TrxLogger.csproj index 2450ff93ab..f8fa6e6985 100644 --- a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Microsoft.TestPlatform.Extensions.TrxLogger.csproj +++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Microsoft.TestPlatform.Extensions.TrxLogger.csproj @@ -20,8 +20,11 @@ - - + + + + + diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/TestElement.cs b/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/TestElement.cs index 9562822962..c35fa8b3a1 100644 --- a/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/TestElement.cs +++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/TestElement.cs @@ -30,6 +30,7 @@ internal abstract class TestElement : ITestElement, IXmlTestStore protected TestExecId executionId; protected TestExecId parentExecutionId; protected TestCategoryItemCollection testCategories; + protected WorkItemCollection workItems; protected TestListCategoryId catId; public TestElement(Guid id, string name, string adapter) @@ -161,6 +162,20 @@ public TestCategoryItemCollection TestCategories } } + /// + /// Gets or sets the work items. + /// + public WorkItemCollection WorkItems + { + get { return this.workItems; } + + set + { + EqtAssert.ParameterNotNull(value, "value"); + this.workItems = value; + } + } + /// /// Gets the adapter name. /// @@ -230,6 +245,8 @@ public virtual void Save(System.Xml.XmlElement element, XmlTestStoreParameters p if (this.parentExecutionId != null) h.SaveGuid(element, "Execution/@parentId", this.parentExecutionId.Id); + h.SaveObject(this.workItems, element, "Workitems", parameters); + XmlTestStoreParameters testIdParameters = XmlTestStoreParameters.GetParameters(); testIdParameters[TestId.IdLocationKey] = "@id"; h.SaveObject(this.id, element, testIdParameters); @@ -245,6 +262,7 @@ private void Initialize() this.executionId = TestExecId.Empty; this.parentExecutionId = TestExecId.Empty; this.testCategories = new TestCategoryItemCollection(); + this.workItems = new WorkItemCollection(); this.isRunnable = true; this.catId = TestListCategoryId.Uncategorized; } diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/WorkItems.cs b/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/WorkItems.cs new file mode 100644 index 0000000000..c21769539d --- /dev/null +++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/ObjectModel/WorkItems.cs @@ -0,0 +1,243 @@ +// 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.TestPlatform.Extensions.TrxLogger.ObjectModel +{ + using System; + using System.Globalization; + using System.Text; + using System.Xml; + using Microsoft.TestPlatform.Extensions.TrxLogger.Utility; + using Microsoft.TestPlatform.Extensions.TrxLogger.XML; + + #region WorkItem + /// + /// Stores an int which represents a workitem + /// + internal sealed class WorkItem : IXmlTestStore + { + #region Fields + [StoreXmlField(Location = ".")] + private int id = 0; + + #endregion + + #region Constructors + /// + /// Create a new item with the workitem set + /// + /// The workitem. + public WorkItem(int workitemId) + { + this.id = workitemId; + } + + #endregion + + #region Properties/Methods + /// + /// Gets the id for this WorkItem + /// + public int Id + { + get + { + return this.id; + } + } + + #endregion + + #region Methods - overrides + /// + /// Compare the values of the items + /// + /// Value being compared to. + /// True if the values are the same and false otherwise. + public override bool Equals(object other) + { + WorkItem otherItem = other as WorkItem; + if (otherItem == null) + { + return false; + } + return this.id == otherItem.id; + } + + /// + /// Convert the workitem to a hashcode + /// + /// Hashcode of the workitem. + public override int GetHashCode() + { + return this.id.GetHashCode(); + } + + /// + /// Convert the workitem to a string + /// + /// The workitem. + public override string ToString() + { + return this.id.ToString(CultureInfo.InvariantCulture); + } + #endregion + + #region IXmlTestStore Members + + /// + /// Saves the class under the XmlElement. + /// + /// XmlElement element + /// XmlTestStoreParameters parameters + public void Save(System.Xml.XmlElement element, XmlTestStoreParameters parameters) + { + new XmlPersistence().SaveSingleFields(element, this, parameters); + } + + #endregion + } + #endregion + + #region WorkItemCollection + /// + /// A collection of ints represent the workitems + /// + internal sealed class WorkItemCollection : EqtBaseCollection + { + #region Constructors + /// + /// Creates an empty WorkItemCollection. + /// + public WorkItemCollection() + { + } + + /// + /// Create a new WorkItemCollection based on the int array. + /// + /// Add these items to the collection. + public WorkItemCollection(int[] items) + { + EqtAssert.ParameterNotNull(items, "items"); + foreach (int i in items) + { + this.Add(new WorkItem(i)); + } + } + + #endregion + + #region Methods + /// + /// Adds the workitem. + /// + /// WorkItem to be added. + public void Add(int item) + { + this.Add(new WorkItem(item)); + } + + /// + /// Adds the workitem. + /// + /// WorkItem to be added. + public override void Add(WorkItem item) + { + EqtAssert.ParameterNotNull(item, "item"); + base.Add(item); + } + + /// + /// Convert the WorkItemCollection to a string. + /// each item is separated by a comma (,) + /// + /// + public override string ToString() + { + StringBuilder returnString = new StringBuilder(); + if (this.Count > 0) + { + returnString.Append(","); + foreach (WorkItem item in this) + { + returnString.Append(item); + returnString.Append(","); + } + } + + return returnString.ToString(); + } + + /// + /// Convert the WorkItemCollection to an array of ints. + /// + /// Array of ints containing the workitems. + public int[] ToArray() + { + int[] result = new int[this.Count]; + + int i = 0; + foreach (WorkItem item in this) + { + result[i++] = item.Id; + } + + return result; + } + + /// + /// Compare the collection items + /// + /// other collection + /// true if the collections contain the same items + public override bool Equals(object obj) + { + WorkItemCollection other = obj as WorkItemCollection; + bool result = false; + + if (other == null) + { + result = false; + } + else if (object.ReferenceEquals(this, other)) + { + result = true; + } + else if (this.Count != other.Count) + { + result = false; + } + else + { + foreach (WorkItem item in this) + { + if (!other.Contains(item)) + { + result = false; + break; + } + } + } + + return result; + } + + /// + /// Return the hash code of this collection + /// + /// The hashcode. + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override void Save(XmlElement element, XmlTestStoreParameters parameters) + { + XmlPersistence xmlPersistence = new XmlPersistence(); + xmlPersistence.SaveHashtable(this.container, element, ".", ".", null, "Workitem", parameters); + } + #endregion + } + #endregion +} diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Properties/AssemblyInfo.cs b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Properties/AssemblyInfo.cs index 57f3f4ab80..51c82b3d1a 100644 --- a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Properties/AssemblyInfo.cs +++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Properties/AssemblyInfo.cs @@ -3,8 +3,9 @@ using System.Reflection; using System.Runtime.InteropServices; + +using Microsoft.VisualStudio.TestPlatform; using Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger; -using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -14,7 +15,6 @@ [assembly: AssemblyCopyright(" Microsoft Corporation. All rights reserved.")] [assembly: AssemblyProduct("Microsoft.TestPlatform.Extensions.TrxLogger")] [assembly: AssemblyTrademark("")] -[assembly: TypesToLoad(typeof(TrxLogger))] // Setting ComVisible to false makes the types in this assembly not visible @@ -24,3 +24,5 @@ // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("60d876ee-f278-4bf8-bc8a-15b356895c6f")] + +[assembly: TestExtensionTypes(typeof(TrxLogger))] \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Utility/Converter.cs b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Utility/Converter.cs index 3ca84b4694..eeb441f0d4 100644 --- a/src/Microsoft.TestPlatform.Extensions.TrxLogger/Utility/Converter.cs +++ b/src/Microsoft.TestPlatform.Extensions.TrxLogger/Utility/Converter.cs @@ -67,6 +67,13 @@ public ITestElement ToTestElement( testElement.TestCategories.Add(testCategory); } + var workItems = GetCustomPropertyValueFromTestCase(rockSteadyTestCase, "WorkItemIds") + .Select(workItem => int.Parse(workItem)); + foreach (int workItem in workItems) + { + testElement.WorkItems.Add(workItem); + } + return testElement; } diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/IBaseProxy.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/IBaseProxy.cs new file mode 100644 index 0000000000..838f6d8807 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/IBaseProxy.cs @@ -0,0 +1,20 @@ +// 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.ObjectModel.Client +{ + /// + /// Provides basic functionality for the Proxy Operation Manager. + /// + public interface IBaseProxy + { + /// + /// Updates the test process start info. + /// + /// + /// The test process start info to be updated. + /// + /// The updated test process start info. + TestProcessStartInfo UpdateTestProcessStartInfo(TestProcessStartInfo testProcessStartInfo); + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/ITestPlatform.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/ITestPlatform.cs index 9dbf71b13c..a842484b04 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/ITestPlatform.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/ITestPlatform.cs @@ -6,39 +6,71 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Client using System; using System.Collections.Generic; + /// + /// Defines the functionality of the test platform. + /// public interface ITestPlatform : IDisposable { /// - /// Update the extensions to be used by the test service + /// Updates the extensions to be used by the test service. /// + /// /// - /// Specifies the path to unit test extensions. - /// If no additional extension is available, then specify null or empty list. + /// Specifies the path to unit test extensions. If no additional extension is available, + /// then specify null or empty list. /// - /// - void UpdateExtensions(IEnumerable pathToAdditionalExtensions, bool skipExtensionFilters); + /// + /// Flag indicating if we should skip the default adapters initialization. + /// + void UpdateExtensions( + IEnumerable pathToAdditionalExtensions, + bool skipExtensionFilters); /// - /// Clear the extensions + /// Clears the extensions. /// void ClearExtensions(); /// - /// Creates a discovery request + /// Creates a discovery request. /// - /// Providing common services and data for Discovery - /// Specifies the discovery parameters + /// + /// Providing common services and data for discovery. + /// Specifies the discovery parameters. /// Test platform options. - /// DiscoveryRequest object - IDiscoveryRequest CreateDiscoveryRequest(IRequestData requestData, DiscoveryCriteria discoveryCriteria, TestPlatformOptions options); + /// + /// A DiscoveryRequest object. + IDiscoveryRequest CreateDiscoveryRequest( + IRequestData requestData, + DiscoveryCriteria discoveryCriteria, + TestPlatformOptions options); /// /// Creates a test run request. /// - /// Providing common services and data for Execution - /// Specifies the test run criteria + /// + /// Providing common services and data for execution. + /// Specifies the test run criteria. /// Test platform options. - /// RunRequest object - ITestRunRequest CreateTestRunRequest(IRequestData requestData, TestRunCriteria testRunCriteria, TestPlatformOptions options); + /// + /// A RunRequest object. + ITestRunRequest CreateTestRunRequest( + IRequestData requestData, + TestRunCriteria testRunCriteria, + TestPlatformOptions options); + + /// + /// Starts a test session. + /// + /// + /// + /// Providing common services and data for test session start. + /// + /// Specifies the start test session criteria. + /// Events handler for handling session events. + void StartTestSession( + IRequestData requestData, + StartTestSessionCriteria criteria, + ITestSessionEventsHandler eventsHandler); } } diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/ITestRunEventsHandler.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/ITestRunEventsHandler.cs index 171da88e2a..ecd37b85c7 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/ITestRunEventsHandler.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/ITestRunEventsHandler.cs @@ -36,7 +36,7 @@ public interface ITestRunEventsHandler : ITestMessageEventHandler } /// - /// Interface for handling generic message events during test discovery or execution + /// Interface for handling generic message events during various operations /// public interface ITestMessageEventHandler { diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/ITestSessionEventsHandler.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/ITestSessionEventsHandler.cs new file mode 100644 index 0000000000..fc3dea783a --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/Interfaces/ITestSessionEventsHandler.cs @@ -0,0 +1,30 @@ +// 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.ObjectModel.Client +{ + /// + /// Interface contract for handling test session events. + /// + public interface ITestSessionEventsHandler : ITestMessageEventHandler + { + /// + /// Dispatch StartTestSession complete event to listeners. + /// + /// + /// The test session info. + void HandleStartTestSessionComplete(TestSessionInfo testSessionInfo); + + /// + /// Dispatch StopTestSession complete event to listeners. + /// + /// + /// + /// The test session info for the session that was stopped. + /// + /// + /// True if the session was successfully stopped, false otherwise. + /// + void HandleStopTestSessionComplete(TestSessionInfo testSessionInfo, bool stopped); + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/StartTestSessionAckPayload.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/StartTestSessionAckPayload.cs new file mode 100644 index 0000000000..5ec1bc5c79 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/StartTestSessionAckPayload.cs @@ -0,0 +1,20 @@ +// 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.ObjectModel.Client.Payloads +{ + using System.Runtime.Serialization; + + /// + /// Class used to define the start test session ack payload sent by the design mode client + /// back to the vstest.console translation layers. + /// + public class StartTestSessionAckPayload + { + /// + /// Gets or sets the test session info. + /// + [DataMember] + public TestSessionInfo TestSessionInfo { get; set; } + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/StartTestSessionPayload.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/StartTestSessionPayload.cs new file mode 100644 index 0000000000..cf25fe44a7 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/StartTestSessionPayload.cs @@ -0,0 +1,45 @@ +// 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.ObjectModel.Client.Payloads +{ + using System.Collections.Generic; + using System.Runtime.Serialization; + + /// + /// Class used to define the start test session payload sent by the vstest.console translation + /// layers into design mode. + /// + public class StartTestSessionPayload + { + /// + /// Gets or sets the sources used for starting the test session. + /// + [DataMember] + public IList Sources { get; set; } + + /// + /// Gets or sets the run settings used for starting the test session. + /// + [DataMember] + public string RunSettings { get; set; } + + /// + /// Gets or sets a flag indicating if debugging is enabled. + /// + [DataMember] + public bool IsDebuggingEnabled { get; set; } + + /// + /// Gets or sets a flag indicating if a custom host launcher should be used. + /// + [DataMember] + public bool HasCustomHostLauncher { get; set; } + + /// + /// Gets or sets the test platform options. + /// + [DataMember] + public TestPlatformOptions TestPlatformOptions { get; set; } + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/StopTestSessionAckPayload.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/StopTestSessionAckPayload.cs new file mode 100644 index 0000000000..ecca18eafd --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/StopTestSessionAckPayload.cs @@ -0,0 +1,26 @@ +// 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.ObjectModel.Client.Payloads +{ + using System.Runtime.Serialization; + + /// + /// Class used to define the stop test session ack payload sent by the design mode client + /// back to the vstest.console translation layers. + /// + public class StopTestSessionAckPayload + { + /// + /// Gets or sets the test session info. + /// + [DataMember] + public TestSessionInfo TestSessionInfo { get; set; } + + /// + /// Gets or sets a value indicating if the session was successfully stopped or not. + /// + [DataMember] + public bool IsStopped { get; set; } + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/TestRunRequestPayload.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/TestRunRequestPayload.cs index 8851fdec14..2c37f3e086 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/TestRunRequestPayload.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/Payloads/TestRunRequestPayload.cs @@ -53,10 +53,12 @@ public class TestRunRequestPayload /// Gets or sets the testplatform options ///
[DataMember] - public TestPlatformOptions TestPlatformOptions - { - get; - set; - } + public TestPlatformOptions TestPlatformOptions { get; set; } + + /// + /// Gets or sets the test session info. + /// + [DataMember] + public TestSessionInfo TestSessionInfo { get; set; } } } diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/StartTestSessionCriteria.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/StartTestSessionCriteria.cs new file mode 100644 index 0000000000..9970b20d5f --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/StartTestSessionCriteria.cs @@ -0,0 +1,34 @@ +// 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.ObjectModel.Client +{ + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; + using System.Collections.Generic; + using System.Runtime.Serialization; + + /// + /// Class used to define the start test session criteria. + /// + [DataContract] + public class StartTestSessionCriteria + { + /// + /// Gets or sets the sources used for starting the test session. + /// + [DataMember] + public IList Sources { get; set; } + + /// + /// Gets or sets the run settings used for starting the test session. + /// + [DataMember] + public string RunSettings { get; set; } + + /// + /// Gets or sets the test host launcher used for starting the test session. + /// + [DataMember] + public ITestHostLauncher TestHostLauncher { get; set; } + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/TestPlatformOptions.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/TestPlatformOptions.cs index f00c8cb3e4..ea7597419e 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Client/TestPlatformOptions.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/TestPlatformOptions.cs @@ -14,6 +14,7 @@ public class TestPlatformOptions /// /// Gets or sets the filter criteria for test cases. /// + /// /// /// This is only used when running tests with sources. /// @@ -23,6 +24,7 @@ public class TestPlatformOptions /// /// Gets or sets the filter options if there are any. /// + /// /// /// This will be valid only if TestCase filter is present. /// @@ -30,13 +32,13 @@ public class TestPlatformOptions public FilterOptions FilterOptions { get; set; } /// - /// Gets or sets whether Metrics should be collected or not. + /// Gets or sets whether metrics should be collected or not. /// [DataMember] public bool CollectMetrics { get; set; } /// - /// Gets or sets whether default adapters should be skipped or not. + /// Gets or sets whether default adapters should be skipped or not. /// [DataMember] public bool SkipDefaultAdapters { get; set; } diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/TestRunCriteria.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/TestRunCriteria.cs index 10e739f382..d92536d314 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Client/TestRunCriteria.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/TestRunCriteria.cs @@ -14,7 +14,7 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Client using Microsoft.VisualStudio.TestPlatform.ObjectModel.Resources; /// - /// Defines the testRun criterion + /// Defines the test run criterion. /// public class TestRunCriteria : BaseTestRunCriteria, ITestRunConfiguration { @@ -24,92 +24,103 @@ public class TestRunCriteria : BaseTestRunCriteria, ITestRunConfiguration /// /// Initializes a new instance of the class. /// - /// - /// Sources which contains tests that should be executed - /// - /// - /// Frequency of run stats event - /// - public TestRunCriteria(IEnumerable sources, long frequencyOfRunStatsChangeEvent) - : this(sources, frequencyOfRunStatsChangeEvent, true) + /// + /// Sources which contains tests that should be executed. + /// Frequency of run stats event. + public TestRunCriteria( + IEnumerable sources, + long frequencyOfRunStatsChangeEvent) + : this( + sources, + frequencyOfRunStatsChangeEvent, + true) { } /// /// Initializes a new instance of the class. /// - /// - /// Sources which contains tests that should be executed - /// - /// - /// Frequency of run stats event - /// + /// + /// Sources which contains tests that should be executed. + /// Frequency of run stats event. /// /// Whether the execution process should be kept alive after the run is finished or not. /// - public TestRunCriteria(IEnumerable sources, long frequencyOfRunStatsChangeEvent, bool keepAlive) - : this(sources, frequencyOfRunStatsChangeEvent, keepAlive, string.Empty) + public TestRunCriteria( + IEnumerable sources, + long frequencyOfRunStatsChangeEvent, + bool keepAlive) + : this( + sources, + frequencyOfRunStatsChangeEvent, + keepAlive, + string.Empty) { } /// /// Initializes a new instance of the class. /// - /// - /// Sources which contains tests that should be executed - /// - /// - /// Frequency of run stats event - /// + /// + /// Sources which contains tests that should be executed. + /// Frequency of run stats event. /// /// Whether the execution process should be kept alive after the run is finished or not. /// - /// - /// Settings used for this run. - /// - public TestRunCriteria(IEnumerable sources, long frequencyOfRunStatsChangeEvent, bool keepAlive, string testSettings) - : this(sources, frequencyOfRunStatsChangeEvent, keepAlive, testSettings, TimeSpan.MaxValue) + /// Settings used for this run. + public TestRunCriteria( + IEnumerable sources, + long frequencyOfRunStatsChangeEvent, + bool keepAlive, + string testSettings) + : this( + sources, + frequencyOfRunStatsChangeEvent, + keepAlive, + testSettings, + TimeSpan.MaxValue) { } /// /// Initializes a new instance of the class. /// - /// - /// Sources which contains tests that should be executed - /// - /// - /// Frequency of run stats event - /// + /// + /// Sources which contains tests that should be executed. + /// Frequency of run stats event. /// /// Whether the execution process should be kept alive after the run is finished or not. /// - /// - /// The test Settings. - /// + /// Settings used for this run. /// /// Timeout that triggers sending results regardless of cache size. /// - public TestRunCriteria(IEnumerable sources, long frequencyOfRunStatsChangeEvent, bool keepAlive, string testSettings, TimeSpan runStatsChangeEventTimeout) - : this(sources, frequencyOfRunStatsChangeEvent, keepAlive, testSettings, runStatsChangeEventTimeout, null) + public TestRunCriteria( + IEnumerable sources, + long frequencyOfRunStatsChangeEvent, + bool keepAlive, + string testSettings, + TimeSpan runStatsChangeEventTimeout) + : this( + sources, + frequencyOfRunStatsChangeEvent, + keepAlive, + testSettings, + runStatsChangeEventTimeout, + null) { } /// /// Initializes a new instance of the class. /// - /// - /// Sources which contains tests that should be executed - /// - /// - /// Frequency of run stats event - /// + /// + /// Sources which contains tests that should be executed. + /// Frequency of run stats event. /// /// Whether the execution process should be kept alive after the run is finished or not. /// - /// - /// Settings used for this run. - /// + /// Settings used for this run. /// /// Timeout that triggers sending results regardless of cache size. /// @@ -123,36 +134,80 @@ public TestRunCriteria( string testSettings, TimeSpan runStatsChangeEventTimeout, ITestHostLauncher testHostLauncher) - : this(sources, frequencyOfRunStatsChangeEvent, keepAlive, testSettings, runStatsChangeEventTimeout, testHostLauncher, null, null) + : this( + sources, + frequencyOfRunStatsChangeEvent, + keepAlive, + testSettings, + runStatsChangeEventTimeout, + testHostLauncher, + null, + null) { } /// /// Initializes a new instance of the class. /// - /// - /// Sources which contains tests that should be executed + /// + /// Sources which contains tests that should be executed. + /// Frequency of run stats event. + /// + /// Whether the execution process should be kept alive after the run is finished or not. /// - /// - /// Frequency of run stats event + /// Settings used for this run. + /// + /// Timeout that triggers sending results regardless of cache size. /// + /// + /// Test host launcher. If null then default will be used. + /// + /// Test case filter. + /// Filter options. + public TestRunCriteria( + IEnumerable sources, + long frequencyOfRunStatsChangeEvent, + bool keepAlive, + string testSettings, + TimeSpan runStatsChangeEventTimeout, + ITestHostLauncher testHostLauncher, + string testCaseFilter, + FilterOptions filterOptions) + : this( + sources, + frequencyOfRunStatsChangeEvent, + keepAlive, + testSettings, + runStatsChangeEventTimeout, + testHostLauncher, + testCaseFilter, + filterOptions, + testSessionInfo: null, + debugEnabledForTestSession: false) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Sources which contains tests that should be executed. + /// Frequency of run stats event. /// /// Whether the execution process should be kept alive after the run is finished or not. /// - /// - /// Settings used for this run. - /// + /// Settings used for this run. /// /// Timeout that triggers sending results regardless of cache size. /// /// /// Test host launcher. If null then default will be used. /// - /// - /// Test case filter. - /// - /// - /// Filter options. + /// Test case filter. + /// Filter options. + /// The test session info object. + /// + /// Indicates if debugging should be enabled when we have test session info available. /// public TestRunCriteria( IEnumerable sources, @@ -162,8 +217,15 @@ public TestRunCriteria( TimeSpan runStatsChangeEventTimeout, ITestHostLauncher testHostLauncher, string testCaseFilter, - FilterOptions filterOptions) - : base(frequencyOfRunStatsChangeEvent, keepAlive, testSettings, runStatsChangeEventTimeout, testHostLauncher) + FilterOptions filterOptions, + TestSessionInfo testSessionInfo, + bool debugEnabledForTestSession) + : base( + frequencyOfRunStatsChangeEvent, + keepAlive, + testSettings, + runStatsChangeEventTimeout, + testHostLauncher) { var testSources = sources as IList ?? sources.ToList(); ValidateArg.NotNullOrEmpty(testSources, "sources"); @@ -173,19 +235,21 @@ public TestRunCriteria( this.TestCaseFilter = testCaseFilter; this.FilterOptions = filterOptions; + + this.TestSessionInfo = testSessionInfo; + this.DebugEnabledForTestSession = debugEnabledForTestSession; } /// /// Initializes a new instance of the class. - /// Create the TestRunCriteria for a test run + /// Create the TestRunCriteria for a test run. /// - /// - /// Sources which contains tests that should be executed - /// - /// - /// The TestRunCriteria - /// - public TestRunCriteria(IEnumerable sources, TestRunCriteria testRunCriteria) + /// + /// Sources which contains tests that should be executed. + /// The test run criteria. + public TestRunCriteria( + IEnumerable sources, + TestRunCriteria testRunCriteria) : base(testRunCriteria) { var testSources = sources as IList ?? sources.ToArray(); @@ -202,18 +266,15 @@ public TestRunCriteria(IEnumerable sources, TestRunCriteria testRunCrite /// /// Initializes a new instance of the class. /// + /// /// - /// Sources which contains tests that should be executed - /// - /// - /// Frequency of run stats event + /// Sources which contains tests that should be executed. /// + /// Frequency of run stats event. /// /// Whether the execution process should be kept alive after the run is finished or not. /// - /// - /// Settings used for this run. - /// + /// Settings used for this run. /// /// Timeout that triggers sending results regardless of cache size. /// @@ -227,7 +288,12 @@ public TestRunCriteria( string testSettings, TimeSpan runStatsChangeEventTimeout, ITestHostLauncher testHostLauncher) - : base(frequencyOfRunStatsChangeEvent, keepAlive, testSettings, runStatsChangeEventTimeout, testHostLauncher) + : base( + frequencyOfRunStatsChangeEvent, + keepAlive, + testSettings, + runStatsChangeEventTimeout, + testHostLauncher) { ValidateArg.NotNullOrEmpty(adapterSourceMap, "adapterSourceMap"); @@ -237,86 +303,99 @@ public TestRunCriteria( /// /// Initializes a new instance of the class. /// - /// - /// Tests which should be executed - /// - /// - /// Frequency of run stats event - /// - public TestRunCriteria(IEnumerable tests, long frequencyOfRunStatsChangeEvent) - : this(tests, frequencyOfRunStatsChangeEvent, false) + /// + /// Tests which should be executed. + /// Frequency of run stats event. + public TestRunCriteria( + IEnumerable tests, + long frequencyOfRunStatsChangeEvent) + : this( + tests, + frequencyOfRunStatsChangeEvent, + false) { } /// /// Initializes a new instance of the class. /// - /// - /// Tests which should be executed - /// - /// - /// Frequency of run stats event - /// + /// + /// Tests which should be executed. + /// Frequency of run stats event. /// - /// Whether or not to keep the test executor process alive after run completion + /// Whether or not to keep the test executor process alive after run completion. /// - public TestRunCriteria(IEnumerable tests, long frequencyOfRunStatsChangeEvent, bool keepAlive) - : this(tests, frequencyOfRunStatsChangeEvent, keepAlive, string.Empty) + public TestRunCriteria( + IEnumerable tests, + long frequencyOfRunStatsChangeEvent, + bool keepAlive) + : this( + tests, + frequencyOfRunStatsChangeEvent, + keepAlive, + string.Empty) { } /// /// Initializes a new instance of the class. /// - /// - /// Tests which should be executed - /// - /// - /// Frequency of run stats event - /// + /// + /// Tests which should be executed. + /// Frequency of run stats event. /// - /// Whether or not to keep the test executor process alive after run completion + /// Whether or not to keep the test executor process alive after run completion. /// - /// - /// Settings used for this run. - /// - public TestRunCriteria(IEnumerable tests, long frequencyOfRunStatsChangeEvent, bool keepAlive, string testSettings) - : this(tests, frequencyOfRunStatsChangeEvent, keepAlive, testSettings, TimeSpan.MaxValue) + /// Settings used for this run. + public TestRunCriteria( + IEnumerable tests, + long frequencyOfRunStatsChangeEvent, + bool keepAlive, + string testSettings) + : this( + tests, + frequencyOfRunStatsChangeEvent, + keepAlive, + testSettings, + TimeSpan.MaxValue) { } /// /// Initializes a new instance of the class. /// - /// - /// Tests which should be executed - /// - /// - /// Frequency of run stats event - /// + /// + /// Tests which should be executed. + /// Frequency of run stats event. /// - /// Whether or not to keep the test executor process alive after run completion - /// - /// - /// Settings used for this run. + /// Whether or not to keep the test executor process alive after run completion. /// + /// Settings used for this run. /// /// Timeout that triggers sending results regardless of cache size. /// - public TestRunCriteria(IEnumerable tests, long frequencyOfRunStatsChangeEvent, bool keepAlive, string testSettings, TimeSpan runStatsChangeEventTimeout) - : this(tests, frequencyOfRunStatsChangeEvent, keepAlive, testSettings, runStatsChangeEventTimeout, null) + public TestRunCriteria( + IEnumerable tests, + long frequencyOfRunStatsChangeEvent, + bool keepAlive, + string testSettings, + TimeSpan runStatsChangeEventTimeout) + : this( + tests, + frequencyOfRunStatsChangeEvent, + keepAlive, + testSettings, + runStatsChangeEventTimeout, + null) { } /// /// Initializes a new instance of the class. /// - /// - /// Tests which should be executed - /// - /// - /// The BaseTestRunCriteria - /// + /// + /// Tests which should be executed. + /// The base test run criteria. public TestRunCriteria(IEnumerable tests, BaseTestRunCriteria baseTestRunCriteria) : base(baseTestRunCriteria) { @@ -329,35 +408,84 @@ public TestRunCriteria(IEnumerable tests, BaseTestRunCriteria baseTest /// /// Initializes a new instance of the class. /// - /// - /// Sources which contains tests that should be executed + /// + /// Tests which should be executed. + /// Frequency of run stats event. + /// + /// Whether or not to keep the test executor process alive after run completion. /// - /// - /// Frequency of run stats event + /// Settings used for this run. + /// + /// Timeout that triggers sending results regardless of cache size. /// - /// - /// Whether or not to keep the test executor process alive after run completion + /// + /// Test host launcher. If null then default will be used. /// - /// - /// Settings used for this run. + public TestRunCriteria( + IEnumerable tests, + long frequencyOfRunStatsChangeEvent, + bool keepAlive, + string testSettings, + TimeSpan runStatsChangeEventTimeout, + ITestHostLauncher testHostLauncher) + : this( + tests, + frequencyOfRunStatsChangeEvent, + keepAlive, + testSettings, + runStatsChangeEventTimeout, + testHostLauncher, + testSessionInfo: null, + debugEnabledForTestSession: false) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Tests which should be executed. + /// Frequency of run stats event. + /// + /// Whether or not to keep the test executor process alive after run completion. /// + /// Settings used for this run. /// /// Timeout that triggers sending results regardless of cache size. /// /// /// Test host launcher. If null then default will be used. /// - public TestRunCriteria(IEnumerable tests, long frequencyOfRunStatsChangeEvent, bool keepAlive, string testSettings, TimeSpan runStatsChangeEventTimeout, ITestHostLauncher testHostLauncher) - : base(frequencyOfRunStatsChangeEvent, keepAlive, testSettings, runStatsChangeEventTimeout, testHostLauncher) + /// The test session info object. + /// + /// Indicates if debugging should be enabled when we have test session info available. + /// + public TestRunCriteria( + IEnumerable tests, + long frequencyOfRunStatsChangeEvent, + bool keepAlive, + string testSettings, + TimeSpan runStatsChangeEventTimeout, + ITestHostLauncher testHostLauncher, + TestSessionInfo testSessionInfo, + bool debugEnabledForTestSession) + : base( + frequencyOfRunStatsChangeEvent, + keepAlive, + testSettings, + runStatsChangeEventTimeout, + testHostLauncher) { var testCases = tests as IList ?? tests.ToList(); ValidateArg.NotNullOrEmpty(testCases, "tests"); this.Tests = testCases; + this.TestSessionInfo = testSessionInfo; + this.DebugEnabledForTestSession = debugEnabledForTestSession; } /// - /// Gets the test Containers (e.g. DLL/EXE/artifacts to scan). + /// Gets the test containers (e.g. DLL/EXE/artifacts to scan). /// [IgnoreDataMember] public IEnumerable Sources @@ -365,7 +493,9 @@ public IEnumerable Sources get { IEnumerable sources = new List(); - return this.AdapterSourceMap?.Values.Aggregate(sources, (current, enumerable) => current.Concat(enumerable)); + return this.AdapterSourceMap?.Values?.Aggregate( + sources, + (current, enumerable) => current.Concat(enumerable)); } } @@ -380,7 +510,7 @@ public IEnumerable Sources /// /// Gets the tests that need to executed in this test run. - /// This will be null if test run is created with specific test containers + /// This will be null if test run is created with specific test containers. /// [DataMember] public IEnumerable Tests { get; private set; } @@ -409,7 +539,7 @@ private set } /// - /// Gets or sets the filter options + /// Gets or sets the filter options. /// /// This is only applicable when TestCaseFilter is present. [DataMember] @@ -431,6 +561,17 @@ private set } } + /// + /// Gets or sets the test session info object. + /// + public TestSessionInfo TestSessionInfo { get; set; } + + /// + /// Gets or sets a flag indicating if debugging should be enabled when we have test session + /// info available. + /// + public bool DebugEnabledForTestSession { get; set; } + /// /// Gets a value indicating whether run criteria is based on specific tests. /// @@ -509,16 +650,15 @@ public override int GetHashCode() } /// - /// Defines the base testRun criterion + /// Defines the base test run criterion. /// public class BaseTestRunCriteria { /// /// Initializes a new instance of the class. /// - /// - /// Run criteria to clone. - /// + /// + /// Run criteria to clone. public BaseTestRunCriteria(BaseTestRunCriteria runCriteria) { ValidateArg.NotNull(runCriteria, "runCriteria"); @@ -533,6 +673,7 @@ public BaseTestRunCriteria(BaseTestRunCriteria runCriteria) /// /// Initializes a new instance of the class. /// + /// /// /// Frequency of TestRunChangedEvent. /// @@ -544,6 +685,7 @@ public BaseTestRunCriteria(long frequencyOfRunStatsChangeEvent) /// /// Initializes a new instance of the class. /// + /// /// /// Frequency of TestRunChangedEvent. /// @@ -558,68 +700,88 @@ public BaseTestRunCriteria(long frequencyOfRunStatsChangeEvent, bool keepAlive) /// /// Initializes a new instance of the class. /// + /// /// /// Frequency of TestRunChangedEvent. /// /// /// Specify if the test host process should be stay alive after run. /// - /// - /// Test run settings. - /// - public BaseTestRunCriteria(long frequencyOfRunStatsChangeEvent, bool keepAlive, string testSettings) - : this(frequencyOfRunStatsChangeEvent, keepAlive, testSettings, TimeSpan.MaxValue) + /// Test run settings. + public BaseTestRunCriteria( + long frequencyOfRunStatsChangeEvent, + bool keepAlive, + string testSettings) + : this( + frequencyOfRunStatsChangeEvent, + keepAlive, + testSettings, + TimeSpan.MaxValue) { } /// /// Initializes a new instance of the class. /// + /// /// /// Frequency of TestRunChangedEvent. /// /// /// Specify if the test host process should be stay alive after run. /// - /// - /// Test run settings. - /// + /// Test run settings. /// /// Timeout for a TestRunChangedEvent. /// - public BaseTestRunCriteria(long frequencyOfRunStatsChangeEvent, bool keepAlive, string testSettings, TimeSpan runStatsChangeEventTimeout) - : this(frequencyOfRunStatsChangeEvent, keepAlive, testSettings, runStatsChangeEventTimeout, null) + public BaseTestRunCriteria( + long frequencyOfRunStatsChangeEvent, + bool keepAlive, + string testSettings, + TimeSpan runStatsChangeEventTimeout) + : this( + frequencyOfRunStatsChangeEvent, + keepAlive, + testSettings, + runStatsChangeEventTimeout, + null) { } /// /// Initializes a new instance of the class. /// + /// /// /// Frequency of TestRunChangedEvent. /// /// /// Specify if the test host process should be stay alive after run. /// - /// - /// Test run settings. - /// + /// Test run settings. /// /// Timeout for a TestRunChangedEvent. /// - /// - /// Test host launcher. - /// - public BaseTestRunCriteria(long frequencyOfRunStatsChangeEvent, bool keepAlive, string testSettings, TimeSpan runStatsChangeEventTimeout, ITestHostLauncher testHostLauncher) + /// Test host launcher. + public BaseTestRunCriteria( + long frequencyOfRunStatsChangeEvent, + bool keepAlive, + string testSettings, + TimeSpan runStatsChangeEventTimeout, + ITestHostLauncher testHostLauncher) { if (frequencyOfRunStatsChangeEvent <= 0) { - throw new ArgumentOutOfRangeException(nameof(frequencyOfRunStatsChangeEvent), Resources.NotificationFrequencyIsNotPositive); + throw new ArgumentOutOfRangeException( + nameof(frequencyOfRunStatsChangeEvent), + Resources.NotificationFrequencyIsNotPositive); } if (runStatsChangeEventTimeout <= TimeSpan.MinValue) { - throw new ArgumentOutOfRangeException(nameof(runStatsChangeEventTimeout), Resources.NotificationTimeoutIsZero); + throw new ArgumentOutOfRangeException( + nameof(runStatsChangeEventTimeout), + Resources.NotificationTimeoutIsZero); } this.FrequencyOfRunStatsChangeEvent = frequencyOfRunStatsChangeEvent; @@ -630,7 +792,8 @@ public BaseTestRunCriteria(long frequencyOfRunStatsChangeEvent, bool keepAlive, } /// - /// Gets a value indicating whether the test executor process should remain alive after run completion. + /// Gets a value indicating whether the test executor process should remain alive after + /// run completion. /// [DataMember] public bool KeepAlive { get; private set; } @@ -650,6 +813,7 @@ public BaseTestRunCriteria(long frequencyOfRunStatsChangeEvent, bool keepAlive, /// /// Gets the frequency of run stats test event. /// + /// /// /// Run stats change event will be raised after completion of these number of tests. /// Note that this event is raised asynchronously and the underlying execution process is not diff --git a/src/Microsoft.TestPlatform.ObjectModel/Client/TestSessionInfo.cs b/src/Microsoft.TestPlatform.ObjectModel/Client/TestSessionInfo.cs new file mode 100644 index 0000000000..21ce34307b --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Client/TestSessionInfo.cs @@ -0,0 +1,64 @@ +// 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.ObjectModel.Client +{ + using System; + using System.Runtime.Serialization; + + /// + /// Defines the test session info object to be passed around between vstest.console and + /// vstest.console wrapper in order to indentify the current session. + /// + [DataContract] + public class TestSessionInfo : IEquatable + { + /// + /// Creates an instance of the current class. + /// + public TestSessionInfo() + { + this.Id = Guid.NewGuid(); + } + + /// + /// Gets the session id. + /// + [DataMember] + public Guid Id { get; private set; } + + /// + /// Calculates the hash code for the current object. + /// + /// + /// An integer representing the computed hashcode value. + public override int GetHashCode() + { + return this.Id.GetHashCode(); + } + + /// + /// Checks if the specified object is equal to the current instance. + /// + /// + /// The object to be checked. + /// + /// True if the two objects are equal, false otherwise. + public override bool Equals(object obj) + { + return this.Equals(obj as TestSessionInfo); + } + + /// + /// Checks if the specified session is equal to the current instance. + /// + /// + /// The session to be checked. + /// + /// True if the two sessions are equal, false otherwise. + public bool Equals(TestSessionInfo other) + { + return other != null && this.Id == other.Id; + } + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/Constants.cs b/src/Microsoft.TestPlatform.ObjectModel/Constants.cs index 9252657190..8a209fb9ad 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Constants.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/Constants.cs @@ -168,7 +168,7 @@ public static class Constants /// /// The default protocol version /// - public static readonly ProtocolConfig DefaultProtocolConfig = new ProtocolConfig { Version = 4 }; + public static readonly ProtocolConfig DefaultProtocolConfig = new ProtocolConfig { Version = 5 }; /// /// The minimum protocol version that has debug support diff --git a/src/Microsoft.TestPlatform.ObjectModel/ManagedNameUtilities/ManagedNameParser.cs b/src/Microsoft.TestPlatform.ObjectModel/ManagedNameUtilities/ManagedNameParser.cs deleted file mode 100644 index f83eab158c..0000000000 --- a/src/Microsoft.TestPlatform.ObjectModel/ManagedNameUtilities/ManagedNameParser.cs +++ /dev/null @@ -1,188 +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.ObjectModel.ManagedNameUtilities -{ - using Microsoft.VisualStudio.TestPlatform.ObjectModel.Resources; - - using System.Collections.Generic; - using System.Diagnostics; - using System.Globalization; - using System.Linq; - - public class ManagedNameParser - { - internal static void ParseTypeName(string fullTypeName, out string namespaceName, out string typeName) - { - int pos = fullTypeName.LastIndexOf('.'); - if (pos == -1) - { - namespaceName = string.Empty; - typeName = fullTypeName; - } - else - { - namespaceName = fullTypeName.Substring(0, pos); - typeName = fullTypeName.Substring(pos + 1); - } - } - - internal static void ParseMethodName(string fullMethodName, out string methodName, out int arity, out string[] parameterTypes) - { - int pos = ParseMethodName(fullMethodName, 0, out methodName, out arity); - pos = ParseParameterTypeList(fullMethodName, pos, out parameterTypes); - if (pos != fullMethodName.Length) - { - string message = string.Format(CultureInfo.CurrentCulture, ManagedNameMessages.ErrorUnexpectedCharactersAtEnd, pos); - throw new InvalidManagedNameException(message); - } - } - - private static string Capture(string fullMethodName, int start, int end) - => fullMethodName.Substring(start, end - start); - - private static int ParseMethodName(string fullMethodName, int start, out string methodName, out int arity) - { - int i = start; - for (; i < fullMethodName.Length; i++) - { - switch (fullMethodName[i]) - { - case var w when char.IsWhiteSpace(w): - string message = string.Format(CultureInfo.CurrentCulture, ManagedNameMessages.ErrorWhitespaceNotValid, i); - throw new InvalidManagedNameException(message); - case '`': - methodName = Capture(fullMethodName, start, i); - return ParseArity(fullMethodName, i, out arity); - case '(': - methodName = Capture(fullMethodName, start, i); - arity = 0; - return i; - } - } - methodName = Capture(fullMethodName, start, i); - arity = 0; - return i; - } - - // parse arity in the form `nn where nn is an integer value. - private static int ParseArity(string fullMethodName, int start, out int arity) - { - arity = 0; - Debug.Assert(fullMethodName[start] == '`'); - - int i = start + 1; // skip initial '`' char - for (; i < fullMethodName.Length; i++) - { - if (fullMethodName[i] == '(') break; - } - if (!int.TryParse(Capture(fullMethodName, start + 1, i), out arity)) - { - string message = string.Format(CultureInfo.CurrentCulture, ManagedNameMessages.ErrorMethodArityMustBeNumeric); - throw new InvalidManagedNameException(message); - } - return i; - } - - private static int ParseParameterTypeList(string fullMethodName, int start, out string[] parameterTypes) - { - parameterTypes = null; - if (start == fullMethodName.Length) - { - return start; - } - Debug.Assert(fullMethodName[start] == '('); - - var types = new List(); - - int i = start + 1; // skip initial '(' char - for (; i < fullMethodName.Length; i++) - { - switch (fullMethodName[i]) - { - case ')': - if (types.Any()) - { - parameterTypes = types.ToArray(); - } - return i + 1; // consume right parens - case ',': - break; - default: - i = ParseParameterType(fullMethodName, i, out var parameterType); - types.Add(parameterType); - break; - } - } - - string message = string.Format(CultureInfo.CurrentCulture, ManagedNameMessages.ErrorIncompleteManagedName); - throw new InvalidManagedNameException(message); - } - - private static int ParseParameterType(string fullMethodName, int start, out string parameterType) - { - parameterType = string.Empty; - - int i = start; - for (; i < fullMethodName.Length; i++) - { - switch (fullMethodName[i]) - { - case '<': - i = ParseGenericBrackets(fullMethodName, i + 1); - break; - case '[': - i = ParseArrayBrackets(fullMethodName, i + 1); - break; - case ',': - case ')': - parameterType = Capture(fullMethodName, start, i); - return i - 1; - case var w when char.IsWhiteSpace(w): - string message = string.Format(CultureInfo.CurrentCulture, ManagedNameMessages.ErrorWhitespaceNotValid, i); - throw new InvalidManagedNameException(message); - } - } - return i; - } - - private static int ParseArrayBrackets(string fullMethodName, int start) - { - for (int i = start; i < fullMethodName.Length; i++) - { - switch (fullMethodName[i]) - { - case ']': - return i; - case var w when char.IsWhiteSpace(w): - string msg = string.Format(CultureInfo.CurrentCulture, ManagedNameMessages.ErrorWhitespaceNotValid, i); - throw new InvalidManagedNameException(msg); - } - } - - string message = string.Format(CultureInfo.CurrentCulture, ManagedNameMessages.ErrorIncompleteManagedName); - throw new InvalidManagedNameException(message); - } - - private static int ParseGenericBrackets(string fullMethodName, int start) - { - for (int i = start; i < fullMethodName.Length; i++) - { - switch (fullMethodName[i]) - { - case '<': - i = ParseGenericBrackets(fullMethodName, i + 1); - break; - case '>': - return i; - case var w when char.IsWhiteSpace(w): - string msg = string.Format(CultureInfo.CurrentCulture, ManagedNameMessages.ErrorWhitespaceNotValid, i); - throw new InvalidManagedNameException(msg); - } - } - - string message = string.Format(CultureInfo.CurrentCulture, ManagedNameMessages.ErrorIncompleteManagedName); - throw new InvalidManagedNameException(message); - } - } -} diff --git a/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj b/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj index e0bcb43aa0..ac7507c007 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj +++ b/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj @@ -78,7 +78,6 @@ - TextTemplatingFileGenerator @@ -91,11 +90,6 @@ True CommonResources.resx - - True - True - ManagedNameMessages.resx - True True @@ -108,18 +102,11 @@ Resources\CommonResources.tt CommonResources.Designer.cs - - ResXFileCodeGenerator - ManagedNameMessages.Designer.cs - ResXFileCodeGenerator Resources.Designer.cs - - - Microsoft.VisualStudio.TestPlatform.ObjectModel diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/ManagedNameMessages.resx b/src/Microsoft.TestPlatform.ObjectModel/Resources/ManagedNameMessages.resx deleted file mode 100644 index 1f24f6db76..0000000000 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/ManagedNameMessages.resx +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ManagedName is incomplete - - - Method arity must be numeric - - - Method '{0}' not found on type '{1}' - {0} is the method name, {1} is the full type name. - - - Type '{0}' not found - {0} is the full type name. - - - Unexpected characters after the end of the ManagedName (pos: {0}) - {0} is the position of unexpected characters - - - Whitespace is not valid in a ManagedName (pos: {0}) - {0} is the position of invalid whitespace - - \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/CommonResources.pt-BR.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/CommonResources.pt-BR.xlf index dbfc0cd023..45dfe43ed1 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/CommonResources.pt-BR.xlf +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/CommonResources.pt-BR.xlf @@ -31,7 +31,7 @@ Test run detected DLL(s) which were built for different framework and platform versions. Following DLL(s) do not match current settings, which are {0} framework and {1} platform.{2}Go to {3} for more details on managing these settings. - A execução de teste detectou DLLs que foram criadas para diferentes versões de estrutura e de plataforma. As DLLs a seguir não correspondem às configurações atuais, que são a estrutura {0} e a plataforma {1}. {2}Acesse {3} para obter mais detalhes sobre o gerenciamento dessas configurações. + A execução de teste detectou DLLs que foram criadas para diferentes versões de estrutura e de plataforma. As DLLs a seguir não correspondem às configurações atuais, que são a estrutura {0} e a plataforma {1}.{2}Acesse {3} para obter mais detalhes sobre o gerenciamento dessas configurações. Testlauf verwendet DLLs für Framework {0} und {1}-Plattform integriert. Folgende DLLs nicht Teil ausführen: {2} zur {3} Einzelheiten auf diese Einstellungen. diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/CommonResources.zh-Hans.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/CommonResources.zh-Hans.xlf index 88e203bf76..e543c91ed8 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/CommonResources.zh-Hans.xlf +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/CommonResources.zh-Hans.xlf @@ -1,6 +1,6 @@  - +
71 diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/CommonResources.zh-Hant.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/CommonResources.zh-Hant.xlf index e9179ed1aa..36568a9ee8 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/CommonResources.zh-Hant.xlf +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/CommonResources.zh-Hant.xlf @@ -1,6 +1,6 @@  - +
71 diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/Resources.zh-Hans.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/Resources.zh-Hans.xlf index 0eac1acb8d..1e6adac792 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/Resources.zh-Hans.xlf +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/Resources.zh-Hans.xlf @@ -1,6 +1,6 @@  - +
284 diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/Resources.zh-Hant.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/Resources.zh-Hant.xlf index 7745f9d077..a99441fcce 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/Resources.zh-Hant.xlf +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/Resources.zh-Hant.xlf @@ -1,6 +1,6 @@  - +
284 diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs index 7728529e6b..5dd1f45ded 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs @@ -10,7 +10,6 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel using System.Linq; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; - using System.Reflection; /// /// Stores information about a test case. @@ -29,8 +28,6 @@ public sealed class TestCase : TestObject private string displayName; private string fullyQualifiedName; private string source; - private string managedMethod; - private string managedType; #region Constructor @@ -66,64 +63,6 @@ public TestCase(string fullyQualifiedName, Uri executorUri, string source) this.Source = source; this.LineNumber = -1; } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Fully qualified name of the test case. - /// - /// - /// Managed method to extract the values of and . - /// - /// - /// The Uri of the executor to use for running this test. - /// - /// - /// Test container source from which the test is discovered. - /// - /// - /// If is specified, TestId will be calculated based on that instead of . - /// - public TestCase(string fullyQualifiedName, MethodBase method, Uri executorUri, string source) - : this(fullyQualifiedName, executorUri, source) - { - ValidateArg.NotNull(method, nameof(method)); - - ManagedNameUtilities.ManagedNameHelper.GetManagedName(method, out var managedType, out var managedMethod); - - ManagedType = managedType; - ManagedMethod = managedMethod; - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Fully qualified name of the test case. - /// - /// - /// Managed method to extract the values of and . - /// - /// - /// The Uri of the executor to use for running this test. - /// - /// - /// Test container source from which the test is discovered. - /// - /// - /// If and are specified, TestId will be calculated based on those instead of . - /// - public TestCase(string fullyQualifiedName, string managedType, string managedMethod, Uri executorUri, string source) - : this(fullyQualifiedName, executorUri, source) - { - ValidateArg.NotNullOrWhiteSpace(managedType, nameof(managedType)); - ValidateArg.NotNullOrWhiteSpace(managedMethod, nameof(managedMethod)); - - ManagedType = managedType; - ManagedMethod = managedMethod; - } - #endregion #region Properties @@ -132,7 +71,7 @@ public TestCase(string fullyQualifiedName, string managedType, string managedMet /// LocalExtensionData which can be used by Adapter developers for local transfer of extended properties. /// Note that this data is available only for in-Proc execution, and may not be available for OutProc executors /// - public Object LocalExtensionData + public object LocalExtensionData { get { return localExtensionData; } set { localExtensionData = value; } @@ -165,34 +104,6 @@ public Guid Id } } - /// - /// Gets or sets the fully specified type name metadata format. - /// - /// - /// NamespaceA.NamespaceB.ClassName`1+InnerClass`2 - /// - [DataMember] - public string ManagedType { - get => managedType; - - // defaultId should be reset as it is based on ManagedType, ManagedMethod and Source. - set => SetVariableAndResetId(ref managedType, value); - } - - /// - /// Gets or sets the fully specified method name metadata format. - /// - /// - /// MethodName`2(ParamTypeA,ParamTypeB,�) - /// - [DataMember] - public string ManagedMethod { - get => managedMethod; - - // defaultId should be reset as it is based on ManagedType, ManagedMethod and Source. - set => SetVariableAndResetId(ref managedMethod, value); - } - /// /// Gets or sets the fully qualified name of the test case. /// @@ -213,14 +124,9 @@ public string DisplayName { get { - if(string.IsNullOrEmpty(this.displayName)) + if (string.IsNullOrEmpty(this.displayName)) { - if (this.HasManagedMethodAndType) - { - return $"{managedType}.{ManagedMethod}"; - } - - return this.FullyQualifiedName; + return this.GetFullyQualifiedName(); } return this.displayName; @@ -288,24 +194,6 @@ public override IEnumerable Properties } } - /// - /// Returns true if both and are not null or whitespace. - /// - public bool HasManagedMethodAndType => !string.IsNullOrWhiteSpace(ManagedType) && !string.IsNullOrWhiteSpace(ManagedMethod); - - /// - public override string ToString() - { - if (this.HasManagedMethodAndType) - { - return $"{ManagedType}.{ManagedMethod}"; - } - else - { - return this.FullyQualifiedName; - } - } - #endregion #region private methods @@ -340,18 +228,11 @@ private Guid GetTestId() // We still need to handle parameters in the case of a Theory or TestGroup of test cases that are only // distinguished by parameters. - var testcaseFullName = this.ExecutorUri + source; - + var testcaseFullName = this.ExecutorUri + source; + // If ManagedType and ManagedMethod properties are filled than TestId should be based on those. - if (this.HasManagedMethodAndType) - { - testcaseFullName += $"{managedType}.{managedMethod}"; - } - else - { - testcaseFullName += this.FullyQualifiedName; - } - + testcaseFullName += this.GetFullyQualifiedName(); + return EqtHash.GuidFromString(testcaseFullName); } @@ -361,6 +242,12 @@ private void SetVariableAndResetId(ref T variable, T value) this.defaultId = Guid.Empty; } + private void SetPropertyAndResetId(TestProperty property, T value) + { + SetPropertyValue(property, value); + this.defaultId = Guid.Empty; + } + #endregion #region Protected Methods @@ -383,10 +270,6 @@ protected override object ProtectedGetPropertyValue(TestProperty property, objec return this.ExecutorUri; case "TestCase.FullyQualifiedName": return this.FullyQualifiedName; - case "TestCase.ManagedType": - return this.ManagedType; - case "TestCase.ManagedMethod": - return this.ManagedMethod; case "TestCase.Id": return this.Id; case "TestCase.LineNumber": @@ -424,14 +307,6 @@ protected override void ProtectedSetPropertyValue(TestProperty property, object this.FullyQualifiedName = value as string; return; - case "TestCase.ManagedType": - this.ManagedType = value as string; - return; - - case "TestCase.ManagedMethod": - this.ManagedMethod = value as string; - return; - case "TestCase.Id": this.Id = value is Guid ? (Guid)value : Guid.Parse(value as string); return; @@ -450,6 +325,32 @@ protected override void ProtectedSetPropertyValue(TestProperty property, object } #endregion + + #region ManagedName and ManagedType implementations + + private static readonly TestProperty ManagedTypeProperty = TestProperty.Register("TestCase.ManagedType", "ManagedType", string.Empty, string.Empty, typeof(string), o => !string.IsNullOrWhiteSpace(o as string), TestPropertyAttributes.Hidden, typeof(TestCase)); + private static readonly TestProperty ManagedMethodProperty = TestProperty.Register("TestCase.ManagedMethod", "ManagedMethod", string.Empty, string.Empty, typeof(string), o => !string.IsNullOrWhiteSpace(o as string), TestPropertyAttributes.Hidden, typeof(TestCase)); + + private bool ContainsManagedMethodAndType => !string.IsNullOrWhiteSpace(ManagedMethod) && !string.IsNullOrWhiteSpace(ManagedType); + + private string ManagedType + { + get => GetPropertyValue(ManagedTypeProperty, null); + set => SetPropertyAndResetId(ManagedTypeProperty, value); + } + + private string ManagedMethod + { + get => GetPropertyValue(ManagedMethodProperty, null); + set => SetPropertyAndResetId(ManagedMethodProperty, value); + } + + private string GetFullyQualifiedName() => ContainsManagedMethodAndType ? $"{ManagedType}.{ManagedMethod}" : FullyQualifiedName; + + #endregion + + /// + public override string ToString() => this.GetFullyQualifiedName(); } /// @@ -465,8 +366,6 @@ public static class TestCaseProperties /// private const string IdLabel = "Id"; private const string FullyQualifiedNameLabel = "FullyQualifiedName"; - private const string ManagedTypeLabel = "ManagedType"; - private const string ManagedMethodLabel = "ManagedMethod"; private const string NameLabel = "Name"; private const string ExecutorUriLabel = "Executor Uri"; private const string SourceLabel = "Source"; @@ -475,31 +374,12 @@ public static class TestCaseProperties #endregion - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly TestProperty Id = TestProperty.Register("TestCase.Id", IdLabel, string.Empty, string.Empty, typeof(Guid), ValidateGuid, TestPropertyAttributes.Hidden, typeof(TestCase)); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly TestProperty FullyQualifiedName = TestProperty.Register("TestCase.FullyQualifiedName", FullyQualifiedNameLabel, string.Empty, string.Empty, typeof(string), ValidateName, TestPropertyAttributes.Hidden, typeof(TestCase)); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly TestProperty ManagedType = TestProperty.Register("TestCase.ManagedType", ManagedTypeLabel, string.Empty, string.Empty, typeof(string), ValidateName, TestPropertyAttributes.Hidden, typeof(TestCase)); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly TestProperty ManagedMethod = TestProperty.Register("TestCase.ManagedMethod", ManagedMethodLabel, string.Empty, string.Empty, typeof(string), ValidateName, TestPropertyAttributes.Hidden, typeof(TestCase)); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly TestProperty DisplayName = TestProperty.Register("TestCase.DisplayName", NameLabel, string.Empty, string.Empty, typeof(string), ValidateDisplay, TestPropertyAttributes.None, typeof(TestCase)); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly TestProperty ExecutorUri = TestProperty.Register("TestCase.ExecutorUri", ExecutorUriLabel, string.Empty, string.Empty, typeof(Uri), ValidateExecutorUri, TestPropertyAttributes.Hidden, typeof(TestCase)); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly TestProperty Source = TestProperty.Register("TestCase.Source", SourceLabel, typeof(string), typeof(TestCase)); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly TestProperty CodeFilePath = TestProperty.Register("TestCase.CodeFilePath", FilePathLabel, typeof(string), typeof(TestCase)); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly TestProperty LineNumber = TestProperty.Register("TestCase.LineNumber", LineNumberLabel, typeof(int), TestPropertyAttributes.Hidden, typeof(TestCase)); internal static TestProperty[] Properties { get; } = @@ -508,8 +388,6 @@ public static class TestCaseProperties DisplayName, ExecutorUri, FullyQualifiedName, - ManagedType, - ManagedMethod, Id, LineNumber, Source @@ -531,7 +409,6 @@ private static bool ValidateExecutorUri(object value) return value != null; } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification = "Required to validate the input value.")] private static bool ValidateGuid(object value) { try diff --git a/src/Microsoft.TestPlatform.ObjectModel/Utilities/AssemblyHelper.cs b/src/Microsoft.TestPlatform.ObjectModel/Utilities/AssemblyHelper.cs index 3c1616c217..880e830449 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Utilities/AssemblyHelper.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/Utilities/AssemblyHelper.cs @@ -3,20 +3,21 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities { -#if NETFRAMEWORK + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; + using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; + using System.Linq; using System.Reflection; - using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter; - /// /// Implementation of finding assembly references using "managed route", i.e. Assembly.Load. /// public static class AssemblyHelper { +#if NETFRAMEWORK private static Version defaultVersion = new Version(); private static Version version45 = new Version("4.5"); @@ -25,7 +26,6 @@ public static class AssemblyHelper /// Only assembly name and public key token are match. Version is ignored for matching. /// Returns null if not able to check if source references assembly. ///
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] public static bool? DoesReferencesAssembly(string source, AssemblyName referenceAssembly) { try @@ -160,7 +160,6 @@ public static KeyValuePair GetFrameworkVersionAn } } - /// /// Returns the full name (AssemblyName.FullName) of the referenced assemblies by the assembly on the specified path. /// @@ -340,6 +339,21 @@ internal static void SetNETFrameworkCompatiblityMode(AppDomainSetup setup, IRunC } } } - } #endif + + public static IEnumerable GetCustomAttributes(this Assembly assembly, string fullyQualifiedName) + { + ValidateArg.NotNull(assembly, nameof(assembly)); + ValidateArg.NotNullOrWhiteSpace(fullyQualifiedName, nameof(fullyQualifiedName)); + + if(assembly.GetType(fullyQualifiedName) is Type attribute) + { + return assembly.GetCustomAttributes(attribute); + } + + return assembly + .GetCustomAttributes() + .Where(i => i.GetType().FullName == fullyQualifiedName); + } + } } diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs index db60124fd1..08d071ac84 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs @@ -404,7 +404,14 @@ private bool LaunchHost(TestProcessStartInfo testHostStartInfo, CancellationToke { EqtTrace.Verbose("DefaultTestHostManager: Starting process '{0}' with command line '{1}'", testHostStartInfo.FileName, testHostStartInfo.Arguments); cancellationToken.ThrowIfCancellationRequested(); - this.testHostProcess = this.processHelper.LaunchProcess(testHostStartInfo.FileName, testHostStartInfo.Arguments, testHostStartInfo.WorkingDirectory, testHostStartInfo.EnvironmentVariables, this.ErrorReceivedCallback, this.ExitCallBack, null) as Process; + this.testHostProcess = this.processHelper.LaunchProcess( + testHostStartInfo.FileName, + testHostStartInfo.Arguments, + testHostStartInfo.WorkingDirectory, + testHostStartInfo.EnvironmentVariables, + this.ErrorReceivedCallback, + this.ExitCallBack, + null) as Process; } else { diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs index eb4149d6b0..63971107a6 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs @@ -425,7 +425,14 @@ private bool LaunchHost(TestProcessStartInfo testHostStartInfo, CancellationToke EqtTrace.Verbose("DotnetTestHostManager: Starting process '{0}' with command line '{1}'", testHostStartInfo.FileName, testHostStartInfo.Arguments); cancellationToken.ThrowIfCancellationRequested(); - this.testHostProcess = this.processHelper.LaunchProcess(testHostStartInfo.FileName, testHostStartInfo.Arguments, testHostStartInfo.WorkingDirectory, testHostStartInfo.EnvironmentVariables, this.ErrorReceivedCallback, this.ExitCallBack, null) as Process; + this.testHostProcess = this.processHelper.LaunchProcess( + testHostStartInfo.FileName, + testHostStartInfo.Arguments, + testHostStartInfo.WorkingDirectory, + testHostStartInfo.EnvironmentVariables, + this.ErrorReceivedCallback, + this.ExitCallBack, + null) as Process; } else { diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Properties/AssemblyInfo.cs b/src/Microsoft.TestPlatform.TestHostProvider/Properties/AssemblyInfo.cs index cfcaf11468..d92238b7ba 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Properties/AssemblyInfo.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Properties/AssemblyInfo.cs @@ -3,8 +3,9 @@ using System.Reflection; using System.Runtime.InteropServices; + +using Microsoft.VisualStudio.TestPlatform; using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting; -using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -14,7 +15,6 @@ [assembly: AssemblyCopyright(" Microsoft Corporation. All rights reserved.")] [assembly: AssemblyProduct("Microsoft.TestPlatform.TestHostRuntimeProvider")] [assembly: AssemblyTrademark("")] -[assembly: TypesToLoad(typeof(DefaultTestHostManager), typeof(DotnetTestHostManager))] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from @@ -23,3 +23,5 @@ // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("83693884-04ee-4083-bae1-e7827b8f5fbc")] + +[assembly: TestExtensionTypes(typeof(DefaultTestHostManager), typeof(DotnetTestHostManager))] \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Utilities/TypesToLoadAttribute.cs b/src/Microsoft.TestPlatform.TestHostProvider/Properties/TestExtensionTypesAttribute.cs similarity index 66% rename from src/Microsoft.TestPlatform.ObjectModel/Utilities/TypesToLoadAttribute.cs rename to src/Microsoft.TestPlatform.TestHostProvider/Properties/TestExtensionTypesAttribute.cs index 5f8824b510..4cce7e2fbc 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Utilities/TypesToLoadAttribute.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Properties/TestExtensionTypesAttribute.cs @@ -1,7 +1,7 @@ // 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.ObjectModel.Utilities +namespace Microsoft.VisualStudio.TestPlatform { using System; @@ -9,14 +9,13 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities /// Custom Attribute to specify the exact types which should be loaded from assembly /// [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [CLSCompliant(false)] - public sealed class TypesToLoadAttribute : Attribute + internal sealed class TestExtensionTypesAttribute : Attribute { - public TypesToLoadAttribute(params Type[] types) + public TestExtensionTypesAttribute(params Type[] types) { - Types = types; + this.Types = types; } public Type[] Types { get; } } -} +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.Utilities/CodeCoverageDataAttachmentsHandler.cs b/src/Microsoft.TestPlatform.Utilities/CodeCoverageDataAttachmentsHandler.cs index 3c2ceeff0f..9e9d559190 100644 --- a/src/Microsoft.TestPlatform.Utilities/CodeCoverageDataAttachmentsHandler.cs +++ b/src/Microsoft.TestPlatform.Utilities/CodeCoverageDataAttachmentsHandler.cs @@ -8,7 +8,6 @@ namespace Microsoft.VisualStudio.TestPlatform.Utilities using System.Collections.ObjectModel; using System.IO; using System.Linq; - using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -16,7 +15,6 @@ namespace Microsoft.VisualStudio.TestPlatform.Utilities using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; - using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; public class CodeCoverageDataAttachmentsHandler : IDataCollectorAttachmentProcessor { @@ -37,17 +35,41 @@ public async Task> ProcessAttachmentSetsAsync(ICollec { if (attachments != null && attachments.Any()) { - var codeCoverageFiles = attachments.Select(coverageAttachment => coverageAttachment.Attachments[0].Uri.LocalPath).ToArray(); - var outputFile = await this.MergeCodeCoverageFilesAsync(codeCoverageFiles, progressReporter, cancellationToken).ConfigureAwait(false); - var attachmentSet = new AttachmentSet(CodeCoverageDataCollectorUri, CoverageFriendlyName); + var coverageReportFilePaths = new List(); + var coverageOtherFilePaths = new List(); - if (!string.IsNullOrEmpty(outputFile)) + foreach (var attachmentSet in attachments) { - attachmentSet.Attachments.Add(new UriDataAttachment(new Uri(outputFile), CoverageFriendlyName)); - return new Collection { attachmentSet }; + foreach (var attachment in attachmentSet.Attachments) + { + if (attachment.Uri.LocalPath.EndsWith(CoverageFileExtension, StringComparison.OrdinalIgnoreCase)) + { + coverageReportFilePaths.Add(attachment.Uri.LocalPath); + } + else + { + coverageOtherFilePaths.Add(attachment.Uri.LocalPath); + } + } + } + + if(coverageReportFilePaths.Count > 1) + { + var mergedCoverageReportFilePath = await this.MergeCodeCoverageFilesAsync(coverageReportFilePaths, progressReporter, cancellationToken).ConfigureAwait(false); + if (!string.IsNullOrEmpty(mergedCoverageReportFilePath)) + { + var resultAttachmentSet = new AttachmentSet(CodeCoverageDataCollectorUri, CoverageFriendlyName); + resultAttachmentSet.Attachments.Add(new UriDataAttachment(new Uri(mergedCoverageReportFilePath), CoverageFriendlyName)); + + foreach (var coverageOtherFilePath in coverageOtherFilePaths) + { + resultAttachmentSet.Attachments.Add(new UriDataAttachment(new Uri(coverageOtherFilePath), string.Empty)); + } + + return new Collection { resultAttachmentSet }; + } } - // In case merging fails(esp in dotnet core we cannot merge), so return filtered list of Code Coverage Attachments return attachments; } @@ -56,11 +78,6 @@ public async Task> ProcessAttachmentSetsAsync(ICollec private async Task MergeCodeCoverageFilesAsync(IList files, IProgress progressReporter, CancellationToken cancellationToken) { - if (files.Count == 1) - { - return files[0]; - } - try { // Warning: Don't remove this method call. @@ -68,8 +85,9 @@ private async Task MergeCodeCoverageFilesAsync(IList files, IPro // We took a dependency on Coverage.CoreLib.Net. In the unlikely case it cannot be // resolved, this method call will throw an exception that will be caught and // absorbed here. - await this.MergeCodeCoverageFilesAsync(files, cancellationToken).ConfigureAwait(false); + var result = await this.MergeCodeCoverageFilesAsync(files, cancellationToken).ConfigureAwait(false); progressReporter?.Report(100); + return result; } catch (OperationCanceledException) { @@ -83,10 +101,10 @@ private async Task MergeCodeCoverageFilesAsync(IList files, IPro ex.ToString()); } - return files[0]; + return null; } - private async Task MergeCodeCoverageFilesAsync(IList files, CancellationToken cancellationToken) + private async Task MergeCodeCoverageFilesAsync(IList files, CancellationToken cancellationToken) { var coverageUtility = new CoverageFileUtility(); @@ -95,6 +113,20 @@ private async Task MergeCodeCoverageFilesAsync(IList files, Cancellation cancellationToken).ConfigureAwait(false); coverageUtility.WriteCoverageFile(files[0], coverageData); + + foreach(var file in files.Skip(1)) + { + try + { + File.Delete(file); + } + catch (Exception ex) + { + EqtTrace.Error($"CodeCoverageDataCollectorAttachmentsHandler: Failed to remove {file}. Error: {ex}"); + } + } + + return files[0]; } } } diff --git a/src/Microsoft.TestPlatform.Utilities/InferRunSettingsHelper.cs b/src/Microsoft.TestPlatform.Utilities/InferRunSettingsHelper.cs index c0edcb8f3f..d9b2ea23be 100644 --- a/src/Microsoft.TestPlatform.Utilities/InferRunSettingsHelper.cs +++ b/src/Microsoft.TestPlatform.Utilities/InferRunSettingsHelper.cs @@ -230,7 +230,7 @@ public static void UpdateTargetFramework(XmlDocument runSettingsDocument, string ///
/// RunSettings used for the run /// True if an incompatible collector is found - public static bool AreRunSettingsCollectorsInCompatibleWithTestSettings(string runsettings) + public static bool AreRunSettingsCollectorsIncompatibleWithTestSettings(string runsettings) { // If there's no embedded testsettings.. bail out if (!IsTestSettingsEnabled(runsettings)) diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITestSession.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITestSession.cs new file mode 100644 index 0000000000..206c3aa009 --- /dev/null +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITestSession.cs @@ -0,0 +1,180 @@ +// 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.VsTestConsole.TranslationLayer.Interfaces +{ + using System.Collections.Generic; + + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; + + /// + /// Defines a test session that can be used to make calls to the vstest.console + /// process. + /// + public interface ITestSession : ITestSessionAsync + { + /// + /// Starts test discovery. + /// + /// + /// The list of source assemblies for the discovery. + /// The run settings for the discovery. + /// The discovery event handler. + void DiscoverTests( + IEnumerable sources, + string discoverySettings, + ITestDiscoveryEventsHandler discoveryEventsHandler); + + /// + /// Starts test discovery. + /// + /// + /// The list of source assemblies for the discovery. + /// The run settings for the discovery. + /// The test platform options. + /// The discovery event handler. + void DiscoverTests( + IEnumerable sources, + string discoverySettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 discoveryEventsHandler); + + /// + /// Cancels the last discovery request. + /// + new void CancelDiscovery(); + + /// + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The run event handler. + void RunTests( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The test platform options. + /// The run event handler. + void RunTests( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The run event handler. + void RunTests( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The test platform options. + /// The run event handler. + void RunTests( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The run event handler. + /// The custom host launcher. + void RunTestsWithCustomTestHost( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The test platform options. + /// The run event handler. + /// The custom host launcher. + void RunTestsWithCustomTestHost( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Starts a test run. + /// + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The run event handler. + /// The custom host launcher. + void RunTestsWithCustomTestHost( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Starts a test run. + /// + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The test platform options. + /// The run event handler. + /// The custom host launcher. + void RunTestsWithCustomTestHost( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Stops the test session. + /// + /// + /// The session event handler. + /// + /// True if the session was successfuly stopped, false otherwise. + bool StopTestSession(ITestSessionEventsHandler eventsHandler); + + /// + /// Cancels the last test run. + /// + new void CancelTestRun(); + + /// + /// Aborts the last test run. + /// + new void AbortTestRun(); + } +} diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITestSessionAsync.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITestSessionAsync.cs new file mode 100644 index 0000000000..9c2aff1496 --- /dev/null +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITestSessionAsync.cs @@ -0,0 +1,182 @@ +// 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.VsTestConsole.TranslationLayer.Interfaces +{ + using System.Collections.Generic; + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; + + /// + /// Defines a test session that can be used to make async calls to the vstest.console + /// process. + /// + public interface ITestSessionAsync + { + /// + /// Starts test discovery. + /// + /// + /// The list of source assemblies for the discovery. + /// The run settings for the discovery. + /// The discovery event handler. + /// + Task DiscoverTestsAsync( + IEnumerable sources, + string discoverySettings, + ITestDiscoveryEventsHandler discoveryEventsHandler); + + /// + /// Starts test discovery. + /// + /// + /// The list of source assemblies for the discovery. + /// The run settings for the discovery. + /// The test platform options. + /// The discovery event handler. + Task DiscoverTestsAsync( + IEnumerable sources, + string discoverySettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 discoveryEventsHandler); + + /// + /// Cancels the last discovery request. + /// + void CancelDiscovery(); + + /// + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The run event handler. + Task RunTestsAsync( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The test platform options. + /// The run event handler. + Task RunTestsAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The run event handler. + Task RunTestsAsync( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The test platform options. + /// The run event handler. + Task RunTestsAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The run event handler. + /// The custom host launcher. + Task RunTestsWithCustomTestHostAsync( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The test platform options. + /// The run event handler. + /// The custom host launcher. + Task RunTestsWithCustomTestHostAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Starts a test run. + /// + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The run event handler. + /// The custom host launcher. + Task RunTestsWithCustomTestHostAsync( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Starts a test run. + /// + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The test platform options. + /// The run event handler. + /// The custom host launcher. + Task RunTestsWithCustomTestHostAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Stops the test session. + /// + /// + /// The session event handler. + /// + /// True if the session was successfuly stopped, false otherwise. + Task StopTestSessionAsync( + ITestSessionEventsHandler eventsHandler); + + /// + /// Cancels the last test run. + /// + void CancelTestRun(); + + /// + /// Aborts the last test run. + /// + void AbortTestRun(); + } +} diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITranslationLayerRequestSender.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITranslationLayerRequestSender.cs index 35e50a9b10..6d016e2b18 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITranslationLayerRequestSender.cs +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITranslationLayerRequestSender.cs @@ -5,8 +5,6 @@ namespace Microsoft.TestPlatform.VsTestConsole.TranslationLayer.Interfaces { using System; using System.Collections.Generic; - using System.Threading; - using System.Threading.Tasks; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; @@ -17,98 +15,165 @@ namespace Microsoft.TestPlatform.VsTestConsole.TranslationLayer.Interfaces internal interface ITranslationLayerRequestSender : IDisposable, ITranslationLayerRequestSenderAsync { /// - /// Initializes the communication for sending requests + /// Initializes communication with the vstest.console.exe process. + /// Hosts a communication channel and asynchronously connects to vstest.console.exe. /// - /// Port Number of the communication channel + /// + /// Port number of the hosted server on this side. int InitializeCommunication(); /// - /// Waits for Request Handler to be connected + /// Waits for the request handler to be connected. /// - /// Time to wait for connection - /// True, if Handler is connected + /// + /// Time to wait for connection. + /// + /// True if the handler has connected, false otherwise. bool WaitForRequestHandlerConnection(int connectionTimeout); /// - /// Close the Sender + /// Closes the sender. /// void Close(); /// - /// Initializes the Extensions while probing additional extension paths + /// Initializes the extensions while probing additional extension paths. /// - /// Paths to check for additional extensions + /// + /// Paths to check for additional extensions. void InitializeExtensions(IEnumerable pathToAdditionalExtensions); /// /// Discovers the tests /// - /// Sources for discovering tests - /// Run settings for discovering tests - /// Options to be passed into the platform - /// EventHandler for discovery events - void DiscoverTests(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestDiscoveryEventsHandler2 discoveryEventsHandler); + /// + /// Sources for discovering tests. + /// Run settings for discovering tests. + /// Options to be passed into the platform. + /// Event handler for discovery events. + void DiscoverTests( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 discoveryEventsHandler); /// - /// Starts the TestRun with given sources and criteria + /// Starts the test run with given sources and criteria. /// - /// Sources for test run - /// RunSettings for test run - /// Options to be passed into the platform - /// EventHandler for test run events - void StartTestRun(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler); + /// + /// Sources for test run. + /// Run settings for test run. + /// Options to be passed into the platform. + /// Test session info. + /// Event handler for test run events. + void StartTestRun( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler); /// - /// Starts the TestRun with given test cases and criteria + /// Starts the test run with given sources and criteria. /// - /// TestCases to run - /// RunSettings for test run - /// Options to be passed into the platform - /// EventHandler for test run events - void StartTestRun(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler); + /// + /// Test cases to run. + /// Run settings for test run. + /// Options to be passed into the platform. + /// Test session info. + /// Event handler for test run events. + void StartTestRun( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler); /// - /// Starts the TestRun with given sources and criteria with custom test host + /// Starts the test run with given sources and criteria and a custom launcher. /// - /// Sources for test run - /// RunSettings for test run - /// Options to be passed into the platform - /// EventHandler for test run events - /// Custom TestHost launcher - void StartTestRunWithCustomHost(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler, ITestHostLauncher customTestHostLauncher); + /// + /// Sources for test run. + /// Run settings for test run. + /// Options to be passed into the platform. + /// Test session info. + /// Event handler for test run events. + /// Custom test host launcher. + void StartTestRunWithCustomHost( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler, + ITestHostLauncher customTestHostLauncher); /// - /// Starts the TestRun with given test cases and criteria with custom test host + /// Starts the test run with given sources and criteria and a custom launcher. /// - /// TestCases to run - /// RunSettings for test run + /// + /// Test cases to run. + /// Run settings for test run. /// Options to be passed into the platform. - /// EventHandler for test run events - /// Custom TestHost launcher - void StartTestRunWithCustomHost(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler, ITestHostLauncher customTestHostLauncher); + /// Test session info. + /// Event handler for test run events. + /// Custom test host launcher. + void StartTestRunWithCustomHost( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Starts a new test session. + /// + /// + /// Sources for test run. + /// Run settings for test run. + /// Options to be passed into the platform. + /// Event handler for test session events. + /// Custom test host launcher. + /// + TestSessionInfo StartTestSession( + IList sources, + string runSettings, + TestPlatformOptions options, + ITestSessionEventsHandler eventsHandler, + ITestHostLauncher testHostLauncher); + + /// + /// Stops the test session. + /// + /// + /// Test session info. + /// Event handler for test session events. + bool StopTestSession( + TestSessionInfo testSessionInfo, + ITestSessionEventsHandler eventsHandler); /// - /// Ends the Session + /// Ends the session. /// void EndSession(); /// - /// Cancel the test run + /// Cancels the test run. /// void CancelTestRun(); /// - /// Abort the test run + /// Aborts the test run. /// void AbortTestRun(); /// - /// On process exit unblocks communication waiting calls + /// On process exit unblocks communication waiting calls. /// void OnProcessExited(); /// - /// Cancels the discovery of tests + /// Cancels the discovery of tests. /// void CancelDiscovery(); } diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITranslationLayerRequestSenderAsync.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITranslationLayerRequestSenderAsync.cs index 23166126d7..563eaea1b6 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITranslationLayerRequestSenderAsync.cs +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/ITranslationLayerRequestSenderAsync.cs @@ -18,43 +18,130 @@ namespace Microsoft.TestPlatform.VsTestConsole.TranslationLayer.Interfaces internal interface ITranslationLayerRequestSenderAsync : IDisposable { /// - /// Asynchronous equivalent of - /// and . + /// Asynchronous equivalent of + /// and . /// Task InitializeCommunicationAsync(int clientConnectionTimeout); /// /// Asynchronous equivalent of ITranslationLayerRequestSender.DiscoverTests/>. /// - Task DiscoverTestsAsync(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestDiscoveryEventsHandler2 discoveryEventsHandler); + Task DiscoverTestsAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 discoveryEventsHandler); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . /// - Task StartTestRunAsync(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler); + Task StartTestRunAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . /// - Task StartTestRunAsync(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler); + Task StartTestRunAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . /// - Task StartTestRunWithCustomHostAsync(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler, ITestHostLauncher customTestHostLauncher); + Task StartTestRunWithCustomHostAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler, + ITestHostLauncher customTestHostLauncher); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . /// - Task StartTestRunWithCustomHostAsync(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler, ITestHostLauncher customTestHostLauncher); + Task StartTestRunWithCustomHostAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler, + ITestHostLauncher customTestHostLauncher); /// - /// Provides back all attachments to TestPlatform for additional processing (for example merging) + /// Asynchronous equivalent of . /// - /// Collection of attachments - /// Enables metrics collection - /// Events handler - /// Cancellation token - Task ProcessTestRunAttachmentsAsync(IEnumerable attachments, bool collectMetrics, ITestRunAttachmentsProcessingEventsHandler testRunAttachmentsProcessingCompleteEventsHandler, CancellationToken cancellationToken); + Task StartTestSessionAsync( + IList sources, + string runSettings, + TestPlatformOptions options, + ITestSessionEventsHandler eventsHandler, + ITestHostLauncher testHostLauncher); + + /// + /// Asynchronous equivalent of . + /// + Task StopTestSessionAsync( + TestSessionInfo testSessionInfo, + ITestSessionEventsHandler eventsHandler); + + /// + /// Provides back all attachments to test platform for additional processing (for example + /// merging). + /// + /// + /// Collection of attachments. + /// Enables metrics collection. + /// Events handler. + /// Cancellation token. + Task ProcessTestRunAttachmentsAsync( + IEnumerable attachments, + bool collectMetrics, + ITestRunAttachmentsProcessingEventsHandler testRunAttachmentsProcessingCompleteEventsHandler, + CancellationToken cancellationToken); } } diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/IVsTestConsoleWrapper.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/IVsTestConsoleWrapper.cs index 79e09b98dd..d3ea821e1e 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/IVsTestConsoleWrapper.cs +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/IVsTestConsoleWrapper.cs @@ -7,6 +7,7 @@ namespace Microsoft.TestPlatform.VsTestConsole.TranslationLayer.Interfaces using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; + using Microsoft.VisualStudio.TestPlatform.VsTestConsole.TranslationLayer.Interfaces; /// /// Controller for various test operations on the test runner. @@ -19,27 +20,54 @@ public interface IVsTestConsoleWrapper : IVsTestConsoleWrapperAsync void StartSession(); /// - /// Initialize the TestPlatform with Paths to extensions like adapters, loggers and any other extensions + /// Initializes the test platform with paths to extensions like adapters, loggers and any + /// other extensions. /// - /// Full Paths to extension DLLs + /// + /// Full paths to extension DLLs. void InitializeExtensions(IEnumerable pathToAdditionalExtensions); /// - /// Start Discover Tests for the given sources and discovery settings. + /// Starts test discovery. /// - /// List of source assemblies, files to discover tests - /// Settings XML for test discovery - /// EventHandler to receive discovery events - void DiscoverTests(IEnumerable sources, string discoverySettings, ITestDiscoveryEventsHandler discoveryEventsHandler); + /// + /// The list of source assemblies for the discovery. + /// The run settings for the discovery. + /// The discovery event handler. + void DiscoverTests( + IEnumerable sources, + string discoverySettings, + ITestDiscoveryEventsHandler discoveryEventsHandler); /// - /// Start Discover Tests for the given sources and discovery settings. + /// Starts test discovery. /// - /// List of source assemblies, files to discover tests - /// Settings XML for test discovery - /// Options to be passed into the platform. - /// EventHandler to receive discovery events - void DiscoverTests(IEnumerable sources, string discoverySettings, TestPlatformOptions options, ITestDiscoveryEventsHandler2 discoveryEventsHandler); + /// + /// The list of source assemblies for the discovery. + /// The run settings for the discovery. + /// The test platform options. + /// The discovery event handler. + void DiscoverTests( + IEnumerable sources, + string discoverySettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 discoveryEventsHandler); + + /// + /// Starts test discovery. + /// + /// + /// The list of source assemblies for the discovery. + /// The run settings for the discovery. + /// The test platform options. + /// The test session info object. + /// The discovery event handler. + void DiscoverTests( + IEnumerable sources, + string discoverySettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestDiscoveryEventsHandler2 discoveryEventsHandler); /// /// Cancels the last discovery request. @@ -47,84 +75,252 @@ public interface IVsTestConsoleWrapper : IVsTestConsoleWrapperAsync new void CancelDiscovery(); /// - /// Starts a test run given a list of sources. + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The run event handler. + void RunTests( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The test platform options. + /// The run event handler. + void RunTests( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The test platform options. + /// The test session info object. + /// The run event handler. + void RunTests( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The run event handler. + void RunTests( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The test platform options. + /// The run event handler. + void RunTests( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The test platform options. + /// The test session info object. + /// The run event handler. + void RunTests( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The run event handler. + /// The custom host launcher. + void RunTestsWithCustomTestHost( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Starts a test run. + /// + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The test platform options. + /// The run event handler. + /// The custom host launcher. + void RunTestsWithCustomTestHost( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Starts a test run. /// - /// Sources to Run tests on - /// RunSettings XML to run the tests - /// EventHandler to receive test run events - void RunTests(IEnumerable sources, string runSettings, ITestRunEventsHandler testRunEventsHandler); + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The test platform options. + /// The test session info object. + /// The run event handler. + /// The custom host launcher. + void RunTestsWithCustomTestHost( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); /// - /// Starts a test run given a list of sources. + /// Starts a test run. /// - /// Sources to Run tests on - /// RunSettings XML to run the tests - /// Options to be passed into the platform. - /// EventHandler to receive test run events - void RunTests(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler); + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The run event handler. + /// The custom host launcher. + void RunTestsWithCustomTestHost( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); /// - /// Starts a test run given a list of test cases + /// Starts a test run. /// - /// TestCases to run - /// RunSettings XML to run the tests - /// EventHandler to receive test run events - void RunTests(IEnumerable testCases, string runSettings, ITestRunEventsHandler testRunEventsHandler); + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The test platform options. + /// The run event handler. + /// The custom host launcher. + void RunTestsWithCustomTestHost( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); /// - /// Starts a test run given a list of test cases + /// Starts a test run. /// - /// TestCases to run - /// RunSettings XML to run the tests - /// Options to be passed into the platform. - /// EventHandler to receive test run events - void RunTests(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler); + /// + /// The list of test cases for the test run. + /// The run settings for the run. + /// The test platform options. + /// The test session info object. + /// The run event handler. + /// The custom host launcher. + void RunTestsWithCustomTestHost( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); /// - /// Starts a test run given a list of sources by giving caller an option to start their own test host. + /// Starts a new test session. /// - /// Sources to Run tests on - /// RunSettings XML to run the tests - /// EventHandler to receive test run events - /// Custom test host launcher for the run. - void RunTestsWithCustomTestHost(IEnumerable sources, string runSettings, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher); + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The session event handler. + /// + /// A test session info object. + ITestSession StartTestSession( + IList sources, + string runSettings, + ITestSessionEventsHandler eventsHandler); /// - /// Starts a test run given a list of sources by giving caller an option to start their own test host. + /// Starts a new test session. /// - /// Sources to Run tests on - /// RunSettings XML to run the tests - /// Options to be passed into the platform. - /// EventHandler to receive test run events - /// Custom test host launcher for the run. - void RunTestsWithCustomTestHost(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher); + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The test platform options. + /// The session event handler. + /// + /// A test session info object. + ITestSession StartTestSession( + IList sources, + string runSettings, + TestPlatformOptions options, + ITestSessionEventsHandler eventsHandler); /// - /// Starts a test run given a list of test cases by giving caller an option to start their own test host + /// Starts a new test session. /// - /// TestCases to run. - /// RunSettings XML to run the tests. - /// EventHandler to receive test run events. - /// Custom test host launcher for the run. - void RunTestsWithCustomTestHost(IEnumerable testCases, string runSettings, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher); + /// + /// The list of source assemblies for the test run. + /// The run settings for the run. + /// The test platform options. + /// The session event handler. + /// The custom host launcher. + /// + /// A test session info object. + ITestSession StartTestSession( + IList sources, + string runSettings, + TestPlatformOptions options, + ITestSessionEventsHandler eventsHandler, + ITestHostLauncher testHostLauncher); /// - /// Starts a test run given a list of test cases by giving caller an option to start their own test host + /// Stops the test session. /// - /// TestCases to run. - /// RunSettings XML to run the tests. - /// Options to be passed into the platform. - /// EventHandler to receive test run events. - /// Custom test host launcher for the run. - void RunTestsWithCustomTestHost(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher); + /// + /// The test session info object. + /// The session event handler. + /// + /// True if the session was successfuly stopped, false otherwise. + bool StopTestSession( + TestSessionInfo testSessionInfo, + ITestSessionEventsHandler eventsHandler); /// - /// Cancel the last test run. + /// Cancels the last test run. /// new void CancelTestRun(); /// - /// Abort the last test run. + /// Aborts the last test run. /// new void AbortTestRun(); diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/IVsTestConsoleWrapperAsync.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/IVsTestConsoleWrapperAsync.cs index 452de38cb6..136e6eec84 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/IVsTestConsoleWrapperAsync.cs +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Interfaces/IVsTestConsoleWrapperAsync.cs @@ -10,32 +10,66 @@ namespace Microsoft.TestPlatform.VsTestConsole.TranslationLayer.Interfaces using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; + using Microsoft.VisualStudio.TestPlatform.VsTestConsole.TranslationLayer.Interfaces; /// - /// Asynchronous equivalent of + /// Asynchronous equivalent of . /// public interface IVsTestConsoleWrapperAsync { /// /// Asynchronous equivalent of . /// - /// Task StartSessionAsync(); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . /// Task InitializeExtensionsAsync(IEnumerable pathToAdditionalExtensions); /// - /// Asynchronous equivalent of + /// Asynchronous equivalent of . /// - Task DiscoverTestsAsync(IEnumerable sources, string discoverySettings, ITestDiscoveryEventsHandler discoveryEventsHandler); + Task DiscoverTestsAsync( + IEnumerable sources, + string discoverySettings, + ITestDiscoveryEventsHandler discoveryEventsHandler); /// - /// Asynchronous equivalent of + /// Asynchronous equivalent of . /// - Task DiscoverTestsAsync(IEnumerable sources, string discoverySettings, TestPlatformOptions options, ITestDiscoveryEventsHandler2 discoveryEventsHandler); + Task DiscoverTestsAsync( + IEnumerable sources, + string discoverySettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 discoveryEventsHandler); + + /// + /// Asynchronous equivalent of . + /// + Task DiscoverTestsAsync( + IEnumerable sources, + string discoverySettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestDiscoveryEventsHandler2 discoveryEventsHandler); /// /// See . @@ -43,44 +77,236 @@ public interface IVsTestConsoleWrapperAsync void CancelDiscovery(); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . + /// + Task RunTestsAsync( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Asynchronous equivalent of . + /// + Task RunTestsAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Asynchronous equivalent of . + /// + Task RunTestsAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Asynchronous equivalent of . + /// + Task RunTestsAsync( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Asynchronous equivalent of . + /// + Task RunTestsAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Asynchronous equivalent of . + /// + Task RunTestsAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler); + + /// + /// Asynchronous equivalent of . + /// + Task RunTestsWithCustomTestHostAsync( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Asynchronous equivalent of . + /// + Task RunTestsWithCustomTestHostAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); + + /// + /// Asynchronous equivalent of . /// - Task RunTestsAsync(IEnumerable sources, string runSettings, ITestRunEventsHandler testRunEventsHandler); + Task RunTestsWithCustomTestHostAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . /// - Task RunTestsAsync(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler); + Task RunTestsWithCustomTestHostAsync( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . /// - Task RunTestsAsync(IEnumerable testCases, string runSettings, ITestRunEventsHandler testRunEventsHandler); + Task RunTestsWithCustomTestHostAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . /// - Task RunTestsAsync(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler); + Task RunTestsWithCustomTestHostAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . /// - Task RunTestsWithCustomTestHostAsync(IEnumerable sources, string runSettings, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher); + Task StartTestSessionAsync( + IList sources, + string runSettings, + ITestSessionEventsHandler eventsHandler); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . /// - Task RunTestsWithCustomTestHostAsync(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher); + Task StartTestSessionAsync( + IList sources, + string runSettings, + TestPlatformOptions options, + ITestSessionEventsHandler eventsHandler); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . /// - Task RunTestsWithCustomTestHostAsync(IEnumerable testCases, string runSettings, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher); + Task StartTestSessionAsync( + IList sources, + string runSettings, + TestPlatformOptions options, + ITestSessionEventsHandler eventsHandler, + ITestHostLauncher testHostLauncher); /// - /// Asynchronous equivalent of . + /// Asynchronous equivalent of . /// - Task RunTestsWithCustomTestHostAsync(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher); + Task StopTestSessionAsync( + TestSessionInfo testSessionInfo, + ITestSessionEventsHandler eventsHandler); /// /// See . @@ -93,15 +319,24 @@ public interface IVsTestConsoleWrapperAsync void AbortTestRun(); /// - /// Provides back all attachments to TestPlatform for additional processing (for example merging) + /// Gets back all attachments to test platform for additional processing (for example merging). /// - /// Collection of attachments - /// XML processing settings - /// Indicates that all test executions are done and all data is provided - /// Enables metrics collection (used for telemetry) - /// EventHandler to receive session complete event - /// Cancellation token - Task ProcessTestRunAttachmentsAsync(IEnumerable attachments, string processingSettings, bool isLastBatch, bool collectMetrics, ITestRunAttachmentsProcessingEventsHandler eventsHandler, CancellationToken cancellationToken); + /// + /// Collection of attachments. + /// XML processing settings. + /// + /// Indicates that all test executions are done and all data is provided. + /// + /// Enables metrics collection (used for telemetry). + /// Event handler to receive session complete event. + /// Cancellation token. + Task ProcessTestRunAttachmentsAsync( + IEnumerable attachments, + string processingSettings, + bool isLastBatch, + bool collectMetrics, + ITestRunAttachmentsProcessingEventsHandler eventsHandler, + CancellationToken cancellationToken); /// /// See . diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/Resources.Designer.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/Resources.Designer.cs index a218efe7f5..222fa23065 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/Resources.Designer.cs +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/Resources.Designer.cs @@ -61,6 +61,24 @@ internal Resources() { } } + /// + /// Looks up a localized string similar to The Start Test Session operation was aborted.. + /// + public static string AbortedStartTestSession { + get { + return ResourceManager.GetString("AbortedStartTestSession", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The Stop Test Session operation was aborted.. + /// + public static string AbortedStopTestSession { + get { + return ResourceManager.GetString("AbortedStopTestSession", resourceCulture); + } + } + /// /// Looks up a localized string similar to The active Test Run Attachments Processing was aborted.. /// diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/Resources.resx b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/Resources.resx index eb053d0a74..5a6313b3fd 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/Resources.resx +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/Resources.resx @@ -117,6 +117,12 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + The Start Test Session operation was aborted. + + + The Stop Test Session operation was aborted. + The active Test Run Attachments Processing was aborted. diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.cs.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.cs.xlf index ef6c350d70..428dc14bdd 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.cs.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.cs.xlf @@ -66,6 +66,16 @@ Aktivní zpracovávání příloh testovacího běhu se přerušilo. + + The Start Test Session operation was aborted. + Operace zahájení testovací relace se přerušila. + + + + The Stop Test Session operation was aborted. + Operace zastavení testovací relace se přerušila. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.de.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.de.xlf index 1f11facce4..d0bc88a7ee 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.de.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.de.xlf @@ -66,6 +66,16 @@ Die Verarbeitung aktiver Testlaufanlagen wurde abgebrochen. + + The Start Test Session operation was aborted. + Der Vorgang zum Starten der Testsitzung wurde abgebrochen. + + + + The Stop Test Session operation was aborted. + Der Vorgang zum Beenden der Testsitzung wurde abgebrochen. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.es.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.es.xlf index 3dede43545..f77fd0cf94 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.es.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.es.xlf @@ -66,6 +66,16 @@ Se ha anulado el procesamiento de los datos adjuntos de la serie de pruebas activa. + + The Start Test Session operation was aborted. + La operación de inicio de la sesión de prueba se ha anulado. + + + + The Stop Test Session operation was aborted. + La operación de detención de la sesión de prueba se ha anulado. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.fr.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.fr.xlf index 680a7ada9c..ba42021532 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.fr.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.fr.xlf @@ -66,6 +66,16 @@ Le traitement des pièces jointes de série de tests actif a été abandonné. + + The Start Test Session operation was aborted. + L'opération de démarrage de la session de test a été abandonnée. + + + + The Stop Test Session operation was aborted. + L'opération d'arrêt de la session de test a été abandonnée. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.it.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.it.xlf index 2717c36e76..1f13379894 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.it.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.it.xlf @@ -66,6 +66,16 @@ L'elaborazione degli allegati dell'esecuzione dei test attiva è stata interrotta. + + The Start Test Session operation was aborted. + L'operazione di avvio della sessione di test è stata interrotta. + + + + The Stop Test Session operation was aborted. + L'operazione di arresto della sessione di test è stata interrotta. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.ja.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.ja.xlf index 2b1038749d..8b2e7dedea 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.ja.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.ja.xlf @@ -66,6 +66,16 @@ アクティブなテストの実行の添付ファイルの処理が中止されました。 + + The Start Test Session operation was aborted. + テスト セッションの開始操作が中止されました。 + + + + The Stop Test Session operation was aborted. + テスト セッションの停止操作が中止されました。 + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.ko.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.ko.xlf index 96d741d53b..c26d5cb125 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.ko.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.ko.xlf @@ -66,6 +66,16 @@ 활성 테스트 실행 첨부 파일 처리가 중단되었습니다. + + The Start Test Session operation was aborted. + 테스트 세션 시작 작업이 중단되었습니다. + + + + The Stop Test Session operation was aborted. + 테스트 세션 중지 작업이 중단되었습니다. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.pl.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.pl.xlf index 30d7fa4159..61ed3c2310 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.pl.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.pl.xlf @@ -66,6 +66,16 @@ Aktywne przetwarzanie załączników przebiegu testu zostało przerwane. + + The Start Test Session operation was aborted. + Operacja uruchamiania sesji testowania została przerwana. + + + + The Stop Test Session operation was aborted. + Operacja zatrzymywania sesji testowania została przerwana. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.pt-BR.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.pt-BR.xlf index eb1e8071d1..f0db97e1cc 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.pt-BR.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.pt-BR.xlf @@ -66,6 +66,16 @@ O Processamento de Anexos de Execução de Teste ativo foi anulado. + + The Start Test Session operation was aborted. + A operação Iniciar a Sessão de Teste foi anulada. + + + + The Stop Test Session operation was aborted. + A operação Parar a Sessão de Teste foi anulada. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.ru.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.ru.xlf index 08f0624c16..043104a8cc 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.ru.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.ru.xlf @@ -66,6 +66,16 @@ Обработка вложений активного тестового запуска прервана. + + The Start Test Session operation was aborted. + Операция запуска сеанса тестирования прервана. + + + + The Stop Test Session operation was aborted. + Операция остановки сеанса тестирования прервана. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.tr.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.tr.xlf index 30dd1c7f21..4f2dca9f9b 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.tr.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.tr.xlf @@ -66,6 +66,16 @@ Etkin Test Çalıştırması Ekleri İşlemi durduruldu. + + The Start Test Session operation was aborted. + Test Oturumunu Başlatma işlemi iptal edildi. + + + + The Stop Test Session operation was aborted. + Test Oturumunu Durdurma işlemi iptal edildi. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.xlf index 7c79b0d188..4aca1abbc0 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.xlf @@ -28,6 +28,16 @@ The active Test Run Attachments Processing was aborted. + + The Start Test Session operation was aborted. + The Start Test Session operation was aborted. + + + + The Stop Test Session operation was aborted. + The Stop Test Session operation was aborted. + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.zh-Hans.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.zh-Hans.xlf index 980fae06e9..c8c54fc528 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.zh-Hans.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.zh-Hans.xlf @@ -1,6 +1,6 @@  - +
23 @@ -66,6 +66,16 @@ 已中止正在进行的测试运行附件处理操作。 + + The Start Test Session operation was aborted. + 已中止启动测试会话操作。 + + + + The Stop Test Session operation was aborted. + 已中止停止测试会话操作。 + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.zh-Hant.xlf b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.zh-Hant.xlf index c0859e0181..135024c53f 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.zh-Hant.xlf +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Resources/xlf/Resources.zh-Hant.xlf @@ -1,6 +1,6 @@  - +
23 @@ -66,6 +66,16 @@ 執行中的測試回合附件處理已中止。 + + The Start Test Session operation was aborted. + 開始測試工作階段作業已中止。 + + + + The Stop Test Session operation was aborted. + 停止測試工作階段作業已中止。 + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/TestSession.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/TestSession.cs new file mode 100644 index 0000000000..d97761a4c9 --- /dev/null +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/TestSession.cs @@ -0,0 +1,373 @@ +// 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.TestPlatform.VsTestConsole.TranslationLayer +{ + using System.Collections.Generic; + using System.Threading.Tasks; + + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; + using Microsoft.VisualStudio.TestPlatform.VsTestConsole.TranslationLayer.Interfaces; + + /// + /// Defines a test session object that can be used to make calls to the vstest.console + /// process. + /// + public class TestSession : ITestSession + { + private TestSessionInfo testSessionInfo; + private VsTestConsoleWrapper consoleWrapper; + + #region Constructors + /// + /// Initializes a new instance of the class. + /// + /// + /// The test session info object. + /// The encapsulated console wrapper. + public TestSession( + TestSessionInfo testSessionInfo, + VsTestConsoleWrapper consoleWrapper) + { + this.testSessionInfo = testSessionInfo; + this.consoleWrapper = consoleWrapper; + } + #endregion + + #region ITestSession + /// + public void AbortTestRun() + { + this.consoleWrapper.AbortTestRun(); + } + + /// + public void CancelDiscovery() + { + this.consoleWrapper.CancelDiscovery(); + } + + /// + public void CancelTestRun() + { + this.consoleWrapper.CancelTestRun(); + } + + /// + public void DiscoverTests( + IEnumerable sources, + string discoverySettings, + ITestDiscoveryEventsHandler discoveryEventsHandler) + { + this.DiscoverTests( + sources, + discoverySettings, + options: null, + discoveryEventsHandler: new DiscoveryEventsHandleConverter(discoveryEventsHandler)); + } + + /// + public void DiscoverTests( + IEnumerable sources, + string discoverySettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 discoveryEventsHandler) + { + // TODO (copoiena): Hook into the wrapper and pass session info here. + this.consoleWrapper.DiscoverTests( + sources, + discoverySettings, + options, + discoveryEventsHandler); + } + + /// + public void RunTests( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler) + { + this.RunTests( + sources, + runSettings, + options: null, + testRunEventsHandler); + } + + /// + public void RunTests( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler) + { + this.consoleWrapper.RunTests( + sources, + runSettings, + options, + this.testSessionInfo, + testRunEventsHandler); + } + + /// + public void RunTests( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler) + { + this.RunTests( + testCases, + runSettings, + options: null, + testRunEventsHandler); + } + + /// + public void RunTests( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler) + { + this.consoleWrapper.RunTests( + testCases, + runSettings, + options, + this.testSessionInfo, + testRunEventsHandler); + } + + /// + public void RunTestsWithCustomTestHost( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + this.RunTestsWithCustomTestHost( + sources, + runSettings, + options: null, + testRunEventsHandler, + customTestHostLauncher); + } + + /// + public void RunTestsWithCustomTestHost( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + this.consoleWrapper.RunTestsWithCustomTestHost( + sources, + runSettings, + options, + this.testSessionInfo, + testRunEventsHandler, + customTestHostLauncher); + } + + /// + public void RunTestsWithCustomTestHost( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + this.RunTestsWithCustomTestHost( + testCases, + runSettings, + options: null, + testRunEventsHandler, + customTestHostLauncher); + } + + /// + public void RunTestsWithCustomTestHost( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + this.consoleWrapper.RunTestsWithCustomTestHost( + testCases, + runSettings, + options, + this.testSessionInfo, + testRunEventsHandler, + customTestHostLauncher); + } + + /// + public bool StopTestSession(ITestSessionEventsHandler eventsHandler) + { + return this.consoleWrapper.StopTestSession( + this.testSessionInfo, + eventsHandler); + } + #endregion + + #region ITestSessionAsync + /// + public async Task DiscoverTestsAsync( + IEnumerable sources, + string discoverySettings, + ITestDiscoveryEventsHandler discoveryEventsHandler) + { + await this.DiscoverTestsAsync( + sources, + discoverySettings, + options: null, + discoveryEventsHandler: new DiscoveryEventsHandleConverter(discoveryEventsHandler)); + } + + /// + public async Task DiscoverTestsAsync( + IEnumerable sources, + string discoverySettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 discoveryEventsHandler) + { + // TODO (copoiena): Hook into the wrapper and pass session info here. + await this.consoleWrapper.DiscoverTestsAsync( + sources, + discoverySettings, + options, + discoveryEventsHandler); + } + + /// + public async Task RunTestsAsync( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler) + { + await this.RunTestsAsync( + sources, + runSettings, + options: null, + testRunEventsHandler); + } + + /// + public async Task RunTestsAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler) + { + await this.consoleWrapper.RunTestsAsync( + sources, + runSettings, + options, + this.testSessionInfo, + testRunEventsHandler); + } + + /// + public async Task RunTestsAsync( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler) + { + await this.RunTestsAsync( + testCases, + runSettings, + options: null, + testRunEventsHandler); + } + + /// + public async Task RunTestsAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler) + { + await this.consoleWrapper.RunTestsAsync( + testCases, + runSettings, + options, + this.testSessionInfo, + testRunEventsHandler); + } + + /// + public async Task RunTestsWithCustomTestHostAsync( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + await this.RunTestsWithCustomTestHostAsync( + sources, + runSettings, + options: null, + testRunEventsHandler, + customTestHostLauncher); + } + + /// + public async Task RunTestsWithCustomTestHostAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + await this.consoleWrapper.RunTestsWithCustomTestHostAsync( + sources, + runSettings, + options, + this.testSessionInfo, + testRunEventsHandler, + customTestHostLauncher); + } + + /// + public async Task RunTestsWithCustomTestHostAsync( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + await this.RunTestsWithCustomTestHostAsync( + testCases, + runSettings, + options: null, + testRunEventsHandler, + customTestHostLauncher); + } + + /// + public async Task RunTestsWithCustomTestHostAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + await this.consoleWrapper.RunTestsWithCustomTestHostAsync( + testCases, + runSettings, + options, + this.testSessionInfo, + testRunEventsHandler, + customTestHostLauncher); + } + + /// + public async Task StopTestSessionAsync(ITestSessionEventsHandler eventsHandler) + { + return await this.consoleWrapper.StopTestSessionAsync( + this.testSessionInfo, + eventsHandler); + } + #endregion + } +} diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleRequestSender.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleRequestSender.cs index 2529e8c6bf..35c7630730 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleRequestSender.cs +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleRequestSender.cs @@ -19,15 +19,21 @@ namespace Microsoft.TestPlatform.VsTestConsole.TranslationLayer using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Payloads; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using TranslationLayerResources = Microsoft.VisualStudio.TestPlatform.VsTestConsole.TranslationLayer.Resources.Resources; /// - /// VstestConsoleRequestSender for sending requests to Vstest.console.exe + /// Vstest console request sender for sending requests to vstest.console.exe /// internal class VsTestConsoleRequestSender : ITranslationLayerRequestSender { + /// + /// The minimum protocol version that has test session support. + /// + private const int MinimumProtocolVersionWithTestSessionSupport = 5; + private readonly ICommunicationManager communicationManager; private readonly IDataSerializer dataSerializer; @@ -37,20 +43,37 @@ internal class VsTestConsoleRequestSender : ITranslationLayerRequestSender private bool handShakeSuccessful = false; - private int protocolVersion = 4; + private int protocolVersion = 5; /// - /// Use to cancel blocking tasks associated with vstest.console process + /// Used to cancel blocking tasks associated with the vstest.console process. /// private CancellationTokenSource processExitCancellationTokenSource; #region Constructor - public VsTestConsoleRequestSender() : this(new SocketCommunicationManager(), JsonDataSerializer.Instance, TestPlatformEventSource.Instance) + /// + /// Initializes a new instance of the class. + /// + public VsTestConsoleRequestSender() + : this( + new SocketCommunicationManager(), + JsonDataSerializer.Instance, + TestPlatformEventSource.Instance) { } - internal VsTestConsoleRequestSender(ICommunicationManager communicationManager, IDataSerializer dataSerializer, ITestPlatformEventSource testPlatformEventSource) + /// + /// Initializes a new instance of the class. + /// + /// + /// The communication manager. + /// The data serializer. + /// The test platform event source. + internal VsTestConsoleRequestSender( + ICommunicationManager communicationManager, + IDataSerializer dataSerializer, + ITestPlatformEventSource testPlatformEventSource) { this.communicationManager = communicationManager; this.dataSerializer = dataSerializer; @@ -61,11 +84,7 @@ internal VsTestConsoleRequestSender(ICommunicationManager communicationManager, #region ITranslationLayerRequestSender - /// - /// Initializes Communication with vstest.console.exe - /// Hosts a communication channel and asynchronously connects to vstest.console.exe - /// - /// Port Number of hosted server on this side + /// public int InitializeCommunication() { if (EqtTrace.IsInfoEnabled) @@ -91,7 +110,9 @@ public int InitializeCommunication() } catch (Exception ex) { - EqtTrace.Error("VsTestConsoleRequestSender.InitializeCommunication: Error initializing communication with VstestConsole: {0}", ex); + EqtTrace.Error( + "VsTestConsoleRequestSender.InitializeCommunication: Error initializing communication with VstestConsole: {0}", + ex); this.handShakeComplete.Set(); } @@ -103,11 +124,7 @@ public int InitializeCommunication() return port; } - /// - /// Waits for Vstest.console.exe Connection for a given timeout. - /// - /// Time to wait for the connection - /// True, if successful + /// public bool WaitForRequestHandlerConnection(int clientConnectionTimeout) { var waitSucess = this.handShakeComplete.WaitOne(clientConnectionTimeout); @@ -130,14 +147,17 @@ public async Task InitializeCommunicationAsync(int clientConnectionTimeout) { port = this.communicationManager.HostServer(new IPEndPoint(IPAddress.Loopback, 0)).Port; var timeoutSource = new CancellationTokenSource(clientConnectionTimeout); - await Task.Run(() => this.communicationManager.AcceptClientAsync(), timeoutSource.Token); + await Task.Run(() => + this.communicationManager.AcceptClientAsync(), timeoutSource.Token); this.handShakeSuccessful = await this.HandShakeWithVsTestConsoleAsync(); this.handShakeComplete.Set(); } catch (Exception ex) { - EqtTrace.Error("VsTestConsoleRequestSender.InitializeCommunicationAsync: Error initializing communication with VstestConsole: {0}", ex); + EqtTrace.Error( + "VsTestConsoleRequestSender.InitializeCommunicationAsync: Error initializing communication with VstestConsole: {0}", + ex); this.handShakeComplete.Set(); } @@ -156,33 +176,58 @@ public void InitializeExtensions(IEnumerable pathToAdditionalExtensions) { EqtTrace.Info($"VsTestConsoleRequestSender.InitializeExtensions: Initializing extensions with additional extensions path {string.Join(",", pathToAdditionalExtensions.ToList())}."); } - this.communicationManager.SendMessage(MessageType.ExtensionsInitialize, pathToAdditionalExtensions, this.protocolVersion); + + this.communicationManager.SendMessage( + MessageType.ExtensionsInitialize, + pathToAdditionalExtensions, + this.protocolVersion); } /// - public void DiscoverTests(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestDiscoveryEventsHandler2 eventHandler) + public void DiscoverTests( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 eventHandler) { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("VsTestConsoleRequestSender.DiscoverTests: Starting test discovery."); } - this.SendMessageAndListenAndReportTestCases(sources, runSettings, options, eventHandler); + + this.SendMessageAndListenAndReportTestCases( + sources, + runSettings, + options, + eventHandler); } - /// - /// Asynchronous equivalent of . - /// - public async Task DiscoverTestsAsync(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestDiscoveryEventsHandler2 eventHandler) + /// + public async Task DiscoverTestsAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 eventHandler) { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("VsTestConsoleRequestSender.DiscoverTestsAsync: Starting test discovery."); } - await this.SendMessageAndListenAndReportTestCasesAsync(sources, runSettings, options, eventHandler); + + await this.SendMessageAndListenAndReportTestCasesAsync( + sources, + runSettings, + options, + eventHandler); } /// - public void StartTestRun(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler) + public void StartTestRun( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler) { if (EqtTrace.IsInfoEnabled) { @@ -191,41 +236,76 @@ public void StartTestRun(IEnumerable sources, string runSettings, TestPl this.SendMessageAndListenAndReportTestResults( MessageType.TestRunAllSourcesWithDefaultHost, - new TestRunRequestPayload() { Sources = sources.ToList(), RunSettings = runSettings, TestPlatformOptions = options }, + new TestRunRequestPayload() + { + Sources = sources.ToList(), + RunSettings = runSettings, + TestPlatformOptions = options, + TestSessionInfo = testSessionInfo + }, runEventsHandler, null); } /// - public async Task StartTestRunAsync(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler) + public async Task StartTestRunAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler) { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("VsTestConsoleRequestSender.StartTestRunAsync: Starting test run."); } + await this.SendMessageAndListenAndReportTestResultsAsync( MessageType.TestRunAllSourcesWithDefaultHost, - new TestRunRequestPayload() { Sources = sources.ToList(), RunSettings = runSettings, TestPlatformOptions = options }, + new TestRunRequestPayload() + { + Sources = sources.ToList(), + RunSettings = runSettings, + TestPlatformOptions = options, + TestSessionInfo = testSessionInfo + }, runEventsHandler, null); } /// - public void StartTestRun(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler) + public void StartTestRun( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler) { if (EqtTrace.IsInfoEnabled) { EqtTrace.Info("VsTestConsoleRequestSender.StartTestRun: Starting test run."); } + this.SendMessageAndListenAndReportTestResults( MessageType.TestRunAllSourcesWithDefaultHost, - new TestRunRequestPayload() { TestCases = testCases.ToList(), RunSettings = runSettings, TestPlatformOptions = options }, + new TestRunRequestPayload() + { + TestCases = testCases.ToList(), + RunSettings = runSettings, + TestPlatformOptions = options, + TestSessionInfo = testSessionInfo + }, runEventsHandler, null); } /// - public async Task StartTestRunAsync(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler) + public async Task StartTestRunAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler) { if (EqtTrace.IsInfoEnabled) { @@ -234,7 +314,13 @@ public async Task StartTestRunAsync(IEnumerable testCases, string runS await this.SendMessageAndListenAndReportTestResultsAsync( MessageType.TestRunAllSourcesWithDefaultHost, - new TestRunRequestPayload() { TestCases = testCases.ToList(), RunSettings = runSettings, TestPlatformOptions = options }, + new TestRunRequestPayload() + { + TestCases = testCases.ToList(), + RunSettings = runSettings, + TestPlatformOptions = options, + TestSessionInfo = testSessionInfo + }, runEventsHandler, null); } @@ -244,6 +330,7 @@ public void StartTestRunWithCustomHost( IEnumerable sources, string runSettings, TestPlatformOptions options, + TestSessionInfo testSessionInfo, ITestRunEventsHandler runEventsHandler, ITestHostLauncher customHostLauncher) { @@ -259,7 +346,8 @@ public void StartTestRunWithCustomHost( Sources = sources.ToList(), RunSettings = runSettings, DebuggingEnabled = customHostLauncher.IsDebug, - TestPlatformOptions = options + TestPlatformOptions = options, + TestSessionInfo = testSessionInfo }, runEventsHandler, customHostLauncher); @@ -270,6 +358,7 @@ public async Task StartTestRunWithCustomHostAsync( IEnumerable sources, string runSettings, TestPlatformOptions options, + TestSessionInfo testSessionInfo, ITestRunEventsHandler runEventsHandler, ITestHostLauncher customHostLauncher) { @@ -285,14 +374,21 @@ await this.SendMessageAndListenAndReportTestResultsAsync( Sources = sources.ToList(), RunSettings = runSettings, DebuggingEnabled = customHostLauncher.IsDebug, - TestPlatformOptions = options + TestPlatformOptions = options, + TestSessionInfo = testSessionInfo }, runEventsHandler, customHostLauncher); } /// - public void StartTestRunWithCustomHost(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler, ITestHostLauncher customHostLauncher) + public void StartTestRunWithCustomHost( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler, + ITestHostLauncher customHostLauncher) { if (EqtTrace.IsInfoEnabled) { @@ -306,14 +402,21 @@ public void StartTestRunWithCustomHost(IEnumerable testCases, string r TestCases = testCases.ToList(), RunSettings = runSettings, DebuggingEnabled = customHostLauncher.IsDebug, - TestPlatformOptions = options + TestPlatformOptions = options, + TestSessionInfo = testSessionInfo }, runEventsHandler, customHostLauncher); } /// - public async Task StartTestRunWithCustomHostAsync(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler runEventsHandler, ITestHostLauncher customHostLauncher) + public async Task StartTestRunWithCustomHostAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler runEventsHandler, + ITestHostLauncher customHostLauncher) { if (EqtTrace.IsInfoEnabled) { @@ -327,12 +430,377 @@ await this.SendMessageAndListenAndReportTestResultsAsync( TestCases = testCases.ToList(), RunSettings = runSettings, DebuggingEnabled = customHostLauncher.IsDebug, - TestPlatformOptions = options + TestPlatformOptions = options, + TestSessionInfo = testSessionInfo }, runEventsHandler, customHostLauncher); } + /// + public TestSessionInfo StartTestSession( + IList sources, + string runSettings, + TestPlatformOptions options, + ITestSessionEventsHandler eventsHandler, + ITestHostLauncher testHostLauncher) + { + // Make sure vstest.console knows how to handle start/stop test session messages. + // Bail out if it doesn't, otherwise we'll hang waiting for a reply from the console + // that will never come. + if (this.protocolVersion < MinimumProtocolVersionWithTestSessionSupport) + { + eventsHandler?.HandleStartTestSessionComplete(null); + return null; + } + + if (EqtTrace.IsInfoEnabled) + { + EqtTrace.Info("VsTestConsoleRequestSender.StartTestSession: Starting test session."); + } + + try + { + var payload = new StartTestSessionPayload + { + // TODO (copoiena): When sharing the test host between test discovery and test + // execution, should we use the test host launcher to launch it ? What side + // effects does this have ? + // + // This is useful for profiling and maybe for launching hosts other than the + // ones managed by us (i.e., the default host and the dotnet host), examples + // including UWP and other hosts that don't implement the ITestRuntimeProvider2 + // interface and/or are not aware of the possibility of attaching to an already + // running process. + Sources = sources, + RunSettings = runSettings, + HasCustomHostLauncher = testHostLauncher != null, + IsDebuggingEnabled = (testHostLauncher != null) + ? testHostLauncher.IsDebug + : false, + TestPlatformOptions = options + }; + + this.communicationManager.SendMessage( + MessageType.StartTestSession, + payload, + this.protocolVersion); + + while (true) + { + var message = this.TryReceiveMessage(); + + switch (message.MessageType) + { + case MessageType.StartTestSessionCallback: + var ackPayload = this.dataSerializer + .DeserializePayload(message); + eventsHandler?.HandleStartTestSessionComplete( + ackPayload.TestSessionInfo); + return ackPayload.TestSessionInfo; + + case MessageType.CustomTestHostLaunch: + this.HandleCustomHostLaunch(testHostLauncher, message); + break; + + case MessageType.EditorAttachDebugger: + this.AttachDebuggerToProcess(testHostLauncher, message); + break; + + case MessageType.TestMessage: + var testMessagePayload = this.dataSerializer + .DeserializePayload(message); + eventsHandler?.HandleLogMessage( + testMessagePayload.MessageLevel, + testMessagePayload.Message); + break; + + default: + EqtTrace.Warning( + "VsTestConsoleRequestSender.StartTestSession: Unexpected message received: {0}", + message.MessageType); + break; + } + } + } + catch (Exception exception) + { + EqtTrace.Error( + "Aborting StartTestSession operation due to error: {0}", + exception); + eventsHandler?.HandleLogMessage( + TestMessageLevel.Error, + TranslationLayerResources.AbortedStartTestSession); + + eventsHandler?.HandleStartTestSessionComplete(null); + } + + this.testPlatformEventSource.TranslationLayerStartTestSessionStop(); + return null; + } + + /// + public async Task StartTestSessionAsync( + IList sources, + string runSettings, + TestPlatformOptions options, + ITestSessionEventsHandler eventsHandler, + ITestHostLauncher testHostLauncher) + { + // Make sure vstest.console knows how to handle start/stop test session messages. + // Bail out if it doesn't, otherwise we'll hang waiting for a reply from the console + // that will never come. + if (this.protocolVersion < MinimumProtocolVersionWithTestSessionSupport) + { + eventsHandler?.HandleStartTestSessionComplete(null); + return await Task.FromResult((TestSessionInfo)null); + } + + if (EqtTrace.IsInfoEnabled) + { + EqtTrace.Info("VsTestConsoleRequestSender.StartTestSession: Starting test session."); + } + + try + { + var payload = new StartTestSessionPayload + { + // TODO (copoiena): When sharing the test host between test discovery and test + // execution, should we use the test host launcher to launch it ? What side + // effects does this have ? + // + // This is useful for profiling and maybe for launching hosts other than the + // ones managed by us (i.e., the default host and the dotnet host), examples + // including UWP and other hosts that don't implement the ITestRuntimeProvider2 + // interface and/or are not aware of the possibility of attaching to an already + // running process. + Sources = sources, + RunSettings = runSettings, + HasCustomHostLauncher = testHostLauncher != null, + IsDebuggingEnabled = (testHostLauncher != null) ? testHostLauncher.IsDebug : false, + TestPlatformOptions = options + }; + + this.communicationManager.SendMessage( + MessageType.StartTestSession, + payload, + this.protocolVersion); + + while (true) + { + var message = await this.TryReceiveMessageAsync().ConfigureAwait(false); + + switch (message.MessageType) + { + case MessageType.StartTestSessionCallback: + var ackPayload = this.dataSerializer + .DeserializePayload(message); + eventsHandler?.HandleStartTestSessionComplete( + ackPayload.TestSessionInfo); + return ackPayload.TestSessionInfo; + + case MessageType.CustomTestHostLaunch: + this.HandleCustomHostLaunch(testHostLauncher, message); + break; + + case MessageType.EditorAttachDebugger: + this.AttachDebuggerToProcess(testHostLauncher, message); + break; + + case MessageType.TestMessage: + var testMessagePayload = this.dataSerializer + .DeserializePayload(message); + eventsHandler?.HandleLogMessage( + testMessagePayload.MessageLevel, + testMessagePayload.Message); + break; + + default: + EqtTrace.Warning( + "VsTestConsoleRequestSender.StartTestSession: Unexpected message received: {0}", + message.MessageType); + break; + } + } + } + catch (Exception exception) + { + EqtTrace.Error("Aborting StartTestSession operation due to error: {0}", exception); + eventsHandler?.HandleLogMessage( + TestMessageLevel.Error, + TranslationLayerResources.AbortedStartTestSession); + + eventsHandler?.HandleStartTestSessionComplete(null); + } + + this.testPlatformEventSource.TranslationLayerStartTestSessionStop(); + return null; + } + + /// + public bool StopTestSession( + TestSessionInfo testSessionInfo, + ITestSessionEventsHandler eventsHandler) + { + // Make sure vstest.console knows how to handle start/stop test session messages. + // Bail out if it doesn't, otherwise we'll hang waiting for a reply from the console + // that will never come. + if (this.protocolVersion < MinimumProtocolVersionWithTestSessionSupport) + { + eventsHandler?.HandleStopTestSessionComplete(testSessionInfo, false); + return false; + } + + if (EqtTrace.IsInfoEnabled) + { + EqtTrace.Info("VsTestConsoleRequestSender.StopTestSession: Stop test session."); + } + + // Due to various considertaions it is possible to end up with a null test session + // after doing the start test session call. However, we should filter out requests + // to stop such a session as soon as possible, at the request sender level. + // + // We do this here instead of on the wrapper level in order to benefit of the + // testplatform events being fired still. + if (testSessionInfo == null) + { + this.testPlatformEventSource.TranslationLayerStopTestSessionStop(); + return true; + } + + try + { + this.communicationManager.SendMessage( + MessageType.StopTestSession, + testSessionInfo, + this.protocolVersion); + + while (true) + { + var message = this.TryReceiveMessage(); + + switch (message.MessageType) + { + case MessageType.StopTestSessionCallback: + var payload = this.dataSerializer.DeserializePayload(message); + eventsHandler?.HandleStopTestSessionComplete(payload.TestSessionInfo, payload.IsStopped); + return payload.IsStopped; + + case MessageType.TestMessage: + var testMessagePayload = this.dataSerializer + .DeserializePayload(message); + eventsHandler?.HandleLogMessage( + testMessagePayload.MessageLevel, + testMessagePayload.Message); + break; + + default: + EqtTrace.Warning( + "VsTestConsoleRequestSender.StopTestSession: Unexpected message received: {0}", + message.MessageType); + break; + } + } + } + catch (Exception exception) + { + EqtTrace.Error( + "Aborting StopTestSession operation for id {0} due to error: {1}", + testSessionInfo?.Id, + exception); + eventsHandler?.HandleLogMessage( + TestMessageLevel.Error, + TranslationLayerResources.AbortedStopTestSession); + + eventsHandler?.HandleStopTestSessionComplete(testSessionInfo, false); + } + + this.testPlatformEventSource.TranslationLayerStopTestSessionStop(); + return false; + } + + /// + public async Task StopTestSessionAsync( + TestSessionInfo testSessionInfo, + ITestSessionEventsHandler eventsHandler) + { + // Make sure vstest.console knows how to handle start/stop test session messages. + // Bail out if it doesn't, otherwise we'll hang waiting for a reply from the console + // that will never come. + if (this.protocolVersion < MinimumProtocolVersionWithTestSessionSupport) + { + eventsHandler?.HandleStopTestSessionComplete(testSessionInfo, false); + return await Task.FromResult(false); + } + + if (EqtTrace.IsInfoEnabled) + { + EqtTrace.Info("VsTestConsoleRequestSender.StopTestSession: Stop test session."); + } + + // Due to various considertaions it is possible to end up with a null test session + // after doing the start test session call. However, we should filter out requests + // to stop such a session as soon as possible, at the request sender level. + // + // We do this here instead of on the wrapper level in order to benefit of the + // testplatform events being fired still. + if (testSessionInfo == null) + { + this.testPlatformEventSource.TranslationLayerStopTestSessionStop(); + return true; + } + + try + { + this.communicationManager.SendMessage( + MessageType.StopTestSession, + testSessionInfo, + this.protocolVersion); + + while (true) + { + var message = await this.TryReceiveMessageAsync().ConfigureAwait(false); + + switch (message.MessageType) + { + case MessageType.StopTestSessionCallback: + var payload = this.dataSerializer.DeserializePayload(message); + eventsHandler?.HandleStopTestSessionComplete(payload.TestSessionInfo, payload.IsStopped); + return payload.IsStopped; + + case MessageType.TestMessage: + var testMessagePayload = this.dataSerializer + .DeserializePayload(message); + eventsHandler?.HandleLogMessage( + testMessagePayload.MessageLevel, + testMessagePayload.Message); + break; + + default: + EqtTrace.Warning( + "VsTestConsoleRequestSender.StopTestSession: Unexpected message received: {0}", + message.MessageType); + break; + } + } + } + catch (Exception exception) + { + EqtTrace.Error( + "Aborting StopTestSession operation for id {0} due to error: {1}", + testSessionInfo?.Id, + exception); + eventsHandler?.HandleLogMessage( + TestMessageLevel.Error, + TranslationLayerResources.AbortedStopTestSession); + + eventsHandler?.HandleStopTestSessionComplete(testSessionInfo, false); + } + + this.testPlatformEventSource.TranslationLayerStopTestSessionStop(); + return false; + } + /// public void CancelTestRun() { @@ -340,6 +808,7 @@ public void CancelTestRun() { EqtTrace.Info("VsTestConsoleRequestSender.CancelTestRun: Canceling test run."); } + this.communicationManager.SendMessage(MessageType.CancelTestRun); } @@ -350,6 +819,7 @@ public void AbortTestRun() { EqtTrace.Info("VsTestConsoleRequestSender.AbortTestRun: Aborting test run."); } + this.communicationManager.SendMessage(MessageType.AbortTestRun); } @@ -360,6 +830,7 @@ public void CancelDiscovery() { EqtTrace.Info("VsTestConsoleRequestSender.CancelDiscovery: Canceling test discovery."); } + this.communicationManager.SendMessage(MessageType.CancelDiscovery); } @@ -375,23 +846,27 @@ public void Close() this.Dispose(); } - /// - /// Sends message for terminating the session - /// + /// public void EndSession() { this.communicationManager.SendMessage(MessageType.SessionEnd); } /// - public Task ProcessTestRunAttachmentsAsync(IEnumerable attachments, bool collectMetrics, ITestRunAttachmentsProcessingEventsHandler testSessionEventsHandler, CancellationToken cancellationToken) + public Task ProcessTestRunAttachmentsAsync( + IEnumerable attachments, + bool collectMetrics, + ITestRunAttachmentsProcessingEventsHandler testSessionEventsHandler, + CancellationToken cancellationToken) { - return this.SendMessageAndListenAndReportAttachmentsProcessingResultAsync(attachments, collectMetrics, testSessionEventsHandler, cancellationToken); + return this.SendMessageAndListenAndReportAttachmentsProcessingResultAsync( + attachments, + collectMetrics, + testSessionEventsHandler, + cancellationToken); } - /// - /// Closes the communication channel - /// + /// public void Dispose() { this.communicationManager?.StopServer(); @@ -403,29 +878,39 @@ private bool HandShakeWithVsTestConsole() { var success = false; var message = this.communicationManager.ReceiveMessage(); + if (message.MessageType == MessageType.SessionConnected) { - this.communicationManager.SendMessage(MessageType.VersionCheck, this.protocolVersion); + this.communicationManager.SendMessage( + MessageType.VersionCheck, + this.protocolVersion); + message = this.communicationManager.ReceiveMessage(); if (message.MessageType == MessageType.VersionCheck) { - this.protocolVersion = this.dataSerializer.DeserializePayload(message); + this.protocolVersion = this.dataSerializer + .DeserializePayload(message); success = true; } else if (message.MessageType == MessageType.ProtocolError) { // TODO : Payload for ProtocolError needs to finalized. - EqtTrace.Error("VsTestConsoleRequestSender.HandShakeWithVsTestConsole: Version Check failed. ProtolError was received from the runner"); + EqtTrace.Error( + "VsTestConsoleRequestSender.HandShakeWithVsTestConsole: Version Check failed. ProtolError was received from the runner"); } else { - EqtTrace.Error("VsTestConsoleRequestSender.HandShakeWithVsTestConsole: VersionCheck Message Expected but different message received: Received MessageType: {0}", message.MessageType); + EqtTrace.Error( + "VsTestConsoleRequestSender.HandShakeWithVsTestConsole: VersionCheck Message Expected but different message received: Received MessageType: {0}", + message.MessageType); } } else { - EqtTrace.Error("VsTestConsoleRequestSender.HandShakeWithVsTestConsole: SessionConnected Message Expected but different message received: Received MessageType: {0}", message.MessageType); + EqtTrace.Error( + "VsTestConsoleRequestSender.HandShakeWithVsTestConsole: SessionConnected Message Expected but different message received: Received MessageType: {0}", + message.MessageType); } return success; @@ -434,11 +919,17 @@ private bool HandShakeWithVsTestConsole() private async Task HandShakeWithVsTestConsoleAsync() { var success = false; - var message = await this.communicationManager.ReceiveMessageAsync(this.processExitCancellationTokenSource.Token); + var message = await this.communicationManager.ReceiveMessageAsync( + this.processExitCancellationTokenSource.Token); + if (message.MessageType == MessageType.SessionConnected) { - this.communicationManager.SendMessage(MessageType.VersionCheck, this.protocolVersion); - message = await this.communicationManager.ReceiveMessageAsync(this.processExitCancellationTokenSource.Token); + this.communicationManager.SendMessage( + MessageType.VersionCheck, + this.protocolVersion); + + message = await this.communicationManager.ReceiveMessageAsync( + this.processExitCancellationTokenSource.Token); if (message.MessageType == MessageType.VersionCheck) { @@ -448,33 +939,49 @@ private async Task HandShakeWithVsTestConsoleAsync() else if (message.MessageType == MessageType.ProtocolError) { // TODO : Payload for ProtocolError needs to finalized. - EqtTrace.Error("VsTestConsoleRequestSender.HandShakeWithVsTestConsoleAsync: Version Check failed. ProtolError was received from the runner"); + EqtTrace.Error( + "VsTestConsoleRequestSender.HandShakeWithVsTestConsoleAsync: Version Check failed. ProtolError was received from the runner"); } else { - EqtTrace.Error("VsTestConsoleRequestSender.HandShakeWithVsTestConsoleAsync: VersionCheck Message Expected but different message received: Received MessageType: {0}", message.MessageType); + EqtTrace.Error( + "VsTestConsoleRequestSender.HandShakeWithVsTestConsoleAsync: VersionCheck Message Expected but different message received: Received MessageType: {0}", + message.MessageType); } } else { - EqtTrace.Error("VsTestConsoleRequestSender.HandShakeWithVsTestConsoleAsync: SessionConnected Message Expected but different message received: Received MessageType: {0}", message.MessageType); + EqtTrace.Error( + "VsTestConsoleRequestSender.HandShakeWithVsTestConsoleAsync: SessionConnected Message Expected but different message received: Received MessageType: {0}", + message.MessageType); } return success; } - private void SendMessageAndListenAndReportTestCases(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestDiscoveryEventsHandler2 eventHandler) + private void SendMessageAndListenAndReportTestCases( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 eventHandler) { try { this.communicationManager.SendMessage( - MessageType.StartDiscovery, - new DiscoveryRequestPayload() { Sources = sources, RunSettings = runSettings, TestPlatformOptions = options }, - this.protocolVersion); + MessageType.StartDiscovery, + new DiscoveryRequestPayload() + { + Sources = sources, + RunSettings = runSettings, + TestPlatformOptions = options + }, + this.protocolVersion); var isDiscoveryComplete = false; - // Cycle through the messages that the vstest.console sends. - // Currently each of the operations are not separate tasks since they should not each take much time. + // Cycle through the messages that vstest.console sends. + // Currently each operation is not a separate task since it should not take that + // much time to complete. + // // This is just a notification. while (!isDiscoveryComplete) { @@ -482,7 +989,8 @@ private void SendMessageAndListenAndReportTestCases(IEnumerable sources, if (string.Equals(MessageType.TestCasesFound, message.MessageType)) { - var testCases = this.dataSerializer.DeserializePayload>(message); + var testCases = this.dataSerializer + .DeserializePayload>(message); eventHandler.HandleDiscoveredTests(testCases); } @@ -490,15 +998,19 @@ private void SendMessageAndListenAndReportTestCases(IEnumerable sources, { if (EqtTrace.IsInfoEnabled) { - EqtTrace.Info("VsTestConsoleRequestSender.SendMessageAndListenAndReportTestCases: Discovery complete."); + EqtTrace.Info( + "VsTestConsoleRequestSender.SendMessageAndListenAndReportTestCases: Discovery complete."); } var discoveryCompletePayload = - this.dataSerializer.DeserializePayload(message); + this.dataSerializer + .DeserializePayload(message); - var discoveryCompleteEventArgs = new DiscoveryCompleteEventArgs(discoveryCompletePayload.TotalTests, discoveryCompletePayload.IsAborted); + var discoveryCompleteEventArgs = new DiscoveryCompleteEventArgs( + discoveryCompletePayload.TotalTests, + discoveryCompletePayload.IsAborted); - // Adding Metrics From VsTestConsole + // Adding metrics from vstest.console. discoveryCompleteEventArgs.Metrics = discoveryCompletePayload.Metrics; eventHandler.HandleDiscoveryComplete( @@ -508,39 +1020,57 @@ private void SendMessageAndListenAndReportTestCases(IEnumerable sources, } else if (string.Equals(MessageType.TestMessage, message.MessageType)) { - var testMessagePayload = this.dataSerializer.DeserializePayload(message); - eventHandler.HandleLogMessage(testMessagePayload.MessageLevel, testMessagePayload.Message); + var testMessagePayload = this.dataSerializer + .DeserializePayload(message); + eventHandler.HandleLogMessage( + testMessagePayload.MessageLevel, + testMessagePayload.Message); } } } catch (Exception exception) { EqtTrace.Error("Aborting Test Discovery Operation: {0}", exception); - eventHandler.HandleLogMessage(TestMessageLevel.Error, TranslationLayerResources.AbortedTestsDiscovery); + eventHandler.HandleLogMessage( + TestMessageLevel.Error, + TranslationLayerResources.AbortedTestsDiscovery); var discoveryCompleteEventArgs = new DiscoveryCompleteEventArgs(-1, true); eventHandler.HandleDiscoveryComplete(discoveryCompleteEventArgs, null); - // Earlier we were closing the connection with vstest.console in case of exceptions - // Removing that code because vstest.console might be in a healthy state and letting the client - // know of the error, so that the TL can wait for the next instruction from the client itself. - // Also, connection termination might not kill the process which could result in files being locked by testhost. + // Earlier we were closing the connection with vstest.console in case of exceptions. + // Removing that code because vstest.console might be in a healthy state and letting + // the client know of the error, so that the TL can wait for the next instruction + // from the client itself. + // Also, connection termination might not kill the process which could result in + // files being locked by testhost. } this.testPlatformEventSource.TranslationLayerDiscoveryStop(); } - private async Task SendMessageAndListenAndReportTestCasesAsync(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestDiscoveryEventsHandler2 eventHandler) + private async Task SendMessageAndListenAndReportTestCasesAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 eventHandler) { try { this.communicationManager.SendMessage( - MessageType.StartDiscovery, - new DiscoveryRequestPayload() { Sources = sources, RunSettings = runSettings, TestPlatformOptions = options }, - this.protocolVersion); + MessageType.StartDiscovery, + new DiscoveryRequestPayload() + { + Sources = sources, + RunSettings = runSettings, + TestPlatformOptions = options + }, + this.protocolVersion); var isDiscoveryComplete = false; - // Cycle through the messages that the vstest.console sends. - // Currently each of the operations are not separate tasks since they should not each take much time. + // Cycle through the messages that vstest.console sends. + // Currently each operation is not a separate task since it should not take that + // much time to complete. + // // This is just a notification. while (!isDiscoveryComplete) { @@ -548,7 +1078,8 @@ private async Task SendMessageAndListenAndReportTestCasesAsync(IEnumerable>(message); + var testCases = this.dataSerializer + .DeserializePayload>(message); eventHandler.HandleDiscoveredTests(testCases); } @@ -556,13 +1087,16 @@ private async Task SendMessageAndListenAndReportTestCasesAsync(IEnumerable(message); - var discoveryCompleteEventArgs = new DiscoveryCompleteEventArgs(discoveryCompletePayload.TotalTests, discoveryCompletePayload.IsAborted); + var discoveryCompleteEventArgs = new DiscoveryCompleteEventArgs( + discoveryCompletePayload.TotalTests, + discoveryCompletePayload.IsAborted); // Adding Metrics from VsTestConsole discoveryCompleteEventArgs.Metrics = discoveryCompletePayload.Metrics; @@ -574,8 +1108,11 @@ private async Task SendMessageAndListenAndReportTestCasesAsync(IEnumerable(message); - eventHandler.HandleLogMessage(testMessagePayload.MessageLevel, testMessagePayload.Message); + var testMessagePayload = this.dataSerializer + .DeserializePayload(message); + eventHandler.HandleLogMessage( + testMessagePayload.MessageLevel, + testMessagePayload.Message); } } } @@ -583,36 +1120,48 @@ private async Task SendMessageAndListenAndReportTestCasesAsync(IEnumerable( + var testRunChangedArgs = this.dataSerializer + .DeserializePayload( message); eventHandler.HandleTestRunStatsChange(testRunChangedArgs); } @@ -620,11 +1169,12 @@ private void SendMessageAndListenAndReportTestResults(string messageType, object { if (EqtTrace.IsInfoEnabled) { - EqtTrace.Info("VsTestConsoleRequestSender.SendMessageAndListenAndReportTestResults: Execution complete."); + EqtTrace.Info( + "VsTestConsoleRequestSender.SendMessageAndListenAndReportTestResults: Execution complete."); } - var testRunCompletePayload = - this.dataSerializer.DeserializePayload(message); + var testRunCompletePayload = this.dataSerializer + .DeserializePayload(message); eventHandler.HandleTestRunComplete( testRunCompletePayload.TestRunCompleteArgs, @@ -635,63 +1185,79 @@ private void SendMessageAndListenAndReportTestResults(string messageType, object } else if (string.Equals(MessageType.TestMessage, message.MessageType)) { - var testMessagePayload = this.dataSerializer.DeserializePayload(message); - eventHandler.HandleLogMessage(testMessagePayload.MessageLevel, testMessagePayload.Message); + var testMessagePayload = this.dataSerializer + .DeserializePayload(message); + eventHandler.HandleLogMessage( + testMessagePayload.MessageLevel, + testMessagePayload.Message); } else if (string.Equals(MessageType.CustomTestHostLaunch, message.MessageType)) { - HandleCustomHostLaunch(customHostLauncher, message); + this.HandleCustomHostLaunch(customHostLauncher, message); } else if (string.Equals(MessageType.EditorAttachDebugger, message.MessageType)) { - AttachDebuggerToProcess(customHostLauncher, message); + this.AttachDebuggerToProcess(customHostLauncher, message); } } } catch (Exception exception) { EqtTrace.Error("Aborting Test Run Operation: {0}", exception); - eventHandler.HandleLogMessage(TestMessageLevel.Error, TranslationLayerResources.AbortedTestsRun); - var completeArgs = new TestRunCompleteEventArgs(null, false, true, exception, null, TimeSpan.Zero); + eventHandler.HandleLogMessage( + TestMessageLevel.Error, + TranslationLayerResources.AbortedTestsRun); + var completeArgs = new TestRunCompleteEventArgs( + null, false, true, exception, null, TimeSpan.Zero); eventHandler.HandleTestRunComplete(completeArgs, null, null, null); - // Earlier we were closing the connection with vstest.console in case of exceptions - // Removing that code because vstest.console might be in a healthy state and letting the client - // know of the error, so that the TL can wait for the next instruction from the client itself. - // Also, connection termination might not kill the process which could result in files being locked by testhost. + // Earlier we were closing the connection with vstest.console in case of exceptions. + // Removing that code because vstest.console might be in a healthy state and letting + // the client know of the error, so that the TL can wait for the next instruction + // from the client itself. + // Also, connection termination might not kill the process which could result in + // files being locked by testhost. } this.testPlatformEventSource.TranslationLayerExecutionStop(); } - private async Task SendMessageAndListenAndReportTestResultsAsync(string messageType, object payload, ITestRunEventsHandler eventHandler, ITestHostLauncher customHostLauncher) + private async Task SendMessageAndListenAndReportTestResultsAsync( + string messageType, + object payload, + ITestRunEventsHandler eventHandler, + ITestHostLauncher customHostLauncher) { try { this.communicationManager.SendMessage(messageType, payload, this.protocolVersion); var isTestRunComplete = false; - // Cycle through the messages that the testhost sends. - // Currently each of the operations are not separate tasks since they should not each take much time. This is just a notification. + // Cycle through the messages that vstest.console sends. + // Currently each operation is not a separate task since it should not take that + // much time to complete. + // + // This is just a notification. while (!isTestRunComplete) { var message = await this.TryReceiveMessageAsync(); if (string.Equals(MessageType.TestRunStatsChange, message.MessageType)) { - var testRunChangedArgs = this.dataSerializer.DeserializePayload( - message); + var testRunChangedArgs = this.dataSerializer + .DeserializePayload(message); eventHandler.HandleTestRunStatsChange(testRunChangedArgs); } else if (string.Equals(MessageType.ExecutionComplete, message.MessageType)) { if (EqtTrace.IsInfoEnabled) { - EqtTrace.Info("VsTestConsoleRequestSender.SendMessageAndListenAndReportTestResultsAsync: Execution complete."); + EqtTrace.Info( + "VsTestConsoleRequestSender.SendMessageAndListenAndReportTestResultsAsync: Execution complete."); } - var testRunCompletePayload = - this.dataSerializer.DeserializePayload(message); + var testRunCompletePayload = this.dataSerializer + .DeserializePayload(message); eventHandler.HandleTestRunComplete( testRunCompletePayload.TestRunCompleteArgs, @@ -702,36 +1268,48 @@ private async Task SendMessageAndListenAndReportTestResultsAsync(string messageT } else if (string.Equals(MessageType.TestMessage, message.MessageType)) { - var testMessagePayload = this.dataSerializer.DeserializePayload(message); - eventHandler.HandleLogMessage(testMessagePayload.MessageLevel, testMessagePayload.Message); + var testMessagePayload = this.dataSerializer + .DeserializePayload(message); + eventHandler.HandleLogMessage( + testMessagePayload.MessageLevel, + testMessagePayload.Message); } else if (string.Equals(MessageType.CustomTestHostLaunch, message.MessageType)) { - HandleCustomHostLaunch(customHostLauncher, message); + this.HandleCustomHostLaunch(customHostLauncher, message); } else if (string.Equals(MessageType.EditorAttachDebugger, message.MessageType)) { - AttachDebuggerToProcess(customHostLauncher, message); + this.AttachDebuggerToProcess(customHostLauncher, message); } } } catch (Exception exception) { EqtTrace.Error("Aborting Test Run Operation: {0}", exception); - eventHandler.HandleLogMessage(TestMessageLevel.Error, TranslationLayerResources.AbortedTestsRun); - var completeArgs = new TestRunCompleteEventArgs(null, false, true, exception, null, TimeSpan.Zero); + eventHandler.HandleLogMessage( + TestMessageLevel.Error, + TranslationLayerResources.AbortedTestsRun); + var completeArgs = new TestRunCompleteEventArgs( + null, false, true, exception, null, TimeSpan.Zero); eventHandler.HandleTestRunComplete(completeArgs, null, null, null); - // Earlier we were closing the connection with vstest.console in case of exceptions - // Removing that code because vstest.console might be in a healthy state and letting the client - // know of the error, so that the TL can wait for the next instruction from the client itself. - // Also, connection termination might not kill the process which could result in files being locked by testhost. + // Earlier we were closing the connection with vstest.console in case of exceptions. + // Removing that code because vstest.console might be in a healthy state and letting + // the client know of the error, so that the TL can wait for the next instruction + // from the client itself. + // Also, connection termination might not kill the process which could result in + // files being locked by testhost. } this.testPlatformEventSource.TranslationLayerExecutionStop(); } - private async Task SendMessageAndListenAndReportAttachmentsProcessingResultAsync(IEnumerable attachments, bool collectMetrics, ITestRunAttachmentsProcessingEventsHandler eventHandler, CancellationToken cancellationToken) + private async Task SendMessageAndListenAndReportAttachmentsProcessingResultAsync( + IEnumerable attachments, + bool collectMetrics, + ITestRunAttachmentsProcessingEventsHandler eventHandler, + CancellationToken cancellationToken) { try { @@ -741,43 +1319,62 @@ private async Task SendMessageAndListenAndReportAttachmentsProcessingResultAsync CollectMetrics = collectMetrics }; - this.communicationManager.SendMessage(MessageType.TestRunAttachmentsProcessingStart, payload); + this.communicationManager.SendMessage( + MessageType.TestRunAttachmentsProcessingStart, + payload); var isTestRunAttachmentsProcessingComplete = false; - using (cancellationToken.Register(() => this.communicationManager.SendMessage(MessageType.TestRunAttachmentsProcessingCancel))) + using (cancellationToken.Register(() => + this.communicationManager.SendMessage(MessageType.TestRunAttachmentsProcessingCancel))) { - // Cycle through the messages that the vstest.console sends. - // Currently each of the operations are not separate tasks since they should not each take much time. + // Cycle through the messages that vstest.console sends. + // Currently each operation is not a separate task since it should not take that + // much time to complete. + // // This is just a notification. while (!isTestRunAttachmentsProcessingComplete) { var message = await this.TryReceiveMessageAsync().ConfigureAwait(false); - if (string.Equals(MessageType.TestRunAttachmentsProcessingComplete, message.MessageType)) + if (string.Equals( + MessageType.TestRunAttachmentsProcessingComplete, + message.MessageType)) { if (EqtTrace.IsInfoEnabled) { - EqtTrace.Info("VsTestConsoleRequestSender.SendMessageAndListenAndReportAttachments: Process complete."); + EqtTrace.Info( + "VsTestConsoleRequestSender.SendMessageAndListenAndReportAttachments: Process complete."); } - var testRunAttachmentsProcessingCompletePayload = this.dataSerializer.DeserializePayload(message); + var testRunAttachmentsProcessingCompletePayload = this.dataSerializer + .DeserializePayload(message); - eventHandler.HandleTestRunAttachmentsProcessingComplete(testRunAttachmentsProcessingCompletePayload.AttachmentsProcessingCompleteEventArgs, testRunAttachmentsProcessingCompletePayload.Attachments); + eventHandler.HandleTestRunAttachmentsProcessingComplete( + testRunAttachmentsProcessingCompletePayload.AttachmentsProcessingCompleteEventArgs, + testRunAttachmentsProcessingCompletePayload.Attachments); isTestRunAttachmentsProcessingComplete = true; } - else if (string.Equals(MessageType.TestRunAttachmentsProcessingProgress, message.MessageType)) + else if (string.Equals( + MessageType.TestRunAttachmentsProcessingProgress, + message.MessageType)) { - var testRunAttachmentsProcessingProgressPayload = this.dataSerializer.DeserializePayload(message); - eventHandler.HandleTestRunAttachmentsProcessingProgress(testRunAttachmentsProcessingProgressPayload.AttachmentsProcessingProgressEventArgs); + var testRunAttachmentsProcessingProgressPayload = this.dataSerializer + .DeserializePayload(message); + eventHandler.HandleTestRunAttachmentsProcessingProgress( + testRunAttachmentsProcessingProgressPayload.AttachmentsProcessingProgressEventArgs); } else if (string.Equals(MessageType.TestMessage, message.MessageType)) { - var testMessagePayload = this.dataSerializer.DeserializePayload(message); - eventHandler.HandleLogMessage(testMessagePayload.MessageLevel, testMessagePayload.Message); + var testMessagePayload = this.dataSerializer + .DeserializePayload(message); + eventHandler.HandleLogMessage( + testMessagePayload.MessageLevel, + testMessagePayload.Message); } else { - EqtTrace.Warning($"VsTestConsoleRequestSender.SendMessageAndListenAndReportAttachments: Unexpected message received {message.MessageType}."); + EqtTrace.Warning( + $"VsTestConsoleRequestSender.SendMessageAndListenAndReportAttachments: Unexpected message received {message.MessageType}."); } } } @@ -785,13 +1382,19 @@ private async Task SendMessageAndListenAndReportAttachmentsProcessingResultAsync catch (Exception exception) { EqtTrace.Error("Aborting Test Session End Operation: {0}", exception); - eventHandler.HandleLogMessage(TestMessageLevel.Error, TranslationLayerResources.AbortedTestRunAttachmentsProcessing); - eventHandler.HandleTestRunAttachmentsProcessingComplete(new TestRunAttachmentsProcessingCompleteEventArgs(false, exception), null); - - // Earlier we were closing the connection with vstest.console in case of exceptions - // Removing that code because vstest.console might be in a healthy state and letting the client - // know of the error, so that the TL can wait for the next instruction from the client itself. - // Also, connection termination might not kill the process which could result in files being locked by testhost. + eventHandler.HandleLogMessage( + TestMessageLevel.Error, + TranslationLayerResources.AbortedTestRunAttachmentsProcessing); + eventHandler.HandleTestRunAttachmentsProcessingComplete( + new TestRunAttachmentsProcessingCompleteEventArgs(false, exception), + null); + + // Earlier we were closing the connection with vstest.console in case of exceptions. + // Removing that code because vstest.console might be in a healthy state and letting + // the client know of the error, so that the TL can wait for the next instruction + // from the client itself. + // Also, connection termination might not kill the process which could result in + // files being locked by testhost. } finally { @@ -802,13 +1405,15 @@ private async Task SendMessageAndListenAndReportAttachmentsProcessingResultAsync private Message TryReceiveMessage() { Message message = null; - var receiverMessageTask = this.communicationManager.ReceiveMessageAsync(this.processExitCancellationTokenSource.Token); + var receiverMessageTask = this.communicationManager.ReceiveMessageAsync( + this.processExitCancellationTokenSource.Token); receiverMessageTask.Wait(); message = receiverMessageTask.Result; if (message == null) { - throw new TransationLayerException(TranslationLayerResources.FailedToReceiveMessage); + throw new TransationLayerException( + TranslationLayerResources.FailedToReceiveMessage); } return message; @@ -816,11 +1421,13 @@ private Message TryReceiveMessage() private async Task TryReceiveMessageAsync() { - Message message = await this.communicationManager.ReceiveMessageAsync(this.processExitCancellationTokenSource.Token); + Message message = await this.communicationManager.ReceiveMessageAsync( + this.processExitCancellationTokenSource.Token); if (message == null) { - throw new TransationLayerException(TranslationLayerResources.FailedToReceiveMessage); + throw new TransationLayerException( + TranslationLayerResources.FailedToReceiveMessage); } return message; @@ -828,34 +1435,48 @@ private async Task TryReceiveMessageAsync() private void HandleCustomHostLaunch(ITestHostLauncher customHostLauncher, Message message) { - var ackPayload = new CustomHostLaunchAckPayload() { HostProcessId = -1, ErrorMessage = null }; + var ackPayload = new CustomHostLaunchAckPayload() + { + HostProcessId = -1, + ErrorMessage = null + }; try { - var testProcessStartInfo = this.dataSerializer.DeserializePayload(message); + var testProcessStartInfo = this.dataSerializer + .DeserializePayload(message); ackPayload.HostProcessId = customHostLauncher != null - ? customHostLauncher.LaunchTestHost(testProcessStartInfo) - : -1; + ? customHostLauncher.LaunchTestHost(testProcessStartInfo) + : -1; } catch (Exception ex) { EqtTrace.Error("Error while launching custom host: {0}", ex); - // Vstest.console will send the abort message properly while cleaning up all the flow, so do not abort here - // Let the ack go through and let vstest.console handle the error + // Vstest.console will send the abort message properly while cleaning up all the + // flow, so do not abort here. + // Let the ack go through and let vstest.console handle the error. ackPayload.ErrorMessage = ex.Message; } finally { - // Always unblock the Vstest.console thread which is indefinitely waiting on this ACK - this.communicationManager.SendMessage(MessageType.CustomTestHostLaunchCallback, ackPayload, this.protocolVersion); + // Always unblock the vstest.console thread which is indefinitely waiting on this + // ACK. + this.communicationManager.SendMessage( + MessageType.CustomTestHostLaunchCallback, + ackPayload, + this.protocolVersion); } } private void AttachDebuggerToProcess(ITestHostLauncher customHostLauncher, Message message) { - var ackPayload = new EditorAttachDebuggerAckPayload() { Attached = false, ErrorMessage = null }; + var ackPayload = new EditorAttachDebuggerAckPayload() + { + Attached = false, + ErrorMessage = null + }; try { @@ -867,7 +1488,9 @@ private void AttachDebuggerToProcess(ITestHostLauncher customHostLauncher, Messa } catch (Exception ex) { - EqtTrace.Error("VsTestConsoleRequestSender.AttachDebuggerToProcess: Error while attaching debugger to process: {0}", ex); + EqtTrace.Error( + "VsTestConsoleRequestSender.AttachDebuggerToProcess: Error while attaching debugger to process: {0}", + ex); // vstest.console will send the abort message properly while cleaning up all the // flow, so do not abort here. @@ -876,8 +1499,12 @@ private void AttachDebuggerToProcess(ITestHostLauncher customHostLauncher, Messa } finally { - // Always unblock the vstest.console thread which is indefintitely waiting on this ACK. - this.communicationManager.SendMessage(MessageType.EditorAttachDebuggerCallback, ackPayload, this.protocolVersion); + // Always unblock the vstest.console thread which is indefintitely waiting on this + // ACK. + this.communicationManager.SendMessage( + MessageType.EditorAttachDebuggerCallback, + ackPayload, + this.protocolVersion); } } } diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleWrapper.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleWrapper.cs index eb8780bdf6..78adc5bb0c 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleWrapper.cs +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleWrapper.cs @@ -9,6 +9,7 @@ namespace Microsoft.TestPlatform.VsTestConsole.TranslationLayer using System.Linq; using System.Threading; using System.Threading.Tasks; + using Microsoft.TestPlatform.VsTestConsole.TranslationLayer.Interfaces; using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers; using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Tracing; @@ -18,6 +19,8 @@ namespace Microsoft.TestPlatform.VsTestConsole.TranslationLayer using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Interfaces; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; + using Microsoft.VisualStudio.TestPlatform.VsTestConsole.TranslationLayer.Interfaces; + using CommunicationUtilitiesResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; using CoreUtilitiesConstants = Microsoft.VisualStudio.TestPlatform.CoreUtilities.Constants; @@ -56,33 +59,55 @@ public class VsTestConsoleWrapper : IVsTestConsoleWrapper /// /// Initializes a new instance of the class. /// + /// /// /// Path to the test runner vstest.console.exe. /// - public VsTestConsoleWrapper(string vstestConsolePath) : - this(vstestConsolePath, ConsoleParameters.Default) + public VsTestConsoleWrapper( + string vstestConsolePath) + : this( + vstestConsolePath, + ConsoleParameters.Default) { } /// /// Initializes a new instance of the class. /// + /// /// Path to the test runner vstest.console.exe. - /// The parameters to be passed onto the runner process - public VsTestConsoleWrapper(string vstestConsolePath, ConsoleParameters consoleParameters) : - this(new VsTestConsoleRequestSender(), new VsTestConsoleProcessManager(vstestConsolePath), consoleParameters, TestPlatformEventSource.Instance, new ProcessHelper()) + /// The parameters to be passed onto the runner process. + public VsTestConsoleWrapper( + string vstestConsolePath, + ConsoleParameters consoleParameters) + : this( + new VsTestConsoleRequestSender(), + new VsTestConsoleProcessManager(vstestConsolePath), + consoleParameters, + TestPlatformEventSource.Instance, + new ProcessHelper()) { } /// /// Initializes a new instance of the class. - /// Defined for testing /// + /// + /// Defined for testing purposes. + /// /// Path to the test runner vstest.console.exe. - /// Path to dotnet exe, needed for CI builds - /// The parameters to be passed onto the runner process - internal VsTestConsoleWrapper(string vstestConsolePath, string dotnetExePath, ConsoleParameters consoleParameters) : - this(new VsTestConsoleRequestSender(), new VsTestConsoleProcessManager(vstestConsolePath, dotnetExePath), consoleParameters, TestPlatformEventSource.Instance, new ProcessHelper()) + /// Path to dotnet exe, needed for CI builds. + /// The parameters to be passed onto the runner process. + internal VsTestConsoleWrapper( + string vstestConsolePath, + string dotnetExePath, + ConsoleParameters consoleParameters) + : this( + new VsTestConsoleRequestSender(), + new VsTestConsoleProcessManager(vstestConsolePath, dotnetExePath), + consoleParameters, + TestPlatformEventSource.Instance, + new ProcessHelper()) { } @@ -90,12 +115,18 @@ internal VsTestConsoleWrapper(string vstestConsolePath, string dotnetExePath, Co /// /// Initializes a new instance of the class. /// + /// /// Sender for test messages. /// Process manager. - /// The parameters to be passed onto the runner process - /// Performance event source - /// Helper for process related utilities - internal VsTestConsoleWrapper(ITranslationLayerRequestSender requestSender, IProcessManager processManager, ConsoleParameters consoleParameters, ITestPlatformEventSource testPlatformEventSource, IProcessHelper processHelper) + /// The parameters to be passed onto the runner process. + /// Performance event source. + /// Helper for process related utilities. + internal VsTestConsoleWrapper( + ITranslationLayerRequestSender requestSender, + IProcessManager processManager, + ConsoleParameters consoleParameters, + ITestPlatformEventSource testPlatformEventSource, + IProcessHelper processHelper) { this.requestSender = requestSender; this.vstestConsoleProcessManager = processManager; @@ -152,22 +183,49 @@ public void InitializeExtensions(IEnumerable pathToAdditionalExtensions) } /// - public void DiscoverTests(IEnumerable sources, string discoverySettings, ITestDiscoveryEventsHandler discoveryEventsHandler) + public void DiscoverTests( + IEnumerable sources, + string discoverySettings, + ITestDiscoveryEventsHandler discoveryEventsHandler) { - this.testPlatformEventSource.TranslationLayerDiscoveryStart(); - this.EnsureInitialized(); + this.DiscoverTests( + sources, + discoverySettings, + options: null, + discoveryEventsHandler: new DiscoveryEventsHandleConverter(discoveryEventsHandler)); + } - // Converts ITestDiscoveryEventsHandler to ITestDiscoveryEventsHandler2 - var discoveryCompleteEventsHandler2 = new DiscoveryEventsHandleConverter(discoveryEventsHandler); - this.requestSender.DiscoverTests(sources, discoverySettings, options: null, discoveryEventsHandler: discoveryCompleteEventsHandler2); + /// + public void DiscoverTests( + IEnumerable sources, + string discoverySettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 discoveryEventsHandler) + { + this.DiscoverTests( + sources, + discoverySettings, + options, + testSessionInfo: null, + discoveryEventsHandler); } /// - public void DiscoverTests(IEnumerable sources, string discoverySettings, TestPlatformOptions options, ITestDiscoveryEventsHandler2 discoveryEventsHandler) + public void DiscoverTests( + IEnumerable sources, + string discoverySettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestDiscoveryEventsHandler2 discoveryEventsHandler) { this.testPlatformEventSource.TranslationLayerDiscoveryStart(); this.EnsureInitialized(); - this.requestSender.DiscoverTests(sources, discoverySettings, options, discoveryEventsHandler); + // TODO (copoiena): Add session info as a parameter. + this.requestSender.DiscoverTests( + sources, + discoverySettings, + options, + discoveryEventsHandler); } /// @@ -177,75 +235,285 @@ public void CancelDiscovery() } /// - public void RunTests(IEnumerable sources, string runSettings, ITestRunEventsHandler testRunEventsHandler) + public void RunTests( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler) + { + this.RunTests( + sources, + runSettings, + options: null, + testRunEventsHandler: testRunEventsHandler); + } + + /// + public void RunTests( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler) { - this.RunTests(sources, runSettings, options: null, testRunEventsHandler: testRunEventsHandler); + this.RunTests( + sources, + runSettings, + options, + testSessionInfo: null, + testRunEventsHandler: testRunEventsHandler); } /// - public void RunTests(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler) + public void RunTests( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler) { var sourceList = sources.ToList(); - this.testPlatformEventSource.TranslationLayerExecutionStart(0, sourceList.Count, 0, runSettings ?? string.Empty); + this.testPlatformEventSource.TranslationLayerExecutionStart( + 0, + sourceList.Count, + 0, + runSettings ?? string.Empty); this.EnsureInitialized(); - this.requestSender.StartTestRun(sourceList, runSettings, options, testRunEventsHandler); + this.requestSender.StartTestRun( + sourceList, + runSettings, + options, + testSessionInfo, + testRunEventsHandler); } /// - public void RunTests(IEnumerable testCases, string runSettings, ITestRunEventsHandler testRunEventsHandler) + public void RunTests( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler) { - var testCaseList = testCases.ToList(); - this.testPlatformEventSource.TranslationLayerExecutionStart(0, 0, testCaseList.Count, runSettings ?? string.Empty); + this.RunTests( + testCases, + runSettings, + options: null, + testRunEventsHandler); + } - this.EnsureInitialized(); - this.requestSender.StartTestRun(testCaseList, runSettings, options: null, runEventsHandler: testRunEventsHandler); + /// + public void RunTests( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler) + { + this.RunTests( + testCases, + runSettings, + options, + testSessionInfo: null, + testRunEventsHandler); } /// - public void RunTests(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler) + public void RunTests( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler) { var testCaseList = testCases.ToList(); - this.testPlatformEventSource.TranslationLayerExecutionStart(0, 0, testCaseList.Count, runSettings ?? string.Empty); + this.testPlatformEventSource.TranslationLayerExecutionStart( + 0, + 0, + testCaseList.Count, + runSettings ?? string.Empty); this.EnsureInitialized(); - this.requestSender.StartTestRun(testCaseList, runSettings, options, testRunEventsHandler); + this.requestSender.StartTestRun( + testCaseList, + runSettings, + options, + testSessionInfo, + testRunEventsHandler); } /// - public void RunTestsWithCustomTestHost(IEnumerable sources, string runSettings, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher) + public void RunTestsWithCustomTestHost( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) { - this.RunTestsWithCustomTestHost(sources, runSettings, options: null, testRunEventsHandler: testRunEventsHandler, customTestHostLauncher: customTestHostLauncher); + this.RunTestsWithCustomTestHost( + sources, + runSettings, + options: null, + testRunEventsHandler: testRunEventsHandler, + customTestHostLauncher: customTestHostLauncher); } /// - public void RunTestsWithCustomTestHost(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher) + public void RunTestsWithCustomTestHost( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + this.RunTestsWithCustomTestHost( + sources, + runSettings, + options, + testSessionInfo: null, + testRunEventsHandler: testRunEventsHandler, + customTestHostLauncher: customTestHostLauncher); + } + + /// + public void RunTestsWithCustomTestHost( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) { var sourceList = sources.ToList(); - this.testPlatformEventSource.TranslationLayerExecutionStart(1, sourceList.Count, 0, runSettings ?? string.Empty); + this.testPlatformEventSource.TranslationLayerExecutionStart( + 1, + sourceList.Count, + 0, + runSettings ?? string.Empty); this.EnsureInitialized(); - this.requestSender.StartTestRunWithCustomHost(sourceList, runSettings, options, testRunEventsHandler, customTestHostLauncher); + this.requestSender.StartTestRunWithCustomHost( + sourceList, + runSettings, + options, + testSessionInfo, + testRunEventsHandler, + customTestHostLauncher); } /// - public void RunTestsWithCustomTestHost(IEnumerable testCases, string runSettings, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher) + public void RunTestsWithCustomTestHost( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + this.RunTestsWithCustomTestHost( + testCases, + runSettings, + options: null, + testRunEventsHandler, + customTestHostLauncher); + } + + /// + public void RunTestsWithCustomTestHost( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + this.RunTestsWithCustomTestHost( + testCases, + runSettings, + options, + testSessionInfo: null, + testRunEventsHandler, + customTestHostLauncher); + } + + /// + public void RunTestsWithCustomTestHost( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) { var testCaseList = testCases.ToList(); - this.testPlatformEventSource.TranslationLayerExecutionStart(1, 0, testCaseList.Count, runSettings ?? string.Empty); + this.testPlatformEventSource.TranslationLayerExecutionStart( + 1, + 0, + testCaseList.Count, + runSettings ?? string.Empty); this.EnsureInitialized(); - this.requestSender.StartTestRunWithCustomHost(testCaseList, runSettings, options: null, runEventsHandler: testRunEventsHandler, customTestHostLauncher: customTestHostLauncher); + this.requestSender.StartTestRunWithCustomHost( + testCaseList, + runSettings, + options, + testSessionInfo, + testRunEventsHandler, + customTestHostLauncher); } /// - public void RunTestsWithCustomTestHost(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher) + public ITestSession StartTestSession( + IList sources, + string runSettings, + ITestSessionEventsHandler eventsHandler) { - var testCaseList = testCases.ToList(); - this.testPlatformEventSource.TranslationLayerExecutionStart(1, 0, testCaseList.Count, runSettings ?? string.Empty); + return this.StartTestSession( + sources, + runSettings, + options: null, + eventsHandler); + } + + /// + public ITestSession StartTestSession( + IList sources, + string runSettings, + TestPlatformOptions options, + ITestSessionEventsHandler eventsHandler) + { + return this.StartTestSession( + sources, + runSettings, + options, + eventsHandler, + testHostLauncher: null); + } + + /// + public ITestSession StartTestSession( + IList sources, + string runSettings, + TestPlatformOptions options, + ITestSessionEventsHandler eventsHandler, + ITestHostLauncher testHostLauncher) + { + this.testPlatformEventSource.TranslationLayerStartTestSessionStart(); + + this.EnsureInitialized(); + return new TestSession( + this.requestSender.StartTestSession( + sources, + runSettings, + options, + eventsHandler, + testHostLauncher), + this); + } + + /// + public bool StopTestSession( + TestSessionInfo testSessionInfo, + ITestSessionEventsHandler eventsHandler) + { + this.testPlatformEventSource.TranslationLayerStopTestSessionStart(); this.EnsureInitialized(); - this.requestSender.StartTestRunWithCustomHost(testCaseList, runSettings, options, testRunEventsHandler, customTestHostLauncher); + return this.requestSender.StopTestSession( + testSessionInfo, + eventsHandler); } /// @@ -315,106 +583,352 @@ public async Task InitializeExtensionsAsync(IEnumerable pathToAdditional } /// - public async Task DiscoverTestsAsync(IEnumerable sources, string discoverySettings, ITestDiscoveryEventsHandler discoveryEventsHandler) + public async Task DiscoverTestsAsync( + IEnumerable sources, + string discoverySettings, + ITestDiscoveryEventsHandler discoveryEventsHandler) { - this.testPlatformEventSource.TranslationLayerDiscoveryStart(); - await this.EnsureInitializedAsync(); - - // Converts ITestDiscoveryEventsHandler to ITestDiscoveryEventsHandler2 - var discoveryCompleteEventsHandler2 = new DiscoveryEventsHandleConverter(discoveryEventsHandler); - await this.requestSender.DiscoverTestsAsync(sources, discoverySettings, options: null, discoveryEventsHandler: discoveryCompleteEventsHandler2); + await this.DiscoverTestsAsync( + sources, + discoverySettings, + options: null, + discoveryEventsHandler: new DiscoveryEventsHandleConverter(discoveryEventsHandler)); } /// - public async Task DiscoverTestsAsync(IEnumerable sources, string discoverySettings, TestPlatformOptions options, ITestDiscoveryEventsHandler2 discoveryEventsHandler) + public async Task DiscoverTestsAsync( + IEnumerable sources, + string discoverySettings, + TestPlatformOptions options, + ITestDiscoveryEventsHandler2 discoveryEventsHandler) + { + await this.DiscoverTestsAsync( + sources, + discoverySettings, + options, + testSessionInfo: null, + discoveryEventsHandler); + } + + /// + public async Task DiscoverTestsAsync( + IEnumerable sources, + string discoverySettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestDiscoveryEventsHandler2 discoveryEventsHandler) { this.testPlatformEventSource.TranslationLayerDiscoveryStart(); await this.EnsureInitializedAsync(); - await this.requestSender.DiscoverTestsAsync(sources, discoverySettings, options, discoveryEventsHandler); + await this.requestSender.DiscoverTestsAsync( + sources, + discoverySettings, + options, + // TODO(copoiena): Add session info as a parameter. + discoveryEventsHandler); } /// - public async Task RunTestsAsync(IEnumerable sources, string runSettings, ITestRunEventsHandler testRunEventsHandler) + public async Task RunTestsAsync( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler) { - await RunTestsAsync(sources, runSettings, null, testRunEventsHandler); + await this.RunTestsAsync( + sources, + runSettings, + options: null, + testRunEventsHandler); } /// - public async Task RunTestsAsync(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler) + public async Task RunTestsAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler) + { + await this.RunTestsAsync( + sources, + runSettings, + options, + testSessionInfo: null, + testRunEventsHandler); + } + + /// + public async Task RunTestsAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler) { var sourceList = sources.ToList(); - this.testPlatformEventSource.TranslationLayerExecutionStart(0, sourceList.Count, 0, runSettings ?? string.Empty); + this.testPlatformEventSource.TranslationLayerExecutionStart( + 0, + sourceList.Count, + 0, + runSettings ?? string.Empty); await this.EnsureInitializedAsync(); - await this.requestSender.StartTestRunAsync(sourceList, runSettings, options, testRunEventsHandler); + await this.requestSender.StartTestRunAsync( + sourceList, + runSettings, + options, + testSessionInfo, + testRunEventsHandler); } /// - public async Task RunTestsAsync(IEnumerable testCases, string runSettings, ITestRunEventsHandler testRunEventsHandler) + public async Task RunTestsAsync( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler) { - var testCaseList = testCases.ToList(); - this.testPlatformEventSource.TranslationLayerExecutionStart(0, 0, testCaseList.Count, runSettings ?? string.Empty); + await this.RunTestsAsync( + testCases, + runSettings, + options: null, + testRunEventsHandler); + } - await this.EnsureInitializedAsync(); - await this.requestSender.StartTestRunAsync(testCaseList, runSettings, options: null, runEventsHandler: testRunEventsHandler); + /// + public async Task RunTestsAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler) + { + await this.RunTestsAsync( + testCases, + runSettings, + options, + testSessionInfo: null, + testRunEventsHandler); } /// - public async Task RunTestsAsync(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler) + public async Task RunTestsAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler) { var testCaseList = testCases.ToList(); - this.testPlatformEventSource.TranslationLayerExecutionStart(0, 0, testCaseList.Count, runSettings ?? string.Empty); + this.testPlatformEventSource.TranslationLayerExecutionStart( + 0, + 0, + testCaseList.Count, + runSettings ?? string.Empty); await this.EnsureInitializedAsync(); - await this.requestSender.StartTestRunAsync(testCaseList, runSettings, options, testRunEventsHandler); + await this.requestSender.StartTestRunAsync( + testCaseList, + runSettings, + options, + testSessionInfo, + testRunEventsHandler); } /// - public async Task RunTestsWithCustomTestHostAsync(IEnumerable sources, string runSettings, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher) + public async Task RunTestsWithCustomTestHostAsync( + IEnumerable sources, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) { - await RunTestsWithCustomTestHostAsync(sources, runSettings, null, testRunEventsHandler, customTestHostLauncher); + await this.RunTestsWithCustomTestHostAsync( + sources, + runSettings, + options: null, + testRunEventsHandler, + customTestHostLauncher); + } + + /// + public async Task RunTestsWithCustomTestHostAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + await this.RunTestsWithCustomTestHostAsync( + sources, + runSettings, + options, + testSessionInfo: null, + testRunEventsHandler, + customTestHostLauncher); } /// - public async Task RunTestsWithCustomTestHostAsync(IEnumerable sources, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher) + public async Task RunTestsWithCustomTestHostAsync( + IEnumerable sources, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) { var sourceList = sources.ToList(); - this.testPlatformEventSource.TranslationLayerExecutionStart(1, sourceList.Count, 0, runSettings ?? string.Empty); + this.testPlatformEventSource.TranslationLayerExecutionStart( + 1, + sourceList.Count, + 0, + runSettings ?? string.Empty); await this.EnsureInitializedAsync(); - await this.requestSender.StartTestRunWithCustomHostAsync(sourceList, runSettings, options, testRunEventsHandler, customTestHostLauncher); + await this.requestSender.StartTestRunWithCustomHostAsync( + sourceList, + runSettings, + options, + testSessionInfo, + testRunEventsHandler, + customTestHostLauncher); } /// - public async Task RunTestsWithCustomTestHostAsync(IEnumerable testCases, string runSettings, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher) + public async Task RunTestsWithCustomTestHostAsync( + IEnumerable testCases, + string runSettings, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) { - var testCaseList = testCases.ToList(); - this.testPlatformEventSource.TranslationLayerExecutionStart(1, 0, testCaseList.Count, runSettings ?? string.Empty); + await this.RunTestsWithCustomTestHostAsync( + testCases, + runSettings, + options: null, + testRunEventsHandler, + customTestHostLauncher); + } - await this.EnsureInitializedAsync(); - await this.requestSender.StartTestRunWithCustomHostAsync(testCaseList, runSettings, options: null, runEventsHandler: testRunEventsHandler, customTestHostLauncher: customTestHostLauncher); + /// + public async Task RunTestsWithCustomTestHostAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) + { + await this.RunTestsWithCustomTestHostAsync( + testCases, + runSettings, + options, + testSessionInfo: null, + testRunEventsHandler, + customTestHostLauncher); } /// - public async Task RunTestsWithCustomTestHostAsync(IEnumerable testCases, string runSettings, TestPlatformOptions options, ITestRunEventsHandler testRunEventsHandler, ITestHostLauncher customTestHostLauncher) + public async Task RunTestsWithCustomTestHostAsync( + IEnumerable testCases, + string runSettings, + TestPlatformOptions options, + TestSessionInfo testSessionInfo, + ITestRunEventsHandler testRunEventsHandler, + ITestHostLauncher customTestHostLauncher) { var testCaseList = testCases.ToList(); - this.testPlatformEventSource.TranslationLayerExecutionStart(1, 0, testCaseList.Count, runSettings ?? string.Empty); + this.testPlatformEventSource.TranslationLayerExecutionStart( + 1, + 0, + testCaseList.Count, + runSettings ?? string.Empty); await this.EnsureInitializedAsync(); - await this.requestSender.StartTestRunWithCustomHostAsync(testCaseList, runSettings, options, testRunEventsHandler, customTestHostLauncher); + await this.requestSender.StartTestRunWithCustomHostAsync( + testCaseList, + runSettings, + options, + testSessionInfo, + testRunEventsHandler, + customTestHostLauncher); } /// - public async Task ProcessTestRunAttachmentsAsync(IEnumerable attachments, string processingSettings, bool isLastBatch, bool collectMetrics, ITestRunAttachmentsProcessingEventsHandler testSessionEventsHandler, CancellationToken cancellationToken) + public async Task StartTestSessionAsync( + IList sources, + string runSettings, + ITestSessionEventsHandler eventsHandler) { - this.testPlatformEventSource.TranslationLayerTestRunAttachmentsProcessingStart(); + return await this.StartTestSessionAsync( + sources, + runSettings, + options: null, + eventsHandler).ConfigureAwait(false); + } + + /// + public async Task StartTestSessionAsync( + IList sources, + string runSettings, + TestPlatformOptions options, + ITestSessionEventsHandler eventsHandler) + { + return await this.StartTestSessionAsync( + sources, + runSettings, + options: null, + eventsHandler, + testHostLauncher: null).ConfigureAwait(false); + } + + /// + public async Task StartTestSessionAsync( + IList sources, + string runSettings, + TestPlatformOptions options, + ITestSessionEventsHandler eventsHandler, + ITestHostLauncher testHostLauncher) + { + this.testPlatformEventSource.TranslationLayerStartTestSessionStart(); await this.EnsureInitializedAsync().ConfigureAwait(false); - await requestSender.ProcessTestRunAttachmentsAsync(attachments, collectMetrics, testSessionEventsHandler, cancellationToken).ConfigureAwait(false); + return new TestSession( + await this.requestSender.StartTestSessionAsync( + sources, + runSettings, + options, + eventsHandler, + testHostLauncher).ConfigureAwait(false), + this); } + /// + public async Task StopTestSessionAsync( + TestSessionInfo testSessionInfo, + ITestSessionEventsHandler eventsHandler) + { + this.testPlatformEventSource.TranslationLayerStopTestSessionStart(); + + await this.EnsureInitializedAsync().ConfigureAwait(false); + return await this.requestSender.StopTestSessionAsync( + testSessionInfo, + eventsHandler).ConfigureAwait(false); + } + + /// + public async Task ProcessTestRunAttachmentsAsync( + IEnumerable attachments, + string processingSettings, + bool isLastBatch, + bool collectMetrics, + ITestRunAttachmentsProcessingEventsHandler testSessionEventsHandler, + CancellationToken cancellationToken) + { + this.testPlatformEventSource.TranslationLayerTestRunAttachmentsProcessingStart(); + + await this.EnsureInitializedAsync().ConfigureAwait(false); + await requestSender.ProcessTestRunAttachmentsAsync( + attachments, + collectMetrics, + testSessionEventsHandler, + cancellationToken).ConfigureAwait(false); + } #endregion diff --git a/src/package/Icon.png b/src/package/Icon.png new file mode 100644 index 0000000000..a0f1fdbf4d Binary files /dev/null and b/src/package/Icon.png differ diff --git a/src/package/external/external.csproj b/src/package/external/external.csproj index bd0f0e5ceb..4627131052 100644 --- a/src/package/external/external.csproj +++ b/src/package/external/external.csproj @@ -26,7 +26,7 @@ - 3.4.3 + 5.8.1 All @@ -45,14 +45,22 @@ 2.0.2 All - - 1.1.0-beta1-62316-01 + + 1.1.0-beta2-21075-01 All $(TestPlatformExternalsVersion) All + + $(CodeCoverageExternalsVersion) + All + + + $(CodeCoverageExternalsVersion) + All + $(TestPlatformExternalsVersion) All diff --git a/src/package/licenses/LICENSE_NET.txt b/src/package/licenses/LICENSE_NET.txt new file mode 100644 index 0000000000..5b03e9dce1 --- /dev/null +++ b/src/package/licenses/LICENSE_NET.txt @@ -0,0 +1,65 @@ +MICROSOFT SOFTWARE LICENSE TERMS + +MICROSOFT .NET LIBRARY + +These license terms are an agreement between you and Microsoft Corporation (or based on where you live, one of its affiliates). They apply to the software named above. The terms also apply to any Microsoft services or updates for the software, except to the extent those have different terms. + +IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS BELOW. + +1. INSTALLATION AND USE RIGHTS. +You may install and use any number of copies of the software to develop and test your applications. + +2. THIRD PARTY COMPONENTS. The software may include third party components with separate legal notices or governed by other agreements, as may be described in the ThirdPartyNotices file(s) accompanying the software. +3. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS. +a. DISTRIBUTABLE CODE. The software is comprised of Distributable Code. “Distributable Code” is code that you are permitted to distribute in applications you develop if you comply with the terms below. +i. Right to Use and Distribute. +· You may copy and distribute the object code form of the software. + +· Third Party Distribution. You may permit distributors of your applications to copy and distribute the Distributable Code as part of those applications. + +ii. Distribution Requirements. For any Distributable Code you distribute, you must +· use the Distributable Code in your applications and not as a standalone distribution; + +· require distributors and external end users to agree to terms that protect it at least as much as this agreement; and + +· indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ fees, related to the distribution or use of your applications, except to the extent that any claim is based solely on the unmodified Distributable Code. + +iii. Distribution Restrictions. You may not +· use Microsoft’s trademarks in your applications’ names or in a way that suggests your applications come from or are endorsed by Microsoft; or + +· modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An “Excluded License” is one that requires, as a condition of use, modification or distribution of code, that (i) it be disclosed or distributed in source code form; or (ii) others have the right to modify it. + +4. DATA. +a. Data Collection. The software may collect information about you and your use of the software, and send that to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may opt-out of many of these scenarios, but not all, as described in the software documentation. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with Microsoft’s privacy statement. Our privacy statement is located at https://go.microsoft.com/fwlink/?LinkID=824704. You can learn more about data collection and its use from the software documentation and our privacy statement. Your use of the software operates as your consent to these practices. +b. Processing of Personal Data. To the extent Microsoft is a processor or subprocessor of personal data in connection with the software, Microsoft makes the commitments in the European Union General Data Protection Regulation Terms of the Online Services Terms to all customers effective May 25, 2018, at https://docs.microsoft.com/en-us/legal/gdpr. +5. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not +· work around any technical limitations in the software; + +· reverse engineer, decompile or disassemble the software, or otherwise attempt to derive the source code for the software, except and to the extent required by third party licensing terms governing use of certain open source components that may be included in the software; + +· remove, minimize, block or modify any notices of Microsoft or its suppliers in the software; + +· use the software in any way that is against the law; or + +· share, publish, rent or lease the software, provide the software as a stand-alone offering for others to use, or transfer the software or this agreement to any third party. + +6. EXPORT RESTRICTIONS. You must comply with all domestic and international export laws and regulations that apply to the software, which include restrictions on destinations, end users, and end use. For further information on export restrictions, visit www.microsoft.com/exporting. +7. SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it. +8. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services. +9. APPLICABLE LAW. If you acquired the software in the United States, Washington law applies to interpretation of and claims for breach of this agreement, and the laws of the state where you live apply to all other claims. If you acquired the software in any other country, its laws apply. +10. CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes certain legal rights. You may have other rights, including consumer rights, under the laws of your state or country. Separate and apart from your relationship with Microsoft, you may also have rights with respect to the party from which you acquired the software. This agreement does not change those other rights if the laws of your state or country do not permit it to do so. For example, if you acquired the software in one of the below regions, or mandatory country law applies, then the following provisions apply to you: +a) Australia. You have statutory guarantees under the Australian Consumer Law and nothing in this agreement is intended to affect those rights. +b) Canada. If you acquired this software in Canada, you may stop receiving updates by turning off the automatic update feature, disconnecting your device from the Internet (if and when you re-connect to the Internet, however, the software will resume checking for and installing updates), or uninstalling the software. The product documentation, if any, may also specify how to turn off updates for your specific device or software. +c) Germany and Austria. +(i) Warranty. The software will perform substantially as described in any Microsoft materials that accompany it. However, Microsoft gives no contractual guarantee in relation to the software. + +(ii) Limitation of Liability. In case of intentional conduct, gross negligence, claims based on the Product Liability Act, as well as in case of death or personal or physical injury, Microsoft is liable according to the statutory law. + +Subject to the foregoing clause (ii), Microsoft will only be liable for slight negligence if Microsoft is in breach of such material contractual obligations, the fulfillment of which facilitate the due performance of this agreement, the breach of which would endanger the purpose of this agreement and the compliance with which a party may constantly trust in (so-called "cardinal obligations"). In other cases of slight negligence, Microsoft will not be liable for slight negligence +11. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS-IS.” YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +12. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES. +This limitation applies to (a) anything related to the software, services, content (including code) on third party Internet sites, or third party applications; and (b) claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. + +It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your state or country may not allow the exclusion or limitation of incidental, consequential or other damages. + + \ No newline at end of file diff --git a/src/package/licenses/LICENSE_VS.txt b/src/package/licenses/LICENSE_VS.txt new file mode 100644 index 0000000000..1db0151059 --- /dev/null +++ b/src/package/licenses/LICENSE_VS.txt @@ -0,0 +1,59 @@ +MICROSOFT SOFTWARE LICENSE TERMS + +MICROSOFT VISUAL STUDIO TEST PLATFORM + +These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. They apply to the software named above. The terms also apply to any Microsoft services or updates for the software, except to the extent those have different terms. + +IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS BELOW. + +1. INSTALLATION AND USE RIGHTS. + +You may install and use any number of copies of the software. + +2. TERMS FOR SPECIFIC COMPONENTS. + +a. Third Party Components. The software may include third party components with separate legal notices or governed by other agreements, as may be described in the ThirdPartyNotices file(s) accompanying the software. Even if such components are governed by other agreements, the disclaimers and the limitations on and exclusions of damages below also apply. + +3. DATA. The software may collect information about you and your use of the software, and send that to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may opt-out of many of these scenarios, but not all, as described in the product documentation. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications and you should provide a copy of Microsoft’s privacy statement to your users. The Microsoft privacy statement is located here https://go.microsoft.com/fwlink/?LinkId=521839. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. + +4. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not + +· work around any technical limitations in the software; + +· reverse engineer, decompile or disassemble the software, or otherwise attempt to derive the source code for the software except, and only to the extent required by third party licensing terms governing the use of certain open source components that may be included in the software; + +· remove, minimize, block or modify any notices of Microsoft or its suppliers in the software; + +· use the software in any way that is against the law; or + +· share, publish, rent or lease the software, or provide the software as a stand-alone hosted as solution for others to use, or transfer the software or this agreement to any third party. + +5. EXPORT RESTRICTIONS. You must comply with all domestic and international export laws and regulations that apply to the software, which include restrictions on destinations, end users, and end use. For further information on export restrictions, visit www.microsoft.com/exporting. + +6. SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it. + +7. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services. + +8. APPLICABLE LAW. If you acquired the software in the United States, Washington law applies to interpretation of and claims for breach of this agreement, and the laws of the state where you live apply to all other claims. If you acquired the software in any other country, its laws apply. + +9. CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes certain legal rights. You may have other rights, including consumer rights, under the laws of your state or country. Separate and apart from your relationship with Microsoft, you may also have rights with respect to the party from which you acquired the software. This agreement does not change those other rights if the laws of your state or country do not permit it to do so. For example, if you acquired the software in one of the below regions, or mandatory country law applies, then the following provisions apply to you: + +a. Australia. You have statutory guarantees under the Australian Consumer Law and nothing in this agreement is intended to affect those rights. + +b. Canada. If you acquired this software in Canada, you may stop receiving updates by turning off the automatic update feature, disconnecting your device from the Internet (if and when you re-connect to the Internet, however, the software will resume checking for and installing updates), or uninstalling the software. The product documentation, if any, may also specify how to turn off updates for your specific device or software. + +c. Germany and Austria. + +(i) Warranty. The properly licensed software will perform substantially as described in any Microsoft materials that accompany the software. However, Microsoft gives no contractual guarantee in relation to the licensed software. + +(ii) Limitation of Liability. In case of intentional conduct, gross negligence, claims based on the Product Liability Act, as well as, in case of death or personal or physical injury, Microsoft is liable according to the statutory law. + +Subject to the foregoing clause (ii), Microsoft will only be liable for slight negligence if Microsoft is in breach of such material contractual obligations, the fulfillment of which facilitate the due performance of this agreement, the breach of which would endanger the purpose of this agreement and the compliance with which a party may constantly trust in (so-called "cardinal obligations"). In other cases of slight negligence, Microsoft will not be liable for slight negligence. + +10. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS-IS.” YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + +11. LIMITATION ON AND EXCLUSION OF DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES. + +This limitation applies to (a) anything related to the software, services, content (including code) on third party Internet sites, or third party applications; and (b) claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. + +It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages. \ No newline at end of file diff --git a/src/package/nuspec/Microsoft.CodeCoverage.nuspec b/src/package/nuspec/Microsoft.CodeCoverage.nuspec index 7028c2f603..2bd731e6e1 100644 --- a/src/package/nuspec/Microsoft.CodeCoverage.nuspec +++ b/src/package/nuspec/Microsoft.CodeCoverage.nuspec @@ -1,5 +1,5 @@ - + Microsoft.CodeCoverage $Version$ @@ -8,18 +8,31 @@ Microsoft true Microsoft.CodeCoverage package brings infra for collecting code coverage from vstest.console.exe and "dotnet test". - http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm + LICENSE_NET.txt http://go.microsoft.com/fwlink/?LinkID=288859 + Icon.png https://github.com/microsoft/vstest/ © Microsoft Corporation. All rights reserved. vstest visual-studio unittest testplatform mstest microsoft test testing codecoverage code-coverage + + + + + + - + + + + @@ -44,13 +57,13 @@ - - + + - + @@ -65,5 +78,19 @@ + + + + + + + + + + + + + + diff --git a/src/package/nuspec/Microsoft.NET.Test.Sdk.nuspec b/src/package/nuspec/Microsoft.NET.Test.Sdk.nuspec index ba59062cb5..7727e08372 100644 --- a/src/package/nuspec/Microsoft.NET.Test.Sdk.nuspec +++ b/src/package/nuspec/Microsoft.NET.Test.Sdk.nuspec @@ -1,5 +1,5 @@ - + Microsoft.NET.Test.Sdk $Version$ @@ -7,12 +7,17 @@ Microsoft Microsoft true - http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm + LICENSE_NET.txt http://go.microsoft.com/fwlink/?LinkID=288859 + Icon.png The MSbuild targets and properties for building .NET test projects. © Microsoft Corporation. All rights reserved. https://github.com/microsoft/vstest/ vstest visual-studio unittest testplatform mstest microsoft test testing + @@ -30,6 +35,7 @@ + @@ -37,15 +43,24 @@ + + + + + + + + + diff --git a/src/package/nuspec/Microsoft.TestPlatform.AdapterUtilities.nuspec b/src/package/nuspec/Microsoft.TestPlatform.AdapterUtilities.nuspec new file mode 100644 index 0000000000..84b41b837e --- /dev/null +++ b/src/package/nuspec/Microsoft.TestPlatform.AdapterUtilities.nuspec @@ -0,0 +1,51 @@ + + + + Microsoft.TestPlatform.AdapterUtilities + 15.0.0 + Microsoft.TestPlatform.AdapterUtilities + Microsoft + Microsoft + true + + Includes helpers for the Test Platform's modern functionality such as standardized fully qualified names and hierarchical test case names. + + LICENSE_NET.txt + http://go.microsoft.com/fwlink/?LinkID=288859 + Icon.png + https://github.com/microsoft/vstest/ + © Microsoft Corporation. All rights reserved. + vstest visual-studio unittest testplatform mstest microsoft test testing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/package/nuspec/Microsoft.TestPlatform.Portable.nuspec b/src/package/nuspec/Microsoft.TestPlatform.Portable.nuspec index 579a948c62..8c8b69365a 100644 --- a/src/package/nuspec/Microsoft.TestPlatform.Portable.nuspec +++ b/src/package/nuspec/Microsoft.TestPlatform.Portable.nuspec @@ -1,5 +1,5 @@  - + Microsoft.TestPlatform.Portable 15.0.0 @@ -9,13 +9,20 @@ true This package contains a subset of binaries for the Visual Studio Test Platform (vstest). vstest provides a modern, cross platform testing engine that also powers the testing on .NET Core. Supports the following popular test frameworks - MSTest v2, xUnit and Nunit with support for extensibility. Visit https://github.com/microsoft/vstest to know more about vstest platform. For running tests based on the MSTest v1 framework, .orderedtest, .webtest and .generictest please use Microsoft.TestPlatform package. This package contains a subset of binaries for the Visual Studio Test Platform (vstest). vstest provides a modern, cross platform testing engine that also powers the testing on .NET Core. Supports the following popular test frameworks - MSTest v2, xUnit and Nunit with support for extensibility. - https://www.visualstudio.com/microsoft-visual-studio-test-platform + LICENSE_VS.txt http://go.microsoft.com/fwlink/?LinkID=288859 + Icon.png https://github.com/microsoft/vstest/ © Microsoft Corporation. All rights reserved. vstest visual-studio unittest testplatform mstest microsoft test testing + + + diff --git a/src/package/nuspec/Microsoft.TestPlatform.nuspec b/src/package/nuspec/Microsoft.TestPlatform.nuspec index 504f900f82..40d8431f98 100644 --- a/src/package/nuspec/Microsoft.TestPlatform.nuspec +++ b/src/package/nuspec/Microsoft.TestPlatform.nuspec @@ -1,5 +1,5 @@  - + Microsoft.TestPlatform 15.0.0 @@ -9,13 +9,20 @@ true This package contains the full set of binaries for the Visual Studio Test Platform (vstest). It provides a modern, cross platform testing engine that powers the testing on .NET Core as well. It integrates with popular test frameworks like MSTest(v1 and v2), xUnit and Nunit with support for extensibility. The package supports running Coded UI tests. While running Coded UI tests, you must ensure that the package version matches the major version of Visual Studio used to build the test binaries. For example, if your Coded UI test project was built using Visual Studio 2019 (version 16.x), you must use test platform version 16.x. Coded UI test is deprecated (https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes-preview#test-tools) and Visual Studio 2019 (Test Platform version 16.x) will be the last version with Coded UI test functionality. Visit https://github.com/microsoft/vstest to know more about vstest platform. This package contains the full set of binaries for the Visual Studio Test Platform (vstest). It provides a modern, cross platform testing engine that powers the testing on .NET Core as well. It integrates with popular test frameworks like MSTest(v1 and v2), xUnit and Nunit with support for extensibility. - https://www.visualstudio.com/microsoft-visual-studio-test-platform + LICENSE_VS.txt http://go.microsoft.com/fwlink/?LinkID=288859 + Icon.png https://github.com/microsoft/vstest/ © Microsoft Corporation. All rights reserved. vstest visual-studio unittest testplatform mstest microsoft test testing + + + @@ -109,7 +116,6 @@ - @@ -258,7 +264,7 @@ - + @@ -266,7 +272,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -512,7 +549,7 @@ - - + + diff --git a/src/package/nuspec/TestPlatform.Build.nuspec b/src/package/nuspec/TestPlatform.Build.nuspec index 92c0d9d73b..3808b2965f 100644 --- a/src/package/nuspec/TestPlatform.Build.nuspec +++ b/src/package/nuspec/TestPlatform.Build.nuspec @@ -1,5 +1,5 @@  - + Microsoft.TestPlatform.Build 15.0.0 @@ -8,13 +8,24 @@ Microsoft true Build tasks and targets for running tests with Test Platform - http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm + LICENSE_NET.txt http://go.microsoft.com/fwlink/?LinkID=288859 + Icon.png https://github.com/microsoft/vstest/ © Microsoft Corporation. All rights reserved. vstest visual-studio unittest testplatform mstest microsoft test testing + + + + + + + diff --git a/src/package/nuspec/TestPlatform.CLI.nuspec b/src/package/nuspec/TestPlatform.CLI.nuspec index ce0da80674..0e72bf5885 100644 --- a/src/package/nuspec/TestPlatform.CLI.nuspec +++ b/src/package/nuspec/TestPlatform.CLI.nuspec @@ -1,5 +1,5 @@  - + Microsoft.TestPlatform.CLI 15.0.0 @@ -8,16 +8,24 @@ Microsoft true The cross platform Microsoft Test Platform. - http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm + LICENSE_NET.txt http://go.microsoft.com/fwlink/?LinkID=288859 + Icon.png https://github.com/microsoft/vstest/ © Microsoft Corporation. All rights reserved. vstest visual-studio unittest testplatform mstest microsoft test testing + + + + diff --git a/src/package/nuspec/TestPlatform.Extensions.TrxLogger.nuspec b/src/package/nuspec/TestPlatform.Extensions.TrxLogger.nuspec index 4ff5a3cbbf..802ce1eba2 100644 --- a/src/package/nuspec/TestPlatform.Extensions.TrxLogger.nuspec +++ b/src/package/nuspec/TestPlatform.Extensions.TrxLogger.nuspec @@ -1,5 +1,5 @@ - + Microsoft.TestPlatform.Extensions.TrxLogger 15.0.0 @@ -8,11 +8,17 @@ Microsoft true C# SDK for the test platform protocol. This SDK can be used in IDE or Editors to use test platform for discovery and execution of tests. - http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm + LICENSE_NET.txt http://go.microsoft.com/fwlink/?LinkID=288859 + Icon.png https://github.com/microsoft/vstest/ © Microsoft Corporation. All rights reserved. vstest visual-studio unittest testplatform mstest microsoft test testing + + @@ -33,6 +39,8 @@ + + diff --git a/src/package/nuspec/TestPlatform.ObjectModel.nuspec b/src/package/nuspec/TestPlatform.ObjectModel.nuspec index f1b881146b..80d194f2e8 100644 --- a/src/package/nuspec/TestPlatform.ObjectModel.nuspec +++ b/src/package/nuspec/TestPlatform.ObjectModel.nuspec @@ -1,5 +1,5 @@  - + Microsoft.TestPlatform.ObjectModel 15.0.0 @@ -8,11 +8,17 @@ Microsoft true The Microsoft Test Platform Object Model. - http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm + LICENSE_NET.txt http://go.microsoft.com/fwlink/?LinkID=288859 + Icon.png https://github.com/microsoft/vstest/ © Microsoft Corporation. All rights reserved. vstest visual-studio unittest testplatform mstest microsoft test testing + + @@ -76,6 +82,8 @@ + + diff --git a/src/package/nuspec/TestPlatform.TestHost.nuspec b/src/package/nuspec/TestPlatform.TestHost.nuspec index a3896fc778..86a4edea10 100644 --- a/src/package/nuspec/TestPlatform.TestHost.nuspec +++ b/src/package/nuspec/TestPlatform.TestHost.nuspec @@ -1,5 +1,5 @@  - + Microsoft.TestPlatform.TestHost $Version$ @@ -8,11 +8,17 @@ Microsoft true Testplatform host executes the test using specified adapter. - http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm + LICENSE_NET.txt http://go.microsoft.com/fwlink/?LinkID=288859 + Icon.png https://github.com/microsoft/vstest/ © Microsoft Corporation. All rights reserved. vstest visual-studio unittest testplatform mstest microsoft test testing + + @@ -25,7 +31,6 @@ - @@ -38,12 +43,18 @@ + + + + + + diff --git a/src/package/nuspec/TestPlatform.TranslationLayer.nuspec b/src/package/nuspec/TestPlatform.TranslationLayer.nuspec index ad12872f4f..420efde67c 100644 --- a/src/package/nuspec/TestPlatform.TranslationLayer.nuspec +++ b/src/package/nuspec/TestPlatform.TranslationLayer.nuspec @@ -1,5 +1,5 @@  - + Microsoft.TestPlatform.TranslationLayer 15.0.0 @@ -8,11 +8,17 @@ Microsoft true C# SDK for the test platform protocol. This SDK can be used in IDE or Editors to use test platform for discovery and execution of tests. - http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm + LICENSE_NET.txt http://go.microsoft.com/fwlink/?LinkID=288859 + Icon.png https://github.com/microsoft/vstest/ © Microsoft Corporation. All rights reserved. vstest visual-studio unittest testplatform mstest microsoft test testing + + @@ -30,6 +36,8 @@ + + diff --git a/src/package/sign/sign.proj b/src/package/sign/sign.proj index 014d06c450..ceb7fdc058 100644 --- a/src/package/sign/sign.proj +++ b/src/package/sign/sign.proj @@ -32,6 +32,9 @@ $(ArtifactsBaseDirectory)netstandard2.0\ + + + $(ArtifactsBaseDirectory)uap10.0\ $(ArtifactsBaseDirectory)obj\$(BuildConfiguration)\$(TargetFramework)\$(TargetRuntime)\ @@ -130,12 +133,10 @@ - - + - @@ -275,16 +276,17 @@ - - - - - + + + + + + - - + + @@ -333,6 +335,7 @@ + @@ -341,6 +344,9 @@ + + + @@ -354,6 +360,7 @@ + @@ -368,20 +375,6 @@ - - - - - - - - - - - - - - @@ -477,6 +470,11 @@ Microsoft400 StrongName + + + Microsoft400 + StrongName + Microsoft400 @@ -542,6 +540,12 @@ IntermediatesDirectory="$(IntermediatesDirectory)" Type="$(SignType)" /> + + + ..\..\ false + true @@ -18,6 +19,7 @@ win7-x86 false + $(AssemblyName.Replace('.x86', '')).$(TargetFramework).x86 diff --git a/src/testhost/testhost.csproj b/src/testhost/testhost.csproj index a55ef48bb7..7c1e88f4a2 100644 --- a/src/testhost/testhost.csproj +++ b/src/testhost/testhost.csproj @@ -3,6 +3,7 @@ ..\..\ false + true @@ -15,6 +16,7 @@ win7-x64 false + $(AssemblyName).$(TargetFramework) diff --git a/src/vstest.console/CommandLine/CommandLineOptions.cs b/src/vstest.console/CommandLine/CommandLineOptions.cs index 64d212043b..4edd13929b 100644 --- a/src/vstest.console/CommandLine/CommandLineOptions.cs +++ b/src/vstest.console/CommandLine/CommandLineOptions.cs @@ -295,14 +295,10 @@ public void AddSource(string source) // Get matching files from file pattern parser matchingFiles = FilePatternParser.GetMatchingFiles(source); } - catch(TestSourceException ex) + catch(TestSourceException ex) when (source.StartsWith("-") || source.StartsWith("/")) { - if(source.StartsWith("-") || source.StartsWith("/")) - { - throw new TestSourceException( - string.Format(CultureInfo.CurrentUICulture, CommandLineResources.InvalidArgument, source)); - } - throw ex; + throw new TestSourceException( + string.Format(CultureInfo.CurrentUICulture, CommandLineResources.InvalidArgument, source), ex); } // Add the matching files to source list this.sources = this.sources.Union(matchingFiles).ToList(); diff --git a/src/vstest.console/CommandLine/InferHelper.cs b/src/vstest.console/CommandLine/InferHelper.cs index 3b3fc46edf..1c74b3e387 100644 --- a/src/vstest.console/CommandLine/InferHelper.cs +++ b/src/vstest.console/CommandLine/InferHelper.cs @@ -22,7 +22,7 @@ internal InferHelper(IAssemblyMetadataProvider assemblyMetadataProvider) /// /// Determines Architecture from sources. /// - public Architecture AutoDetectArchitecture(List sources, IDictionary sourcePlatforms, Architecture defaultArchitecture) + public Architecture AutoDetectArchitecture(IList sources, IDictionary sourcePlatforms, Architecture defaultArchitecture) { var architecture = defaultArchitecture; try @@ -86,7 +86,7 @@ public Architecture AutoDetectArchitecture(List sources, IDictionary /// Determines Framework from sources. ///
- public Framework AutoDetectFramework(List sources, IDictionary sourceFrameworkVersions) + public Framework AutoDetectFramework(IList sources, IDictionary sourceFrameworkVersions) { Framework framework = Framework.DefaultFramework; try diff --git a/src/vstest.console/CommandLine/TestSourceException.cs b/src/vstest.console/CommandLine/TestSourceException.cs index 0cb6903b17..05f5e734f2 100644 --- a/src/vstest.console/CommandLine/TestSourceException.cs +++ b/src/vstest.console/CommandLine/TestSourceException.cs @@ -25,7 +25,17 @@ public TestSourceException() ///
/// Message for the exception. public TestSourceException(string message) - : base(message) + : this(message, innerException: null) + { + } + + /// + /// Initializes with the message and innerException. + /// + /// Message for the exception. + /// The exception that is the cause of the current exception, or a null reference. + public TestSourceException(string message, Exception innerException) + : base(message, innerException) { } diff --git a/src/vstest.console/TestPlatformHelpers/TestRequestManager.cs b/src/vstest.console/TestPlatformHelpers/TestRequestManager.cs index 5832a59534..5ce2fdacb5 100644 --- a/src/vstest.console/TestPlatformHelpers/TestRequestManager.cs +++ b/src/vstest.console/TestPlatformHelpers/TestRequestManager.cs @@ -3,6 +3,16 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.TestPlatformHelpers { + using System; + using System.Xml; + using System.IO; + using System.Linq; + using System.Xml.XPath; + using System.Threading; + using System.Reflection; + using System.Threading.Tasks; + using System.Collections.Generic; + using Microsoft.VisualStudio.TestPlatform.Client; using Microsoft.VisualStudio.TestPlatform.Client.RequestHelper; using Microsoft.VisualStudio.TestPlatform.CommandLine.Internal; @@ -25,55 +35,53 @@ namespace Microsoft.VisualStudio.TestPlatform.CommandLine.TestPlatformHelpers using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions; using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces; using Microsoft.VisualStudio.TestPlatform.Utilities; - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Reflection; - using System.Threading; - using System.Threading.Tasks; - using System.Xml; - using System.Xml.XPath; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client.Payloads; /// - /// Defines the TestRequestManger which can fire off discovery and test run requests + /// Defines the test request manger which can fire off discovery and test run requests. /// internal class TestRequestManager : ITestRequestManager { - private readonly ITestPlatform testPlatform; - private CommandLineOptions commandLineOptions; - private readonly ITestPlatformEventSource testPlatformEventSource; - private TestRunResultAggregator testRunResultAggregator; private static ITestRequestManager testRequestManagerInstance; - private InferHelper inferHelper; + private const int runRequestTimeout = 5000; - private bool telemetryOptedIn; - private readonly object syncObject = new object(); + + private readonly ITestPlatform testPlatform; + private readonly ITestPlatformEventSource testPlatformEventSource; private readonly Task metricsPublisher; + private readonly object syncObject = new object(); + private bool isDisposed; + private bool telemetryOptedIn; + private CommandLineOptions commandLineOptions; + private TestRunResultAggregator testRunResultAggregator; + private InferHelper inferHelper; private IProcessHelper processHelper; private ITestRunAttachmentsProcessingManager attachmentsProcessingManager; /// - /// Maintains the current active execution request - /// Assumption : There can only be one active execution request. + /// Maintains the current active execution request. + /// Assumption: There can only be one active execution request. /// private ITestRunRequest currentTestRunRequest; /// - /// Maintains the current active discovery request - /// Assumption : There can only be one active discovery request. + /// Maintains the current active discovery request. + /// Assumption: There can only be one active discovery request. /// private IDiscoveryRequest currentDiscoveryRequest; /// - /// Maintains the current active test run attachments processing cancellation token source - /// Assumption : There can only be one active attachments processing request. + /// Maintains the current active test run attachments processing cancellation token source. + /// Assumption: There can only be one active attachments processing request. /// private CancellationTokenSource currentAttachmentsProcessingCancellationTokenSource; #region Constructor + /// + /// Initializes a new instance of the class. + /// public TestRequestManager() : this( CommandLineOptions.Instance, @@ -81,13 +89,25 @@ public TestRequestManager() TestRunResultAggregator.Instance, TestPlatformEventSource.Instance, new InferHelper(AssemblyMetadataProvider.Instance), - MetricsPublisherFactory.GetMetricsPublisher(IsTelemetryOptedIn(), CommandLineOptions.Instance.IsDesignMode), + MetricsPublisherFactory.GetMetricsPublisher( + IsTelemetryOptedIn(), + CommandLineOptions.Instance.IsDesignMode), new ProcessHelper(), - new TestRunAttachmentsProcessingManager(TestPlatformEventSource.Instance, new CodeCoverageDataAttachmentsHandler())) + new TestRunAttachmentsProcessingManager( + TestPlatformEventSource.Instance, + new CodeCoverageDataAttachmentsHandler())) { } - internal TestRequestManager(CommandLineOptions commandLineOptions, ITestPlatform testPlatform, TestRunResultAggregator testRunResultAggregator, ITestPlatformEventSource testPlatformEventSource, InferHelper inferHelper, Task metricsPublisher, IProcessHelper processHelper, ITestRunAttachmentsProcessingManager attachmentsProcessingManager) + internal TestRequestManager( + CommandLineOptions commandLineOptions, + ITestPlatform testPlatform, + TestRunResultAggregator testRunResultAggregator, + ITestPlatformEventSource testPlatformEventSource, + InferHelper inferHelper, + Task metricsPublisher, + IProcessHelper processHelper, + ITestRunAttachmentsProcessingManager attachmentsProcessingManager) { this.testPlatform = testPlatform; this.commandLineOptions = commandLineOptions; @@ -101,6 +121,9 @@ internal TestRequestManager(CommandLineOptions commandLineOptions, ITestPlatform #endregion + /// + /// Gets the test request manager instance. + /// public static ITestRequestManager Instance { get @@ -117,33 +140,30 @@ public static ITestRequestManager Instance #region ITestRequestManager /// - public void InitializeExtensions(IEnumerable pathToAdditionalExtensions, bool skipExtensionFilters) + public void InitializeExtensions( + IEnumerable pathToAdditionalExtensions, + bool skipExtensionFilters) { - // It is possible for an Editor/IDE to keep running the runner in design mode for long duration. - // We clear the extensions cache to ensure the extensions don't get reused across discovery/run - // requests. + // It is possible for an Editor/IDE to keep running the runner in design mode for long + // duration. We clear the extensions cache to ensure the extensions don't get reused + // across discovery/run requests. EqtTrace.Info("TestRequestManager.InitializeExtensions: Initialize extensions started."); this.testPlatform.ClearExtensions(); this.testPlatform.UpdateExtensions(pathToAdditionalExtensions, skipExtensionFilters); EqtTrace.Info("TestRequestManager.InitializeExtensions: Initialize extensions completed."); } - /// - /// Resets the command options - /// + /// public void ResetOptions() { this.commandLineOptions.Reset(); } - /// - /// Discover Tests given a list of sources, run settings. - /// - /// Discovery payload - /// EventHandler for discovered tests - /// Protocol related information - /// True, if successful - public void DiscoverTests(DiscoveryRequestPayload discoveryPayload, ITestDiscoveryEventsRegistrar discoveryEventsRegistrar, ProtocolConfig protocolConfig) + /// + public void DiscoverTests( + DiscoveryRequestPayload discoveryPayload, + ITestDiscoveryEventsRegistrar discoveryEventsRegistrar, + ProtocolConfig protocolConfig) { EqtTrace.Info("TestRequestManager.DiscoverTests: Discovery tests started."); @@ -155,7 +175,11 @@ public void DiscoverTests(DiscoveryRequestPayload discoveryPayload, ITestDiscove } var requestData = this.GetRequestData(protocolConfig); - if (this.UpdateRunSettingsIfRequired(runsettings, discoveryPayload.Sources?.ToList(), discoveryEventsRegistrar, out string updatedRunsettings)) + if (this.UpdateRunSettingsIfRequired( + runsettings, + discoveryPayload.Sources?.ToList(), + discoveryEventsRegistrar, + out string updatedRunsettings)) { runsettings = updatedRunsettings; } @@ -166,34 +190,42 @@ public void DiscoverTests(DiscoveryRequestPayload discoveryPayload, ITestDiscove if (requestData.IsTelemetryOptedIn) { - // Collect Metrics + // Collect metrics. this.CollectMetrics(requestData, runConfiguration); - // Collect Commands + // Collect commands. this.LogCommandsTelemetryPoints(requestData); } - // create discovery request - var criteria = new DiscoveryCriteria(discoveryPayload.Sources, batchSize, this.commandLineOptions.TestStatsEventTimeout, runsettings) + // Create discovery request. + var criteria = new DiscoveryCriteria( + discoveryPayload.Sources, + batchSize, + this.commandLineOptions.TestStatsEventTimeout, + runsettings) { - TestCaseFilter = this.commandLineOptions.TestCaseFilterValue ?? testCaseFilterFromRunsettings + TestCaseFilter = this.commandLineOptions.TestCaseFilterValue + ?? testCaseFilterFromRunsettings }; - // Make sure to run the run request inside a lock as the below section is not thread-safe - // There can be only one discovery or execution request at a given point in time + // Make sure to run the run request inside a lock as the below section is not thread-safe. + // There can be only one discovery or execution request at a given point in time. lock (this.syncObject) { try { EqtTrace.Info("TestRequestManager.DiscoverTests: Synchronization context taken"); - this.currentDiscoveryRequest = this.testPlatform.CreateDiscoveryRequest(requestData, criteria, discoveryPayload.TestPlatformOptions); + this.currentDiscoveryRequest = this.testPlatform.CreateDiscoveryRequest( + requestData, + criteria, + discoveryPayload.TestPlatformOptions); discoveryEventsRegistrar?.RegisterDiscoveryEvents(this.currentDiscoveryRequest); - // Notify start of discovery start + // Notify start of discovery start. this.testPlatformEventSource.DiscoveryRequestStart(); - // Start the discovery of tests and wait for completion + // Start the discovery of tests and wait for completion. this.currentDiscoveryRequest.DiscoverAsync(); this.currentDiscoveryRequest.WaitForCompletion(); } @@ -201,7 +233,7 @@ public void DiscoverTests(DiscoveryRequestPayload discoveryPayload, ITestDiscove { if (this.currentDiscoveryRequest != null) { - // Dispose the discovery request and unregister for events + // Dispose the discovery request and unregister for events. discoveryEventsRegistrar?.UnregisterDiscoveryEvents(currentDiscoveryRequest); this.currentDiscoveryRequest.Dispose(); this.currentDiscoveryRequest = null; @@ -210,21 +242,20 @@ public void DiscoverTests(DiscoveryRequestPayload discoveryPayload, ITestDiscove EqtTrace.Info("TestRequestManager.DiscoverTests: Discovery tests completed."); this.testPlatformEventSource.DiscoveryRequestStop(); - // Posts the Discovery Complete event. - this.metricsPublisher.Result.PublishMetrics(TelemetryDataConstants.TestDiscoveryCompleteEvent, requestData.MetricsCollection.Metrics); + // Posts the discovery complete event. + this.metricsPublisher.Result.PublishMetrics( + TelemetryDataConstants.TestDiscoveryCompleteEvent, + requestData.MetricsCollection.Metrics); } } } - /// - /// Run Tests with given a set of test cases. - /// - /// TestRun request Payload - /// TestHost Launcher for the run - /// event registrar for run events - /// Protocol related information - /// True, if successful - public void RunTests(TestRunRequestPayload testRunRequestPayload, ITestHostLauncher testHostLauncher, ITestRunEventsRegistrar testRunEventsRegistrar, ProtocolConfig protocolConfig) + /// + public void RunTests( + TestRunRequestPayload testRunRequestPayload, + ITestHostLauncher testHostLauncher, + ITestRunEventsRegistrar testRunEventsRegistrar, + ProtocolConfig protocolConfig) { EqtTrace.Info("TestRequestManager.RunTests: run tests started."); @@ -241,14 +272,21 @@ public void RunTests(TestRunRequestPayload testRunRequestPayload, ITestHostLaunc // Get sources to auto detect fx and arch for both run selected or run all scenario. var sources = GetSources(testRunRequestPayload); - if (this.UpdateRunSettingsIfRequired(runsettings, sources, testRunEventsRegistrar, out string updatedRunsettings)) + if (this.UpdateRunSettingsIfRequired( + runsettings, + sources, + testRunEventsRegistrar, + out string updatedRunsettings)) { runsettings = updatedRunsettings; } - if (InferRunSettingsHelper.AreRunSettingsCollectorsInCompatibleWithTestSettings(runsettings)) + if (InferRunSettingsHelper.AreRunSettingsCollectorsIncompatibleWithTestSettings(runsettings)) { - throw new SettingsException(string.Format(Resources.RunsettingsWithDCErrorMessage, runsettings)); + throw new SettingsException( + string.Format( + Resources.RunsettingsWithDCErrorMessage, + runsettings)); } var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runsettings); @@ -256,28 +294,34 @@ public void RunTests(TestRunRequestPayload testRunRequestPayload, ITestHostLaunc if (requestData.IsTelemetryOptedIn) { - // Collect Metrics + // Collect metrics. this.CollectMetrics(requestData, runConfiguration); - // Collect Commands + // Collect commands. this.LogCommandsTelemetryPoints(requestData); - // Collect data for Legacy Settings + // Collect data for legacy settings. this.LogTelemetryForLegacySettings(requestData, runsettings); } - // get Fakes data collector settings + // Get Fakes data collector settings. if (!string.Equals(Environment.GetEnvironmentVariable("VSTEST_SKIP_FAKES_CONFIGURATION"), "1")) { - // The commandline Options do not have sources in design time mode, - // and so we fall back to using sources instead + // The commandline options do not have sources in design time mode, + // and so we fall back to using sources instead. if (this.commandLineOptions.Sources.Any()) { - GenerateFakesUtilities.GenerateFakesSettings(this.commandLineOptions, this.commandLineOptions.Sources.ToList(), ref runsettings); + GenerateFakesUtilities.GenerateFakesSettings( + this.commandLineOptions, + this.commandLineOptions.Sources.ToList(), + ref runsettings); } else if (sources.Any()) { - GenerateFakesUtilities.GenerateFakesSettings(this.commandLineOptions, sources, ref runsettings); + GenerateFakesUtilities.GenerateFakesSettings( + this.commandLineOptions, + sources, + ref runsettings); } } @@ -291,7 +335,10 @@ public void RunTests(TestRunRequestPayload testRunRequestPayload, ITestHostLaunc this.commandLineOptions.TestStatsEventTimeout, testHostLauncher, testRunRequestPayload.TestPlatformOptions?.TestCaseFilter, - testRunRequestPayload.TestPlatformOptions?.FilterOptions); + testRunRequestPayload.TestPlatformOptions?.FilterOptions, + testRunRequestPayload.TestSessionInfo, + debugEnabledForTestSession: testRunRequestPayload.TestSessionInfo != null + && testRunRequestPayload.DebuggingEnabled); } else { @@ -301,13 +348,20 @@ public void RunTests(TestRunRequestPayload testRunRequestPayload, ITestHostLaunc testRunRequestPayload.KeepAlive, runsettings, this.commandLineOptions.TestStatsEventTimeout, - testHostLauncher); + testHostLauncher, + testRunRequestPayload.TestSessionInfo, + debugEnabledForTestSession: testRunRequestPayload.TestSessionInfo != null + && testRunRequestPayload.DebuggingEnabled); } - // Run tests + // Run tests. try { - this.RunTests(requestData, runCriteria, testRunEventsRegistrar, testRunRequestPayload.TestPlatformOptions); + this.RunTests( + requestData, + runCriteria, + testRunEventsRegistrar, + testRunRequestPayload.TestPlatformOptions); EqtTrace.Info("TestRequestManager.RunTests: run tests completed."); } finally @@ -315,30 +369,40 @@ public void RunTests(TestRunRequestPayload testRunRequestPayload, ITestHostLaunc this.testPlatformEventSource.ExecutionRequestStop(); // Post the run complete event - this.metricsPublisher.Result.PublishMetrics(TelemetryDataConstants.TestExecutionCompleteEvent, requestData.MetricsCollection.Metrics); + this.metricsPublisher.Result.PublishMetrics( + TelemetryDataConstants.TestExecutionCompleteEvent, + requestData.MetricsCollection.Metrics); } } /// - public void ProcessTestRunAttachments(TestRunAttachmentsProcessingPayload attachmentsProcessingPayload, ITestRunAttachmentsProcessingEventsHandler attachmentsProcessingEventsHandler, ProtocolConfig protocolConfig) + public void ProcessTestRunAttachments( + TestRunAttachmentsProcessingPayload attachmentsProcessingPayload, + ITestRunAttachmentsProcessingEventsHandler attachmentsProcessingEventsHandler, + ProtocolConfig protocolConfig) { EqtTrace.Info("TestRequestManager.ProcessTestRunAttachments: Test run attachments processing started."); this.telemetryOptedIn = attachmentsProcessingPayload.CollectMetrics; var requestData = this.GetRequestData(protocolConfig); - // Make sure to run the run request inside a lock as the below section is not thread-safe - // There can be only one discovery, execution or attachments processing request at a given point in time + // Make sure to run the run request inside a lock as the below section is not thread-safe. + // There can be only one discovery, execution or attachments processing request at a given + // point in time. lock (this.syncObject) { try { - EqtTrace.Info("TestRequestManager.ProcessTestRunAttachments: Synchronization context taken"); + EqtTrace.Info("TestRequestManager.ProcessTestRunAttachments: Synchronization context taken."); this.testPlatformEventSource.TestRunAttachmentsProcessingRequestStart(); this.currentAttachmentsProcessingCancellationTokenSource = new CancellationTokenSource(); - Task task = this.attachmentsProcessingManager.ProcessTestRunAttachmentsAsync(requestData, attachmentsProcessingPayload.Attachments, attachmentsProcessingEventsHandler, this.currentAttachmentsProcessingCancellationTokenSource.Token); + Task task = this.attachmentsProcessingManager.ProcessTestRunAttachmentsAsync( + requestData, + attachmentsProcessingPayload.Attachments, + attachmentsProcessingEventsHandler, + this.currentAttachmentsProcessingCancellationTokenSource.Token); task.Wait(); } finally @@ -352,47 +416,116 @@ public void ProcessTestRunAttachments(TestRunAttachmentsProcessingPayload attach EqtTrace.Info("TestRequestManager.ProcessTestRunAttachments: Test run attachments processing completed."); this.testPlatformEventSource.TestRunAttachmentsProcessingRequestStop(); - // Post the attachments processing complete event - this.metricsPublisher.Result.PublishMetrics(TelemetryDataConstants.TestAttachmentsProcessingCompleteEvent, requestData.MetricsCollection.Metrics); + // Post the attachments processing complete event. + this.metricsPublisher.Result.PublishMetrics( + TelemetryDataConstants.TestAttachmentsProcessingCompleteEvent, + requestData.MetricsCollection.Metrics); + } + } + } + + /// + public void StartTestSession( + StartTestSessionPayload payload, + ITestHostLauncher testHostLauncher, + ITestSessionEventsHandler eventsHandler, + ProtocolConfig protocolConfig) + { + EqtTrace.Info("TestRequestManager.StartTestSession: Starting test session."); + + if (payload.TestPlatformOptions != null) + { + this.telemetryOptedIn = payload.TestPlatformOptions.CollectMetrics; + } + + var requestData = this.GetRequestData(protocolConfig); + + if (this.UpdateRunSettingsIfRequired( + payload.RunSettings, + payload.Sources, + null, + out string updatedRunsettings)) + { + payload.RunSettings = updatedRunsettings; + } + + if (InferRunSettingsHelper.AreRunSettingsCollectorsIncompatibleWithTestSettings(payload.RunSettings)) + { + throw new SettingsException( + string.Format( + Resources.RunsettingsWithDCErrorMessage, + payload.RunSettings)); + } + + // TODO (copoiena): Collect metrics ? + + lock (this.syncObject) + { + try + { + EqtTrace.Info("TestRequestManager.StartTestRunner: Synchronization context taken."); + this.testPlatformEventSource.StartTestSessionStart(); + + var criteria = new StartTestSessionCriteria() + { + Sources = payload.Sources, + RunSettings = payload.RunSettings, + TestHostLauncher = testHostLauncher + }; + + this.testPlatform.StartTestSession(requestData, criteria, eventsHandler); + } + finally + { + EqtTrace.Info("TestRequestManager.StartTestSession: Starting test session completed."); + this.testPlatformEventSource.StartTestSessionStop(); + + // Post the attachments processing complete event. + this.metricsPublisher.Result.PublishMetrics( + TelemetryDataConstants.StartTestSessionCompleteEvent, + requestData.MetricsCollection.Metrics); } } } private void LogTelemetryForLegacySettings(IRequestData requestData, string runsettings) { - requestData.MetricsCollection.Add(TelemetryDataConstants.TestSettingsUsed, InferRunSettingsHelper.IsTestSettingsEnabled(runsettings)); + requestData.MetricsCollection.Add( + TelemetryDataConstants.TestSettingsUsed, + InferRunSettingsHelper.IsTestSettingsEnabled(runsettings)); - if (InferRunSettingsHelper.TryGetLegacySettingElements(runsettings, out Dictionary legacySettingsTelemetry)) + if (InferRunSettingsHelper.TryGetLegacySettingElements( + runsettings, + out Dictionary legacySettingsTelemetry)) { foreach (var ciData in legacySettingsTelemetry) { // We are collecting telemetry for the legacy nodes and attributes used in the runsettings. - requestData.MetricsCollection.Add(string.Format("{0}.{1}", TelemetryDataConstants.LegacySettingPrefix, ciData.Key), ciData.Value); + requestData.MetricsCollection.Add( + string.Format( + "{0}.{1}", + TelemetryDataConstants.LegacySettingPrefix, + ciData.Key), + ciData.Value); } } } - /// - /// Cancel the test run. - /// + /// public void CancelTestRun() { EqtTrace.Info("TestRequestManager.CancelTestRun: Sending cancel request."); this.currentTestRunRequest?.CancelAsync(); } - /// - /// Cancel the test discovery. - /// + /// public void CancelDiscovery() { EqtTrace.Info("TestRequestManager.CancelTestDiscovery: Sending cancel request."); this.currentDiscoveryRequest?.Abort(); } - /// - /// Aborts the test run. - /// + /// public void AbortTestRun() { EqtTrace.Info("TestRequestManager.AbortTestRun: Sending abort request."); @@ -430,28 +563,41 @@ private void Dispose(bool disposing) } } - private bool UpdateRunSettingsIfRequired(string runsettingsXml, List sources, IBaseTestEventsRegistrar registrar, out string updatedRunSettingsXml) + private bool UpdateRunSettingsIfRequired( + string runsettingsXml, + IList sources, + IBaseTestEventsRegistrar registrar, + out string updatedRunSettingsXml) { bool settingsUpdated = false; updatedRunSettingsXml = runsettingsXml; - IDictionary sourcePlatforms = new Dictionary(); - IDictionary sourceFrameworks = new Dictionary(); + var sourcePlatforms = new Dictionary(); + var sourceFrameworks = new Dictionary(); if (!string.IsNullOrEmpty(runsettingsXml)) { // TargetFramework is full CLR. Set DesignMode based on current context. using (var stream = new StringReader(runsettingsXml)) - using (var reader = XmlReader.Create(stream, XmlRunSettingsUtilities.ReaderSettings)) + using (var reader = XmlReader.Create( + stream, + XmlRunSettingsUtilities.ReaderSettings)) { var document = new XmlDocument(); document.Load(reader); var navigator = document.CreateNavigator(); var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runsettingsXml); - var loggerRunSettings = XmlRunSettingsUtilities.GetLoggerRunSettings(runsettingsXml) ?? new LoggerRunSettings(); - - settingsUpdated |= this.UpdateFramework(document, navigator, sources, sourceFrameworks, registrar, out Framework chosenFramework); - - // Choose default architecture based on the framework + var loggerRunSettings = XmlRunSettingsUtilities.GetLoggerRunSettings(runsettingsXml) + ?? new LoggerRunSettings(); + + settingsUpdated |= this.UpdateFramework( + document, + navigator, + sources, + sourceFrameworks, + registrar, + out Framework chosenFramework); + + // Choose default architecture based on the framework. // For .NET core, the default platform architecture should be based on the process. Architecture defaultArchitecture = Architecture.X86; if (chosenFramework.Name.IndexOf("netstandard", StringComparison.OrdinalIgnoreCase) >= 0 @@ -459,22 +605,37 @@ private bool UpdateRunSettingsIfRequired(string runsettingsXml, List sou || chosenFramework.Name.IndexOf("net5", StringComparison.OrdinalIgnoreCase) >= 0) { #if NETCOREAPP - // We are running in vstest.console that is either started via dotnet.exe or via vstest.console.exe .NET Core - // executable. For AnyCPU dlls this should resolve 32-bit SDK when running from 32-bit dotnet process and + // We are running in vstest.console that is either started via dotnet.exe + // or via vstest.console.exe .NET Core executable. For AnyCPU dlls this + // should resolve 32-bit SDK when running from 32-bit dotnet process and // 64-bit SDK when running from 64-bit dotnet process. defaultArchitecture = Environment.Is64BitProcess ? Architecture.X64 : Architecture.X86; #else - // We are running in vstest.console.exe that was built against .NET Framework. This console prefers 32-bit - // because it needs to run as 32-bit to be compatible with QTAgent. It runs as 32-bit both under VS and - // in Developer console. Set the default architecture based on the OS architecture, to find 64-bit dotnet SDK - // when running AnyCPU dll on 64-bit system, and 32-bit SDK when running AnyCPU dll on 32-bit OS. + // We are running in vstest.console.exe that was built against .NET + // Framework. This console prefers 32-bit because it needs to run as 32-bit + // to be compatible with QTAgent. It runs as 32-bit both under VS and in + // Developer console. Set the default architecture based on the OS + // architecture, to find 64-bit dotnet SDK when running AnyCPU dll on 64-bit + // system, and 32-bit SDK when running AnyCPU dll on 32-bit OS. // We want to find 64-bit SDK because it is more likely to be installed. defaultArchitecture = Environment.Is64BitOperatingSystem ? Architecture.X64 : Architecture.X86; #endif } - settingsUpdated |= this.UpdatePlatform(document, navigator, sources, sourcePlatforms, defaultArchitecture, out Architecture chosenPlatform); - this.CheckSourcesForCompatibility(chosenFramework, chosenPlatform, defaultArchitecture, sourcePlatforms, sourceFrameworks, registrar); + settingsUpdated |= this.UpdatePlatform( + document, + navigator, + sources, + sourcePlatforms, + defaultArchitecture, + out Architecture chosenPlatform); + this.CheckSourcesForCompatibility( + chosenFramework, + chosenPlatform, + defaultArchitecture, + sourcePlatforms, + sourceFrameworks, + registrar); settingsUpdated |= this.UpdateDesignMode(document, runConfiguration); settingsUpdated |= this.UpdateCollectSourceInformation(document, runConfiguration); settingsUpdated |= this.UpdateTargetDevice(navigator, document, runConfiguration); @@ -487,23 +648,33 @@ private bool UpdateRunSettingsIfRequired(string runsettingsXml, List sou return settingsUpdated; } - private bool AddOrUpdateConsoleLogger(XmlDocument document, RunConfiguration runConfiguration, LoggerRunSettings loggerRunSettings) + private bool AddOrUpdateConsoleLogger( + XmlDocument document, + RunConfiguration runConfiguration, + LoggerRunSettings loggerRunSettings) { - // Update console logger settings + // Update console logger settings. bool consoleLoggerUpdated = this.UpdateConsoleLoggerIfExists(document, loggerRunSettings); // In case of CLI, add console logger if not already present. - bool designMode = runConfiguration.DesignModeSet ? runConfiguration.DesignMode : this.commandLineOptions.IsDesignMode; + bool designMode = runConfiguration.DesignModeSet + ? runConfiguration.DesignMode + : this.commandLineOptions.IsDesignMode; if (!designMode && !consoleLoggerUpdated) { this.AddConsoleLogger(document, loggerRunSettings); } - // Update is required 1) in case of CLI 2) in case of design mode if console logger is present in runsettings. + // Update is required: + // 1) in case of CLI; + // 2) in case of design mode if console logger is present in runsettings. return !designMode || consoleLoggerUpdated; } - private bool UpdateTargetDevice(XPathNavigator navigator, XmlDocument document, RunConfiguration runConfiguration) + private bool UpdateTargetDevice( + XPathNavigator navigator, + XmlDocument document, + RunConfiguration runConfiguration) { bool updateRequired = InferRunSettingsHelper.TryGetDeviceXml(navigator, out string deviceXml); if (updateRequired) @@ -513,12 +684,16 @@ private bool UpdateTargetDevice(XPathNavigator navigator, XmlDocument document, return updateRequired; } - private bool UpdateCollectSourceInformation(XmlDocument document, RunConfiguration runConfiguration) + private bool UpdateCollectSourceInformation( + XmlDocument document, + RunConfiguration runConfiguration) { bool updateRequired = !runConfiguration.CollectSourceInformationSet; if (updateRequired) { - InferRunSettingsHelper.UpdateCollectSourceInformation(document, this.commandLineOptions.ShouldCollectSourceInformation); + InferRunSettingsHelper.UpdateCollectSourceInformation( + document, + this.commandLineOptions.ShouldCollectSourceInformation); } return updateRequired; } @@ -529,15 +704,29 @@ private bool UpdateDesignMode(XmlDocument document, RunConfiguration runConfigur bool updateRequired = !runConfiguration.DesignModeSet; if (updateRequired) { - InferRunSettingsHelper.UpdateDesignMode(document, this.commandLineOptions.IsDesignMode); + InferRunSettingsHelper.UpdateDesignMode( + document, + this.commandLineOptions.IsDesignMode); } return updateRequired; } - private void CheckSourcesForCompatibility(Framework chosenFramework, Architecture chosenPlatform, Architecture defaultArchitecture, IDictionary sourcePlatforms, IDictionary sourceFrameworks, IBaseTestEventsRegistrar registrar) + private void CheckSourcesForCompatibility( + Framework chosenFramework, + Architecture chosenPlatform, + Architecture defaultArchitecture, + IDictionary sourcePlatforms, + IDictionary sourceFrameworks, + IBaseTestEventsRegistrar registrar) { - // Find compatible sources - var compatibleSources = InferRunSettingsHelper.FilterCompatibleSources(chosenPlatform, defaultArchitecture, chosenFramework, sourcePlatforms, sourceFrameworks, out var incompatibleSettingWarning); + // Find compatible sources. + var compatibleSources = InferRunSettingsHelper.FilterCompatibleSources( + chosenPlatform, + defaultArchitecture, + chosenFramework, + sourcePlatforms, + sourceFrameworks, + out var incompatibleSettingWarning); // Raise warnings for incompatible sources if (!string.IsNullOrEmpty(incompatibleSettingWarning)) @@ -554,36 +743,59 @@ private void CheckSourcesForCompatibility(Framework chosenFramework, Architectur } } - private bool UpdatePlatform(XmlDocument document, XPathNavigator navigator, List sources, IDictionary sourcePlatforms, Architecture defaultArchitecture, out Architecture chosenPlatform) + private bool UpdatePlatform( + XmlDocument document, + XPathNavigator navigator, + IList sources, + IDictionary sourcePlatforms, + Architecture defaultArchitecture, + out Architecture chosenPlatform) { - // Get platform from sources - var inferedPlatform = inferHelper.AutoDetectArchitecture(sources, sourcePlatforms, defaultArchitecture); + // Get platform from sources. + var inferedPlatform = inferHelper.AutoDetectArchitecture( + sources, + sourcePlatforms, + defaultArchitecture); - // Get platform from runsettings + // Get platform from runsettings. bool updatePlatform = IsAutoPlatformDetectRequired(navigator, out chosenPlatform); - // Update platform if required. For command line scenario update happens in ArgumentProcessor. + // Update platform if required. For command line scenario update happens in + // ArgumentProcessor. if (updatePlatform) { - InferRunSettingsHelper.UpdateTargetPlatform(document, inferedPlatform.ToString(), overwrite: true); + InferRunSettingsHelper.UpdateTargetPlatform( + document, + inferedPlatform.ToString(), + overwrite: true); chosenPlatform = inferedPlatform; } return updatePlatform; } - private bool UpdateFramework(XmlDocument document, XPathNavigator navigator, List sources, IDictionary sourceFrameworks, IBaseTestEventsRegistrar registrar, out Framework chosenFramework) + private bool UpdateFramework( + XmlDocument document, + XPathNavigator navigator, + IList sources, + IDictionary sourceFrameworks, + IBaseTestEventsRegistrar registrar, + out Framework chosenFramework) { - // Get framework from sources + // Get framework from sources. var inferedFramework = inferHelper.AutoDetectFramework(sources, sourceFrameworks); // Get framework from runsettings. bool updateFramework = IsAutoFrameworkDetectRequired(navigator, out chosenFramework); - // Update framework if required. For command line scenario update happens in ArgumentProcessor. + // Update framework if required. For command line scenario update happens in + // ArgumentProcessor. if (updateFramework) { - InferRunSettingsHelper.UpdateTargetFramework(document, inferedFramework?.ToString(), overwrite: true); + InferRunSettingsHelper.UpdateTargetFramework( + document, + inferedFramework?.ToString(), + overwrite: true); chosenFramework = inferedFramework; } @@ -614,7 +826,10 @@ private void AddConsoleLogger(XmlDocument document, LoggerRunSettings loggerRunS }; loggerRunSettings.LoggerSettingsList.Add(consoleLogger); - RunSettingsProviderExtensions.UpdateRunSettingsXmlDocumentInnerXml(document, Constants.LoggerRunSettingsName, loggerRunSettings.ToXml().InnerXml); + RunSettingsProviderExtensions.UpdateRunSettingsXmlDocumentInnerXml( + document, + Constants.LoggerRunSettingsName, + loggerRunSettings.ToXml().InnerXml); } /// @@ -623,7 +838,9 @@ private void AddConsoleLogger(XmlDocument document, LoggerRunSettings loggerRunS /// Runsettings document. /// Logger run settings. /// True if updated console logger in runsettings successfully. - private bool UpdateConsoleLoggerIfExists(XmlDocument document, LoggerRunSettings loggerRunSettings) + private bool UpdateConsoleLoggerIfExists( + XmlDocument document, + LoggerRunSettings loggerRunSettings) { var defaultConsoleLogger = new LoggerSettings { @@ -639,24 +856,36 @@ private bool UpdateConsoleLoggerIfExists(XmlDocument document, LoggerRunSettings var consoleLogger = loggerRunSettings.LoggerSettingsList[existingLoggerIndex]; consoleLogger.AssemblyQualifiedName = typeof(ConsoleLogger).AssemblyQualifiedName; consoleLogger.CodeBase = typeof(ConsoleLogger).GetTypeInfo().Assembly.Location; - RunSettingsProviderExtensions.UpdateRunSettingsXmlDocumentInnerXml(document, Constants.LoggerRunSettingsName, loggerRunSettings.ToXml().InnerXml); + RunSettingsProviderExtensions.UpdateRunSettingsXmlDocumentInnerXml( + document, + Constants.LoggerRunSettingsName, + loggerRunSettings.ToXml().InnerXml); + return true; } return false; } - private void RunTests(IRequestData requestData, TestRunCriteria testRunCriteria, ITestRunEventsRegistrar testRunEventsRegistrar, TestPlatformOptions options) + private void RunTests( + IRequestData requestData, + TestRunCriteria testRunCriteria, + ITestRunEventsRegistrar testRunEventsRegistrar, + TestPlatformOptions options) { - // Make sure to run the run request inside a lock as the below section is not thread-safe - // TranslationLayer can process faster as it directly gets the raw un-serialized messages whereas - // below logic needs to deserialize and do some cleanup - // While this section is cleaning up, TranslationLayer can trigger run causing multiple threads to run the below section at the same time + // Make sure to run the run request inside a lock as the below section is not thread-safe. + // TranslationLayer can process faster as it directly gets the raw un-serialized messages + // whereas below logic needs to deserialize and do some cleanup. + // While this section is cleaning up, TranslationLayer can trigger run causing multiple + // threads to run the below section at the same time. lock (this.syncObject) { try { - this.currentTestRunRequest = this.testPlatform.CreateTestRunRequest(requestData, testRunCriteria, options); + this.currentTestRunRequest = this.testPlatform.CreateTestRunRequest( + requestData, + testRunCriteria, + options); this.testRunResultAggregator.RegisterTestRunEvents(this.currentTestRunRequest); testRunEventsRegistrar?.RegisterTestRunEvents(this.currentTestRunRequest); @@ -688,21 +917,26 @@ private void RunTests(IRequestData requestData, TestRunCriteria testRunCriteria, } } - private bool IsAutoFrameworkDetectRequired(XPathNavigator navigator, out Framework chosenFramework) + private bool IsAutoFrameworkDetectRequired( + XPathNavigator navigator, + out Framework chosenFramework) { bool required = true; chosenFramework = null; if (commandLineOptions.IsDesignMode) { bool isValidFx = - InferRunSettingsHelper.TryGetFrameworkXml(navigator, out var frameworkFromrunsettingsXml); + InferRunSettingsHelper.TryGetFrameworkXml( + navigator, + out var frameworkFromrunsettingsXml); required = !isValidFx || string.IsNullOrWhiteSpace(frameworkFromrunsettingsXml); if (!required) { chosenFramework = Framework.FromString(frameworkFromrunsettingsXml); } } - else if (!commandLineOptions.IsDesignMode && commandLineOptions.FrameworkVersionSpecified) + else if (!commandLineOptions.IsDesignMode + && commandLineOptions.FrameworkVersionSpecified) { required = false; chosenFramework = commandLineOptions.TargetFrameworkVersion; @@ -711,17 +945,24 @@ private bool IsAutoFrameworkDetectRequired(XPathNavigator navigator, out Framewo return required; } - private bool IsAutoPlatformDetectRequired(XPathNavigator navigator, out Architecture chosenPlatform) + private bool IsAutoPlatformDetectRequired( + XPathNavigator navigator, + out Architecture chosenPlatform) { bool required = true; chosenPlatform = Architecture.Default; if (commandLineOptions.IsDesignMode) { - bool isValidPlatform = InferRunSettingsHelper.TryGetPlatformXml(navigator, out var platformXml); + bool isValidPlatform = InferRunSettingsHelper.TryGetPlatformXml( + navigator, + out var platformXml); + required = !isValidPlatform || string.IsNullOrWhiteSpace(platformXml); if (!required) { - chosenPlatform = (Architecture)Enum.Parse(typeof(Architecture), platformXml, true); + chosenPlatform = (Architecture)Enum.Parse( + typeof(Architecture), + platformXml, true); } } else if (!commandLineOptions.IsDesignMode && commandLineOptions.ArchitectureSpecified) @@ -734,45 +975,65 @@ private bool IsAutoPlatformDetectRequired(XPathNavigator navigator, out Architec } /// - /// Collect Metrics + /// Collect metrics. /// - /// Request Data for common Discovery/Execution Services - /// RunConfiguration + /// Request data for common Discovery/Execution services. + /// Run configuration. private void CollectMetrics(IRequestData requestData, RunConfiguration runConfiguration) { // Collecting Target Framework. - requestData.MetricsCollection.Add(TelemetryDataConstants.TargetFramework, runConfiguration.TargetFramework.Name); + requestData.MetricsCollection.Add( + TelemetryDataConstants.TargetFramework, + runConfiguration.TargetFramework.Name); // Collecting Target Platform. - requestData.MetricsCollection.Add(TelemetryDataConstants.TargetPlatform, runConfiguration.TargetPlatform.ToString()); + requestData.MetricsCollection.Add( + TelemetryDataConstants.TargetPlatform, + runConfiguration.TargetPlatform.ToString()); // Collecting Max CPU count. - requestData.MetricsCollection.Add(TelemetryDataConstants.MaxCPUcount, runConfiguration.MaxCpuCount); + requestData.MetricsCollection.Add( + TelemetryDataConstants.MaxCPUcount, + runConfiguration.MaxCpuCount); - // Collecting Target Device. Here, it will be updated run settings so, target device will be under run configuration only. + // Collecting Target Device. Here, it will be updated run settings so, target device + // will be under run configuration only. var targetDevice = runConfiguration.TargetDevice; if (string.IsNullOrEmpty(targetDevice)) { - requestData.MetricsCollection.Add(TelemetryDataConstants.TargetDevice, "Local Machine"); + requestData.MetricsCollection.Add( + TelemetryDataConstants.TargetDevice, + "Local Machine"); } - else if (targetDevice.Equals("Device", StringComparison.Ordinal) || targetDevice.Contains("Emulator")) + else if (targetDevice.Equals("Device", StringComparison.Ordinal) + || targetDevice.Contains("Emulator")) { - requestData.MetricsCollection.Add(TelemetryDataConstants.TargetDevice, targetDevice); + requestData.MetricsCollection.Add( + TelemetryDataConstants.TargetDevice, + targetDevice); } else { - // For IOT scenarios - requestData.MetricsCollection.Add(TelemetryDataConstants.TargetDevice, "Other"); + // For IOT scenarios. + requestData.MetricsCollection.Add( + TelemetryDataConstants.TargetDevice, + "Other"); } - // Collecting TestPlatform Version - requestData.MetricsCollection.Add(TelemetryDataConstants.TestPlatformVersion, Product.Version); + // Collecting TestPlatform version. + requestData.MetricsCollection.Add( + TelemetryDataConstants.TestPlatformVersion, + Product.Version); - // Collecting TargetOS - requestData.MetricsCollection.Add(TelemetryDataConstants.TargetOS, new PlatformEnvironment().OperatingSystemVersion); + // Collecting TargetOS. + requestData.MetricsCollection.Add( + TelemetryDataConstants.TargetOS, + new PlatformEnvironment().OperatingSystemVersion); - //Collecting DisableAppDomain - requestData.MetricsCollection.Add(TelemetryDataConstants.DisableAppDomain, runConfiguration.DisableAppDomain); + //Collecting DisableAppDomain. + requestData.MetricsCollection.Add( + TelemetryDataConstants.DisableAppDomain, + runConfiguration.DisableAppDomain); } @@ -784,7 +1045,8 @@ private void CollectMetrics(IRequestData requestData, RunConfiguration runConfig private static bool IsTelemetryOptedIn() { var telemetryStatus = Environment.GetEnvironmentVariable("VSTEST_TELEMETRY_OPTEDIN"); - return !string.IsNullOrEmpty(telemetryStatus) && telemetryStatus.Equals("1", StringComparison.Ordinal); + return !string.IsNullOrEmpty(telemetryStatus) + && telemetryStatus.Equals("1", StringComparison.Ordinal); } /// @@ -853,14 +1115,16 @@ private void LogCommandsTelemetryPoints(IRequestData requestData) } } - requestData.MetricsCollection.Add(TelemetryDataConstants.CommandLineSwitches, string.Join(",", commandsUsed.ToArray())); + requestData.MetricsCollection.Add( + TelemetryDataConstants.CommandLineSwitches, + string.Join(",", commandsUsed.ToArray())); } /// - /// Gets Request Data + /// Gets request data. /// - /// Protocol Config - /// + /// Protocol config. + /// Request data. private IRequestData GetRequestData(ProtocolConfig protocolConfig) { return new RequestData @@ -877,11 +1141,13 @@ private IRequestData GetRequestData(ProtocolConfig protocolConfig) private List GetSources(TestRunRequestPayload testRunRequestPayload) { List sources = new List(); - if (testRunRequestPayload.Sources != null && testRunRequestPayload.Sources.Count > 0) + if (testRunRequestPayload.Sources != null + && testRunRequestPayload.Sources.Count > 0) { sources = testRunRequestPayload.Sources; } - else if (testRunRequestPayload.TestCases != null && testRunRequestPayload.TestCases.Count > 0) + else if (testRunRequestPayload.TestCases != null + && testRunRequestPayload.TestCases.Count > 0) { ISet sourcesSet = new HashSet(); foreach (var testCase in testRunRequestPayload.TestCases) diff --git a/test/DataCollectors/TraceDataCollector.UnitTests/DefaultCodeCoverageConfig.xml b/test/DataCollectors/TraceDataCollector.UnitTests/DefaultCodeCoverageConfig.xml deleted file mode 100644 index 619819d6d3..0000000000 --- a/test/DataCollectors/TraceDataCollector.UnitTests/DefaultCodeCoverageConfig.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - .*CPPUnitTestFramework.* - .*vstest.console.* - .*microsoft.intellitrace.* - .*testhost.* - .*datacollector.* - .*microsoft.teamfoundation.testplatform.* - .*microsoft.visualstudio.testplatform.* - .*microsoft.visualstudio.testwindow.* - .*microsoft.visualstudio.mstest.* - .*microsoft.visualstudio.qualitytools.* - .*microsoft.vssdk.testhostadapter.* - .*microsoft.vssdk.testhostframework.* - .*qtagent32.* - .*msvcr.*dll$ - .*msvcp.*dll$ - .*clr.dll$ - .*clr.ni.dll$ - .*clrjit.dll$ - .*clrjit.ni.dll$ - .*mscoree.dll$ - .*mscoreei.dll$ - .*mscoreei.ni.dll$ - .*mscorlib.dll$ - .*mscorlib.ni.dll$ - .*cryptbase.dll$ - .*bcryptPrimitives.dll$ - - - True - True - True - false - - - - ^std::.* - ^ATL::.* - .*::__GetTestMethodInfo.* - .*__CxxPureMSILEntry.* - ^Microsoft::VisualStudio::CppCodeCoverageFramework::.* - ^Microsoft::VisualStudio::CppUnitTestFramework::.* - .*::YOU_CAN_ONLY_DESIGNATE_ONE_.* - ^__.* - .*::__.* - - - - - ^System.Diagnostics.DebuggerHiddenAttribute$ - ^System.Diagnostics.DebuggerNonUserCodeAttribute$ - System.Runtime.CompilerServices.CompilerGeneratedAttribute$ - ^System.CodeDom.Compiler.GeneratedCodeAttribute$ - ^System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute$ - ^Microsoft.VisualStudio.TestPlatform.TestSDKAutoGeneratedCode.* - - - - - .*\\atlmfc\\.* - .*\\vctools\\.* - .*\\public\\sdk\\.* - .*\\externalapis\\.* - .*\\microsoft sdks\\.* - .*\\vc\\include\\.* - .*\\msclr\\.* - .*\\ucrt\\.* - - - - - diff --git a/test/DataCollectors/TraceDataCollector.UnitTests/DynamicCoverageDataCollectorImplTests.cs b/test/DataCollectors/TraceDataCollector.UnitTests/DynamicCoverageDataCollectorImplTests.cs deleted file mode 100644 index 4b1b3f182f..0000000000 --- a/test/DataCollectors/TraceDataCollector.UnitTests/DynamicCoverageDataCollectorImplTests.cs +++ /dev/null @@ -1,489 +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.TraceDataCollector.UnitTests -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Globalization; - using System.IO; - using System.Xml; - using Coverage; - using Coverage.Interfaces; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - using Newtonsoft.Json; - using Newtonsoft.Json.Linq; - using TestPlatform.ObjectModel.DataCollection; - using TraceCollector; - using TraceCollector.Interfaces; - - [TestClass] - public class DynamicCoverageDataCollectorImplTests - { - private const string DefaultConfigFileName = "CodeCoverage.config"; - private const string DefaultCoverageFileName = "abc.coverage"; - - private static XmlElement sampleConfigurationElement = - DynamicCoverageDataCollectorImplTests.CreateXmlElement($@" - {DefaultCoverageFileName} - - - "); - - private DynamicCoverageDataCollectorImpl collectorImpl; - private Mock vanguardMock; - private Mock dataCollectionSinkMock; - private Mock dataCollectionLoggerMock; - private Mock directoryHelperMock; - private Mock fileHelperMock; - private Mock profilersLocationProviderMock; - - private string aConfigFileName; - private string atempDirectory; - private string tempSessionDir; - - public DynamicCoverageDataCollectorImplTests() - { - this.vanguardMock = new Mock(); - this.dataCollectionSinkMock = new Mock(); - this.dataCollectionLoggerMock = new Mock(); - this.directoryHelperMock = new Mock(); - this.fileHelperMock = new Mock(); - this.profilersLocationProviderMock = new Mock(); - this.tempSessionDir = null; - this.collectorImpl = new DynamicCoverageDataCollectorImpl(this.vanguardMock.Object, this.directoryHelperMock.Object, this.fileHelperMock.Object, this.profilersLocationProviderMock.Object); - this.SetupForInitialize(); - this.collectorImpl.Initialize(DynamicCoverageDataCollectorImplTests.sampleConfigurationElement, this.dataCollectionSinkMock.Object, this.dataCollectionLoggerMock.Object); - } - - [TestCleanup] - public void Cleanup() - { - if (this.tempSessionDir != null) - { - if (Directory.Exists(this.tempSessionDir)) - { - Directory.Delete(this.tempSessionDir, true); - } - } - } - - #region Initialize Tests - [TestMethod] - public void InitializeShouldCreateDefaultCodeCoverageSettingsIfConfigElementIsNull() - { - this.directoryHelperMock.Setup(d => d.CreateDirectory(It.IsAny())) - .Callback((path) => Directory.CreateDirectory(path)); - - this.fileHelperMock.Setup(f => f.WriteAllText(It.IsAny(), It.IsAny())) - .Callback((path, content) => { File.WriteAllText(path, content); }); - - this.collectorImpl.Initialize(null, this.dataCollectionSinkMock.Object, this.dataCollectionLoggerMock.Object); - - Assert.AreEqual(DynamicCoverageDataCollectorImplTests.DefaultConfigFileName, Path.GetFileName(this.aConfigFileName)); - StringAssert.Contains(this.aConfigFileName, Path.GetTempPath()); - this.CompareWithDefaultConfig(); - } - - [TestMethod] - public void InitializeShouldGenerateCodeCoverageDepsJsonFile() - { - this.directoryHelperMock.Setup(d => d.CreateDirectory(It.IsAny())) - .Callback((path) => Directory.CreateDirectory(path)); - - this.fileHelperMock.Setup(f => f.WriteAllText(It.IsAny(), It.IsAny())) - .Callback((path, content) => { File.WriteAllText(path, content); }); - - this.profilersLocationProviderMock.Setup(lp => lp.GetCodeCoverageShimPath()).Returns(@"C:\aaa\bbb\Microsoft.VisualStudio.CodeCoverage.Shim.dll"); - - this.collectorImpl.Initialize(null, this.dataCollectionSinkMock.Object, this.dataCollectionLoggerMock.Object); - - var obj = JObject.Parse(File.ReadAllText(this.collectorImpl.CodeCoverageDepsJsonFilePath)); - - var expected = @" -{ - ""runtimeTarget"": { - ""name"": ""codecoverage"", - ""signature"": """" - }, - ""targets"": { - ""codecoverage"": { - ""Microsoft.VisualStudio.CodeCoverage.Shim/15.0.0.0"": { - ""runtime"": { - ""C:/aaa/bbb/Microsoft.VisualStudio.CodeCoverage.Shim.dll"": { } - } - } - } - }, - ""libraries"": { - ""Microsoft.VisualStudio.CodeCoverage.Shim/15.0.0.0"": { - ""type"": ""reference"", - ""serviceable"": false, - ""sha512"": """" - } - } -}"; - - Assert.AreEqual(expected.Trim(), File.ReadAllText(this.collectorImpl.CodeCoverageDepsJsonFilePath).Trim()); - } - - [TestMethod] - public void InitializeShouldInitializeVanguardWithRightCoverageSettings() - { - XmlElement configElement = - DynamicCoverageDataCollectorImplTests.CreateXmlElement(@""); - - this.directoryHelperMock.Setup(d => d.CreateDirectory(It.IsAny())) - .Callback((path) => - { - this.tempSessionDir = path; - Directory.CreateDirectory(path); - }); - - this.fileHelperMock.Setup(f => f.WriteAllText(It.IsAny(), It.IsAny())) - .Callback((path, content) => { File.WriteAllText(path, content); }); - - this.collectorImpl.Initialize(configElement, this.dataCollectionSinkMock.Object, this.dataCollectionLoggerMock.Object); - - XmlDocument defaultDocument = new XmlDocument(); - defaultDocument.LoadXml(DynamicCoverageDataCollectorImplTests.GetDefaultCodeCoverageConfig()); - - Assert.AreEqual(DynamicCoverageDataCollectorImplTests.DefaultConfigFileName, Path.GetFileName(this.aConfigFileName)); - - XmlDocument currentDocument = new XmlDocument(); - currentDocument.LoadXml(File.ReadAllText(this.aConfigFileName)); - - var codeCoverageNodes = new Tuple(currentDocument.DocumentElement, defaultDocument.DocumentElement); - - this.CompareResults(codeCoverageNodes.Item1, codeCoverageNodes.Item2, "./ModulePaths/Exclude"); - this.CompareResults(codeCoverageNodes.Item1, codeCoverageNodes.Item2, "./Functions/Exclude"); - this.CompareResults(codeCoverageNodes.Item1, codeCoverageNodes.Item2, "./Attributes/Exclude"); - this.CompareResults(codeCoverageNodes.Item1, codeCoverageNodes.Item2, "./Sources/Exclude"); - } - - [TestMethod] - public void InitializeShouldInitializeDefaultConfigIfNoCodeCoverageConfigExists() - { - XmlElement configElement = - DynamicCoverageDataCollectorImplTests.CreateXmlElement($".NETCoreApp,Version=v1.1"); - - this.directoryHelperMock.Setup(d => d.CreateDirectory(It.IsAny())) - .Callback((path) => - { - this.tempSessionDir = path; - Directory.CreateDirectory(path); - }); - - this.fileHelperMock.Setup(f => f.WriteAllText(It.IsAny(), It.IsAny())) - .Callback((path, content) => { File.WriteAllText(path, content); }); - - this.collectorImpl.Initialize(configElement, this.dataCollectionSinkMock.Object, this.dataCollectionLoggerMock.Object); - - this.CompareWithDefaultConfig(); - } - - [TestMethod] - public void InitializeShouldRegisterForSendFileCompleteEvent() - { - this.directoryHelperMock.Setup(d => d.Exists(this.atempDirectory)).Returns(true); - this.dataCollectionSinkMock.Raise(s => s.SendFileCompleted += null, new AsyncCompletedEventArgs(null, false, null)); - this.directoryHelperMock.Verify(d => d.Exists(this.atempDirectory)); - this.directoryHelperMock.Verify(d => d.Delete(this.atempDirectory, true)); - } - - [TestMethod] - public void InitializeShouldCreateTempDirectoryForSession() - { - this.directoryHelperMock.Verify(d => d.CreateDirectory(this.atempDirectory)); - } - - #endregion - - #region Dispose Tests - [TestMethod] - public void DisposeShouldStopVanguard() - { - this.collectorImpl.Dispose(); - this.vanguardMock.Verify(v => v.Stop()); - } - - [TestMethod] - public void DisposeShouldDisposeVanguard() - { - this.collectorImpl.Dispose(); - this.vanguardMock.Verify(v => v.Dispose()); - } - - [TestMethod] - public void DisposeShouldDeleteTempDirectory() - { - this.directoryHelperMock.Setup(d => d.Exists(this.atempDirectory)).Returns(true); - this.collectorImpl.Dispose(); - this.directoryHelperMock.Verify(d => d.Delete(this.atempDirectory, true)); - } - - [TestMethod] - public void DisposeShouldNotDeleteTempDirectoryIfNotExists() - { - this.directoryHelperMock.Setup(d => d.Exists(this.atempDirectory)).Returns(false); - this.collectorImpl.Dispose(); - this.directoryHelperMock.Verify(d => d.Delete(this.atempDirectory, true), Times.Never); - } - - [TestMethod] - public void DisposeShouldUnregisterFileCompleteEvent() - { - this.collectorImpl.Dispose(); - this.dataCollectionSinkMock.Raise(s => s.SendFileCompleted += null, new AsyncCompletedEventArgs(null, false, null)); - this.directoryHelperMock.Verify(d => d.Exists(this.atempDirectory), Times.Once); - } - - #endregion - - #region SessionStart Tests - - [TestMethod] - public void SessionStartShouldCreateDirectoryForCoverageFile() - { - var sessionStartEventArgs = new SessionStartEventArgs(); - var coverageFilePath = string.Empty; - - this.vanguardMock.Setup(v => v.Start(It.IsAny(), It.IsAny())) - .Callback((filePath, dcContext) => - { - coverageFilePath = filePath; - }); - this.collectorImpl.SessionStart(null, sessionStartEventArgs); - - StringAssert.StartsWith(Path.GetDirectoryName(coverageFilePath), this.atempDirectory); - StringAssert.EndsWith(coverageFilePath, DynamicCoverageDataCollectorImplTests.DefaultCoverageFileName); - } - - [TestMethod] - public void SessionStartShouldUseAutoGenrateCoverageFileNameIfNotSpecified() - { - var sessionStartEventArgs = new SessionStartEventArgs(); - var coverageFilePath = string.Empty; - - this.collectorImpl.Initialize(null, this.dataCollectionSinkMock.Object, this.dataCollectionLoggerMock.Object); - this.vanguardMock.Setup(v => v.Start(It.IsAny(), It.IsAny())) - .Callback((filePath, dcContext) => - { - coverageFilePath = filePath; - }); - this.collectorImpl.SessionStart(null, sessionStartEventArgs); - - StringAssert.StartsWith(Path.GetDirectoryName(coverageFilePath), this.atempDirectory); - StringAssert.Contains(coverageFilePath, DynamicCoverageDataCollectorImplTests.GetAutoGenerageCodeCoverageFileNamePrefix()); - } - - [TestMethod] - public void SessionStartShouldLogWarningOnFailToCreateDirectory() - { - var sessionStartEventArgs = new SessionStartEventArgs(); - - var expectedErrorMessage = "Failed to create directory"; - var directoryPath = string.Empty; - - this.directoryHelperMock.Setup(d => d.CreateDirectory(It.IsAny())) - .Callback((d) => { directoryPath = d; }) - .Throws(new Exception(expectedErrorMessage)); - - var actualLoggedMessage = string.Empty; - this.dataCollectionLoggerMock.Setup(l => l.LogError(It.IsAny(), It.IsAny())) - .Callback((c, m) => { actualLoggedMessage = m; }); - - var actualErrorMessage = Assert.ThrowsException(() => this.collectorImpl.SessionStart(null, sessionStartEventArgs)).Message; - - Assert.AreEqual(expectedErrorMessage, actualErrorMessage); - - var expectedLogMessage = string.Format("Failed to create directory: {0} with error:System.Exception: {1}", directoryPath, expectedErrorMessage); - - StringAssert.StartsWith(actualLoggedMessage, expectedLogMessage); - } - - [TestMethod] - public void SessionStartShouldStartVanguard() - { - var sessionStartEventArgs = new SessionStartEventArgs(); - - this.collectorImpl.SessionStart(null, sessionStartEventArgs); - - this.vanguardMock.Verify(v => v.Start(It.IsAny(), It.IsAny())); - } - - [TestMethod] - public void SessionStartShouldLogErrorOnException() - { - var sessionStartEventArgs = new SessionStartEventArgs(); - var exceptionMessage = "Vanguard not found"; - Exception expectedEx = null; - this.vanguardMock.Setup(d => d.Start(It.IsAny(), It.IsAny())) - .Throws(new VanguardException(exceptionMessage)); - this.dataCollectionLoggerMock - .Setup(l => l.LogError(It.IsAny(), It.IsAny())) - .Callback((context, ex) => - { - expectedEx = ex; - }); - var actualEx = Assert.ThrowsException(() => this.collectorImpl.SessionStart(null, sessionStartEventArgs)); - - this.vanguardMock.Verify(v => v.Start(It.IsAny(), It.IsAny())); - Assert.AreEqual(expectedEx, actualEx); - StringAssert.Contains(actualEx.Message, exceptionMessage); - } - - #endregion - - #region SessionStart Tests - - [TestMethod] - public void SessionEndShouldStopVanguard() - { - var sessionEndEventArgs = new SessionEndEventArgs(); - - this.collectorImpl.SessionEnd(null, sessionEndEventArgs); - - this.vanguardMock.Verify(v => v.Stop()); - } - - [TestMethod] - public void SessionEndShouldSendCoverageFile() - { - string tempFile = Path.GetTempFileName(); - var sessionEndEventArgs = new SessionEndEventArgs(); - this.fileHelperMock.Setup(f => f.Exists(It.IsAny())).Returns(true); - this.collectorImpl.SessionEnd(null, sessionEndEventArgs); - - this.dataCollectionSinkMock.Verify(s => s.SendFileAsync(It.IsAny(), It.IsAny(), false)); - } - - #endregion - - internal static XmlElement CreateXmlElement(string xmlString) - { - var doc = new XmlDocument(); - using ( - var xmlReader = XmlReader.Create( - new StringReader(xmlString), - new XmlReaderSettings() { CloseInput = true, DtdProcessing = DtdProcessing.Prohibit })) - { - doc.Load(xmlReader); - } - - return doc.DocumentElement; - } - - #region private methods - - private static string GetAutoGenerageCodeCoverageFileNamePrefix() - { - string GetUserName() - { - return Environment.GetEnvironmentVariable("USERNAME") ?? Environment.GetEnvironmentVariable("USER"); - } - - return string.Format( - CultureInfo.InvariantCulture, - "{0}_{1}", - GetUserName(), - Environment.MachineName); - } - - private static string GetDefaultCodeCoverageConfig() - { - string result = string.Empty; - - using (Stream stream = typeof(DynamicCoverageDataCollectorImplTests).Assembly. - GetManifestResourceStream("Microsoft.VisualStudio.TraceDataCollector.UnitTests.DefaultCodeCoverageConfig.xml")) - { - using (StreamReader sr = new StreamReader(stream)) - { - result = sr.ReadToEnd(); - } - } - - return result; - } - - private void SetupForInitialize() - { - this.vanguardMock.Setup(v => v.Initialize( - It.IsAny(), - It.IsAny(), - It.IsAny())) - .Callback( - (sessionName, configFileName, logger) => - { - this.aConfigFileName = configFileName; - }); - - this.directoryHelperMock.Setup(d => d.CreateDirectory(It.IsAny())).Callback( - (directoryPath) => { this.atempDirectory = directoryPath; }); - } - - private void CompareWithDefaultConfig() - { - Assert.AreEqual( - DynamicCoverageDataCollectorImplTests.GetDefaultCodeCoverageConfig().Replace(" ", string.Empty) - .Replace("\r", string.Empty).Replace("\n", string.Empty), - File.ReadAllText(this.aConfigFileName).Replace(" ", string.Empty).Replace("\r", string.Empty).Replace("\n", string.Empty)); - } - - private XmlNode ExtractNode(XmlNode node, string path) - { - try - { - return node.SelectSingleNode(path); - } - catch - { - } - - return null; - } - - private Tuple ExtractNodes(XmlNode currentSettingsRoot, XmlNode defaultSettingsRoot, string path) - { - var currentNode = this.ExtractNode(currentSettingsRoot, path); - var defaultNode = this.ExtractNode(defaultSettingsRoot, path); - Assert.IsNotNull(currentNode); - Assert.IsNotNull(defaultNode); - - return new Tuple(currentNode, defaultNode); - } - - private void CompareResults(XmlNode currentSettingsRoot, XmlNode defaultSettingsRoot, string path) - { - var nodes = this.ExtractNodes(currentSettingsRoot, defaultSettingsRoot, path); - - Assert.AreEqual(nodes.Item1.ChildNodes.Count, nodes.Item2.ChildNodes.Count); - - var set = new HashSet(); - foreach (XmlNode child in nodes.Item1.ChildNodes) - { - if (!set.Contains(child.OuterXml)) - { - set.Add(child.OuterXml); - } - } - - foreach (XmlNode child in nodes.Item2.ChildNodes) - { - if (!set.Contains(child.OuterXml)) - { - set.Add(child.OuterXml); - continue; - } - - set.Remove(child.OuterXml); - } - - Assert.AreEqual(set.Count, 0); - } - - #endregion - } -} diff --git a/test/DataCollectors/TraceDataCollector.UnitTests/DynamicCoverageDataCollectorTests.cs b/test/DataCollectors/TraceDataCollector.UnitTests/DynamicCoverageDataCollectorTests.cs deleted file mode 100644 index a30769e1d1..0000000000 --- a/test/DataCollectors/TraceDataCollector.UnitTests/DynamicCoverageDataCollectorTests.cs +++ /dev/null @@ -1,412 +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.TraceDataCollector.UnitTests -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Xml; - using Coverage; - using Coverage.Interfaces; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - using TestPlatform.ObjectModel.DataCollection; - using TraceCollector; - using TraceCollector.Interfaces; - using IDataCollectionSink = TraceCollector.IDataCollectionSink; - - [TestClass] - public class DynamicCoverageDataCollectorTests - { - private const string DefaultConfig = - ".NETCoreApp,Version=v2.0x64"; - - private const string ConfigWithClrIeEnabledForNetCore = - @" - .NETCoreApp,Version=v2.0 - x64 - true - false - false - "; - - private const string ConfigWithClrIeEnabled = - @" - .NETCoreApp,Version=v2.0 - x64 - true - true - true - "; - - private TestableDynamicCoverageDataCollector collector; - private Mock vanguardLocationProviderMock; - private Mock implMock; - private Mock eventsMock; - private Mock sinkMock; - private Mock loggerMock; - private Mock agentContextMock; - private Mock environmentMock; - - public DynamicCoverageDataCollectorTests() - { - this.vanguardLocationProviderMock = new Mock(); - this.implMock = new Mock(); - this.eventsMock = new Mock(); - this.sinkMock = new Mock(); - this.loggerMock = new Mock(); - this.agentContextMock = new Mock(); - this.environmentMock = new Mock(); - this.collector = new TestableDynamicCoverageDataCollector(this.vanguardLocationProviderMock.Object, this.implMock.Object, this.environmentMock.Object); - - this.vanguardLocationProviderMock.Setup(u => u.GetVanguardProfilerX86Path()).Returns(@"covrun86"); - this.vanguardLocationProviderMock.Setup(u => u.GetVanguardProfilerX64Path()).Returns(@"covrun64"); - this.vanguardLocationProviderMock.Setup(u => u.GetVanguardProfilerConfigX86Path()).Returns(@"config86"); - this.vanguardLocationProviderMock.Setup(u => u.GetVanguardProfilerConfigX64Path()).Returns(@"config64"); - this.vanguardLocationProviderMock.Setup(u => u.GetClrInstrumentationEngineX86Path()).Returns(@"clrie86"); - this.vanguardLocationProviderMock.Setup(u => u.GetClrInstrumentationEngineX64Path()).Returns(@"clrie64"); - - this.implMock.Setup(i => i.CodeCoverageDepsJsonFilePath).Returns(@"C:\temp\codecoverage.deps.json"); - - this.environmentMock.Setup(e => e.OperatingSystem).Returns(PlatformOperatingSystem.Windows); - var configElement = DynamicCoverageDataCollectorImplTests.CreateXmlElement(DynamicCoverageDataCollectorTests.DefaultConfig); - this.collector.Initialize(configElement, this.eventsMock.Object, this.sinkMock.Object, this.loggerMock.Object, this.agentContextMock.Object); - } - - [TestCleanup] - public void CleanEnvVariables() - { - Environment.SetEnvironmentVariable("VANGUARD_CLR_IE_INSTRUMENTATION_NETCORE", null); - Environment.SetEnvironmentVariable("VANGUARD_CLR_IE_INSTRUMENTATION_NETFRAMEWORK", null); - } - - [TestMethod] - public void InitializeShouldNotThrowOnNullConfig() - { - XmlElement actualConfig = null; - this.implMock.Setup(i => i.Initialize( - It.IsAny(), - It.IsAny(), - It.IsAny())) - .Callback((config, sink, logger) => - { - actualConfig = config; - }); - - this.collector.Initialize(null, this.eventsMock.Object, this.sinkMock.Object, this.loggerMock.Object, this.agentContextMock.Object); - - Assert.IsNull(actualConfig); - } - - [TestMethod] - public void InitializeShouldLogWarningIfCurrentOperatingSystemIsUnix() - { - this.environmentMock.Setup(e => e.OperatingSystem).Returns(PlatformOperatingSystem.Unix); - this.collector = new TestableDynamicCoverageDataCollector(this.vanguardLocationProviderMock.Object, null, this.environmentMock.Object); - - this.collector.Initialize( - null, - this.eventsMock.Object, - this.sinkMock.Object, - this.loggerMock.Object, - this.agentContextMock.Object); - - var expectedExMsg = - "No code coverage data available. Code coverage is currently supported only on Windows."; - - this.loggerMock.Verify(l => l.LogWarning(It.IsAny(), expectedExMsg)); - } - - [TestMethod] - public void InitializeShouldNotRegisterForSessionEvents() - { - this.implMock = new Mock(); - this.environmentMock.Setup(e => e.OperatingSystem).Returns(PlatformOperatingSystem.Unix); - this.collector = new TestableDynamicCoverageDataCollector(this.vanguardLocationProviderMock.Object, null, this.environmentMock.Object); - - this.collector.Initialize( - null, - this.eventsMock.Object, - this.sinkMock.Object, - this.loggerMock.Object, - this.agentContextMock.Object); - - this.eventsMock.Raise(e => e.SessionStart += null, new SessionStartEventArgs()); - this.eventsMock.Raise(e => e.SessionEnd += null, new SessionEndEventArgs()); - - this.implMock.Verify(i => i.SessionStart(It.IsAny(), It.IsAny()), Times.Never); - this.implMock.Verify(i => i.SessionEnd(It.IsAny(), It.IsAny()), Times.Never); - } - - [TestMethod] - public void InitializeShouldRegisterForSessionStartEvent() - { - this.eventsMock.Raise(e => e.SessionStart += null, new SessionStartEventArgs()); - - this.implMock.Verify(i => i.SessionStart(It.IsAny(), It.IsAny())); - } - - [TestMethod] - public void InitializeShouldRegisterForSessionEndEvent() - { - this.eventsMock.Raise(e => e.SessionEnd += null, new SessionEndEventArgs()); - - this.implMock.Verify(i => i.SessionEnd(It.IsAny(), It.IsAny())); - } - - [TestMethod] - public void InitializeShouldNotLogMessageOnException() - { - var exceptionReason = "Failed to create directory"; - this.implMock.Setup(i => i.Initialize( - It.IsAny(), - It.IsAny(), - It.IsAny())) - .Throws(new Exception(exceptionReason)); - - var actualErrorMessage = string.Empty; - this.loggerMock.Setup(l => l.LogError(It.IsAny(), It.IsAny())) - .Callback((c, m) => { actualErrorMessage = m; }); - Assert.ThrowsException(() => this.collector.Initialize(null, this.eventsMock.Object, this.sinkMock.Object, this.loggerMock.Object, this.agentContextMock.Object)); - - this.loggerMock.Verify(l => l.LogError(It.IsAny(), It.IsAny()), Times.Once()); - - var expectedMessagePrefix = "Failed to initialize code coverage datacollector with error:"; - StringAssert.StartsWith(actualErrorMessage, expectedMessagePrefix); - StringAssert.Contains(actualErrorMessage, exceptionReason); - } - - [TestMethod] - public void GetEnvironmentVariablesShouldReturnRightEnvVaribles() - { - var expectedEnvVariables = new Dictionary - { - { "CORECLR_ENABLE_PROFILING", "1" }, - { "CORECLR_PROFILER_PATH_32", "covrun86" }, - { "CORECLR_PROFILER_PATH_64", "covrun64" }, - { "CORECLR_PROFILER", "{E5F256DC-7959-4DD6-8E4F-C11150AB28E0}" }, - { "CODE_COVERAGE_SESSION_NAME", "MTM_123" }, - { "COR_PROFILER_PATH_32", "covrun86" }, - { "COR_PROFILER_PATH_64", "covrun64" }, - { "COR_ENABLE_PROFILING", "1" }, - { "COR_PROFILER", "{E5F256DC-7959-4DD6-8E4F-C11150AB28E0}" }, - { "MicrosoftInstrumentationEngine_ConfigPath32_VanguardInstrumentationProfiler", "config86" }, - { "MicrosoftInstrumentationEngine_ConfigPath64_VanguardInstrumentationProfiler", "config64" }, - { "VANGUARD_DOTNET_ADDITIONAL_DEPS", @"C:\temp\codecoverage.deps.json" }, - }; - - this.implMock.Setup(i => i.GetSessionName()).Returns("MTM_123"); - - var envVars = this.collector.GetEnvironmentVariables(); - - VerifyEnvironmentVariables(expectedEnvVariables, envVars); - } - - [TestMethod] - public void GetEnvironmentVariablesShouldReturnRightEnvVariblesClrInstrumentationEngineEnabled() - { - var configElement = DynamicCoverageDataCollectorImplTests.CreateXmlElement(DynamicCoverageDataCollectorTests.ConfigWithClrIeEnabled); - this.collector.Initialize(configElement, this.eventsMock.Object, this.sinkMock.Object, this.loggerMock.Object, this.agentContextMock.Object); - - var expectedEnvVariables = new Dictionary - { - { "CORECLR_ENABLE_PROFILING", "1" }, - { "CORECLR_PROFILER_PATH_32", "clrie86" }, - { "CORECLR_PROFILER_PATH_64", "clrie64" }, - { "CORECLR_PROFILER", "{324F817A-7420-4E6D-B3C1-143FBED6D855}" }, - { "CODE_COVERAGE_SESSION_NAME", "MTM_123" }, - { "COR_PROFILER_PATH_32", "clrie86" }, - { "COR_PROFILER_PATH_64", "clrie64" }, - { "COR_ENABLE_PROFILING", "1" }, - { "COR_PROFILER", "{324F817A-7420-4E6D-B3C1-143FBED6D855}" }, - { "MicrosoftInstrumentationEngine_ConfigPath32_VanguardInstrumentationProfiler", "config86" }, - { "MicrosoftInstrumentationEngine_ConfigPath64_VanguardInstrumentationProfiler", "config64" }, - { "MicrosoftInstrumentationEngine_LogLevel", "Errors" }, - { "MicrosoftInstrumentationEngine_LogLevel_{2A1F2A34-8192-44AC-A9D8-4FCC03DCBAA8}", "Errors" }, - { "MicrosoftInstrumentationEngine_DisableCodeSignatureValidation", "1" }, - { "MicrosoftInstrumentationEngine_FileLogPath", @"GENERATED" }, - { "VANGUARD_DOTNET_ADDITIONAL_DEPS", @"C:\temp\codecoverage.deps.json" } - }; - - this.implMock.Setup(i => i.GetSessionName()).Returns("MTM_123"); - - var envVars = this.collector.GetEnvironmentVariables(); - - VerifyEnvironmentVariables(expectedEnvVariables, envVars); - } - - [TestMethod] - public void GetEnvironmentVariablesShouldReturnRightEnvVariblesClrInstrumentationEngineEnabledThroughEnvVars() - { - Environment.SetEnvironmentVariable("VANGUARD_CLR_IE_INSTRUMENTATION_NETCORE", "1"); - Environment.SetEnvironmentVariable("VANGUARD_CLR_IE_INSTRUMENTATION_NETFRAMEWORK", "1"); - - var configElement = DynamicCoverageDataCollectorImplTests.CreateXmlElement(DynamicCoverageDataCollectorTests.DefaultConfig); - this.collector.Initialize(configElement, this.eventsMock.Object, this.sinkMock.Object, this.loggerMock.Object, this.agentContextMock.Object); - - var expectedEnvVariables = new Dictionary - { - { "CORECLR_ENABLE_PROFILING", "1" }, - { "CORECLR_PROFILER_PATH_32", "clrie86" }, - { "CORECLR_PROFILER_PATH_64", "clrie64" }, - { "CORECLR_PROFILER", "{324F817A-7420-4E6D-B3C1-143FBED6D855}" }, - { "CODE_COVERAGE_SESSION_NAME", "MTM_123" }, - { "COR_PROFILER_PATH_32", "clrie86" }, - { "COR_PROFILER_PATH_64", "clrie64" }, - { "COR_ENABLE_PROFILING", "1" }, - { "COR_PROFILER", "{324F817A-7420-4E6D-B3C1-143FBED6D855}" }, - { "MicrosoftInstrumentationEngine_ConfigPath32_VanguardInstrumentationProfiler", "config86" }, - { "MicrosoftInstrumentationEngine_ConfigPath64_VanguardInstrumentationProfiler", "config64" }, - { "MicrosoftInstrumentationEngine_LogLevel", "Errors" }, - { "MicrosoftInstrumentationEngine_LogLevel_{2A1F2A34-8192-44AC-A9D8-4FCC03DCBAA8}", "Errors" }, - { "MicrosoftInstrumentationEngine_DisableCodeSignatureValidation", "1" }, - { "MicrosoftInstrumentationEngine_FileLogPath", @"GENERATED" }, - { "VANGUARD_DOTNET_ADDITIONAL_DEPS", @"C:\temp\codecoverage.deps.json" } - }; - - this.implMock.Setup(i => i.GetSessionName()).Returns("MTM_123"); - - var envVars = this.collector.GetEnvironmentVariables(); - - VerifyEnvironmentVariables(expectedEnvVariables, envVars); - } - - [TestMethod] - public void GetEnvironmentVariablesShouldReturnRightEnvVariblesClrInstrumentationEngineEnabledForNetCore() - { - var configElement = DynamicCoverageDataCollectorImplTests.CreateXmlElement(DynamicCoverageDataCollectorTests.ConfigWithClrIeEnabledForNetCore); - this.collector.Initialize(configElement, this.eventsMock.Object, this.sinkMock.Object, this.loggerMock.Object, this.agentContextMock.Object); - - var expectedEnvVariables = new Dictionary - { - { "CORECLR_ENABLE_PROFILING", "1" }, - { "CORECLR_PROFILER_PATH_32", "clrie86" }, - { "CORECLR_PROFILER_PATH_64", "clrie64" }, - { "CORECLR_PROFILER", "{324F817A-7420-4E6D-B3C1-143FBED6D855}" }, - { "CODE_COVERAGE_SESSION_NAME", "MTM_123" }, - { "COR_PROFILER_PATH_32", "covrun86" }, - { "COR_PROFILER_PATH_64", "covrun64" }, - { "COR_ENABLE_PROFILING", "1" }, - { "COR_PROFILER", "{E5F256DC-7959-4DD6-8E4F-C11150AB28E0}" }, - { "MicrosoftInstrumentationEngine_ConfigPath32_VanguardInstrumentationProfiler", "config86" }, - { "MicrosoftInstrumentationEngine_ConfigPath64_VanguardInstrumentationProfiler", "config64" }, - { "MicrosoftInstrumentationEngine_LogLevel", "Errors" }, - { "MicrosoftInstrumentationEngine_LogLevel_{2A1F2A34-8192-44AC-A9D8-4FCC03DCBAA8}", "Errors" }, - { "MicrosoftInstrumentationEngine_DisableCodeSignatureValidation", "1" }, - { "MicrosoftInstrumentationEngine_FileLogPath", @"GENERATED" } - }; - - this.implMock.Setup(i => i.GetSessionName()).Returns("MTM_123"); - - var envVars = this.collector.GetEnvironmentVariables(); - - VerifyEnvironmentVariables(expectedEnvVariables, envVars); - } - - [TestMethod] - public void GetEnvironmentVariablesShouldReturnRightEnvVariblesClrInstrumentationEngineEnabledForNetCoreThroughEnvVar() - { - Environment.SetEnvironmentVariable("VANGUARD_CLR_IE_INSTRUMENTATION_NETCORE", "1"); - Environment.SetEnvironmentVariable("VANGUARD_CLR_IE_INSTRUMENTATION_NETFRAMEWORK", "0"); - - var configElement = DynamicCoverageDataCollectorImplTests.CreateXmlElement(DynamicCoverageDataCollectorTests.DefaultConfig); - this.collector.Initialize(configElement, this.eventsMock.Object, this.sinkMock.Object, this.loggerMock.Object, this.agentContextMock.Object); - - var expectedEnvVariables = new Dictionary - { - { "CORECLR_ENABLE_PROFILING", "1" }, - { "CORECLR_PROFILER_PATH_32", "clrie86" }, - { "CORECLR_PROFILER_PATH_64", "clrie64" }, - { "CORECLR_PROFILER", "{324F817A-7420-4E6D-B3C1-143FBED6D855}" }, - { "CODE_COVERAGE_SESSION_NAME", "MTM_123" }, - { "COR_PROFILER_PATH_32", "covrun86" }, - { "COR_PROFILER_PATH_64", "covrun64" }, - { "COR_ENABLE_PROFILING", "1" }, - { "COR_PROFILER", "{E5F256DC-7959-4DD6-8E4F-C11150AB28E0}" }, - { "MicrosoftInstrumentationEngine_ConfigPath32_VanguardInstrumentationProfiler", "config86" }, - { "MicrosoftInstrumentationEngine_ConfigPath64_VanguardInstrumentationProfiler", "config64" }, - { "MicrosoftInstrumentationEngine_LogLevel", "Errors" }, - { "MicrosoftInstrumentationEngine_LogLevel_{2A1F2A34-8192-44AC-A9D8-4FCC03DCBAA8}", "Errors" }, - { "MicrosoftInstrumentationEngine_DisableCodeSignatureValidation", "1" }, - { "MicrosoftInstrumentationEngine_FileLogPath", @"GENERATED" }, - { "VANGUARD_DOTNET_ADDITIONAL_DEPS", @"C:\temp\codecoverage.deps.json" } - }; - - this.implMock.Setup(i => i.GetSessionName()).Returns("MTM_123"); - - var envVars = this.collector.GetEnvironmentVariables(); - - VerifyEnvironmentVariables(expectedEnvVariables, envVars); - } - - [TestMethod] - public void GetEnvironmentVariablesShouldReturnNoEnvVaribles() - { - this.implMock = new Mock(); - this.environmentMock.Setup(e => e.OperatingSystem).Returns(PlatformOperatingSystem.Unix); - this.collector = new TestableDynamicCoverageDataCollector(this.vanguardLocationProviderMock.Object, null, this.environmentMock.Object); - - this.collector.Initialize( - null, - this.eventsMock.Object, - this.sinkMock.Object, - this.loggerMock.Object, - this.agentContextMock.Object); - var envVars = this.collector.GetEnvironmentVariables(); - - Assert.IsFalse(envVars.Any(), "No environment variables set on unix."); - } - - [TestMethod] - public void DisposeShouldDisposeImpl() - { - this.collector.Dispose(); - this.implMock.Verify(i => i.Dispose()); - } - - [TestMethod] - public void DisposeShouldUnsubcribeEvents() - { - this.collector.Dispose(); - this.eventsMock.Raise(e => e.SessionStart += null, new SessionStartEventArgs()); - this.eventsMock.Raise(e => e.SessionEnd += null, new SessionEndEventArgs()); - - this.implMock.Verify(i => i.SessionStart(It.IsAny(), It.IsAny()), Times.Never); - this.implMock.Verify(i => i.SessionEnd(It.IsAny(), It.IsAny()), Times.Never); - } - - private static void VerifyEnvironmentVariables(Dictionary expectedEnvVariables, IEnumerable> envVars) - { - foreach (var pair in envVars) - { - Console.WriteLine(pair.Key + " ==> " + pair.Value); - } - - Assert.AreEqual(expectedEnvVariables.Count, envVars.Count()); - - foreach (var pair in envVars) - { - Assert.IsTrue(expectedEnvVariables.ContainsKey(pair.Key), $"unexpected env variable {pair}"); - Assert.IsTrue(pair.Key == "MicrosoftInstrumentationEngine_FileLogPath" || expectedEnvVariables[pair.Key].Equals(pair.Value), $"unexpected env variable {pair}"); - } - } - - private class TestableDynamicCoverageDataCollector : DynamicCoverageDataCollector - { - public TestableDynamicCoverageDataCollector( - IProfilersLocationProvider vanguardLocationProvider, - IDynamicCoverageDataCollectorImpl impl, - IEnvironment environment) - : base(vanguardLocationProvider, impl, environment) - { - } - - public new IEnumerable> GetEnvironmentVariables() - { - return base.GetEnvironmentVariables(); - } - } - } -} diff --git a/test/DataCollectors/TraceDataCollector.UnitTests/Microsoft.TestPlatform.TraceDataCollector.UnitTests.csproj b/test/DataCollectors/TraceDataCollector.UnitTests/Microsoft.TestPlatform.TraceDataCollector.UnitTests.csproj deleted file mode 100644 index c38d997b27..0000000000 --- a/test/DataCollectors/TraceDataCollector.UnitTests/Microsoft.TestPlatform.TraceDataCollector.UnitTests.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - ..\..\..\ - true - true - - - - Microsoft.VisualStudio.TraceDataCollector.UnitTests - - - netcoreapp2.1 - true - true - Exe - Microsoft.TestPlatform.TraceDataCollector.UnitTests - - - - - - - - - - - - - diff --git a/test/DataCollectors/TraceDataCollector.UnitTests/ProfilersLocationProviderTests.cs b/test/DataCollectors/TraceDataCollector.UnitTests/ProfilersLocationProviderTests.cs deleted file mode 100644 index 74a3c46ac1..0000000000 --- a/test/DataCollectors/TraceDataCollector.UnitTests/ProfilersLocationProviderTests.cs +++ /dev/null @@ -1,119 +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.TraceDataCollector.UnitTests -{ - using System; - using System.IO; - using System.Reflection; - using TestTools.UnitTesting; - using TraceCollector; - - [TestClass] - [TestCategory("Windows")] - public class ProfilersLocationProviderTests - { - private ProfilersLocationProvider vanguardLocationProvider; - - public ProfilersLocationProviderTests() - { - this.vanguardLocationProvider = new ProfilersLocationProvider(); - } - - [TestCleanup] - public void CleanEnvVariables() - { - Environment.SetEnvironmentVariable("CLRIEX86InstallDir", null); - Environment.SetEnvironmentVariable("CLRIEX64InstallDir", null); - } - - [TestMethod] - public void GetVanguardPathShouldReturnRightPath() - { - var actualPath = this.vanguardLocationProvider.GetVanguardPath(); - - Assert.AreEqual(Path.Join(this.GetCurrentAssemblyLocation(), @"CodeCoverage\CodeCoverage.exe"), actualPath); - } - - [TestMethod] - public void GetVanguardProfilerX86PathShouldReturnRightDirectory() - { - var actualPath = this.vanguardLocationProvider.GetVanguardProfilerX86Path(); - - Assert.AreEqual(Path.Join(this.GetCurrentAssemblyLocation(), @"CodeCoverage\covrun32.dll"), actualPath); - } - - [TestMethod] - public void GetVanguardProfilerX64PathShouldReturnRightDirectory() - { - var actualPath = this.vanguardLocationProvider.GetVanguardProfilerX64Path(); - - Assert.AreEqual(Path.Join(this.GetCurrentAssemblyLocation(), @"CodeCoverage\amd64\covrun64.dll"), actualPath); - } - - [TestMethod] - public void GetVanguardProfilerConfigX86PathShouldReturnRightDirectory() - { - var actualPath = this.vanguardLocationProvider.GetVanguardProfilerConfigX86Path(); - - Assert.AreEqual(Path.Join(this.GetCurrentAssemblyLocation(), @"CodeCoverage\VanguardInstrumentationProfiler_x86.config"), actualPath); - } - - [TestMethod] - public void GetVanguardProfilerConfigX64PathShouldReturnRightDirectory() - { - var actualPath = this.vanguardLocationProvider.GetVanguardProfilerConfigX64Path(); - - Assert.AreEqual(Path.Join(this.GetCurrentAssemblyLocation(), @"CodeCoverage\amd64\VanguardInstrumentationProfiler_x64.config"), actualPath); - } - - [TestMethod] - public void GetCodeCoverageShimPathShouldReturnRightDirectory() - { - var actualPath = this.vanguardLocationProvider.GetCodeCoverageShimPath(); - - Assert.AreEqual(Path.Join(this.GetCurrentAssemblyLocation(), @"CodeCoverage\coreclr\Microsoft.VisualStudio.CodeCoverage.Shim.dll"), actualPath); - } - - [TestMethod] - public void GetClrInstrumentationEngineX86PathShouldReturnRightDirectory() - { - var actualDir = this.vanguardLocationProvider.GetClrInstrumentationEngineX86Path(); - - Assert.AreEqual(Path.Join(this.GetCurrentAssemblyLocation(), @"InstrumentationEngine\x86\MicrosoftInstrumentationEngine_x86.dll"), actualDir); - } - - [TestMethod] - public void GetClrInstrumentationEngineX64PathShouldReturnRightDirectory() - { - var actualDir = this.vanguardLocationProvider.GetClrInstrumentationEngineX64Path(); - - Assert.AreEqual(Path.Join(this.GetCurrentAssemblyLocation(), @"InstrumentationEngine\x64\MicrosoftInstrumentationEngine_x64.dll"), actualDir); - } - - [TestMethod] - public void GetClrInstrumentationEngineX86PathShouldReturnRightDirectoryIfEnvVariableSet() - { - Environment.SetEnvironmentVariable("CLRIEX86InstallDir", @"C:\temp"); - - var actualDir = this.vanguardLocationProvider.GetClrInstrumentationEngineX86Path(); - - Assert.AreEqual(@"C:\temp\MicrosoftInstrumentationEngine_x86.dll", actualDir); - } - - [TestMethod] - public void GetClrInstrumentationEngineX64PathShouldReturnRightDirectoryIfEnvVariableSet() - { - Environment.SetEnvironmentVariable("CLRIEX64InstallDir", @"C:\temp"); - - var actualDir = this.vanguardLocationProvider.GetClrInstrumentationEngineX64Path(); - - Assert.AreEqual(@"C:\temp\MicrosoftInstrumentationEngine_x64.dll", actualDir); - } - - private string GetCurrentAssemblyLocation() - { - return Path.GetDirectoryName(typeof(ProfilersLocationProviderTests).GetTypeInfo().Assembly.Location); - } - } -} diff --git a/test/DataCollectors/TraceDataCollector.UnitTests/Program.cs b/test/DataCollectors/TraceDataCollector.UnitTests/Program.cs deleted file mode 100644 index 7f39953476..0000000000 --- a/test/DataCollectors/TraceDataCollector.UnitTests/Program.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -namespace Microsoft.VisualStudio.TestPlatform.Common.DataCollector.UnitTests -{ - /// - /// Main entry point for the command line runner. - /// - public static class Program - { - public static void Main(string[] args) - { - } - } -} \ No newline at end of file diff --git a/test/DataCollectors/TraceDataCollector.UnitTests/Properties/AssemblyInfo.cs b/test/DataCollectors/TraceDataCollector.UnitTests/Properties/AssemblyInfo.cs deleted file mode 100644 index fb892d21e1..0000000000 --- a/test/DataCollectors/TraceDataCollector.UnitTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,21 +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. - -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("datacollector.UnitTests")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("00aa21f3-31e4-4748-ac0b-c4eadb41ca24")] diff --git a/test/DataCollectors/TraceDataCollector.UnitTests/VanguardCommandBuilderTests.cs b/test/DataCollectors/TraceDataCollector.UnitTests/VanguardCommandBuilderTests.cs deleted file mode 100644 index 26b9e6ec94..0000000000 --- a/test/DataCollectors/TraceDataCollector.UnitTests/VanguardCommandBuilderTests.cs +++ /dev/null @@ -1,50 +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.TraceDataCollector.UnitTests -{ - using Coverage; - using Coverage.Interfaces; - using TestTools.UnitTesting; - - [TestClass] - public class VanguardCommandBuilderTests - { - private VanguardCommandBuilder vanguardCommandBuilder; - - public VanguardCommandBuilderTests() - { - this.vanguardCommandBuilder = new VanguardCommandBuilder(); - } - - [TestMethod] - public void GenerateCommandLineShouldReturnCommandForCollectCommand() - { - string sessionName = "session1", outputName = "output1", configFileName = "configFileName1"; - string expectedCommand = $"collect /session:{sessionName} /output:\"{outputName}\" /config:\"{configFileName}\""; - - var actualCommand = this.vanguardCommandBuilder.GenerateCommandLine( - VanguardCommand.Collect, - sessionName, - outputName, - configFileName); - - Assert.AreEqual(expectedCommand, actualCommand); - } - - [TestMethod] - public void GenerateCommandLineShouldReturnCommandForShutdownCommand() - { - string sessionName = "session1"; - string expectedCommand = $"shutdown /session:{sessionName}"; - - var actualCommand = this.vanguardCommandBuilder.GenerateCommandLine( - VanguardCommand.Shutdown, - sessionName, - null, - null); - - Assert.AreEqual(expectedCommand, actualCommand); - } - } -} diff --git a/test/DataCollectors/TraceDataCollector.UnitTests/VanguardTests.cs b/test/DataCollectors/TraceDataCollector.UnitTests/VanguardTests.cs deleted file mode 100644 index e4d567e866..0000000000 --- a/test/DataCollectors/TraceDataCollector.UnitTests/VanguardTests.cs +++ /dev/null @@ -1,204 +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.TraceDataCollector.UnitTests -{ - using System; - using System.ComponentModel; - using System.Globalization; - using System.IO; - using System.Text; - using System.Threading; - using Coverage; - using Coverage.Interfaces; - using global::TestPlatform.TestUtilities; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - using TestPlatform.CoreUtilities.Helpers; - using TestPlatform.ObjectModel; - using TestPlatform.ObjectModel.DataCollection; - using TraceCollector; - using TraceCollector.Interfaces; - - [TestClass] - [TestCategory("Windows")] - public class VanguardTests - { - private const string CodeCoverageExeFileName = "CodeCoverage"; - private const string ConfigFileNameFormat = - @"{0}\{1}\CodeCoverage.config"; // {TempDirPath}\{Session_GUID}\CodeCoverage.config - - private const string ConfigXml = - @" - - - .*Tests.dll - - - True - True - True - False - - "; - - private Vanguard vanguard; - private string sessionName; - private string configFileName; - private Mock dataCollectionLoggerMock; - private Mock vanguardLocationProviderMock; - private string outputFileName; - private string outputDir; - private DataCollectionContext dataCollectionContext; - private Mock vanguardCommandBuilderMock; - private IProcessJobObject processJobObject; - - public VanguardTests() - { - TestCase testcase = new TestCase { Id = Guid.NewGuid() }; - this.dataCollectionContext = new DataCollectionContext(testcase); - this.dataCollectionLoggerMock = new Mock(); - this.processJobObject = new ProcessJobObject(); - this.vanguardCommandBuilderMock = new Mock(); - this.vanguardLocationProviderMock = new Mock(); - - this.vanguard = new Vanguard(this.vanguardLocationProviderMock.Object, this.vanguardCommandBuilderMock.Object, this.processJobObject); - this.sessionName = Guid.NewGuid().ToString(); - this.configFileName = string.Format(VanguardTests.ConfigFileNameFormat, Path.GetTempPath(), this.sessionName); - this.outputDir = Path.GetDirectoryName(this.configFileName); - Directory.CreateDirectory(this.outputDir); - File.WriteAllText(this.configFileName, VanguardTests.ConfigXml); - this.outputFileName = Path.Combine(this.outputDir, Guid.NewGuid() + ".coverage"); - this.vanguardCommandBuilderMock.Setup(c => - c.GenerateCommandLine(VanguardCommand.Shutdown, this.sessionName, It.IsAny(), It.IsAny())) - .Returns(VanguardTests.GetShutdownCommand(this.sessionName)); - this.vanguard.Initialize(this.sessionName, this.configFileName, this.dataCollectionLoggerMock.Object); - this.vanguardLocationProviderMock.Setup(c => c.GetVanguardPath()).Returns(Path.Combine(Directory.GetCurrentDirectory(), "CodeCoverage", "CodeCoverage.exe")); - } - - [TestCleanup] - public void Cleanup() - { - Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, string.Empty); - this.vanguard.Stop(); - File.Delete(this.configFileName); - Directory.Delete(this.outputDir, true); - } - - [TestMethod] - public void InitializeShouldCreateConfigFile() - { - Assert.IsTrue(File.Exists(this.configFileName)); - StringAssert.Contains( - VanguardTests.ConfigXml.Replace(" ", string.Empty).Replace(Environment.NewLine, string.Empty), - File.ReadAllText(this.configFileName).Replace(" ", string.Empty).Replace(Environment.NewLine, string.Empty)); - } - - [Ignore] - [TestMethod] - public void StartShouldStartVanguardProcessWithCollectCommand() - { - var cts = new CancellationTokenSource(); - var numOfProcessCreatedTask = NumberOfProcessLaunchedUtility.NumberOfProcessCreated( - cts, - VanguardTests.CodeCoverageExeFileName); - - this.vanguardCommandBuilderMock.Setup(c => - c.GenerateCommandLine(VanguardCommand.Collect, It.IsAny(), It.IsAny(), It.IsAny())) - .Returns(VanguardTests.GetCollectCommand(this.sessionName, this.outputFileName, this.configFileName)); - - this.vanguard.Start(this.outputFileName, this.dataCollectionContext); - cts.Cancel(); - - var numOfProcessCreated = numOfProcessCreatedTask.Result.Count; - - // TODO find the reason why additional process launched when collecting code coverage. - Assert.IsTrue(numOfProcessCreated == 1 || numOfProcessCreated == 2, $"Number of process created:{numOfProcessCreated} expected is 1 or 2."); - } - - [TestMethod] - [ExpectedException(typeof(Win32Exception))] - public void StartShouldThrowOnInvalidVarguardPath() - { - this.vanguardLocationProviderMock.Setup(c => c.GetVanguardPath()).Returns(Path.Combine(Directory.GetCurrentDirectory(), "WrongExePath.exe")); - this.vanguard.Start(this.outputFileName, this.dataCollectionContext); - } - - [TestMethod] - public void StartShouldThrowOnInvalidCommandLine() - { - var expectedErrorMessage = - "Running event not received from CodeCoverage.exe. Check eventlogs for failure reason."; - this.vanguardCommandBuilderMock - .Setup(c => c.GenerateCommandLine( - VanguardCommand.Collect, - It.IsAny(), - It.IsAny(), - It.IsAny())).Returns("invalid command"); - var exception = Assert.ThrowsException(() => this.vanguard.Start(this.outputFileName, this.dataCollectionContext)); - Assert.AreEqual(expectedErrorMessage, exception.Message); - } - - [TestMethod] - [Ignore("This test is flaky")] - public void StartShouldThrowOnTimeout() - { - Environment.SetEnvironmentVariable(EnvironmentHelper.VstestConnectionTimeout, "0"); - var expectedErrorMessage = - "Failed to receive running event from CodeCoverage.exe in 0 seconds, This may occur due to machine slowness, please set environment variable VSTEST_CONNECTION_TIMEOUT to increase timeout."; - this.vanguardCommandBuilderMock - .Setup(c => c.GenerateCommandLine( - VanguardCommand.Collect, - It.IsAny(), - It.IsAny(), - It.IsAny())).Returns(VanguardTests.GetCollectCommand(this.sessionName, this.outputFileName, this.configFileName)); - var exception = Assert.ThrowsException(() => this.vanguard.Start(this.outputFileName, this.dataCollectionContext)); - Assert.AreEqual(expectedErrorMessage, exception.Message); - } - - [Ignore] - [TestMethod] - public void StopShouldLaunchVarguardWithShutdownCommand() - { - var cts = new CancellationTokenSource(); - var numOfProcessCreatedTask = NumberOfProcessLaunchedUtility.NumberOfProcessCreated( - cts, - VanguardTests.CodeCoverageExeFileName); - this.vanguardCommandBuilderMock - .Setup(c => c.GenerateCommandLine( - VanguardCommand.Collect, - It.IsAny(), - It.IsAny(), - It.IsAny())).Returns(VanguardTests.GetCollectCommand(this.sessionName, this.outputFileName, this.configFileName)); - this.vanguard.Start(this.outputFileName, this.dataCollectionContext); - this.vanguard.Stop(); - cts.Cancel(); - - var numOfProcessCreated = numOfProcessCreatedTask.Result.Count; - - // TODO find the reason why additional process launched when collecting code coverage. - Assert.IsTrue(numOfProcessCreated == 2 || numOfProcessCreated == 4, $"Number of process created:{numOfProcessCreated} expected is 2 or 4."); - } - - private static string GetCollectCommand(string sessionName, string outputName, string configurationFileName) - { - StringBuilder builder = new StringBuilder(); - builder.AppendFormat( - CultureInfo.InvariantCulture, - "collect /session:{0} /output:\"{1}\" /config:\"{2}\"", - sessionName, - outputName, - configurationFileName); - - return builder.ToString(); - } - - private static string GetShutdownCommand(string sessionName) - { - StringBuilder builder = new StringBuilder(); - builder.AppendFormat(CultureInfo.InvariantCulture, "shutdown /session:{0}", sessionName); - - return builder.ToString(); - } - } -} diff --git a/test/Microsoft.TestPlatform.AcceptanceTests/CodeCoverageAcceptanceTestBase.cs b/test/Microsoft.TestPlatform.AcceptanceTests/CodeCoverageAcceptanceTestBase.cs index a05b509d20..eb87327c37 100644 --- a/test/Microsoft.TestPlatform.AcceptanceTests/CodeCoverageAcceptanceTestBase.cs +++ b/test/Microsoft.TestPlatform.AcceptanceTests/CodeCoverageAcceptanceTestBase.cs @@ -19,14 +19,19 @@ public class CodeCoverageAcceptanceTestBase : AcceptanceTestBase */ protected const double ExpectedMinimalModuleCoverage = 30.0; - protected string GetCodeCoveragePath() + protected string GetNetStandardAdapterPath() { return Path.Combine(IntegrationTestEnvironment.TestPlatformRootDirectory, "artifacts", IntegrationTestEnvironment.BuildConfiguration, "Microsoft.CodeCoverage"); } + protected string GetNetFrameworkAdapterPath() + { + return Path.Combine(IntegrationTestEnvironment.TestPlatformRootDirectory, "artifacts", IntegrationTestEnvironment.BuildConfiguration, "net451", "win7-x64", "Extensions"); + } + protected string GetCodeCoverageExePath() { - return Path.Combine(this.GetCodeCoveragePath(), "CodeCoverage", "CodeCoverage.exe"); + return Path.Combine(this.GetNetStandardAdapterPath(), "CodeCoverage", "CodeCoverage.exe"); } protected XmlNode GetModuleNode(XmlNode node, string name) diff --git a/test/Microsoft.TestPlatform.AcceptanceTests/CodeCoverageTests.cs b/test/Microsoft.TestPlatform.AcceptanceTests/CodeCoverageTests.cs index 06f6038722..53c191bc10 100644 --- a/test/Microsoft.TestPlatform.AcceptanceTests/CodeCoverageTests.cs +++ b/test/Microsoft.TestPlatform.AcceptanceTests/CodeCoverageTests.cs @@ -204,7 +204,7 @@ private string CreateArguments( var assemblyPaths = this.GetAssetFullPath(testParameters.AssemblyName); string traceDataCollectorDir = Path.Combine(IntegrationTestEnvironment.TestPlatformRootDirectory, - "src", "DataCollectors", "TraceDataCollector", "bin", IntegrationTestEnvironment.BuildConfiguration, "netstandard2.0"); + "artifacts", IntegrationTestEnvironment.BuildConfiguration, "Microsoft.CodeCoverage"); string diagFileName = Path.Combine(this.resultsDirectory, "diaglog.txt"); var arguments = PrepareArguments(assemblyPaths, this.GetTestAdapterPath(), string.Empty, diff --git a/test/Microsoft.TestPlatform.AcceptanceTests/DiscoveryTests.cs b/test/Microsoft.TestPlatform.AcceptanceTests/DiscoveryTests.cs index d671d4d94c..155772fbd5 100644 --- a/test/Microsoft.TestPlatform.AcceptanceTests/DiscoveryTests.cs +++ b/test/Microsoft.TestPlatform.AcceptanceTests/DiscoveryTests.cs @@ -4,7 +4,13 @@ namespace Microsoft.TestPlatform.AcceptanceTests { using System; + using System.Collections.Generic; using System.IO; + using System.Linq; + using System.Reflection; + + using Microsoft.TestPlatform.TestUtilities; + using Microsoft.VisualStudio.TestPlatform.Common.Utilities; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] @@ -91,5 +97,31 @@ public void DiscoverTestsShouldShowProperWarningIfNoTestsOnTestCaseFilter(Runner this.ExitCodeEquals(0); } + + [TestMethod] + public void TypesToLoadAttributeTests() + { + var environment = new IntegrationTestEnvironment(); + var extensionsDirectory = environment.ExtensionsDirectory; + var extensionsToVerify = new Dictionary + { + {"Microsoft.TestPlatform.Extensions.EventLogCollector.dll", new[] { "Microsoft.TestPlatform.Extensions.EventLogCollector.EventLogDataCollector"} }, + {"Microsoft.TestPlatform.Extensions.BlameDataCollector.dll", new[] { "Microsoft.TestPlatform.Extensions.BlameDataCollector.BlameLogger", "Microsoft.TestPlatform.Extensions.BlameDataCollector.BlameCollector" } }, + {"Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger.dll", new[] { "Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger.HtmlLogger" } }, + {"Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger.dll", new[] { "Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger.TrxLogger" } }, + {"Microsoft.TestPlatform.TestHostRuntimeProvider.dll", new[] { "Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting.DefaultTestHostManager", "Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting.DotnetTestHostManager" } } + }; + + foreach (var extension in extensionsToVerify.Keys) + { + var assemblyFile = Path.Combine(extensionsDirectory, extension); + var assembly = Assembly.LoadFrom(assemblyFile); + + var expected = extensionsToVerify[extension]; + var actual = TypesToLoadUtilities.GetTypesToLoad(assembly).Select(i => i.FullName).ToArray(); + + CollectionAssert.AreEquivalent(expected, actual, $"Specified types using TypesToLoadAttribute in \"{extension}\" assembly doesn't match the expected."); + } + } } } diff --git a/test/Microsoft.TestPlatform.AcceptanceTests/DotnetTestTests.cs b/test/Microsoft.TestPlatform.AcceptanceTests/DotnetTestTests.cs new file mode 100644 index 0000000000..1743a747d5 --- /dev/null +++ b/test/Microsoft.TestPlatform.AcceptanceTests/DotnetTestTests.cs @@ -0,0 +1,79 @@ +// 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.TestPlatform.AcceptanceTests +{ + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class DotnetTestTests : AcceptanceTestBase + { + [TestMethod] + // patched dotnet is not published on non-windows systems + [TestCategory("Windows-Review")] + [NetCoreTargetFrameworkDataSource] + public void RunDotnetTestWithCsproj(RunnerInfo runnerInfo) + { + AcceptanceTestBase.SetTestEnvironment(this.testEnvironment, runnerInfo); + + var projectName = "SimpleTestProject.csproj"; + var projectPath = this.GetProjectFullPath(projectName); + + this.InvokeDotnetTest($@"{projectPath} --logger:""Console;Verbosity=normal"""); + + // ensure our dev version is used + this.StdOutputContains("-dev"); + this.ValidateSummaryStatus(1, 1, 1); + this.ExitCodeEquals(1); + } + + + [TestMethod] + // patched dotnet is not published on non-windows systems + [TestCategory("Windows-Review")] + [NetCoreTargetFrameworkDataSource] + public void RunDotnetTestWithDll(RunnerInfo runnerInfo) + { + AcceptanceTestBase.SetTestEnvironment(this.testEnvironment, runnerInfo); + + var assemblyPath = this.BuildMultipleAssemblyPath("SimpleTestProject.dll").Trim('\"'); + this.InvokeDotnetTest($@"{assemblyPath} --logger:""Console;Verbosity=normal"""); + + // ensure our dev version is used + this.StdOutputContains("-dev"); + this.ValidateSummaryStatus(1, 1, 1); + this.ExitCodeEquals(1); + } + + [TestMethod] + // patched dotnet is not published on non-windows systems + [TestCategory("Windows-Review")] + [NetCoreTargetFrameworkDataSource] + public void PassInlineSettings(RunnerInfo runnerInfo) + { + AcceptanceTestBase.SetTestEnvironment(this.testEnvironment, runnerInfo); + + var projectName = "ParametrizedTestProject.csproj"; + var projectPath = this.GetProjectFullPath(projectName); + this.InvokeDotnetTest($@"{projectPath} --logger:""Console;Verbosity=normal"" -- TestRunParameters.Parameter(name =\""weburl\"", value=\""http://localhost//def\"")"); + this.ValidateSummaryStatus(1, 0, 0); + this.ExitCodeEquals(0); + } + + [TestMethod] + // patched dotnet is not published on non-windows systems + [TestCategory("Windows-Review")] + [NetCoreTargetFrameworkDataSource] + public void PassInlineSettingsToDll(RunnerInfo runnerInfo) + { + + AcceptanceTestBase.SetTestEnvironment(this.testEnvironment, runnerInfo); + + var assemblyPath = this.BuildMultipleAssemblyPath("ParametrizedTestProject.dll").Trim('\"'); + this.InvokeDotnetTest($@"{assemblyPath} --logger:""Console;Verbosity=normal"" -- TestRunParameters.Parameter(name=\""weburl\"", value=\""http://localhost//def\"")"); + + this.ValidateSummaryStatus(1, 0, 0); + this.ExitCodeEquals(0); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.TestPlatform.AcceptanceTests/TestPlatformNugetPackageTests.cs b/test/Microsoft.TestPlatform.AcceptanceTests/TestPlatformNugetPackageTests.cs index 57ce0f7d8f..384215d185 100644 --- a/test/Microsoft.TestPlatform.AcceptanceTests/TestPlatformNugetPackageTests.cs +++ b/test/Microsoft.TestPlatform.AcceptanceTests/TestPlatformNugetPackageTests.cs @@ -25,8 +25,15 @@ public static void ClassInit(TestContext testContext) nugetPackageFolder = Path.Combine(packageLocation, Path.GetFileNameWithoutExtension(nugetPackage)); ZipFile.ExtractToDirectory(nugetPackage, nugetPackageFolder); - Directory.Move(Path.Combine(nugetPackageFolder, "tools", "net451", "Team%20Tools"), Path.Combine(nugetPackageFolder, "tools", "net451", "Team Tools")); - Directory.Move(Path.Combine(nugetPackageFolder, "tools", "net451", "Team Tools", "Dynamic%20Code%20Coverage%20Tools"), Path.Combine(nugetPackageFolder, "tools", "net451", "Team Tools", "Dynamic Code Coverage Tools")); + TryMoveDirectory( + sourceDirName: Path.Combine(nugetPackageFolder, "tools", "net451", "Team%20Tools"), + destDirName: Path.Combine(nugetPackageFolder, "tools", "net451", "Team Tools") + ); + + TryMoveDirectory( + sourceDirName: Path.Combine(nugetPackageFolder, "tools", "net451", "Team Tools", "Dynamic%20Code%20Coverage%20Tools"), + destDirName: Path.Combine(nugetPackageFolder, "tools", "net451", "Team Tools", "Dynamic Code Coverage Tools") + ); } [ClassCleanup] @@ -97,5 +104,13 @@ private string CreateCodeCoverageArguments( return arguments; } + + private static void TryMoveDirectory(string sourceDirName, string destDirName) + { + if (Directory.Exists(sourceDirName)) + { + Directory.Move(sourceDirName, destDirName); + } + } } } diff --git a/test/Microsoft.TestPlatform.AcceptanceTests/TranslationLayerTests/CodeCoverageTests.cs b/test/Microsoft.TestPlatform.AcceptanceTests/TranslationLayerTests/CodeCoverageTests.cs index 94fabb2a4b..462201a076 100644 --- a/test/Microsoft.TestPlatform.AcceptanceTests/TranslationLayerTests/CodeCoverageTests.cs +++ b/test/Microsoft.TestPlatform.AcceptanceTests/TranslationLayerTests/CodeCoverageTests.cs @@ -18,7 +18,11 @@ namespace Microsoft.TestPlatform.AcceptanceTests.TranslationLayerTests using Microsoft.VisualStudio.TestTools.UnitTesting; using Castle.Core.Internal; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; + [TestClass] + //Code coverage only supported on windows (based on the message in output) + [TestCategory("Windows-Review")] public class CodeCoverageTests : CodeCoverageAcceptanceTestBase { private IVsTestConsoleWrapper vstestConsoleWrapper; @@ -48,7 +52,7 @@ public void TestRunWithCodeCoverage(RunnerInfo runnerInfo) this.Setup(); // act - this.vstestConsoleWrapper.RunTests(this.GetTestAssemblies(), this.GetCodeCoverageRunSettings(1), this.runEventHandler); + this.vstestConsoleWrapper.RunTests(this.GetTestAssemblies(), this.GetCodeCoverageRunSettings(1), new TestPlatformOptions { CollectMetrics = true }, this.runEventHandler); // assert Assert.AreEqual(6, this.runEventHandler.TestResults.Count); @@ -57,6 +61,33 @@ public void TestRunWithCodeCoverage(RunnerInfo runnerInfo) Assert.AreEqual(expectedNumberOfAttachments, this.runEventHandler.Attachments.Count); AssertCoverageResults(this.runEventHandler.Attachments); + + Assert.AreEqual("e5f256dc-7959-4dd6-8e4f-c11150ab28e0", this.runEventHandler.Metrics["VS.TestPlatform.DataCollector.CorProfiler.datacollector://microsoft/CodeCoverage/2.0"]); + Assert.AreEqual("e5f256dc-7959-4dd6-8e4f-c11150ab28e0", this.runEventHandler.Metrics["VS.TestPlatform.DataCollector.CoreClrProfiler.datacollector://microsoft/CodeCoverage/2.0"]); + } + + [TestMethod] + [NetFullTargetFrameworkDataSource] + [NetCoreTargetFrameworkDataSource] + public void TestRunWithCodeCoverageUsingClrIe(RunnerInfo runnerInfo) + { + // arrange + AcceptanceTestBase.SetTestEnvironment(this.testEnvironment, runnerInfo); + this.Setup(); + + // act + this.vstestConsoleWrapper.RunTests(this.GetTestAssemblies(), this.GetCodeCoverageRunSettings(1, true), new TestPlatformOptions { CollectMetrics = true }, this.runEventHandler); + + // assert + Assert.AreEqual(6, this.runEventHandler.TestResults.Count); + + int expectedNumberOfAttachments = 1; + Assert.AreEqual(expectedNumberOfAttachments, this.runEventHandler.Attachments.Count); + + AssertCoverageResults(this.runEventHandler.Attachments); + + Assert.AreEqual("324f817a-7420-4e6d-b3c1-143fbed6d855", this.runEventHandler.Metrics["VS.TestPlatform.DataCollector.CorProfiler.datacollector://microsoft/CodeCoverage/2.0"]); + Assert.AreEqual("324f817a-7420-4e6d-b3c1-143fbed6d855", this.runEventHandler.Metrics["VS.TestPlatform.DataCollector.CoreClrProfiler.datacollector://microsoft/CodeCoverage/2.0"]); } [TestMethod] @@ -69,13 +100,16 @@ public void TestRunWithCodeCoverageParallel(RunnerInfo runnerInfo) this.Setup(); // act - this.vstestConsoleWrapper.RunTests(this.GetTestAssemblies(), this.GetCodeCoverageRunSettings(4), this.runEventHandler); + this.vstestConsoleWrapper.RunTests(this.GetTestAssemblies(), this.GetCodeCoverageRunSettings(4), new TestPlatformOptions { CollectMetrics = true }, this.runEventHandler); // assert Assert.AreEqual(6, this.runEventHandler.TestResults.Count); Assert.AreEqual(1, this.runEventHandler.Attachments.Count); AssertCoverageResults(this.runEventHandler.Attachments); + + Assert.AreEqual("e5f256dc-7959-4dd6-8e4f-c11150ab28e0", this.runEventHandler.Metrics["VS.TestPlatform.DataCollector.CorProfiler.datacollector://microsoft/CodeCoverage/2.0"]); + Assert.AreEqual("e5f256dc-7959-4dd6-8e4f-c11150ab28e0", this.runEventHandler.Metrics["VS.TestPlatform.DataCollector.CoreClrProfiler.datacollector://microsoft/CodeCoverage/2.0"]); } [TestMethod] @@ -124,7 +158,7 @@ public async Task TestRunWithCodeCoverageAndAttachmentsProcessing(RunnerInfo run Assert.IsTrue(testRunAttachmentsProcessingEventHandler.CompleteArgs.Metrics.ContainsKey(TelemetryDataConstants.TimeTakenInSecForAttachmentsProcessing)); Assert.IsTrue(File.Exists(runEventHandler.Attachments.First().Attachments.First().Uri.LocalPath)); - Assert.IsTrue(File.Exists(runEventHandler.Attachments.Last().Attachments.First().Uri.LocalPath) != testEnvironment.RunnerFramework.Equals(IntegrationTestBase.DesktopRunnerFramework)); + Assert.IsTrue(!File.Exists(runEventHandler.Attachments.Last().Attachments.First().Uri.LocalPath)); } [TestMethod] @@ -170,7 +204,7 @@ public async Task TestRunWithCodeCoverageAndAttachmentsProcessingNoMetrics(Runne Assert.IsTrue(testRunAttachmentsProcessingEventHandler.CompleteArgs.Metrics.IsNullOrEmpty()); Assert.IsTrue(File.Exists(runEventHandler.Attachments.First().Attachments.First().Uri.LocalPath)); - Assert.IsTrue(File.Exists(runEventHandler.Attachments.Last().Attachments.First().Uri.LocalPath) != testEnvironment.RunnerFramework.Equals(IntegrationTestBase.DesktopRunnerFramework)); + Assert.IsTrue(!File.Exists(runEventHandler.Attachments.Last().Attachments.First().Uri.LocalPath)); } [TestMethod] @@ -220,76 +254,7 @@ public async Task TestRunWithCodeCoverageAndAttachmentsProcessingModuleDuplicate Assert.IsTrue(testRunAttachmentsProcessingEventHandler.CompleteArgs.Metrics.ContainsKey(TelemetryDataConstants.TimeTakenInSecForAttachmentsProcessing)); Assert.IsTrue(File.Exists(runEventHandler.Attachments.First().Attachments.First().Uri.LocalPath)); - Assert.IsTrue(File.Exists(runEventHandler.Attachments.Last().Attachments.First().Uri.LocalPath) != testEnvironment.RunnerFramework.Equals(IntegrationTestBase.DesktopRunnerFramework)); - } - - [TestMethod] - [NetFullTargetFrameworkDataSource] - [NetCoreTargetFrameworkDataSource] - public async Task TestRunWithCodeCoverageAndAttachmentsProcessingCancelled(RunnerInfo runnerInfo) - { - // arrange - AcceptanceTestBase.SetTestEnvironment(this.testEnvironment, runnerInfo); - this.Setup(); - - if (!testEnvironment.RunnerFramework.Equals(IntegrationTestBase.DesktopRunnerFramework)) return; - - this.vstestConsoleWrapper.RunTests(this.GetTestAssemblies().Take(1), this.GetCodeCoverageRunSettings(1), this.runEventHandler); - Assert.AreEqual(3, this.runEventHandler.TestResults.Count); - Assert.AreEqual(1, this.runEventHandler.Attachments.Count); - - List attachments = Enumerable.Range(0, 1000).Select(i => this.runEventHandler.Attachments.First()).ToList(); - - CancellationTokenSource cts = new CancellationTokenSource(); - - Task attachmentsProcessing = this.vstestConsoleWrapper.ProcessTestRunAttachmentsAsync(attachments, null, true, true, testRunAttachmentsProcessingEventHandler, cts.Token); - - while (true) - { - try - { - if (testRunAttachmentsProcessingEventHandler.ProgressArgs.Count >= 3) - break; - } - catch - { - // ignore - } - await Task.Delay(100); - } - - // act - cts.Cancel(); - - // Assert - await attachmentsProcessing; - testRunAttachmentsProcessingEventHandler.EnsureSuccess(); - - Assert.AreEqual(1000, this.testRunAttachmentsProcessingEventHandler.Attachments.Count); - - Assert.IsTrue(testRunAttachmentsProcessingEventHandler.CompleteArgs.IsCanceled); - Assert.IsNull(testRunAttachmentsProcessingEventHandler.CompleteArgs.Error); - - Assert.IsTrue(3 <= testRunAttachmentsProcessingEventHandler.ProgressArgs.Count); - for (int i = 0; i < testRunAttachmentsProcessingEventHandler.ProgressArgs.Count; i++) - { - VisualStudio.TestPlatform.ObjectModel.Client.TestRunAttachmentsProcessingProgressEventArgs progressArgs = testRunAttachmentsProcessingEventHandler.ProgressArgs[i]; - Assert.AreEqual(1, progressArgs.CurrentAttachmentProcessorIndex); - Assert.AreEqual("datacollector://microsoft/CodeCoverage/2.0", progressArgs.CurrentAttachmentProcessorUris.First().AbsoluteUri); - Assert.AreEqual(1, progressArgs.AttachmentProcessorsCount); - - if (i == 0) - { - Assert.AreEqual(0, progressArgs.CurrentAttachmentProcessorProgress); - } - } - - Assert.AreEqual("Canceled", testRunAttachmentsProcessingEventHandler.CompleteArgs.Metrics[TelemetryDataConstants.AttachmentsProcessingState]); - Assert.AreEqual(1000L, testRunAttachmentsProcessingEventHandler.CompleteArgs.Metrics[TelemetryDataConstants.NumberOfAttachmentsSentForProcessing]); - Assert.AreEqual(1000L, testRunAttachmentsProcessingEventHandler.CompleteArgs.Metrics[TelemetryDataConstants.NumberOfAttachmentsAfterProcessing]); - Assert.IsTrue(testRunAttachmentsProcessingEventHandler.CompleteArgs.Metrics.ContainsKey(TelemetryDataConstants.TimeTakenInSecForAttachmentsProcessing)); - - Assert.IsTrue(File.Exists(runEventHandler.Attachments.First().Attachments.First().Uri.LocalPath)); + Assert.IsTrue(!File.Exists(runEventHandler.Attachments.Last().Attachments.First().Uri.LocalPath)); } [TestMethod] @@ -333,19 +298,21 @@ private IList GetProjects() /// Default RunSettings /// /// - private string GetCodeCoverageRunSettings(int cpuCount) + private string GetCodeCoverageRunSettings(int cpuCount, bool useClrIeInstrumentationEngine = false) { string runSettingsXml = $@" {FrameworkArgValue} - {this.GetCodeCoveragePath()} + {this.GetNetStandardAdapterPath()} {cpuCount} + {useClrIeInstrumentationEngine} + {useClrIeInstrumentationEngine} diff --git a/test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/FindMethodExtensions.cs b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/FindMethodExtensions.cs similarity index 97% rename from test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/FindMethodExtensions.cs rename to test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/FindMethodExtensions.cs index dee213e414..8455bcb5f2 100644 --- a/test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/FindMethodExtensions.cs +++ b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/FindMethodExtensions.cs @@ -1,7 +1,7 @@ // 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.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests +namespace Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.UnitTests { using Microsoft.CodeAnalysis; diff --git a/test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/ManagedNameParserTests.cs b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/ManagedNameParserTests.cs similarity index 82% rename from test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/ManagedNameParserTests.cs rename to test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/ManagedNameParserTests.cs index b56b54774c..5747d460da 100644 --- a/test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/ManagedNameParserTests.cs +++ b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/ManagedNameParserTests.cs @@ -1,9 +1,9 @@ // 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.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests +namespace Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.UnitTests { - using Microsoft.VisualStudio.TestPlatform.ObjectModel.ManagedNameUtilities; + using Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] @@ -12,9 +12,9 @@ public class ManagedNameParserTests [TestMethod] public void ParseTypeName() { - (string, string) Parse(string fullTypeName) + (string, string) Parse(string managedTypeName) { - ManagedNameParser.ParseTypeName(fullTypeName, out var namespaceName, out var typeName); + ManagedNameParser.ParseManagedTypeName(managedTypeName, out var namespaceName, out var typeName); return (namespaceName, typeName); }; @@ -29,9 +29,9 @@ public void ParseTypeName() [TestMethod] public void ParseMethodName() { - (string, int, string[]) Parse(string methodName) + (string, int, string[]) Parse(string managedMethodName) { - ManagedNameParser.ParseMethodName(methodName, out var method, out var arity, out var parameterTypes); + ManagedNameParser.ParseManagedMethodName(managedMethodName, out var method, out var arity, out var parameterTypes); return (method, arity, parameterTypes); } @@ -58,7 +58,7 @@ public void ParseInvalidMethodName() { (string, int, string[]) Parse(string methodName) { - ManagedNameParser.ParseMethodName(methodName, out var method, out var arity, out var parameterTypes); + ManagedNameParser.ParseManagedMethodName(methodName, out var method, out var arity, out var parameterTypes); return (method, arity, parameterTypes); } diff --git a/test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/ManagedNameRoundTripTests.cs b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/ManagedNameRoundTripTests.cs similarity index 80% rename from test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/ManagedNameRoundTripTests.cs rename to test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/ManagedNameRoundTripTests.cs index bc69a9dcc1..5ff18ae6ad 100644 --- a/test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/ManagedNameRoundTripTests.cs +++ b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/ManagedNameRoundTripTests.cs @@ -1,11 +1,11 @@ // 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.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests +namespace Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.UnitTests { using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; - using Microsoft.VisualStudio.TestPlatform.ObjectModel.ManagedNameUtilities; + using Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.IO; @@ -35,8 +35,8 @@ public void Simple1() methodInfo: typeof(TestClasses.Outer).GetMethod("Method0"), containingTypeSymbol: outer, methodSymbol: outer.FindMethod("Method0"), - fullTypeName: "TestClasses.Outer", - fullMethodName: "Method0"); + managedTypeName: "TestClasses.Outer", + managedMethodName: "Method0"); } [TestMethod] @@ -48,8 +48,8 @@ public void Simple2() methodInfo: typeof(TestClasses.Outer).GetMethod("Method1"), containingTypeSymbol: outer, methodSymbol: outer.FindMethod("Method1"), - fullTypeName: "TestClasses.Outer", - fullMethodName: "Method1(System.Int32)"); + managedTypeName: "TestClasses.Outer", + managedMethodName: "Method1(System.Int32)"); } [TestMethod] @@ -61,8 +61,8 @@ public void Simple3() methodInfo: typeof(TestClasses.Outer).GetMethod("Method2"), containingTypeSymbol: outer, methodSymbol: outer.FindMethod("Method2"), - fullTypeName: "TestClasses.Outer", - fullMethodName: "Method2(System.Collections.Generic.List`1)"); + managedTypeName: "TestClasses.Outer", + managedMethodName: "Method2(System.Collections.Generic.List`1)"); } [TestMethod] @@ -74,8 +74,8 @@ public void Simple4() methodInfo: typeof(TestClasses.Outer).GetMethod("Method3"), containingTypeSymbol: outer, methodSymbol: outer.FindMethod("Method3"), - fullTypeName: "TestClasses.Outer", - fullMethodName: "Method3(System.String,System.Int32)"); + managedTypeName: "TestClasses.Outer", + managedMethodName: "Method3(System.String,System.Int32)"); } [TestMethod] @@ -87,8 +87,8 @@ public void Nested1() methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method0"), containingTypeSymbol: outerInner, methodSymbol: outerInner.FindMethod("Method0"), - fullTypeName: "TestClasses.Outer+Inner", - fullMethodName: "Method0"); + managedTypeName: "TestClasses.Outer+Inner", + managedMethodName: "Method0"); } [TestMethod] @@ -100,8 +100,8 @@ public void Nested2() methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method1"), containingTypeSymbol: outerInner, methodSymbol: outerInner.FindMethod("Method1"), - fullTypeName: "TestClasses.Outer+Inner", - fullMethodName: "Method1(System.Int32)"); + managedTypeName: "TestClasses.Outer+Inner", + managedMethodName: "Method1(System.Int32)"); } [TestMethod] @@ -113,8 +113,8 @@ public void OpenGeneric1() methodInfo: typeof(TestClasses.Outer<>).GetMethod("Method0"), containingTypeSymbol: outerT, methodSymbol: outerT.FindMethod("Method0"), - fullTypeName: "TestClasses.Outer`1", - fullMethodName: "Method0"); + managedTypeName: "TestClasses.Outer`1", + managedMethodName: "Method0"); } [TestMethod] @@ -126,8 +126,8 @@ public void OpenGeneric2() methodInfo: typeof(TestClasses.Outer<>).GetMethod("Method1"), containingTypeSymbol: outerT, methodSymbol: outerT.FindMethod("Method1"), - fullTypeName: "TestClasses.Outer`1", - fullMethodName: "Method1(!0)"); + managedTypeName: "TestClasses.Outer`1", + managedMethodName: "Method1(!0)"); } [TestMethod] @@ -139,8 +139,8 @@ public void OpenGeneric3() methodInfo: typeof(TestClasses.Outer<>).GetMethod("Method2"), containingTypeSymbol: outerT, methodSymbol: outerT.FindMethod("Method2"), - fullTypeName: "TestClasses.Outer`1", - fullMethodName: "Method2`1(!!0[])"); + managedTypeName: "TestClasses.Outer`1", + managedMethodName: "Method2`1(!!0[])"); } [TestMethod] @@ -152,8 +152,8 @@ public void OpenGeneric4() methodInfo: typeof(TestClasses.Outer<>).GetMethod("Method3"), containingTypeSymbol: outerT, methodSymbol: outerT.FindMethod("Method3"), - fullTypeName: "TestClasses.Outer`1", - fullMethodName: "Method3`1(!0,!!0)"); + managedTypeName: "TestClasses.Outer`1", + managedMethodName: "Method3`1(!0,!!0)"); } [TestMethod] @@ -165,8 +165,8 @@ public void OpenGenericNested1() methodInfo: typeof(TestClasses.Outer<>.Inner<>).GetMethod("Method0"), containingTypeSymbol: outerTInnterV, methodSymbol: outerTInnterV.FindMethod("Method0"), - fullTypeName: "TestClasses.Outer`1+Inner`1", - fullMethodName: "Method0"); + managedTypeName: "TestClasses.Outer`1+Inner`1", + managedMethodName: "Method0"); } [TestMethod] @@ -178,8 +178,8 @@ public void OpenGenericNested2() methodInfo: typeof(TestClasses.Outer<>.Inner<>).GetMethod("Method1"), containingTypeSymbol: outerTInnterV, methodSymbol: outerTInnterV.FindMethod("Method1"), - fullTypeName: "TestClasses.Outer`1+Inner`1", - fullMethodName: "Method1(!0)"); + managedTypeName: "TestClasses.Outer`1+Inner`1", + managedMethodName: "Method1(!0)"); } [TestMethod] @@ -191,8 +191,8 @@ public void OpenGenericNested3() methodInfo: typeof(TestClasses.Outer<>.Inner<>).GetMethod("Method2"), containingTypeSymbol: outerTInnterV, methodSymbol: outerTInnterV.FindMethod("Method2"), - fullTypeName: "TestClasses.Outer`1+Inner`1", - fullMethodName: "Method2(!1)"); + managedTypeName: "TestClasses.Outer`1+Inner`1", + managedMethodName: "Method2(!1)"); } [TestMethod] @@ -204,8 +204,8 @@ public void OpenGenericNested4() methodInfo: typeof(TestClasses.Outer<>.Inner<>).GetMethod("Method3"), containingTypeSymbol: outerTInnterV, methodSymbol: outerTInnterV.FindMethod("Method3"), - fullTypeName: "TestClasses.Outer`1+Inner`1", - fullMethodName: "Method3`1(!0,!!0,!1)"); + managedTypeName: "TestClasses.Outer`1+Inner`1", + managedMethodName: "Method3`1(!0,!!0,!1)"); } [TestMethod] @@ -217,8 +217,8 @@ public void OpenGenericNested5() methodInfo: typeof(TestClasses.Outer<>.Inner<>).GetMethod("Method4"), containingTypeSymbol: outerTInnterV, methodSymbol: outerTInnterV.FindMethod("Method4"), - fullTypeName: "TestClasses.Outer`1+Inner`1", - fullMethodName: "Method4`2(!!1,!!0)"); + managedTypeName: "TestClasses.Outer`1+Inner`1", + managedMethodName: "Method4`2(!!1,!!0)"); } [TestMethod] @@ -230,8 +230,8 @@ public void OpenGenericNested6() methodInfo: typeof(TestClasses.Outer<>.Inner<>.MoreInner<>).GetMethod("Method0"), containingTypeSymbol: outerTInnerVMoreInnerI, methodSymbol: outerTInnerVMoreInnerI.FindMethod("Method0"), - fullTypeName: "TestClasses.Outer`1+Inner`1+MoreInner`1", - fullMethodName: "Method0`1(!0,!1,!2,!!0)"); + managedTypeName: "TestClasses.Outer`1+Inner`1+MoreInner`1", + managedMethodName: "Method0`1(!0,!1,!2,!!0)"); } [TestMethod] @@ -244,8 +244,8 @@ public void ClosedGeneric1() methodInfo: typeof(TestClasses.Outer).GetMethod("Method0"), containingTypeSymbol: outerTInt, methodSymbol: outerTInt.FindMethod("Method0"), - fullTypeName: "TestClasses.Outer`1", - fullMethodName: "Method0"); + managedTypeName: "TestClasses.Outer`1", + managedMethodName: "Method0"); } [TestMethod] @@ -258,8 +258,8 @@ public void ClosedGeneric2() methodInfo: typeof(TestClasses.Outer).GetMethod("Method1"), containingTypeSymbol: outerTInt, methodSymbol: outerTInt.FindMethod("Method1"), - fullTypeName: "TestClasses.Outer`1", - fullMethodName: "Method1(!0)"); + managedTypeName: "TestClasses.Outer`1", + managedMethodName: "Method1(!0)"); } [TestMethod] @@ -272,8 +272,8 @@ public void ClosedGeneric3() methodInfo: typeof(TestClasses.Outer).GetMethod("Method2"), containingTypeSymbol: outerTInt, methodSymbol: outerTInt.FindMethod("Method2"), - fullTypeName: "TestClasses.Outer`1", - fullMethodName: "Method2`1(!!0[])"); + managedTypeName: "TestClasses.Outer`1", + managedMethodName: "Method2`1(!!0[])"); } [TestMethod] @@ -286,8 +286,8 @@ public void ClosedGeneric4() methodInfo: typeof(TestClasses.Outer).GetMethod("Method3"), containingTypeSymbol: outerTInt, methodSymbol: outerTInt.FindMethod("Method3"), - fullTypeName: "TestClasses.Outer`1", - fullMethodName: "Method3`1(!0,!!0)"); + managedTypeName: "TestClasses.Outer`1", + managedMethodName: "Method3`1(!0,!!0)"); } [TestMethod] @@ -302,8 +302,8 @@ public void ClosedGenericNested1() methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method0"), containingTypeSymbol: outerTIntInnerVString, methodSymbol: outerTIntInnerVString.FindMethod("Method0"), - fullTypeName: "TestClasses.Outer`1+Inner`1", - fullMethodName: "Method0"); + managedTypeName: "TestClasses.Outer`1+Inner`1", + managedMethodName: "Method0"); } [TestMethod] @@ -318,8 +318,8 @@ public void ClosedGenericNested2() methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method1"), containingTypeSymbol: outerTIntInnerVString, methodSymbol: outerTIntInnerVString.FindMethod("Method1"), - fullTypeName: "TestClasses.Outer`1+Inner`1", - fullMethodName: "Method1(!0)"); + managedTypeName: "TestClasses.Outer`1+Inner`1", + managedMethodName: "Method1(!0)"); } [TestMethod] @@ -334,8 +334,8 @@ public void ClosedGenericNested3() methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method2"), containingTypeSymbol: outerTIntInnerVString, methodSymbol: outerTIntInnerVString.FindMethod("Method2"), - fullTypeName: "TestClasses.Outer`1+Inner`1", - fullMethodName: "Method2(!1)"); + managedTypeName: "TestClasses.Outer`1+Inner`1", + managedMethodName: "Method2(!1)"); } [TestMethod] @@ -350,8 +350,8 @@ public void ClosedGenericNested4() methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method3"), containingTypeSymbol: outerTIntInnerVString, methodSymbol: outerTIntInnerVString.FindMethod("Method3"), - fullTypeName: "TestClasses.Outer`1+Inner`1", - fullMethodName: "Method3`1(!0,!!0,!1)"); + managedTypeName: "TestClasses.Outer`1+Inner`1", + managedMethodName: "Method3`1(!0,!!0,!1)"); } [TestMethod] @@ -366,8 +366,8 @@ public void ClosedGenericNested5() methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method4"), containingTypeSymbol: outerTIntInnerVString, methodSymbol: outerTIntInnerVString.FindMethod("Method4"), - fullTypeName: "TestClasses.Outer`1+Inner`1", - fullMethodName: "Method4`2(!!1,!!0)"); + managedTypeName: "TestClasses.Outer`1+Inner`1", + managedMethodName: "Method4`2(!!1,!!0)"); } [TestMethod] @@ -381,8 +381,8 @@ public void ClosedGenericMethod1() methodInfo: typeof(TestClasses.Outer).GetMethod("Method3").MakeGenericMethod(typeof(string)), containingTypeSymbol: outerTInt, methodSymbol: outerTInt.FindMethod("Method3").Construct(@string), - fullTypeName: "TestClasses.Outer`1", - fullMethodName: "Method3`1(!0,!!0)"); + managedTypeName: "TestClasses.Outer`1", + managedMethodName: "Method3`1(!0,!!0)"); } [TestMethod] @@ -395,8 +395,8 @@ public void ClosedGenericMethod2() methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method2").MakeGenericMethod(typeof(int)), containingTypeSymbol: outerInner, methodSymbol: outerInner.FindMethod("Method2").Construct(@int), - fullTypeName: "TestClasses.Outer+Inner", - fullMethodName: "Method2`1(System.Int32)"); + managedTypeName: "TestClasses.Outer+Inner", + managedMethodName: "Method2`1(System.Int32)"); } [TestMethod] @@ -411,8 +411,8 @@ public void ClosedGenericMethod3() methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method3").MakeGenericMethod(typeof(float), typeof(string)), containingTypeSymbol: outerInner, methodSymbol: outerInner.FindMethod("Method3").Construct(@float, @string), - fullTypeName: "TestClasses.Outer+Inner", - fullMethodName: "Method3`2(System.Int32)"); + managedTypeName: "TestClasses.Outer+Inner", + managedMethodName: "Method3`2(System.Int32)"); } [TestMethod] @@ -424,8 +424,8 @@ public void ExplicitInterfaceImplementation1() methodInfo: typeof(TestClasses.Impl).GetMethod("TestClasses.IImplementation.ImplMethod0", PrivateBindingFlags), containingTypeSymbol: impl, methodSymbol: impl.FindMethod("TestClasses.IImplementation.ImplMethod0"), - fullTypeName: "TestClasses.Impl", - fullMethodName: "TestClasses.IImplementation.ImplMethod0"); + managedTypeName: "TestClasses.Impl", + managedMethodName: "TestClasses.IImplementation.ImplMethod0"); } [TestMethod] @@ -437,8 +437,8 @@ public void ExplicitInterfaceImplementation2() methodInfo: typeof(TestClasses.Impl).GetMethod("TestClasses.IImplementation.ImplMethod1", PrivateBindingFlags), containingTypeSymbol: impl, methodSymbol: impl.FindMethod("TestClasses.IImplementation.ImplMethod1"), - fullTypeName: "TestClasses.Impl", - fullMethodName: "TestClasses.IImplementation.ImplMethod1(System.Int32)"); + managedTypeName: "TestClasses.Impl", + managedMethodName: "TestClasses.IImplementation.ImplMethod1(System.Int32)"); } [TestMethod] @@ -450,8 +450,8 @@ public void GenericExplicitInterfaceImplementation1() methodInfo: typeof(TestClasses.Impl<>).GetMethod("TestClasses.IImplementation.ImplMethod0", PrivateBindingFlags), containingTypeSymbol: implT, methodSymbol: implT.FindMethod("TestClasses.IImplementation.ImplMethod0"), - fullTypeName: "TestClasses.Impl`1", - fullMethodName: "TestClasses.IImplementation.ImplMethod0"); + managedTypeName: "TestClasses.Impl`1", + managedMethodName: "TestClasses.IImplementation.ImplMethod0"); } [TestMethod] @@ -463,8 +463,8 @@ public void GenericExplicitInterfaceImplementation2() methodInfo: typeof(TestClasses.Impl<>).GetMethod("TestClasses.IImplementation.ImplMethod1", PrivateBindingFlags), containingTypeSymbol: implT, methodSymbol: implT.FindMethod("TestClasses.IImplementation.ImplMethod1"), - fullTypeName: "TestClasses.Impl`1", - fullMethodName: "TestClasses.IImplementation.ImplMethod1(!0)"); + managedTypeName: "TestClasses.Impl`1", + managedMethodName: "TestClasses.IImplementation.ImplMethod1(!0)"); } [TestMethod] @@ -476,8 +476,8 @@ public void GenericExplicitInterfaceImplementation3() methodInfo: typeof(TestClasses.Impl<>).GetMethod("TestClasses.IImplementation.ImplMethod2", PrivateBindingFlags), containingTypeSymbol: implT, methodSymbol: implT.FindMethod("TestClasses.IImplementation.ImplMethod2"), - fullTypeName: "TestClasses.Impl`1", - fullMethodName: "TestClasses.IImplementation.ImplMethod2`1(!0,!!0,System.String)"); + managedTypeName: "TestClasses.Impl`1", + managedMethodName: "TestClasses.IImplementation.ImplMethod2`1(!0,!!0,System.String)"); } [TestMethod] @@ -489,8 +489,8 @@ public void Inheritance1() methodInfo: typeof(TestClasses.OuterPrime).GetMethod("Method3"), containingTypeSymbol: outerPrime, methodSymbol: outerPrime.FindMethod("Method3"), - fullTypeName: "TestClasses.OuterPrime", - fullMethodName: "Method3(System.String,System.Int32)"); + managedTypeName: "TestClasses.OuterPrime", + managedMethodName: "Method3(System.String,System.Int32)"); } [TestMethod] @@ -502,8 +502,8 @@ public void Inheritance2() methodInfo: typeof(TestClasses.OuterPrime<>).GetMethod("Method3"), containingTypeSymbol: outerPrimeZ, methodSymbol: outerPrimeZ.FindMethod("Method3"), - fullTypeName: "TestClasses.OuterPrime`1", - fullMethodName: "Method3`1(!0,!!0)"); + managedTypeName: "TestClasses.OuterPrime`1", + managedMethodName: "Method3`1(!0,!!0)"); } [TestMethod] @@ -515,8 +515,8 @@ public void Inheritance3() methodInfo: typeof(TestClasses.OuterPrime<,>).GetMethod("Method3"), containingTypeSymbol: outerPrimeYZ, methodSymbol: outerPrimeYZ.FindMethod("Method3"), - fullTypeName: "TestClasses.OuterPrime`2", - fullMethodName: "Method3`1(!1,!!0)"); + managedTypeName: "TestClasses.OuterPrime`2", + managedMethodName: "Method3`1(!1,!!0)"); } [TestMethod] @@ -528,8 +528,8 @@ public void Inheritance4() methodInfo: typeof(TestClasses.OuterString).GetMethod("Method3"), containingTypeSymbol: outerString, methodSymbol: outerString.FindMethod("Method3"), - fullTypeName: "TestClasses.OuterString", - fullMethodName: "Method3`1(System.String,!!0)"); + managedTypeName: "TestClasses.OuterString", + managedMethodName: "Method3`1(System.String,!!0)"); } [TestMethod] @@ -541,8 +541,8 @@ public void Overloads1() methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0()"), containingTypeSymbol: overloads, methodSymbol: overloads.FindMethod("Overload0", 0), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0"); } [TestMethod] @@ -555,8 +555,8 @@ public void Overloads2() methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0(Int32)"), containingTypeSymbol: overloads, methodSymbol: overloads.FindMethod("Overload0", 0, @int), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0(System.Int32)"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0(System.Int32)"); } [TestMethod] @@ -569,8 +569,8 @@ public void Overloads3() methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0(Int32, TestClasses.Overloads)"), containingTypeSymbol: overloads, methodSymbol: overloads.FindMethod("Overload0", 0, @int, overloads), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0(System.Int32,TestClasses.Overloads)"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0(System.Int32,TestClasses.Overloads)"); } [TestMethod] @@ -584,8 +584,8 @@ public void Overloads4() methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0(Int32*)"), containingTypeSymbol: overloads, methodSymbol: overloads.FindMethod("Overload0", 0, intptr), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0(System.Int32*)"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0(System.Int32*)"); } [TestMethod] @@ -598,8 +598,8 @@ public void Overloads5() methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0(System.Object)"), containingTypeSymbol: overloads, methodSymbol: overloads.FindMethod("Overload0", 0, dynamic), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0(System.Object)"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0(System.Object)"); } [TestMethod] @@ -611,8 +611,8 @@ public void Overloads6() methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U](U)"), containingTypeSymbol: overloads, methodSymbol: overloads.FindMethod("Overload0", 1, 1, m => m.Parameters.Single().Type == m.TypeParameters.Single()), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0`1(!!0)"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0`1(!!0)"); } [TestMethod] @@ -624,8 +624,8 @@ public void Overloads7() methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U]()"), containingTypeSymbol: overloads, methodSymbol: overloads.FindMethod("Overload0", 1), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0`1"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0`1"); } [TestMethod] @@ -637,8 +637,8 @@ public void Overloads8() methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U,T]()"), containingTypeSymbol: overloads, methodSymbol: overloads.FindMethod("Overload0", 2), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0`2"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0`2"); } [TestMethod] @@ -653,8 +653,8 @@ public void Overloads9() m => m.Parameters.Single().Type is IArrayTypeSymbol arrayType && arrayType.Rank == 1 && arrayType.ElementType == m.TypeParameters.Single()), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0`1(!!0[])"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0`1(!!0[])"); } [TestMethod] @@ -671,8 +671,8 @@ public void Overloads10() arrayType.ElementType is IArrayTypeSymbol innerArrayType && innerArrayType.Rank == 1 && innerArrayType.ElementType == m.TypeParameters.Single()), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0`1(!!0[][])"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0`1(!!0[][])"); } [TestMethod] @@ -687,8 +687,8 @@ public void Overloads11() m => m.Parameters.Single().Type is IArrayTypeSymbol arrayType && arrayType.Rank == 2 && arrayType.ElementType == m.TypeParameters.Single()), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0`1(!!0[,])"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0`1(!!0[,])"); } [TestMethod] @@ -703,8 +703,8 @@ public void Overloads12() m => m.Parameters.Single().Type is IArrayTypeSymbol arrayType && arrayType.Rank == 3 && arrayType.ElementType == m.TypeParameters.Single()), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0`1(!!0[,,])"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0`1(!!0[,,])"); } [TestMethod] @@ -718,8 +718,8 @@ public void Overloads13() methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U](System.Collections.Generic.List`1[System.Int32])"), containingTypeSymbol: overloads, methodSymbol: overloads.FindMethod("Overload0", 1, listInt), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0`1(System.Collections.Generic.List`1)"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0`1(System.Collections.Generic.List`1)"); } [TestMethod] @@ -736,8 +736,8 @@ public void Overloads14() m.Parameters.Single().Type is INamedTypeSymbol p && p.OriginalDefinition == list && p.TypeArguments.Single() == m.TypeParameters.Single()), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0`1(System.Collections.Generic.List`1)"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0`1(System.Collections.Generic.List`1)"); } [TestMethod] @@ -757,8 +757,8 @@ public void Overloads15() m.Parameters.Last() is INamedTypeSymbol p2 && p2.OriginalDefinition == tuple2 && p2.TypeArguments.SequenceEqual(m.TypeParameters.Reverse())), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0`2(System.Tuple`2,System.Tuple`2)"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0`2(System.Tuple`2,System.Tuple`2)"); } [TestMethod] @@ -777,8 +777,8 @@ public void Overloads16() p.OriginalDefinition == tuple1 && p.TypeArguments.Single() is INamedTypeSymbol t && t.OriginalDefinition == tuple2), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0(System.Tuple`1>)"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0(System.Tuple`1>)"); } [TestMethod] @@ -796,8 +796,8 @@ public void Overloads17() m.Parameters.Single().Type is INamedTypeSymbol p && p.OriginalDefinition == tuple2 && p.TypeArguments.All(t => t.OriginalDefinition == tuple1)), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0(System.Tuple`2,System.Tuple`1>)"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0(System.Tuple`2,System.Tuple`1>)"); } [TestMethod] @@ -815,8 +815,8 @@ public void Overloads18() p.OriginalDefinition == tuple1 && p.TypeArguments.Single() is INamedTypeSymbol t && t.OriginalDefinition == tuple1), - fullTypeName: "TestClasses.Overloads", - fullMethodName: "Overload0`1(System.Tuple`1>>)"); + managedTypeName: "TestClasses.Overloads", + managedMethodName: "Overload0`1(System.Tuple`1>>)"); } #region Helpers @@ -824,45 +824,45 @@ private void VerifyRoundTrip( MethodInfo methodInfo, INamedTypeSymbol containingTypeSymbol, IMethodSymbol methodSymbol, - string fullTypeName, - string fullMethodName) + string managedTypeName, + string managedMethodName) { - VerifyRoundTripFromMethodInfo(methodInfo, fullTypeName, fullMethodName); - VerifyRoundTripFromName(fullTypeName, fullMethodName, methodInfo); - // VerifyRoundTripFromMethodSymbol(containingTypeSymbol, methodSymbol, fullTypeName, fullMethodName); - // VerifyRoundTripFromName(fullTypeName, fullMethodName, containingTypeSymbol, methodSymbol); + VerifyRoundTripFromMethodInfo(methodInfo, managedTypeName, managedMethodName); + VerifyRoundTripFromName(managedTypeName, managedMethodName, methodInfo); + // VerifyRoundTripFromMethodSymbol(containingTypeSymbol, methodSymbol, managedTypeName, managedMethodName); + // VerifyRoundTripFromName(managedTypeName, managedMethodName, containingTypeSymbol, methodSymbol); } private void VerifyRoundTripFromMethodInfo( MethodInfo methodInfo, - string expectedFullTypeName, - string expectedFullMethodName) + string expectedManagedTypeName, + string expectedManagedMethodName) { // Generate the fqn for the Reflection MethodInfo - ManagedNameHelper.GetManagedName(methodInfo, out var fullTypeName, out var fullMethodName); + ManagedNameHelper.GetManagedName(methodInfo, out var managedTypeName, out var managedMethodName); - Assert.AreEqual(expectedFullTypeName, fullTypeName); - Assert.AreEqual(expectedFullMethodName, fullMethodName); + Assert.AreEqual(expectedManagedTypeName, managedTypeName); + Assert.AreEqual(expectedManagedMethodName, managedMethodName); // Lookup the Reflection MethodInfo using fullTypeName and fullMethodName - var roundTrippedMethodInfo = ManagedNameHelper.GetManagedName( + var roundTrippedMethodInfo = ManagedNameHelper.GetMethod( Assembly.GetExecutingAssembly(), - fullTypeName, - fullMethodName); + managedTypeName, + managedMethodName); Assert.AreEqual(methodInfo.MetadataToken, roundTrippedMethodInfo.MetadataToken); } private void VerifyRoundTripFromName( - string fullTypeName, - string fullMethodName, + string managedTypeName, + string managedMethodName, MethodInfo expectedMethodInfo) { // Lookup the Reflection MethodInfo using fullTypeName and fullMethodName - var methodInfo = ManagedNameHelper.GetManagedName( + var methodInfo = ManagedNameHelper.GetMethod( Assembly.GetExecutingAssembly(), - fullTypeName, - fullMethodName); + managedTypeName, + managedMethodName); Assert.AreEqual(expectedMethodInfo.MetadataToken, methodInfo.MetadataToken); @@ -872,8 +872,8 @@ private void VerifyRoundTripFromName( out var roundTrippedFullTypeName, out var roundTrippedFullMethodName); - Assert.AreEqual(fullTypeName, roundTrippedFullTypeName); - Assert.AreEqual(fullMethodName, roundTrippedFullMethodName); + Assert.AreEqual(managedTypeName, roundTrippedFullTypeName); + Assert.AreEqual(managedMethodName, roundTrippedFullMethodName); } // private void VerifyRoundTripFromMethodSymbol( diff --git a/test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests.csproj b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/Microsoft.TestPlatform.AdapterUtilities.UnitTests.csproj similarity index 81% rename from test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests.csproj rename to test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/Microsoft.TestPlatform.AdapterUtilities.UnitTests.csproj index 87797a50dc..dabed0d2f0 100644 --- a/test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests.csproj +++ b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/Microsoft.TestPlatform.AdapterUtilities.UnitTests.csproj @@ -8,7 +8,7 @@ netcoreapp2.1 Exe - Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests + Microsoft.TestPlatform.AdapterUtilities.UnitTests true 3.8.0-3.20427.2 $(NoWarn);RS1024 @@ -19,12 +19,16 @@ - + + + + + PreserveNewest - - + + diff --git a/test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/Program.cs b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/Program.cs similarity index 78% rename from test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/Program.cs rename to test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/Program.cs index fbe5689406..e6fb5d296f 100644 --- a/test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/Program.cs +++ b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/Program.cs @@ -1,7 +1,7 @@ // 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.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests +namespace Microsoft.TestPlatform.AdapterUtilities.UnitTests { public static class Program { diff --git a/test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/TestClasses.cs b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/TestClasses.cs similarity index 100% rename from test/Microsoft.TestPlatform.ObjectModel.ManagedNameUtilities.UnitTests/TestClasses.cs rename to test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/TestClasses.cs diff --git a/test/Microsoft.TestPlatform.Client.UnitTests/DesignMode/DesignModeClientTests.cs b/test/Microsoft.TestPlatform.Client.UnitTests/DesignMode/DesignModeClientTests.cs index 583f3106b9..b39c620579 100644 --- a/test/Microsoft.TestPlatform.Client.UnitTests/DesignMode/DesignModeClientTests.cs +++ b/test/Microsoft.TestPlatform.Client.UnitTests/DesignMode/DesignModeClientTests.cs @@ -39,7 +39,7 @@ public class DesignModeClientTests private readonly DesignModeClient designModeClient; - private readonly int protocolVersion = 4; + private readonly int protocolVersion = 5; private readonly AutoResetEvent complateEvent; @@ -133,7 +133,7 @@ public void DesignModeClientConnectShouldNotSendConnectedIfServerConnectionTimes public void DesignModeClientDuringConnectShouldHighestCommonVersionWhenReceivedVersionIsGreaterThanSupportedVersion() { - var verCheck = new Message { MessageType = MessageType.VersionCheck, Payload = 4 }; + var verCheck = new Message { MessageType = MessageType.VersionCheck, Payload = 5 }; var sessionEnd = new Message { MessageType = MessageType.SessionEnd }; this.mockCommunicationManager.Setup(cm => cm.WaitForServerConnection(It.IsAny())).Returns(true); this.mockCommunicationManager.SetupSequence(cm => cm.ReceiveMessage()).Returns(verCheck).Returns(sessionEnd); diff --git a/test/Microsoft.TestPlatform.Client.UnitTests/DesignMode/DesignModeTestHostLauncherFactoryTests.cs b/test/Microsoft.TestPlatform.Client.UnitTests/DesignMode/DesignModeTestHostLauncherFactoryTests.cs index 79d961f685..177d73d5f1 100644 --- a/test/Microsoft.TestPlatform.Client.UnitTests/DesignMode/DesignModeTestHostLauncherFactoryTests.cs +++ b/test/Microsoft.TestPlatform.Client.UnitTests/DesignMode/DesignModeTestHostLauncherFactoryTests.cs @@ -17,7 +17,7 @@ public void DesignModeTestHostFactoryShouldReturnNonDebugLauncherIfDebuggingDisa { var mockDesignModeClient = new Mock(); var testRunRequestPayload = new TestRunRequestPayload { DebuggingEnabled = false }; - var launcher = DesignModeTestHostLauncherFactory.GetCustomHostLauncherForTestRun(mockDesignModeClient.Object, testRunRequestPayload); + var launcher = DesignModeTestHostLauncherFactory.GetCustomHostLauncherForTestRun(mockDesignModeClient.Object, testRunRequestPayload.DebuggingEnabled); Assert.IsFalse(launcher.IsDebug, "Factory must not return debug launcher if debugging is disabled."); } @@ -27,7 +27,7 @@ public void DesignModeTestHostFactoryShouldReturnDebugLauncherIfDebuggingEnabled { var mockDesignModeClient = new Mock(); var testRunRequestPayload = new TestRunRequestPayload { DebuggingEnabled = true }; - var launcher = DesignModeTestHostLauncherFactory.GetCustomHostLauncherForTestRun(mockDesignModeClient.Object, testRunRequestPayload); + var launcher = DesignModeTestHostLauncherFactory.GetCustomHostLauncherForTestRun(mockDesignModeClient.Object, testRunRequestPayload.DebuggingEnabled); Assert.IsTrue(launcher.IsDebug, "Factory must return non-debug launcher if debugging is enabled."); } diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionRequestHandlerTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionRequestHandlerTests.cs index 08779a496b..98c6473770 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionRequestHandlerTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionRequestHandlerTests.cs @@ -14,12 +14,14 @@ namespace Microsoft.TestPlatform.CommunicationUtilities.UnitTests using Microsoft.VisualStudio.TestPlatform.Common.DataCollection; using Microsoft.VisualStudio.TestPlatform.Common.DataCollector.Interfaces; using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework; + using Microsoft.VisualStudio.TestPlatform.Common.Telemetry; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serialization; using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; @@ -42,6 +44,8 @@ public class DataCollectionRequestHandlerTests private TestableDataCollectionRequestHandler requestHandler; private Mock mockDataSerializer; private Mock mockFileHelper; + private Mock mockRequestData; + private Mock mockMetricsCollection; private Message afterTestRunEnd = new Message() { MessageType = MessageType.AfterTestRunEnd, Payload = "false" }; private Message beforeTestRunStart = new Message() { @@ -58,7 +62,10 @@ public DataCollectionRequestHandlerTests() this.mockDataCollectionTestCaseEventHandler = new Mock(); this.mockDataCollectionTestCaseEventHandler.Setup(x => x.WaitForRequestHandlerConnection(It.IsAny())).Returns(true); this.mockFileHelper = new Mock(); - this.requestHandler = new TestableDataCollectionRequestHandler(this.mockCommunicationManager.Object, this.mockMessageSink.Object, this.mockDataCollectionManager.Object, this.mockDataCollectionTestCaseEventHandler.Object, this.mockDataSerializer.Object, this.mockFileHelper.Object); + this.mockRequestData = new Mock(); + this.mockMetricsCollection = new Mock(); + this.mockRequestData.Setup(r => r.MetricsCollection).Returns(this.mockMetricsCollection.Object); + this.requestHandler = new TestableDataCollectionRequestHandler(this.mockCommunicationManager.Object, this.mockMessageSink.Object, this.mockDataCollectionManager.Object, this.mockDataCollectionTestCaseEventHandler.Object, this.mockDataSerializer.Object, this.mockFileHelper.Object, this.mockRequestData.Object); this.mockCommunicationManager.SetupSequence(x => x.ReceiveMessage()).Returns(this.beforeTestRunStart).Returns(this.afterTestRunEnd); @@ -217,7 +224,7 @@ public void ProcessRequestsShouldProcessRequests() // Verify AfterTestRun events. this.mockDataCollectionManager.Verify(x => x.SessionEnded(It.IsAny()), Times.Once); - this.mockCommunicationManager.Verify(x => x.SendMessage(MessageType.AfterTestRunEndResult, It.IsAny>()), Times.Once); + this.mockCommunicationManager.Verify(x => x.SendMessage(MessageType.AfterTestRunEndResult, It.IsAny()), Times.Once); } [TestMethod] @@ -371,5 +378,50 @@ public void ProcessRequestShouldCallSessionStartWithCorrectTestSources() y => y.GetPropertyValue>("TestSources").Contains("test1.dll") && y.GetPropertyValue>("TestSources").Contains("test2.dll")))); } + + [TestMethod] + public void ProcessRequestShouldEnableTelemetry() + { + var beforeTestRunStartPayload = new BeforeTestRunStartPayload { SettingsXml = "settingsxml", Sources = new List { "test1.dll", "test2.dll" }, IsTelemetryOptedIn = true }; + this.mockRequestData.Setup(r => r.IsTelemetryOptedIn).Returns(false); + this.mockDataSerializer.Setup(x => x.DeserializePayload(It.Is(y => y.MessageType == MessageType.BeforeTestRunStart))) + .Returns(beforeTestRunStartPayload); + var message = new Message() { MessageType = MessageType.BeforeTestRunStart, Payload = JToken.FromObject(beforeTestRunStartPayload) }; + this.mockCommunicationManager.SetupSequence(x => x.ReceiveMessage()).Returns(message).Returns(this.afterTestRunEnd); + this.requestHandler.ProcessRequests(); + + this.mockRequestData.VerifySet(r => r.IsTelemetryOptedIn = true); + this.mockRequestData.VerifySet(r => r.MetricsCollection = It.IsAny()); + } + + [TestMethod] + public void ProcessRequestShouldNotEnableTelemetryIfTelemetryEnabled() + { + var beforeTestRunStartPayload = new BeforeTestRunStartPayload { SettingsXml = "settingsxml", Sources = new List { "test1.dll", "test2.dll" }, IsTelemetryOptedIn = true }; + this.mockRequestData.Setup(r => r.IsTelemetryOptedIn).Returns(true); + this.mockDataSerializer.Setup(x => x.DeserializePayload(It.Is(y => y.MessageType == MessageType.BeforeTestRunStart))) + .Returns(beforeTestRunStartPayload); + var message = new Message() { MessageType = MessageType.BeforeTestRunStart, Payload = JToken.FromObject(beforeTestRunStartPayload) }; + this.mockCommunicationManager.SetupSequence(x => x.ReceiveMessage()).Returns(message).Returns(this.afterTestRunEnd); + this.requestHandler.ProcessRequests(); + + this.mockRequestData.VerifySet(r => r.IsTelemetryOptedIn = It.IsAny(), Times.Never); + this.mockRequestData.VerifySet(r => r.MetricsCollection = It.IsAny(), Times.Never); + } + + [TestMethod] + public void ProcessRequestShouldNotEnableTelemetryIfTelemetryEnablingNotRequested() + { + var beforeTestRunStartPayload = new BeforeTestRunStartPayload { SettingsXml = "settingsxml", Sources = new List { "test1.dll", "test2.dll" }, IsTelemetryOptedIn = false }; + this.mockRequestData.Setup(r => r.IsTelemetryOptedIn).Returns(false); + this.mockDataSerializer.Setup(x => x.DeserializePayload(It.Is(y => y.MessageType == MessageType.BeforeTestRunStart))) + .Returns(beforeTestRunStartPayload); + var message = new Message() { MessageType = MessageType.BeforeTestRunStart, Payload = JToken.FromObject(beforeTestRunStartPayload) }; + this.mockCommunicationManager.SetupSequence(x => x.ReceiveMessage()).Returns(message).Returns(this.afterTestRunEnd); + this.requestHandler.ProcessRequests(); + + this.mockRequestData.VerifySet(r => r.IsTelemetryOptedIn = It.IsAny(), Times.Never); + this.mockRequestData.VerifySet(r => r.MetricsCollection = It.IsAny(), Times.Never); + } } } \ No newline at end of file diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionRequestSenderTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionRequestSenderTests.cs index 74381f5136..1e1c9cca49 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionRequestSenderTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionRequestSenderTests.cs @@ -6,7 +6,7 @@ namespace Microsoft.TestPlatform.CommunicationUtilities.UnitTests using System; using System.Collections.Generic; using System.Collections.ObjectModel; - + using Microsoft.VisualStudio.TestPlatform.Common.DataCollection; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; @@ -39,17 +39,21 @@ public void SendAfterTestRunEndAndGetResultShouldReturnAttachments() var attachment = new AttachmentSet(datacollectorUri, displayName); attachment.Attachments.Add(new UriDataAttachment(attachmentUri, "filename.txt")); - this.mockDataSerializer.Setup(x => x.DeserializePayload>(It.IsAny())).Returns(new Collection() { attachment }); + this.mockDataSerializer.Setup(x => x.DeserializePayload(It.IsAny())).Returns( + new AfterTestRunEndResult(new Collection() { attachment }, new Dictionary())); this.mockCommunicationManager.Setup(x => x.ReceiveMessage()).Returns(new Message() { MessageType = MessageType.AfterTestRunEndResult, Payload = null }); - var attachmentSets = this.requestSender.SendAfterTestRunEndAndGetResult(null, false); + var result = this.requestSender.SendAfterTestRunEndAndGetResult(null, false); - Assert.IsNotNull(attachmentSets); - Assert.AreEqual(1, attachmentSets.Count); - Assert.IsNotNull(attachmentSets[0]); - Assert.AreEqual(displayName, attachmentSets[0].DisplayName); - Assert.AreEqual(datacollectorUri, attachmentSets[0].Uri); - Assert.AreEqual(attachmentUri, attachmentSets[0].Attachments[0].Uri); + Assert.IsNotNull(result); + Assert.IsNotNull(result.AttachmentSets); + Assert.IsNotNull(result.Metrics); + Assert.AreEqual(1, result.AttachmentSets.Count); + Assert.AreEqual(0, result.Metrics.Count); + Assert.IsNotNull(result.AttachmentSets[0]); + Assert.AreEqual(displayName, result.AttachmentSets[0].DisplayName); + Assert.AreEqual(datacollectorUri, result.AttachmentSets[0].Uri); + Assert.AreEqual(attachmentUri, result.AttachmentSets[0].Attachments[0].Uri); } [TestMethod] @@ -65,9 +69,9 @@ public void SendBeforeTestRunStartAndGetResultShouldSendBeforeTestRunStartMessag { var testSources = new List() { "test1.dll" }; this.mockCommunicationManager.Setup(x => x.ReceiveMessage()).Returns(new Message() { MessageType = MessageType.BeforeTestRunStartResult, Payload = null }); - this.requestSender.SendBeforeTestRunStartAndGetResult(string.Empty, testSources, null); + this.requestSender.SendBeforeTestRunStartAndGetResult(string.Empty, testSources, true, null); - this.mockCommunicationManager.Verify(x => x.SendMessage(MessageType.BeforeTestRunStart, It.IsAny())); + this.mockCommunicationManager.Verify(x => x.SendMessage(MessageType.BeforeTestRunStart, It.Is(p => p.SettingsXml == string.Empty && p.IsTelemetryOptedIn))); } } } diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs index 7f16a8a11b..f84c978312 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs @@ -238,7 +238,7 @@ public void TestResultObjectShouldSerializeAttachmentsV2(int version) result.StartTime = default(DateTimeOffset); result.EndTime = default(DateTimeOffset); result.Attachments.Add(new AttachmentSet(new Uri("http://dummyUri"), "sampleAttachment")); - var expectedJson = "{\"TestCase\":{\"Id\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\",\"ManagedType\":null,\"ManagedMethod\":null,\"FullyQualifiedName\":\"sampleTestClass.sampleTestCase\",\"DisplayName\":\"sampleTestClass.sampleTestCase\",\"ExecutorUri\":\"executor://sampleTestExecutor\",\"Source\":\"sampleTest.dll\",\"CodeFilePath\":null,\"LineNumber\":-1,\"Properties\":[]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Outcome\":0,\"ErrorMessage\":null,\"ErrorStackTrace\":null,\"DisplayName\":null,\"Messages\":[],\"ComputerName\":null,\"Duration\":\"00:00:00\",\"StartTime\":\"0001-01-01T00:00:00+00:00\",\"EndTime\":\"0001-01-01T00:00:00+00:00\",\"Properties\":[]}"; + var expectedJson = "{\"TestCase\":{\"Id\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\",\"FullyQualifiedName\":\"sampleTestClass.sampleTestCase\",\"DisplayName\":\"sampleTestClass.sampleTestCase\",\"ExecutorUri\":\"executor://sampleTestExecutor\",\"Source\":\"sampleTest.dll\",\"CodeFilePath\":null,\"LineNumber\":-1,\"Properties\":[]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Outcome\":0,\"ErrorMessage\":null,\"ErrorStackTrace\":null,\"DisplayName\":null,\"Messages\":[],\"ComputerName\":null,\"Duration\":\"00:00:00\",\"StartTime\":\"0001-01-01T00:00:00+00:00\",\"EndTime\":\"0001-01-01T00:00:00+00:00\",\"Properties\":[]}"; var json = Serialize(result, version); diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestDoubles/TestableDataCollectionRequestHandler.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestDoubles/TestableDataCollectionRequestHandler.cs index 375272f712..b613e78c21 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestDoubles/TestableDataCollectionRequestHandler.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestDoubles/TestableDataCollectionRequestHandler.cs @@ -6,6 +6,7 @@ namespace Microsoft.TestPlatform.CommunicationUtilities.UnitTests.TestDoubles using Microsoft.VisualStudio.TestPlatform.Common.DataCollector.Interfaces; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces; /// @@ -13,8 +14,8 @@ namespace Microsoft.TestPlatform.CommunicationUtilities.UnitTests.TestDoubles /// internal class TestableDataCollectionRequestHandler : DataCollectionRequestHandler { - public TestableDataCollectionRequestHandler(ICommunicationManager communicationManager, IMessageSink messageSink, IDataCollectionManager dataCollectionManager, IDataCollectionTestCaseEventHandler dataCollectionTestCaseEventHandler, IDataSerializer dataSerializer, IFileHelper fIleHelper) - : base(communicationManager, messageSink, dataCollectionManager, dataCollectionTestCaseEventHandler, dataSerializer, fIleHelper) + public TestableDataCollectionRequestHandler(ICommunicationManager communicationManager, IMessageSink messageSink, IDataCollectionManager dataCollectionManager, IDataCollectionTestCaseEventHandler dataCollectionTestCaseEventHandler, IDataSerializer dataSerializer, IFileHelper fIleHelper, IRequestData requestData) + : base(communicationManager, messageSink, dataCollectionManager, dataCollectionTestCaseEventHandler, dataSerializer, fIleHelper, requestData) { } } diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerWithDataCollectionTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerWithDataCollectionTests.cs index abfde51160..b8e2819084 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerWithDataCollectionTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerWithDataCollectionTests.cs @@ -99,7 +99,7 @@ public void InitializeShouldSaveExceptionMessagesIfThrownByDataCollectionProcess { var mockRequestSender = new Mock(); var testSources = new List() { "abc.dll", "efg.dll" }; - mockRequestSender.Setup(x => x.SendBeforeTestRunStartAndGetResult(string.Empty, testSources, It.IsAny())).Throws(new Exception("MyException")); + mockRequestSender.Setup(x => x.SendBeforeTestRunStartAndGetResult(string.Empty, testSources, It.IsAny(), It.IsAny())).Throws(new Exception("MyException")); mockRequestSender.Setup(x => x.WaitForRequestHandlerConnection(It.IsAny())).Returns(true); var mockDataCollectionLauncher = new Mock(); @@ -224,7 +224,7 @@ public TestProcessStartInfo UpdateTestProcessStartInfoWrapper(TestProcessStartIn return this.UpdateTestProcessStartInfo(testProcessStartInfo); } - protected override TestProcessStartInfo UpdateTestProcessStartInfo(TestProcessStartInfo testProcessStartInfo) + public override TestProcessStartInfo UpdateTestProcessStartInfo(TestProcessStartInfo testProcessStartInfo) { return base.UpdateTestProcessStartInfo(testProcessStartInfo); } diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/ProxyDataCollectionManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/ProxyDataCollectionManagerTests.cs index c89ffb9fa8..e69707fd9c 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/ProxyDataCollectionManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/DataCollection/ProxyDataCollectionManagerTests.cs @@ -156,16 +156,17 @@ public void BeforeTestRunStartShouldPassRunSettingsWithExtensionsFolderUpdatedAs string runsettings = $""; var sourceList = new List() { "testsource1.dll" }; this.proxyDataCollectionManager = new ProxyDataCollectionManager(this.mockRequestData.Object, runsettings, sourceList, this.mockDataCollectionRequestSender.Object, this.mockProcessHelper.Object, this.mockDataCollectionLauncher.Object); + this.mockRequestData.Setup(r => r.IsTelemetryOptedIn).Returns(true); BeforeTestRunStartResult res = new BeforeTestRunStartResult(new Dictionary(), 123); - this.mockDataCollectionRequestSender.Setup(x => x.SendBeforeTestRunStartAndGetResult(It.IsAny(), It.IsAny>(), It.IsAny())).Returns(res); + this.mockDataCollectionRequestSender.Setup(x => x.SendBeforeTestRunStartAndGetResult(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny())).Returns(res); var result = this.proxyDataCollectionManager.BeforeTestRunStart(true, true, null); var extensionsFolderPath = Path.Combine(Path.GetDirectoryName(typeof(ITestPlatform).GetTypeInfo().Assembly.Location), "Extensions"); var expectedSettingsXML = $"{extensionsFolderPath}"; this.mockDataCollectionRequestSender.Verify( - x => x.SendBeforeTestRunStartAndGetResult(expectedSettingsXML, sourceList, It.IsAny()), Times.Once); + x => x.SendBeforeTestRunStartAndGetResult(expectedSettingsXML, sourceList, true, It.IsAny()), Times.Once); } [TestMethod] @@ -173,12 +174,12 @@ public void BeforeTestRunStartShouldReturnDataCollectorParameters() { BeforeTestRunStartResult res = new BeforeTestRunStartResult(new Dictionary(), 123); var sourceList = new List() { "testsource1.dll" }; - this.mockDataCollectionRequestSender.Setup(x => x.SendBeforeTestRunStartAndGetResult(It.IsAny(), It.IsAny>(), It.IsAny())).Returns(res); + this.mockDataCollectionRequestSender.Setup(x => x.SendBeforeTestRunStartAndGetResult(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny())).Returns(res); var result = this.proxyDataCollectionManager.BeforeTestRunStart(true, true, null); this.mockDataCollectionRequestSender.Verify( - x => x.SendBeforeTestRunStartAndGetResult(It.IsAny(), sourceList, It.IsAny()), Times.Once); + x => x.SendBeforeTestRunStartAndGetResult(It.IsAny(), sourceList, false, It.IsAny()), Times.Once); Assert.IsNotNull(result); Assert.AreEqual(res.DataCollectionEventsPort, result.DataCollectionEventsPort); Assert.AreEqual(res.EnvironmentVariables.Count, result.EnvironmentVariables.Count); @@ -189,7 +190,7 @@ public void BeforeTestRunStartsShouldInvokeRunEventsHandlerIfExceptionIsThrown() { var mockRunEventsHandler = new Mock(); this.mockDataCollectionRequestSender.Setup( - x => x.SendBeforeTestRunStartAndGetResult(It.IsAny(), new List() { "testsource1.dll" }, It.IsAny())) + x => x.SendBeforeTestRunStartAndGetResult(It.IsAny(), new List() { "testsource1.dll" }, false, It.IsAny())) .Throws(); var result = this.proxyDataCollectionManager.BeforeTestRunStart(true, true, mockRunEventsHandler.Object); @@ -207,27 +208,35 @@ public void SendBeforeTestRunStartAndGetResultShouldBeInvokedWithCorrectTestSour this.proxyDataCollectionManager = new ProxyDataCollectionManager(this.mockRequestData.Object, string.Empty, testSources, this.mockDataCollectionRequestSender.Object, this.mockProcessHelper.Object, this.mockDataCollectionLauncher.Object); BeforeTestRunStartResult res = new BeforeTestRunStartResult(new Dictionary(), 123); - this.mockDataCollectionRequestSender.Setup(x => x.SendBeforeTestRunStartAndGetResult(string.Empty, testSources, It.IsAny())).Returns(res); + this.mockDataCollectionRequestSender.Setup(x => x.SendBeforeTestRunStartAndGetResult(string.Empty, testSources, It.IsAny(), It.IsAny())).Returns(res); var result = this.proxyDataCollectionManager.BeforeTestRunStart(true, true, null); this.mockDataCollectionRequestSender.Verify( - x => x.SendBeforeTestRunStartAndGetResult(string.Empty, testSources, It.IsAny()), Times.Once); + x => x.SendBeforeTestRunStartAndGetResult(string.Empty, testSources, false, It.IsAny()), Times.Once); Assert.IsNotNull(result); Assert.AreEqual(res.DataCollectionEventsPort, result.DataCollectionEventsPort); Assert.AreEqual(res.EnvironmentVariables.Count, result.EnvironmentVariables.Count); } [TestMethod] - public void AfterTestRunEndShouldReturnAttachments() + [DataRow(false)] + [DataRow(true)] + public void AfterTestRunEndShouldReturnAttachments(bool telemetryOptedIn) { var attachments = new Collection(); var dispName = "MockAttachments"; var uri = new Uri("Mock://Attachments"); var attachmentSet = new AttachmentSet(uri, dispName); attachments.Add(attachmentSet); + this.mockRequestData.Setup(m => m.IsTelemetryOptedIn).Returns(telemetryOptedIn); - this.mockDataCollectionRequestSender.Setup(x => x.SendAfterTestRunEndAndGetResult(It.IsAny(), It.IsAny())).Returns(attachments); + var metrics = new Dictionary() + { + {"key", "value"} + }; + + this.mockDataCollectionRequestSender.Setup(x => x.SendAfterTestRunEndAndGetResult(It.IsAny(), It.IsAny())).Returns(new AfterTestRunEndResult(attachments, metrics)); var result = this.proxyDataCollectionManager.AfterTestRunEnd(false, null); @@ -236,6 +245,15 @@ public void AfterTestRunEndShouldReturnAttachments() Assert.IsNotNull(result[0]); Assert.AreEqual(dispName, result[0].DisplayName); Assert.AreEqual(uri, result[0].Uri); + + if (telemetryOptedIn) + { + mockMetricsCollection.Verify(m => m.Add("key", "value"), Times.Once); + } + else + { + mockMetricsCollection.Verify(m => m.Add(It.IsAny(), It.IsAny()), Times.Never); + } } [TestMethod] diff --git a/test/Microsoft.TestPlatform.Extensions.TrxLogger.UnitTests/TrxLoggerTests.cs b/test/Microsoft.TestPlatform.Extensions.TrxLogger.UnitTests/TrxLoggerTests.cs index c55c000053..67dd775c4a 100644 --- a/test/Microsoft.TestPlatform.Extensions.TrxLogger.UnitTests/TrxLoggerTests.cs +++ b/test/Microsoft.TestPlatform.Extensions.TrxLogger.UnitTests/TrxLoggerTests.cs @@ -736,13 +736,11 @@ public void CustomTrxFileNameShouldConstructFromLogFileParameter() Assert.AreEqual(Path.Combine(TrxLoggerTests.DefaultTestRunDirectory, TrxLoggerTests.DefaultLogFileNameParameterValue), this.testableTrxLogger.trxFile, "Wrong Trx file name"); } - - /// /// Unit test for reading TestCategories from the TestCase which is part of test result. /// [TestMethod] - public void GetCustomPropertyValueFromTestCaseShouldReadCategoyrAttributesFromTestCase() + public void GetCustomPropertyValueFromTestCaseShouldReadCategoryAttributesFromTestCase() { ObjectModel.TestCase testCase1 = CreateTestCase("TestCase1"); TestProperty testProperty = TestProperty.Register("MSTestDiscoverer.TestCategory", "String array property", string.Empty, string.Empty, typeof(string[]), null, TestPropertyAttributes.Hidden, typeof(TestObject)); @@ -759,6 +757,24 @@ public void GetCustomPropertyValueFromTestCaseShouldReadCategoyrAttributesFromTe CollectionAssert.AreEqual(listCategoriesExpected, listCategoriesActual); } + [TestMethod] + public void GetCustomPropertyValueFromTestCaseShouldReadWorkItemAttributesFromTestCase() + { + ObjectModel.TestCase testCase1 = CreateTestCase("TestCase1"); + TestProperty testProperty = TestProperty.Register("WorkItemIds", "String array property", string.Empty, string.Empty, typeof(string[]), null, TestPropertyAttributes.Hidden, typeof(TestObject)); + + testCase1.SetPropertyValue(testProperty, new[] { "99999", "0" }); + + var converter = new Converter(new Mock().Object, new TrxFileHelper()); + List listWorkItemsActual = converter.GetCustomPropertyValueFromTestCase(testCase1, "WorkItemIds"); + + List listWorkItemsExpected = new List(); + listWorkItemsExpected.Add("99999"); + listWorkItemsExpected.Add("0"); + + CollectionAssert.AreEqual(listWorkItemsExpected, listWorkItemsActual); + } + [TestMethod] public void CRLFCharactersShouldGetRetainedInTrx() { diff --git a/test/Microsoft.TestPlatform.Extensions.TrxLogger.UnitTests/Utility/ConverterTests.cs b/test/Microsoft.TestPlatform.Extensions.TrxLogger.UnitTests/Utility/ConverterTests.cs index 6311ba1715..e4c2323f83 100644 --- a/test/Microsoft.TestPlatform.Extensions.TrxLogger.UnitTests/Utility/ConverterTests.cs +++ b/test/Microsoft.TestPlatform.Extensions.TrxLogger.UnitTests/Utility/ConverterTests.cs @@ -98,6 +98,22 @@ public void ToTestElementShouldAssignTestCategoryOfUnitTestElement() CollectionAssert.AreEqual(expected, unitTestElement.TestCategories.ToArray().OrderByDescending(x => x.ToString()).ToArray()); } + [TestMethod] + public void ToTestElementShouldAssignWorkitemOfUnitTestElement() + { + TestPlatformObjectModel.TestCase testCase = CreateTestCase("TestCase1"); + TestPlatformObjectModel.TestResult result = new TestPlatformObjectModel.TestResult(testCase); + TestProperty testProperty = TestProperty.Register("WorkItemIds", "String array property", string.Empty, string.Empty, typeof(string[]), null, TestPropertyAttributes.Hidden, typeof(TestObject)); + + testCase.SetPropertyValue(testProperty, new[] { "3", "99999", "0" }); + + var unitTestElement = this.converter.ToTestElement(testCase.Id, Guid.Empty, Guid.Empty, testCase.DisplayName, TrxLoggerConstants.UnitTestType, testCase); + + int[] expected = new[] { 0, 3, 99999 }; + + CollectionAssert.AreEquivalent(expected, unitTestElement.WorkItems.ToArray()); + } + /// /// Unit test for regression when there's no test categories. /// diff --git a/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs b/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs index fef9744160..34e62512c2 100644 --- a/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs +++ b/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs @@ -129,8 +129,25 @@ public void InvokeVsTest(string arguments) /// Arguments provided to vstest.console.exe public void InvokeDotnetTest(string arguments) { - this.ExecutePatchedDotnet("test", arguments, out this.standardTestOutput, out this.standardTestError, out this.runnerExitCode); - this.FormatStandardOutCome(); + var vstestConsolePath = Path.Combine(IntegrationTestEnvironment.TestPlatformRootDirectory, "artifacts", IntegrationTestEnvironment.BuildConfiguration, "netcoreapp2.1", "vstest.console.dll"); + var env = "VSTEST_CONSOLE_PATH"; + var originalVstestConsolePath = Environment.GetEnvironmentVariable(env); + + try + { + Environment.SetEnvironmentVariable(env, vstestConsolePath); + if (arguments.Contains(".csproj")) + { + arguments = $@"-p:VsTestConsolePath=""{vstestConsolePath}"" " + arguments; + } + + this.ExecutePatchedDotnet("test", arguments, out this.standardTestOutput, out this.standardTestError, out this.runnerExitCode); + this.FormatStandardOutCome(); + } + finally + { + Environment.SetEnvironmentVariable(env, originalVstestConsolePath); + } } /// diff --git a/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestEnvironment.cs b/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestEnvironment.cs index cff43c4ca2..62e8031dd0 100644 --- a/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestEnvironment.cs +++ b/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestEnvironment.cs @@ -17,7 +17,8 @@ namespace Microsoft.TestPlatform.TestUtilities /// public class IntegrationTestEnvironment { - public static string TestPlatformRootDirectory = Environment.GetEnvironmentVariable("TP_ROOT_DIR"); + public static string TestPlatformRootDirectory = Environment.GetEnvironmentVariable("TP_ROOT_DIR") + ?? Path.GetFullPath(@"..\..\..\..\..".Replace('\\', Path.DirectorySeparatorChar)); private static Dictionary dependencyVersions; @@ -97,7 +98,6 @@ public string PublishDirectory { get { - // this used to switch to src\package\package\bin\based on whether // this is running in cli, but that's a bad idea, the console there does not have // a runtime config and will fail to start with error testhostpolicy.dll not found @@ -117,6 +117,11 @@ public string PublishDirectory } } + /// + /// Gets the extensions directory for vstest.console package. + /// + public string ExtensionsDirectory => Path.Combine(PublishDirectory, "Extensions"); + /// /// Gets the target framework. /// Supported values = net451, netcoreapp1.0. diff --git a/test/Microsoft.TestPlatform.Utilities.UnitTests/CodeCoverageDataAttachmentsHandlerTests.cs b/test/Microsoft.TestPlatform.Utilities.UnitTests/CodeCoverageDataAttachmentsHandlerTests.cs index b87bdc8dae..f1373f5f6e 100644 --- a/test/Microsoft.TestPlatform.Utilities.UnitTests/CodeCoverageDataAttachmentsHandlerTests.cs +++ b/test/Microsoft.TestPlatform.Utilities.UnitTests/CodeCoverageDataAttachmentsHandlerTests.cs @@ -45,8 +45,8 @@ public async Task HandleDataCollectionAttachmentSetsShouldReturnEmptySetWhenNoAt [TestMethod] public async Task HandleDataCollectionAttachmentSetsShouldReturnInputIfOnly1Attachment() { - var attachmentSet = new AttachmentSet(new Uri("//badrui//"), string.Empty); - attachmentSet.Attachments.Add(new UriDataAttachment(new Uri("C:\\temp\\aa"), "coverage")); + var attachmentSet = new AttachmentSet(new Uri("datacollector://microsoft/CodeCoverage/2.0"), string.Empty); + attachmentSet.Attachments.Add(new UriDataAttachment(new Uri("C:\\temp\\aa.coverage"), "coverage")); Collection attachment = new Collection { attachmentSet }; ICollection resultAttachmentSets = await @@ -54,15 +54,53 @@ public async Task HandleDataCollectionAttachmentSetsShouldReturnInputIfOnly1Atta Assert.IsNotNull(resultAttachmentSets); Assert.IsTrue(resultAttachmentSets.Count == 1); + Assert.IsTrue(resultAttachmentSets.First().Attachments.Count == 1); Assert.AreEqual("datacollector://microsoft/CodeCoverage/2.0", resultAttachmentSets.First().Uri.AbsoluteUri); - Assert.AreEqual("file:///C:/temp/aa", resultAttachmentSets.First().Attachments.First().Uri.AbsoluteUri); + Assert.AreEqual("file:///C:/temp/aa.coverage", resultAttachmentSets.First().Attachments.First().Uri.AbsoluteUri); + } + + [TestMethod] + public async Task HandleDataCollectionAttachmentSetsShouldReturnInputIfOnly1LogsAttachment() + { + var attachmentSet = new AttachmentSet(new Uri("datacollector://microsoft/CodeCoverage/2.0"), string.Empty); + attachmentSet.Attachments.Add(new UriDataAttachment(new Uri("C:\\temp\\aa.logs"), "coverage")); + + Collection attachment = new Collection { attachmentSet }; + ICollection resultAttachmentSets = await + coverageDataAttachmentsHandler.ProcessAttachmentSetsAsync(attachment, mockProgressReporter.Object, null, CancellationToken.None); + + Assert.IsNotNull(resultAttachmentSets); + Assert.IsTrue(resultAttachmentSets.Count == 1); + Assert.IsTrue(resultAttachmentSets.First().Attachments.Count == 1); + Assert.AreEqual("datacollector://microsoft/CodeCoverage/2.0", resultAttachmentSets.First().Uri.AbsoluteUri); + Assert.AreEqual("file:///C:/temp/aa.logs", resultAttachmentSets.First().Attachments.First().Uri.AbsoluteUri); + } + + [TestMethod] + public async Task HandleDataCollectionAttachmentSetsShouldReturnInputIfOnlySeveralLogsAttachmentAnd1Report() + { + var attachmentSet = new AttachmentSet(new Uri("datacollector://microsoft/CodeCoverage/2.0"), string.Empty); + attachmentSet.Attachments.Add(new UriDataAttachment(new Uri("C:\\temp\\aa.coverage"), "coverage")); + + var attachmentSet1 = new AttachmentSet(new Uri("datacollector://microsoft/CodeCoverage/2.0"), string.Empty); + attachmentSet1.Attachments.Add(new UriDataAttachment(new Uri("C:\\temp\\aa.logs"), "coverage")); + attachmentSet1.Attachments.Add(new UriDataAttachment(new Uri("C:\\temp\\bb.logs"), "coverage")); + + Collection attachment = new Collection { attachmentSet, attachmentSet1 }; + ICollection resultAttachmentSets = await + coverageDataAttachmentsHandler.ProcessAttachmentSetsAsync(attachment, mockProgressReporter.Object, null, CancellationToken.None); + + Assert.IsNotNull(resultAttachmentSets); + Assert.IsTrue(resultAttachmentSets.Count == 2); + Assert.IsTrue(resultAttachmentSets.First().Attachments.Count == 1); + Assert.IsTrue(resultAttachmentSets.Last().Attachments.Count == 2); } [TestMethod] public async Task HandleDataCollectionAttachmentSetsShouldThrowIfCancellationRequested() { var attachmentSet = new AttachmentSet(new Uri("//badrui//"), string.Empty); - attachmentSet.Attachments.Add(new UriDataAttachment(new Uri("C:\\temp\\aa"), "coverage")); + attachmentSet.Attachments.Add(new UriDataAttachment(new Uri("C:\\temp\\aa.coverage"), "coverage")); CancellationTokenSource cts = new CancellationTokenSource(); cts.Cancel(); diff --git a/test/Microsoft.TestPlatform.Utilities.UnitTests/InferRunSettingsHelperTests.cs b/test/Microsoft.TestPlatform.Utilities.UnitTests/InferRunSettingsHelperTests.cs index 6c0a22e6bd..cc3618d49f 100644 --- a/test/Microsoft.TestPlatform.Utilities.UnitTests/InferRunSettingsHelperTests.cs +++ b/test/Microsoft.TestPlatform.Utilities.UnitTests/InferRunSettingsHelperTests.cs @@ -665,9 +665,9 @@ public void RunSettingsWithCodeCoverageAndInlineTestSettingsXml() "; // Act and validate - Assert.IsFalse(InferRunSettingsHelper.AreRunSettingsCollectorsInCompatibleWithTestSettings( + Assert.IsFalse(InferRunSettingsHelper.AreRunSettingsCollectorsIncompatibleWithTestSettings( runSettingsWithCodeCoverageAndInlineTestSettingsXml), "Invalid response"); - Assert.IsTrue(InferRunSettingsHelper.AreRunSettingsCollectorsInCompatibleWithTestSettings( + Assert.IsTrue(InferRunSettingsHelper.AreRunSettingsCollectorsIncompatibleWithTestSettings( ConvertOutOfProcToInProcDataCollectionSettings(runSettingsWithCodeCoverageAndInlineTestSettingsXml)), "Invalid response"); } @@ -698,9 +698,9 @@ public void RunSettingsWithFakesAndCodeCoverageAndInlineTestSettingsXml() "; // Act and validate - Assert.IsFalse(InferRunSettingsHelper.AreRunSettingsCollectorsInCompatibleWithTestSettings( + Assert.IsFalse(InferRunSettingsHelper.AreRunSettingsCollectorsIncompatibleWithTestSettings( runSettingsWithFakesAndCodeCoverageAndInlineTestSettingsXml), "Invalid response"); - Assert.IsTrue(InferRunSettingsHelper.AreRunSettingsCollectorsInCompatibleWithTestSettings( + Assert.IsTrue(InferRunSettingsHelper.AreRunSettingsCollectorsIncompatibleWithTestSettings( ConvertOutOfProcToInProcDataCollectionSettings(runSettingsWithFakesAndCodeCoverageAndInlineTestSettingsXml)), "Invalid response"); } @@ -728,9 +728,9 @@ public void RunSettingsWithEnabledAndDisabledCollectorAndNoEmbeddedTestSettingsX "; // Act and validate - Assert.IsFalse(InferRunSettingsHelper.AreRunSettingsCollectorsInCompatibleWithTestSettings( + Assert.IsFalse(InferRunSettingsHelper.AreRunSettingsCollectorsIncompatibleWithTestSettings( runSettingsWithEnabledAndDisabledCollectorAndInlineTestSettingsXml), "Invalid response"); - Assert.IsFalse(InferRunSettingsHelper.AreRunSettingsCollectorsInCompatibleWithTestSettings( + Assert.IsFalse(InferRunSettingsHelper.AreRunSettingsCollectorsIncompatibleWithTestSettings( ConvertOutOfProcToInProcDataCollectionSettings(runSettingsWithEnabledAndDisabledCollectorAndInlineTestSettingsXml)), "Invalid response"); } @@ -763,9 +763,9 @@ public void RunSettingsWithEnabledAndDisabledCollectorAndInlineTestSettingsXml() "; // Act and validate - Assert.IsTrue(InferRunSettingsHelper.AreRunSettingsCollectorsInCompatibleWithTestSettings( + Assert.IsTrue(InferRunSettingsHelper.AreRunSettingsCollectorsIncompatibleWithTestSettings( runSettingsWithEnabledAndDisabledCollectorAndInlineTestSettingsXml), "Invalid response"); - Assert.IsTrue(InferRunSettingsHelper.AreRunSettingsCollectorsInCompatibleWithTestSettings( + Assert.IsTrue(InferRunSettingsHelper.AreRunSettingsCollectorsIncompatibleWithTestSettings( ConvertOutOfProcToInProcDataCollectionSettings(runSettingsWithEnabledAndDisabledCollectorAndInlineTestSettingsXml)), "Invalid response"); } @@ -798,9 +798,9 @@ public void RunSettingsWithDisabledCollectionSettingsAndInlineTestSettingsXml() "; // Act and validate - Assert.IsFalse(InferRunSettingsHelper.AreRunSettingsCollectorsInCompatibleWithTestSettings( + Assert.IsFalse(InferRunSettingsHelper.AreRunSettingsCollectorsIncompatibleWithTestSettings( runSettingsWithDisabledCollectionSettingsAndInlineTestSettingsXml), "Invalid response"); - Assert.IsFalse(InferRunSettingsHelper.AreRunSettingsCollectorsInCompatibleWithTestSettings( + Assert.IsFalse(InferRunSettingsHelper.AreRunSettingsCollectorsIncompatibleWithTestSettings( ConvertOutOfProcToInProcDataCollectionSettings(runSettingsWithDisabledCollectionSettingsAndInlineTestSettingsXml)), "Invalid response"); } diff --git a/test/TestAssets/CPPSimpleTestProject/Microsoft.TestPlatform.Asset.NativeCPP.nuspec b/test/TestAssets/CPPSimpleTestProject/Microsoft.TestPlatform.Asset.NativeCPP.nuspec index 1aa97e694e..b2df3444ec 100644 --- a/test/TestAssets/CPPSimpleTestProject/Microsoft.TestPlatform.Asset.NativeCPP.nuspec +++ b/test/TestAssets/CPPSimpleTestProject/Microsoft.TestPlatform.Asset.NativeCPP.nuspec @@ -7,7 +7,7 @@ Microsoft Microsoft false - http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm + LICENSE_NET.txt http://go.microsoft.com/fwlink/?LinkID=288859 MSDia typelib for reading debug symbols from managed code. Copyright © Microsoft Corporation @@ -17,6 +17,7 @@ + diff --git a/test/TestAssets/ParametrizedTestProject/ParametrizedTestProject.csproj b/test/TestAssets/ParametrizedTestProject/ParametrizedTestProject.csproj new file mode 100644 index 0000000000..bb61631802 Binary files /dev/null and b/test/TestAssets/ParametrizedTestProject/ParametrizedTestProject.csproj differ diff --git a/test/TestAssets/ParametrizedTestProject/UnitTest1.cs b/test/TestAssets/ParametrizedTestProject/UnitTest1.cs new file mode 100644 index 0000000000..a9de50d564 --- /dev/null +++ b/test/TestAssets/ParametrizedTestProject/UnitTest1.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ParametrizedTestProject +{ + /// + /// The unit test 1. + /// + [TestClass] + public class UnitTest1 + { + public TestContext TestContext { get; set; } + + /// + /// The passing test. + /// + [TestMethod] + public void CheckingParameters() + { + Assert.AreEqual("http://localhost//def", TestContext.Properties["weburl"]); + } + } +} diff --git a/test/TestAssets/QualityToolsAssets/Microsoft.TestPlatform.QTools.Assets.nuspec b/test/TestAssets/QualityToolsAssets/Microsoft.TestPlatform.QTools.Assets.nuspec index 55ac1c4235..1090df2b39 100644 --- a/test/TestAssets/QualityToolsAssets/Microsoft.TestPlatform.QTools.Assets.nuspec +++ b/test/TestAssets/QualityToolsAssets/Microsoft.TestPlatform.QTools.Assets.nuspec @@ -7,7 +7,7 @@ Microsoft Microsoft false - http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm + LICENSE_NET.txt http://go.microsoft.com/fwlink/?LinkID=288859 MSDia typelib for reading debug symbols from managed code. Copyright © Microsoft Corporation @@ -17,6 +17,7 @@ + diff --git a/test/TestAssets/TestAssets.sln b/test/TestAssets/TestAssets.sln index d2b2ef6850..8aa29c6ac7 100644 --- a/test/TestAssets/TestAssets.sln +++ b/test/TestAssets/TestAssets.sln @@ -88,6 +88,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "timeout", "timeout\timeout. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "problematic-child", "problematic-child\problematic-child.csproj", "{5FB9DFB8-2453-40EA-AAAD-D44677BCDF50}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ParametrizedTestProject", "ParametrizedTestProject\ParametrizedTestProject.csproj", "{CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -578,6 +580,18 @@ Global {5FB9DFB8-2453-40EA-AAAD-D44677BCDF50}.Release|x64.Build.0 = Release|Any CPU {5FB9DFB8-2453-40EA-AAAD-D44677BCDF50}.Release|x86.ActiveCfg = Release|Any CPU {5FB9DFB8-2453-40EA-AAAD-D44677BCDF50}.Release|x86.Build.0 = Release|Any CPU + {CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}.Debug|x64.ActiveCfg = Debug|Any CPU + {CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}.Debug|x64.Build.0 = Debug|Any CPU + {CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}.Debug|x86.ActiveCfg = Debug|Any CPU + {CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}.Debug|x86.Build.0 = Debug|Any CPU + {CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}.Release|Any CPU.Build.0 = Release|Any CPU + {CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}.Release|x64.ActiveCfg = Release|Any CPU + {CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}.Release|x64.Build.0 = Release|Any CPU + {CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}.Release|x86.ActiveCfg = Release|Any CPU + {CA82D2B3-CCF7-4F68-8840-286BA2D5B23B}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs b/test/TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs index 3b2a134a68..828cd0f22c 100644 --- a/test/TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs +++ b/test/TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs @@ -37,7 +37,7 @@ public class VsTestConsoleRequestSenderTests private readonly int WaitTimeout = 2000; - private int protocolVersion = 4; + private int protocolVersion = 5; private IDataSerializer serializer = JsonDataSerializer.Instance; public VsTestConsoleRequestSenderTests() @@ -743,7 +743,7 @@ public void StartTestRunShouldCompleteWithZeroTests() var runComplete = CreateMessage(MessageType.ExecutionComplete, payload); this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runComplete)); - this.requestSender.StartTestRun(new List() { "1.dll" }, null, new TestPlatformOptions(), mockHandler.Object); + this.requestSender.StartTestRun(new List() { "1.dll" }, null, new TestPlatformOptions(), null, mockHandler.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -772,7 +772,7 @@ public async Task StartTestRunAsyncShouldCompleteWithZeroTests() var runComplete = CreateMessage(MessageType.ExecutionComplete, payload); this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runComplete)); - await this.requestSender.StartTestRunAsync(new List() { "1.dll" }, null, null, mockHandler.Object); + await this.requestSender.StartTestRunAsync(new List() { "1.dll" }, null, null, null, mockHandler.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -827,7 +827,7 @@ public void StartTestRunShouldCompleteWithSingleTestAndMessage() this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runComplete)); }); - this.requestSender.StartTestRun(new List() { "1.dll" }, null, new TestPlatformOptions(), mockHandler.Object); + this.requestSender.StartTestRun(new List() { "1.dll" }, null, new TestPlatformOptions(), null, mockHandler.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -882,7 +882,7 @@ public async Task StartTestRunAsyncShouldCompleteWithSingleTestAndMessage() this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runComplete)); }); - await this.requestSender.StartTestRunAsync(new List() { "1.dll" }, null, null, mockHandler.Object); + await this.requestSender.StartTestRunAsync(new List() { "1.dll" }, null, null, null, mockHandler.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -904,7 +904,7 @@ public void StartTestRunShouldNotThrowIfTestPlatformOptionsIsNull() Callback((string msg, object requestpayload, int protocol) => { receivedRequest = (TestRunRequestPayload)requestpayload; }); // Act. - this.requestSender.StartTestRun(sources, null, null, mockHandler.Object); + this.requestSender.StartTestRun(sources, null, null, null, mockHandler.Object); // Assert. Assert.IsNotNull(receivedRequest); @@ -927,7 +927,7 @@ public void StartTestRunShouldIncludeFilterInRequestPayload() Callback((string msg, object requestpayload, int protocol) => { receivedRequest = (TestRunRequestPayload)requestpayload; }); // Act. - this.requestSender.StartTestRun(sources, null, new TestPlatformOptions() { TestCaseFilter = filter }, mockHandler.Object); + this.requestSender.StartTestRun(sources, null, new TestPlatformOptions() { TestCaseFilter = filter }, null, mockHandler.Object); // Assert. Assert.IsNotNull(receivedRequest); @@ -990,7 +990,7 @@ public void StartTestRunWithCustomHostShouldComplete() this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runprocessInfoPayload)); - this.requestSender.StartTestRunWithCustomHost(new List() { "1.dll" }, null, new TestPlatformOptions(), mockHandler.Object, mockLauncher.Object); + this.requestSender.StartTestRunWithCustomHost(new List() { "1.dll" }, null, new TestPlatformOptions(), null, mockHandler.Object, mockLauncher.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -1054,7 +1054,7 @@ public async Task StartTestRunAsyncWithCustomHostShouldComplete() this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runprocessInfoPayload)); - await this.requestSender.StartTestRunWithCustomHostAsync(new List() { "1.dll" }, null, null, mockHandler.Object, mockLauncher.Object); + await this.requestSender.StartTestRunWithCustomHostAsync(new List() { "1.dll" }, null, null, null, mockHandler.Object, mockLauncher.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -1106,7 +1106,7 @@ public void StartTestRunWithCustomHostShouldNotAbortAndSendErrorToVstestConsoleI this.mockCommunicationManager.Setup(cm => cm.SendMessage(It.IsAny(), It.IsAny(), this.protocolVersion)). Callback(() => this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runComplete))); - this.requestSender.StartTestRunWithCustomHost(new List() { "1.dll" }, null, new TestPlatformOptions(), mockHandler.Object, mockLauncher.Object); + this.requestSender.StartTestRunWithCustomHost(new List() { "1.dll" }, null, new TestPlatformOptions(), null, mockHandler.Object, mockLauncher.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -1155,7 +1155,7 @@ public async Task StartTestRunAsyncWithCustomHostShouldNotAbortAndSendErrorToVst this.mockCommunicationManager.Setup(cm => cm.SendMessage(It.IsAny(), It.IsAny(), this.protocolVersion)). Callback(() => this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runComplete))); - await this.requestSender.StartTestRunWithCustomHostAsync(new List() { "1.dll" }, null, null, mockHandler.Object, mockLauncher.Object); + await this.requestSender.StartTestRunWithCustomHostAsync(new List() { "1.dll" }, null, null, null, mockHandler.Object, mockLauncher.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -1175,7 +1175,7 @@ public void StartTestRunWithCustomHostShouldNotThrowIfTestPlatformOptionsIsNull( Callback((string msg, object requestpayload, int protocol) => { receivedRequest = (TestRunRequestPayload)requestpayload; }); // Act. - this.requestSender.StartTestRunWithCustomHost(sources, null, null, mockHandler.Object, new Mock().Object); + this.requestSender.StartTestRunWithCustomHost(sources, null, null, null, mockHandler.Object, new Mock().Object); // Assert. Assert.IsNotNull(receivedRequest); @@ -1198,7 +1198,7 @@ public void StartTestRunWithCustomHostShouldIncludeFilterInRequestPayload() Callback((string msg, object requestpayload, int protocol) => { receivedRequest = (TestRunRequestPayload)requestpayload; }); // Act. - this.requestSender.StartTestRunWithCustomHost(sources, null, new TestPlatformOptions() { TestCaseFilter = filter }, mockHandler.Object, new Mock().Object); + this.requestSender.StartTestRunWithCustomHost(sources, null, new TestPlatformOptions() { TestCaseFilter = filter }, null, mockHandler.Object, new Mock().Object); // Assert. Assert.IsNotNull(receivedRequest); @@ -1225,7 +1225,7 @@ public void StartTestRunWithSelectedTestsShouldCompleteWithZeroTests() var runComplete = CreateMessage(MessageType.ExecutionComplete, payload); this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runComplete)); - this.requestSender.StartTestRun(new List(), null, new TestPlatformOptions(), mockHandler.Object); + this.requestSender.StartTestRun(new List(), null, new TestPlatformOptions(), null, mockHandler.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -1252,7 +1252,7 @@ public async Task StartTestRunAsyncWithSelectedTestsShouldCompleteWithZeroTests( var runComplete = CreateMessage(MessageType.ExecutionComplete, payload); this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runComplete)); - await this.requestSender.StartTestRunAsync(new List(), null, new TestPlatformOptions(), mockHandler.Object); + await this.requestSender.StartTestRunAsync(new List(), null, new TestPlatformOptions(), null, mockHandler.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -1306,7 +1306,7 @@ public void StartTestRunWithSelectedTestsShouldCompleteWithSingleTestAndMessage( this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runComplete)); }); - this.requestSender.StartTestRun(testCaseList, null, new TestPlatformOptions(), mockHandler.Object); + this.requestSender.StartTestRun(testCaseList, null, new TestPlatformOptions(), null, mockHandler.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -1360,7 +1360,7 @@ public async Task StartTestRunAsyncWithSelectedTestsShouldCompleteWithSingleTest this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runComplete)); }); - await this.requestSender.StartTestRunAsync(testCaseList, null, new TestPlatformOptions(), mockHandler.Object); + await this.requestSender.StartTestRunAsync(testCaseList, null, new TestPlatformOptions(), null, mockHandler.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -1412,7 +1412,7 @@ public void StartTestRunWithSelectedTestsHavingTraitsShouldReturnTestRunComplete receivedChangeEventArgs = stats; }); - this.requestSender.StartTestRun(testCaseList, null, new TestPlatformOptions(), mockHandler.Object); + this.requestSender.StartTestRun(testCaseList, null, new TestPlatformOptions(), null, mockHandler.Object); Assert.IsNotNull(receivedChangeEventArgs); Assert.IsTrue(receivedChangeEventArgs.NewTestResults.Count() > 0); @@ -1468,7 +1468,7 @@ public async Task StartTestRunAsyncWithSelectedTestsHavingTraitsShouldReturnTest receivedChangeEventArgs = stats; }); - await this.requestSender.StartTestRunAsync(testCaseList, null, new TestPlatformOptions(), mockHandler.Object); + await this.requestSender.StartTestRunAsync(testCaseList, null, new TestPlatformOptions(), null, mockHandler.Object); Assert.IsNotNull(receivedChangeEventArgs); Assert.IsTrue(receivedChangeEventArgs.NewTestResults.Count() > 0); @@ -1525,7 +1525,7 @@ public void StartTestRunWithSelectedTestsHavingTraitsShouldReturnTestRunStatsWit this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runComplete)); }); - this.requestSender.StartTestRun(testCaseList, null, new TestPlatformOptions(), mockHandler.Object); + this.requestSender.StartTestRun(testCaseList, null, new TestPlatformOptions(), null, mockHandler.Object); Assert.IsNotNull(receivedChangeEventArgs); Assert.IsTrue(receivedChangeEventArgs.NewTestResults.Any()); @@ -1582,7 +1582,7 @@ public async Task StartTestRunAsyncWithSelectedTestsHavingTraitsShouldReturnTest this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runComplete)); }); - await this.requestSender.StartTestRunAsync(testCaseList, null, new TestPlatformOptions(), mockHandler.Object); + await this.requestSender.StartTestRunAsync(testCaseList, null, new TestPlatformOptions(), null, mockHandler.Object); Assert.IsNotNull(receivedChangeEventArgs); Assert.IsTrue(receivedChangeEventArgs.NewTestResults.Any()); @@ -1647,7 +1647,7 @@ public void StartTestRunWithCustomHostWithSelectedTestsComplete() this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runprocessInfoPayload)); - this.requestSender.StartTestRunWithCustomHost(testCaseList, null, new TestPlatformOptions(), mockHandler.Object, mockLauncher.Object); + this.requestSender.StartTestRunWithCustomHost(testCaseList, null, new TestPlatformOptions(), null, mockHandler.Object, mockLauncher.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -1709,7 +1709,7 @@ public async Task StartTestRunWithCustomHostAsyncWithSelectedTestsShouldComplete this.mockCommunicationManager.Setup(cm => cm.ReceiveMessageAsync(It.IsAny())).Returns(Task.FromResult(runprocessInfoPayload)); - await this.requestSender.StartTestRunWithCustomHostAsync(testCaseList, null, new TestPlatformOptions(), mockHandler.Object, mockLauncher.Object); + await this.requestSender.StartTestRunWithCustomHostAsync(testCaseList, null, new TestPlatformOptions(), null, mockHandler.Object, mockLauncher.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), It.IsAny(), null, null), Times.Once, "Run Complete must be called"); @@ -1752,7 +1752,7 @@ public void StartTestRunWithCustomHostInParallelShouldCallCustomHostMultipleTime } }); this.requestSender.InitializeCommunication(); - this.requestSender.StartTestRunWithCustomHost(sources, null, new TestPlatformOptions(), mockHandler.Object, mockLauncher.Object); + this.requestSender.StartTestRunWithCustomHost(sources, null, new TestPlatformOptions(), null, mockHandler.Object, mockLauncher.Object); mockLauncher.Verify(ml => ml.LaunchTestHost(It.IsAny()), Times.Exactly(2)); } @@ -1792,7 +1792,7 @@ public async Task StartTestRunWithCustomHostAsyncInParallelShouldCallCustomHostM }); await this.requestSender.InitializeCommunicationAsync(this.WaitTimeout); - await this.requestSender.StartTestRunWithCustomHostAsync(sources, null, null, mockHandler.Object, mockLauncher.Object); + await this.requestSender.StartTestRunWithCustomHostAsync(sources, null, null, null, mockHandler.Object, mockLauncher.Object); mockLauncher.Verify(ml => ml.LaunchTestHost(It.IsAny()), Times.Exactly(2)); } @@ -1807,7 +1807,7 @@ public void StartTestRunShouldAbortOnExceptionInSendMessage() this.mockCommunicationManager.Setup(cm => cm.SendMessage(MessageType.TestRunAllSourcesWithDefaultHost, payload, this.protocolVersion)).Throws(exception); - this.requestSender.StartTestRun(sources, null, new TestPlatformOptions(), mockHandler.Object); + this.requestSender.StartTestRun(sources, null, new TestPlatformOptions(), null, mockHandler.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), null, null, null), Times.Once, "Test Run Complete must be called"); mockHandler.Verify(mh => mh.HandleLogMessage(TestMessageLevel.Error, It.IsAny()), Times.Once, "TestMessage event must be called"); @@ -1824,7 +1824,7 @@ public async Task StartTestRunAsyncShouldAbortOnExceptionInSendMessage() this.mockCommunicationManager.Setup(cm => cm.SendMessage(MessageType.TestRunAllSourcesWithDefaultHost, payload, this.protocolVersion)).Throws(exception); - await this.requestSender.StartTestRunAsync(sources, null, null, mockHandler.Object); + await this.requestSender.StartTestRunAsync(sources, null, null, null, mockHandler.Object); mockHandler.Verify(mh => mh.HandleTestRunComplete(It.IsAny(), null, null, null), Times.Once, "Test Run Complete must be called"); mockHandler.Verify(mh => mh.HandleLogMessage(TestMessageLevel.Error, It.IsAny()), Times.Once, "TestMessage event must be called"); @@ -1857,7 +1857,7 @@ public void StartTestRunShouldLogErrorOnProcessExited() mockHandler.Setup(mh => mh.HandleTestRunComplete(It.IsAny(), null, null, null)).Callback(() => manualEvent.Set()); - this.requestSender.StartTestRun(sources, null, new TestPlatformOptions(), mockHandler.Object); + this.requestSender.StartTestRun(sources, null, new TestPlatformOptions(), null, mockHandler.Object); manualEvent.WaitOne(); mockHandler.Verify(mh => mh.HandleLogMessage(TestMessageLevel.Error, It.IsAny()), Times.Once); @@ -1886,7 +1886,7 @@ public async Task StartTestRunAsyncShouldLogErrorOnProcessExited() Assert.IsTrue(c.IsCancellationRequested); }).Returns(Task.FromResult((Message)null)); - await this.requestSender.StartTestRunAsync(sources, null, null, mockHandler.Object); + await this.requestSender.StartTestRunAsync(sources, null, null, null, mockHandler.Object); mockHandler.Verify(mh => mh.HandleLogMessage(TestMessageLevel.Error, It.IsAny()), Times.Once); } diff --git a/test/TranslationLayer.UnitTests/VsTestConsoleWrapperAsyncTests.cs b/test/TranslationLayer.UnitTests/VsTestConsoleWrapperAsyncTests.cs index fed30c3eb9..be3777ccb8 100644 --- a/test/TranslationLayer.UnitTests/VsTestConsoleWrapperAsyncTests.cs +++ b/test/TranslationLayer.UnitTests/VsTestConsoleWrapperAsyncTests.cs @@ -182,7 +182,7 @@ public async Task RunTestsAsyncWithSourcesShouldSucceed() { await this.consoleWrapper.RunTestsAsync(this.testSources, "RunSettings", new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunAsync(this.testSources, "RunSettings", null, It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunAsync(this.testSources, "RunSettings", null, null, It.IsAny()), Times.Once); } @@ -191,7 +191,7 @@ public async Task RunTestsAsyncWithSourcesAndNullOptionsShouldSucceedOnNullOptio { await this.consoleWrapper.RunTestsAsync(this.testSources, "RunSettings", null, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunAsync(this.testSources, "RunSettings", null, It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunAsync(this.testSources, "RunSettings", null, null, It.IsAny()), Times.Once); } @@ -201,7 +201,7 @@ public async Task RunTestsAsyncWithSourcesAndOptionsShouldSucceedOnOptions() var options = new TestPlatformOptions(); await this.consoleWrapper.RunTestsAsync(this.testSources, "RunSettings", options, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunAsync(this.testSources, "RunSettings", options, It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunAsync(this.testSources, "RunSettings", options, null, It.IsAny()), Times.Once); } [TestMethod] @@ -213,7 +213,7 @@ await this.consoleWrapper.RunTestsWithCustomTestHostAsync( new Mock().Object, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHostAsync(this.testSources, "RunSettings", null, It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHostAsync(this.testSources, "RunSettings", null, null, It.IsAny(), It.IsAny()), Times.Once); } [TestMethod] @@ -226,7 +226,7 @@ await this.consoleWrapper.RunTestsWithCustomTestHostAsync( new Mock().Object, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHostAsync(this.testSources, "RunSettings", null, It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHostAsync(this.testSources, "RunSettings", null, null, It.IsAny(), It.IsAny()), Times.Once); } [TestMethod] @@ -241,7 +241,7 @@ await this.consoleWrapper.RunTestsWithCustomTestHostAsync( new Mock().Object, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHostAsync(this.testSources, "RunSettings", options, It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHostAsync(this.testSources, "RunSettings", options, null, It.IsAny(), It.IsAny()), Times.Once); } [TestMethod] @@ -249,7 +249,7 @@ public async Task RunTestsAsyncWithSelectedTestsShouldSucceed() { await this.consoleWrapper.RunTestsAsync(this.testCases, "RunSettings", new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunAsync(this.testCases, "RunSettings", It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunAsync(this.testCases, "RunSettings", It.IsAny(), null, It.IsAny()), Times.Once); } [TestMethod] @@ -257,7 +257,7 @@ public async Task RunTestsAsyncWithSelectedTestsAndOptionsShouldSucceedOnNullOpt { await this.consoleWrapper.RunTestsAsync(this.testCases, "RunSettings", null, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunAsync(this.testCases, "RunSettings", null, It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunAsync(this.testCases, "RunSettings", null, null, It.IsAny()), Times.Once); } [TestMethod] @@ -267,7 +267,7 @@ public async Task RunTestsAsyncWithSelectedTestsAndOptionsShouldSucceedOnOptions await this.consoleWrapper.RunTestsAsync(this.testCases, "RunSettings", options, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunAsync(this.testCases, "RunSettings", options, It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunAsync(this.testCases, "RunSettings", options, null, It.IsAny()), Times.Once); } [TestMethod] @@ -279,7 +279,7 @@ await this.consoleWrapper.RunTestsWithCustomTestHostAsync( new Mock().Object, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHostAsync(this.testCases, "RunSettings", It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHostAsync(this.testCases, "RunSettings", It.IsAny(), null, It.IsAny(), It.IsAny()), Times.Once); } [TestMethod] @@ -292,7 +292,7 @@ await this.consoleWrapper.RunTestsWithCustomTestHostAsync( new Mock().Object, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHostAsync(this.testCases, "RunSettings", null, It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHostAsync(this.testCases, "RunSettings", null, null, It.IsAny(), It.IsAny()), Times.Once); } [TestMethod] @@ -306,7 +306,7 @@ await this.consoleWrapper.RunTestsWithCustomTestHostAsync( new Mock().Object, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHostAsync(this.testCases, "RunSettings", options, It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHostAsync(this.testCases, "RunSettings", options, null, It.IsAny(), It.IsAny()), Times.Once); } [TestMethod] diff --git a/test/TranslationLayer.UnitTests/VsTestConsoleWrapperTests.cs b/test/TranslationLayer.UnitTests/VsTestConsoleWrapperTests.cs index ee9c0f6a23..caedfbd902 100644 --- a/test/TranslationLayer.UnitTests/VsTestConsoleWrapperTests.cs +++ b/test/TranslationLayer.UnitTests/VsTestConsoleWrapperTests.cs @@ -180,7 +180,7 @@ public void RunTestsWithSourcesShouldSucceed() { this.consoleWrapper.RunTests(this.testSources, "RunSettings", new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRun(this.testSources, "RunSettings", It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRun(this.testSources, "RunSettings", It.IsAny(), null, It.IsAny()), Times.Once); } [TestMethod] @@ -192,7 +192,7 @@ public void RunTestsWithSourcesAndNullOptionsShouldPassOnNullOptions() null, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRun(this.testSources, "RunSettings", null, It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRun(this.testSources, "RunSettings", null, null, It.IsAny()), Times.Once); } [TestMethod] @@ -205,7 +205,7 @@ public void RunTestsWithSourcesAndOptionsShouldPassOnOptions() options, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRun(this.testSources, "RunSettings", options, It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRun(this.testSources, "RunSettings", options, null, It.IsAny()), Times.Once); } [TestMethod] @@ -217,7 +217,7 @@ public void RunTestsWithSourcesAndCustomHostShouldSucceed() new Mock().Object, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHost(this.testSources, "RunSettings", It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHost(this.testSources, "RunSettings", It.IsAny(), null, It.IsAny(), It.IsAny()), Times.Once); } [TestMethod] @@ -236,6 +236,7 @@ public void RunTestsWithSourcesAndOptionsUsingACustomHostShouldPassOnOptions() this.testSources, "RunSettings", options, + null, It.IsAny(), It.IsAny()), Times.Once); @@ -246,7 +247,7 @@ public void RunTestsWithSelectedTestsShouldSucceed() { this.consoleWrapper.RunTests(this.testCases, "RunSettings", new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRun(this.testCases, "RunSettings", It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRun(this.testCases, "RunSettings", It.IsAny(), null, It.IsAny()), Times.Once); } [TestMethod] @@ -254,7 +255,7 @@ public void RunTestsWithSelectedTestsAndNullOptionsShouldPassOnNullOptions() { this.consoleWrapper.RunTests(this.testCases, "RunSettings", null, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRun(this.testCases, "RunSettings", null, It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRun(this.testCases, "RunSettings", null, null, It.IsAny()), Times.Once); } [TestMethod] @@ -264,7 +265,7 @@ public void RunTestsWithSelectedTestsAndOptionsShouldPassOnOptions() this.consoleWrapper.RunTests(this.testCases, "RunSettings", options, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRun(this.testCases, "RunSettings", options, It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRun(this.testCases, "RunSettings", options, null, It.IsAny()), Times.Once); } [TestMethod] @@ -276,7 +277,7 @@ public void RunTestsWithSelectedTestsAndCustomLauncherShouldSucceed() new Mock().Object, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHost(this.testCases, "RunSettings", It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHost(this.testCases, "RunSettings", It.IsAny(), null, It.IsAny(), It.IsAny()), Times.Once); } [TestMethod] @@ -289,7 +290,7 @@ public void RunTestsWithSelectedTestsAndNullOptionsUsingACustomHostShouldPassOnN new Mock().Object, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHost(this.testCases, "RunSettings", null, It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHost(this.testCases, "RunSettings", null, null, It.IsAny(), It.IsAny()), Times.Once); } [TestMethod] @@ -304,7 +305,7 @@ public void RunTestsWithSelectedTestsAndOptionsUsingACustomHostShouldPassOnOptio new Mock().Object, new Mock().Object); - this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHost(this.testCases, "RunSettings", options, It.IsAny(), It.IsAny()), Times.Once); + this.mockRequestSender.Verify(rs => rs.StartTestRunWithCustomHost(this.testCases, "RunSettings", options, null, It.IsAny(), It.IsAny()), Times.Once); } [TestMethod] diff --git a/test/datacollector.UnitTests/DataCollectionManagerTests.cs b/test/datacollector.UnitTests/DataCollectionManagerTests.cs index 81e98d6b95..26828281eb 100644 --- a/test/datacollector.UnitTests/DataCollectionManagerTests.cs +++ b/test/datacollector.UnitTests/DataCollectionManagerTests.cs @@ -32,6 +32,7 @@ public class DataCollectionManagerTests private List> envVarList; private List> codeCoverageEnvVarList; private Mock mockDataCollectionAttachmentManager; + private Mock mockDataCollectionTelemetryManager; public DataCollectionManagerTests() { @@ -47,8 +48,9 @@ public DataCollectionManagerTests() this.mockMessageSink = new Mock(); this.mockDataCollectionAttachmentManager = new Mock(); this.mockDataCollectionAttachmentManager.SetReturnsDefault>(new List()); + this.mockDataCollectionTelemetryManager = new Mock(); - this.dataCollectionManager = new TestableDataCollectionManager(this.mockDataCollectionAttachmentManager.Object, this.mockMessageSink.Object, this.mockDataCollector.Object, this.mockCodeCoverageDataCollector.Object); + this.dataCollectionManager = new TestableDataCollectionManager(this.mockDataCollectionAttachmentManager.Object, this.mockMessageSink.Object, this.mockDataCollector.Object, this.mockCodeCoverageDataCollector.Object, this.mockDataCollectionTelemetryManager.Object); } [TestMethod] @@ -183,6 +185,8 @@ public void InitializeDataCollectorsShouldLoadDataCollectorAndReturnEnvironmentV var result = this.dataCollectionManager.InitializeDataCollectors(this.dataCollectorSettings); Assert.AreEqual("value", result["key"]); + + this.mockDataCollectionTelemetryManager.Verify(tm => tm.RecordEnvironmentVariableAddition(It.IsAny(), "key", "value")); } [TestMethod] @@ -223,14 +227,19 @@ public void InitializeDataCollectorsShouldReturnFirstEnvironmentVariableIfMoreTh var result = this.dataCollectionManager.InitializeDataCollectors(this.dataCollectorSettings); Assert.AreEqual("value", result["key"]); + + this.mockDataCollectionTelemetryManager.Verify(tm => tm.RecordEnvironmentVariableAddition(It.IsAny(), "key", "value")); + this.mockDataCollectionTelemetryManager.Verify(tm => tm.RecordEnvironmentVariableConflict(It.IsAny(), "key", "value1", "value")); } [TestMethod] public void InitializeDataCollectorsShouldReturnOtherThanCodeCoverageEnvironmentVariableIfMoreThanOneVariablesWithSameKeyIsSpecified() { this.envVarList.Add(new KeyValuePair("cor_profiler", "clrie")); + this.envVarList.Add(new KeyValuePair("same_key", "same_value")); this.codeCoverageEnvVarList.Add(new KeyValuePair("cor_profiler", "direct")); this.codeCoverageEnvVarList.Add(new KeyValuePair("clrie_profiler_vanguard", "path")); + this.codeCoverageEnvVarList.Add(new KeyValuePair("same_key", "same_value")); this.dataCollectorSettings = string.Format(this.defaultRunSettings, string.Format(this.defaultDataCollectionSettings, "Code Coverage", "my://custom/ccdatacollector", this.mockDataCollector.Object.GetType().AssemblyQualifiedName, typeof(DataCollectionManagerTests).GetTypeInfo().Assembly.Location, string.Empty) + @@ -238,9 +247,16 @@ public void InitializeDataCollectorsShouldReturnOtherThanCodeCoverageEnvironment var result = this.dataCollectionManager.InitializeDataCollectors(this.dataCollectorSettings); - Assert.AreEqual(2, result.Count); + Assert.AreEqual(3, result.Count); Assert.AreEqual("clrie", result["cor_profiler"]); Assert.AreEqual("path", result["clrie_profiler_vanguard"]); + Assert.AreEqual("same_value", result["same_key"]); + + this.mockDataCollectionTelemetryManager.Verify(tm => tm.RecordEnvironmentVariableAddition(It.Is(i => i.DataCollectorConfig.FriendlyName == this.friendlyName), "cor_profiler", "clrie")); + this.mockDataCollectionTelemetryManager.Verify(tm => tm.RecordEnvironmentVariableConflict(It.Is(i => i.DataCollectorConfig.FriendlyName == "Code Coverage"), "cor_profiler", "direct", "clrie")); + this.mockDataCollectionTelemetryManager.Verify(tm => tm.RecordEnvironmentVariableAddition(It.Is(i => i.DataCollectorConfig.FriendlyName == "Code Coverage"), "clrie_profiler_vanguard", "path")); + this.mockDataCollectionTelemetryManager.Verify(tm => tm.RecordEnvironmentVariableAddition(It.Is(i => i.DataCollectorConfig.FriendlyName == this.friendlyName), "same_key", "same_value")); + this.mockDataCollectionTelemetryManager.Verify(tm => tm.RecordEnvironmentVariableConflict(It.Is(i => i.DataCollectorConfig.FriendlyName == "Code Coverage"), "same_key", "same_value", "same_value")); } [TestMethod] @@ -483,13 +499,13 @@ internal class TestableDataCollectionManager : DataCollectionManager DataCollector dataCollector; DataCollector ccDataCollector; - public TestableDataCollectionManager(IDataCollectionAttachmentManager datacollectionAttachmentManager, IMessageSink messageSink, DataCollector dataCollector, DataCollector ccDataCollector) : this(datacollectionAttachmentManager, messageSink) + public TestableDataCollectionManager(IDataCollectionAttachmentManager datacollectionAttachmentManager, IMessageSink messageSink, DataCollector dataCollector, DataCollector ccDataCollector, IDataCollectionTelemetryManager dataCollectionTelemetryManager) : this(datacollectionAttachmentManager, messageSink, dataCollectionTelemetryManager) { this.dataCollector = dataCollector; this.ccDataCollector = ccDataCollector; } - internal TestableDataCollectionManager(IDataCollectionAttachmentManager datacollectionAttachmentManager, IMessageSink messageSink) : base(datacollectionAttachmentManager, messageSink) + internal TestableDataCollectionManager(IDataCollectionAttachmentManager datacollectionAttachmentManager, IMessageSink messageSink, IDataCollectionTelemetryManager dataCollectionTelemetryManager) : base(datacollectionAttachmentManager, messageSink, dataCollectionTelemetryManager) { } diff --git a/test/datacollector.UnitTests/DataCollectionTelemetryManagerTests.cs b/test/datacollector.UnitTests/DataCollectionTelemetryManagerTests.cs new file mode 100644 index 0000000000..a0fbdb3bd2 --- /dev/null +++ b/test/datacollector.UnitTests/DataCollectionTelemetryManagerTests.cs @@ -0,0 +1,228 @@ +using Microsoft.VisualStudio.TestPlatform.Common.DataCollector; +using Microsoft.VisualStudio.TestPlatform.Common.DataCollector.Interfaces; +using Microsoft.VisualStudio.TestPlatform.Common.DataCollector.UnitTests; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using System; +using System.Collections.Generic; + +namespace Microsoft.VisualStudio.TestPlatform.DataCollector.UnitTests +{ + [TestClass] + public class DataCollectionTelemetryManagerTests + { + private readonly Mock mockRequestData; + private readonly Mock mockMetricsCollection; + private readonly DataCollectionTelemetryManager telemetryManager; + private readonly DataCollectorInformation dataCollectorInformation; + + public DataCollectionTelemetryManagerTests() + { + this.mockRequestData = new Mock(); + this.mockMetricsCollection = new Mock(); + this.mockRequestData.Setup(m => m.MetricsCollection).Returns(this.mockMetricsCollection.Object); + + var dataCollectorMock = new Mock(); + var evnVariablesMock = dataCollectorMock.As(); + evnVariablesMock.Setup(a => a.GetTestExecutionEnvironmentVariables()).Returns(new KeyValuePair[] + { + new KeyValuePair("MicrosoftInstrumentationEngine_ConfigPath32_VanguardInstrumentationProfiler", "path1"), + new KeyValuePair("MicrosoftInstrumentationEngine_ConfigPath64_VanguardInstrumentationProfiler", "path2") + }); + + this.dataCollectorInformation = new DataCollectorInformation( + dataCollectorMock.Object, + null, + new DataCollectorConfig(typeof(CustomDataCollector)), + null, + new Mock().Object, + new TestPlatformDataCollectionEvents(), + new Mock().Object, + string.Empty); + + this.telemetryManager = new DataCollectionTelemetryManager(this.mockRequestData.Object); + } + + [TestMethod] + public void RecordEnvironmentVariableAddition_ShouldDoNothing_IfNotProfilerVariable() + { + // act + this.telemetryManager.RecordEnvironmentVariableAddition(this.dataCollectorInformation, "key", "value"); + + // assert + this.mockMetricsCollection.Verify(c => c.Add(It.IsAny(), It.IsAny()), Times.Never); + } + + [TestMethod] + public void RecordEnvironmentVariableConflict_ShouldDoNothing_IfNotProfilerVariable_ValuesSame() + { + // act + this.telemetryManager.RecordEnvironmentVariableConflict(this.dataCollectorInformation, "key", "value", "value"); + + // assert + this.mockMetricsCollection.Verify(c => c.Add(It.IsAny(), It.IsAny()), Times.Never); + } + + [TestMethod] + public void RecordEnvironmentVariableConflict_ShouldDoNothing_IfNotProfilerVariable_ValuesDifferent() + { + // act + this.telemetryManager.RecordEnvironmentVariableConflict(this.dataCollectorInformation, "key", "value", "othervalue"); + + // assert + this.mockMetricsCollection.Verify(c => c.Add(It.IsAny(), It.IsAny()), Times.Never); + } + + [TestMethod] + [DataRow("{E5F256DC-7959-4DD6-8E4F-C11150AB28E0}", "e5f256dc-7959-4dd6-8e4f-c11150ab28e0")] + [DataRow("{324F817A-7420-4E6D-B3C1-143FBED6D855}", "324f817a-7420-4e6d-b3c1-143fbed6d855")] + [DataRow("{9317ae81-bcd8-47b7-aaa1-a28062e41c71}", "9317ae81-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71}", "aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{E5F256DC-7959-4DD6-8E4F-c11150AB28E0}", "e5f256dc-7959-4dd6-8e4f-c11150ab28e0")] + [DataRow("{324f817a-7420-4e6d-b3c1-143fbEd6d855}", "324f817a-7420-4e6d-b3c1-143fbed6d855")] + [DataRow("{9317AE81-bcd8-47b7-AAA1-A28062E41C71}", "9317ae81-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("AAAAAAAAAAAAA", "00000000-0000-0000-0000-000000000000")] + public void RecordEnvironmentVariableAddition_ShouldCollectTelemetry_IfCorProfilerVariable(string profilerGuid, string profilerName) + { + // act + this.telemetryManager.RecordEnvironmentVariableAddition(this.dataCollectorInformation, "COR_PROFILER", profilerGuid); + + // assert + this.mockMetricsCollection.Verify(c => c.Add($"VS.TestPlatform.DataCollector.CorProfiler.{dataCollectorInformation.DataCollectorConfig.TypeUri}", profilerName), Times.Once); + } + + [TestMethod] + [DataRow("{E5F256DC-7959-4DD6-8E4F-C11150AB28E0}", "e5f256dc-7959-4dd6-8e4f-c11150ab28e0")] + [DataRow("{324F817A-7420-4E6D-B3C1-143FBED6D855}", "324f817a-7420-4e6d-b3c1-143fbed6d855")] + [DataRow("{9317ae81-bcd8-47b7-aaa1-a28062e41c71}", "9317ae81-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71}", "aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{E5F256DC-7959-4DD6-8E4F-c11150AB28E0}", "e5f256dc-7959-4dd6-8e4f-c11150ab28e0")] + [DataRow("{324f817a-7420-4e6d-b3c1-143fbEd6d855}", "324f817a-7420-4e6d-b3c1-143fbed6d855")] + [DataRow("{9317AE81-bcd8-47b7-AAA1-A28062E41C71}", "9317ae81-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("AAAAAAAAAAAAA", "00000000-0000-0000-0000-000000000000")] + public void RecordEnvironmentVariableAddition_ShouldCollectTelemetry_IfCoreClrProfilerVariable(string profilerGuid, string profilerName) + { + // act + this.telemetryManager.RecordEnvironmentVariableAddition(this.dataCollectorInformation, "CORECLR_PROFILER", profilerGuid); + + // assert + this.mockMetricsCollection.Verify(c => c.Add($"VS.TestPlatform.DataCollector.CoreClrProfiler.{dataCollectorInformation.DataCollectorConfig.TypeUri}", profilerName), Times.Once); + } + + [TestMethod] + [DataRow("{0f8fad5b-d9cb-469f-a165-70867728950e}", "{E5F256DC-7959-4DD6-8E4F-C11150AB28E0}", "e5f256dc-7959-4dd6-8e4f-c11150ab28e0")] + [DataRow("{0f8fad5b-d9cb-469f-a165-70867728950e}", "{324F817A-7420-4E6D-B3C1-143FBED6D855}", "324f817a-7420-4e6d-b3c1-143fbed6d855")] + [DataRow("{0f8fad5b-d9cb-469f-a165-70867728950e}", "{9317ae81-bcd8-47b7-aaa1-a28062e41c71}", "9317ae81-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{0f8fad5b-d9cb-469f-a165-70867728950e}", "{aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71}", "aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{324f817a-7420-4e6d-b3c1-143fbEd6d855}", "{E5F256DC-7959-4DD6-8E4F-c11150AB28E0}", "e5f256dc-7959-4dd6-8e4f-c11150ab28e0")] + [DataRow("{0f8fad5b-d9cb-469f-a165-70867728950e}", "{324f817a-7420-4e6d-b3c1-143fbEd6d855}", "324f817a-7420-4e6d-b3c1-143fbed6d855")] + [DataRow("{324f817a-7420-4e6d-b3c1-143fbEd6d855}", "{9317AE81-bcd8-47b7-AAA1-A28062E41C71}", "9317ae81-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{324f817a-7420-4e6d-b3c1-143fbEd6d855}", "AAAAAAAAAAAAA", "00000000-0000-0000-0000-000000000000")] + public void RecordEnvironmentVariableConflict_ShouldCollectOverwrittenTelemetry_IfCorProfilerVariable(string existingProfilerGuid, string profilerGuid, string expectedOverwrittenProfiler) + { + // act + this.telemetryManager.RecordEnvironmentVariableConflict(this.dataCollectorInformation, "COR_PROFILER", profilerGuid, existingProfilerGuid); + + // assert + this.mockMetricsCollection.Verify(c => c.Add($"VS.TestPlatform.DataCollector.CorProfiler.{dataCollectorInformation.DataCollectorConfig.TypeUri}", $"{Guid.Parse(existingProfilerGuid)}(overwritten:{expectedOverwrittenProfiler})"), Times.Once); + } + + [TestMethod] + [DataRow("{0f8fad5b-d9cb-469f-a165-70867728950e}", "{E5F256DC-7959-4DD6-8E4F-C11150AB28E0}", "e5f256dc-7959-4dd6-8e4f-c11150ab28e0")] + [DataRow("{0f8fad5b-d9cb-469f-a165-70867728950e}", "{324F817A-7420-4E6D-B3C1-143FBED6D855}", "324f817a-7420-4e6d-b3c1-143fbed6d855")] + [DataRow("{0f8fad5b-d9cb-469f-a165-70867728950e}", "{9317ae81-bcd8-47b7-aaa1-a28062e41c71}", "9317ae81-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{0f8fad5b-d9cb-469f-a165-70867728950e}", "{aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71}", "aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{324f817a-7420-4e6d-b3c1-143fbEd6d855}", "{E5F256DC-7959-4DD6-8E4F-c11150AB28E0}", "e5f256dc-7959-4dd6-8e4f-c11150ab28e0")] + [DataRow("{0f8fad5b-d9cb-469f-a165-70867728950e}", "{324f817a-7420-4e6d-b3c1-143fbEd6d855}", "324f817a-7420-4e6d-b3c1-143fbed6d855")] + [DataRow("{324f817a-7420-4e6d-b3c1-143fbEd6d855}", "{9317AE81-bcd8-47b7-AAA1-A28062E41C71}", "9317ae81-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{324f817a-7420-4e6d-b3c1-143fbEd6d855}", "AAAAAAAAAAAAA", "00000000-0000-0000-0000-000000000000")] + public void RecordEnvironmentVariableConflict_ShouldCollectOverwrittenTelemetry_IfCoreClrProfilerVariable(string existingProfilerGuid, string profilerGuid, string expectedOverwrittenProfiler) + { + // act + this.telemetryManager.RecordEnvironmentVariableConflict(this.dataCollectorInformation, "CORECLR_PROFILER", profilerGuid, existingProfilerGuid); + + // assert + this.mockMetricsCollection.Verify(c => c.Add($"VS.TestPlatform.DataCollector.CoreClrProfiler.{dataCollectorInformation.DataCollectorConfig.TypeUri}", $"{Guid.Parse(existingProfilerGuid)}(overwritten:{expectedOverwrittenProfiler})"), Times.Once); + } + + [TestMethod] + [DataRow("{E5F256DC-7959-4DD6-8E4F-C11150AB28E0}")] + [DataRow("{324F817A-7420-4E6D-B3C1-143FBED6D855}")] + [DataRow("{9317ae81-bcd8-47b7-aaa1-a28062e41c71}")] + [DataRow("{aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71}")] + [DataRow("{E5F256DC-7959-4DD6-8E4F-c11150AB28E0}")] + [DataRow("{324f817a-7420-4e6d-b3c1-143fbEd6d855}")] + [DataRow("{9317AE81-bcd8-47b7-AAA1-A28062E41C71}")] + [DataRow("AAAAAAAAAAAAA")] + public void RecordEnvironmentVariableConflict_ShouldCollectClrIeTelemetry_IfCorProfilerVariableAndCollectorSpecifiesClrIeProfile(string profilerGuid) + { + // arrange + this.dataCollectorInformation.SetTestExecutionEnvironmentVariables(); + + // act + this.telemetryManager.RecordEnvironmentVariableConflict(this.dataCollectorInformation, "COR_PROFILER", profilerGuid, "{324F817A-7420-4E6D-B3C1-143FBED6D855}"); + + // assert + this.mockMetricsCollection.Verify(c => c.Add($"VS.TestPlatform.DataCollector.CorProfiler.{dataCollectorInformation.DataCollectorConfig.TypeUri}", "324f817a-7420-4e6d-b3c1-143fbed6d855"), Times.Once); + } + + [TestMethod] + [DataRow("{E5F256DC-7959-4DD6-8E4F-C11150AB28E0}")] + [DataRow("{324F817A-7420-4E6D-B3C1-143FBED6D855}")] + [DataRow("{9317ae81-bcd8-47b7-aaa1-a28062e41c71}")] + [DataRow("{aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71}")] + [DataRow("{E5F256DC-7959-4DD6-8E4F-c11150AB28E0}")] + [DataRow("{324f817a-7420-4e6d-b3c1-143fbEd6d855}")] + [DataRow("{9317AE81-bcd8-47b7-AAA1-A28062E41C71}")] + [DataRow("AAAAAAAAAAAAA")] + public void RecordEnvironmentVariableConflict_ShouldCollectClrIeTelemetry_IfCoreClrProfilerVariableAndCollectorSpecifiesClrIeProfile(string profilerGuid) + { + // arrange + this.dataCollectorInformation.SetTestExecutionEnvironmentVariables(); + + // act + this.telemetryManager.RecordEnvironmentVariableConflict(this.dataCollectorInformation, "CORECLR_PROFILER", profilerGuid, "{324F817A-7420-4E6D-B3C1-143FBED6D855}"); + + // assert + this.mockMetricsCollection.Verify(c => c.Add($"VS.TestPlatform.DataCollector.CoreClrProfiler.{dataCollectorInformation.DataCollectorConfig.TypeUri}", "324f817a-7420-4e6d-b3c1-143fbed6d855"), Times.Once); + } + + [TestMethod] + [DataRow("{E5F256DC-7959-4DD6-8E4F-C11150AB28E0}", "e5f256dc-7959-4dd6-8e4f-c11150ab28e0")] + [DataRow("{324F817A-7420-4E6D-B3C1-143FBED6D855}", "324f817a-7420-4e6d-b3c1-143fbed6d855")] + [DataRow("{9317ae81-bcd8-47b7-aaa1-a28062e41c71}", "9317ae81-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71}", "aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{E5F256DC-7959-4DD6-8E4F-c11150AB28E0}", "e5f256dc-7959-4dd6-8e4f-c11150ab28e0")] + [DataRow("{324f817a-7420-4e6d-b3c1-143fbEd6d855}", "324f817a-7420-4e6d-b3c1-143fbed6d855")] + [DataRow("{9317AE81-bcd8-47b7-AAA1-A28062E41C71}", "9317ae81-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("AAAAAAAAAAAAA", "00000000-0000-0000-0000-000000000000")] + public void RecordEnvironmentVariableConflict_ShouldCollectTelemetry_IfCorProfilerVariableAndBothValuesSame(string profilerGuid, string profilerName) + { + // act + this.telemetryManager.RecordEnvironmentVariableConflict(this.dataCollectorInformation, "COR_PROFILER", profilerGuid, profilerGuid.ToLower()); + + // assert + this.mockMetricsCollection.Verify(c => c.Add($"VS.TestPlatform.DataCollector.CorProfiler.{dataCollectorInformation.DataCollectorConfig.TypeUri}", profilerName), Times.Once); + } + + [TestMethod] + [DataRow("{E5F256DC-7959-4DD6-8E4F-C11150AB28E0}", "e5f256dc-7959-4dd6-8e4f-c11150ab28e0")] + [DataRow("{324F817A-7420-4E6D-B3C1-143FBED6D855}", "324f817a-7420-4e6d-b3c1-143fbed6d855")] + [DataRow("{9317ae81-bcd8-47b7-aaa1-a28062e41c71}", "9317ae81-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71}", "aaaaaaaa-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("{E5F256DC-7959-4DD6-8E4F-c11150AB28E0}", "e5f256dc-7959-4dd6-8e4f-c11150ab28e0")] + [DataRow("{324f817a-7420-4e6d-b3c1-143fbEd6d855}", "324f817a-7420-4e6d-b3c1-143fbed6d855")] + [DataRow("{9317AE81-bcd8-47b7-AAA1-A28062E41C71}", "9317ae81-bcd8-47b7-aaa1-a28062e41c71")] + [DataRow("AAAAAAAAAAAAA", "00000000-0000-0000-0000-000000000000")] + public void RecordEnvironmentVariableConflict_ShouldCollectTelemetry_IfCoreClrProfilerVariableAndBothValuesSame(string profilerGuid, string profilerName) + { + // act + this.telemetryManager.RecordEnvironmentVariableConflict(this.dataCollectorInformation, "CORECLR_PROFILER", profilerGuid, profilerGuid.ToUpper()); + + // assert + this.mockMetricsCollection.Verify(c => c.Add($"VS.TestPlatform.DataCollector.CoreClrProfiler.{dataCollectorInformation.DataCollectorConfig.TypeUri}", profilerName), Times.Once); + } + } +} diff --git a/test/vstest.console.UnitTests/TestPlatformHelpers/TestRequestManagerTests.cs b/test/vstest.console.UnitTests/TestPlatformHelpers/TestRequestManagerTests.cs index e8f7ba2a30..76e5d1ac92 100644 --- a/test/vstest.console.UnitTests/TestPlatformHelpers/TestRequestManagerTests.cs +++ b/test/vstest.console.UnitTests/TestPlatformHelpers/TestRequestManagerTests.cs @@ -235,7 +235,7 @@ public void DiscoverTestsShouldPassSameProtocolConfigInRequestData() RunSettings = DefaultRunsettings }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; IRequestData actualRequestData = null; var mockDiscoveryRequest = new Mock(); @@ -259,7 +259,7 @@ public void DiscoverTestsShouldPassSameProtocolConfigInRequestData() this.testRequestManager.DiscoverTests(payload, mockDiscoveryRegistrar.Object, mockProtocolConfig); // Verify. - Assert.AreEqual(4, actualRequestData.ProtocolConfig.Version); + Assert.AreEqual(5, actualRequestData.ProtocolConfig.Version); } @@ -285,7 +285,7 @@ public void DiscoverTestsShouldCollectMetrics() " }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; var mockDiscoveryRegistrar = new Mock(); IRequestData actualRequestData = null; @@ -335,7 +335,7 @@ public void DiscoverTestsShouldCollectTargetDeviceLocalMachineIfTargetDeviceStri " }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; var mockDiscoveryRegistrar = new Mock(); IRequestData actualRequestData = null; @@ -379,7 +379,7 @@ public void DiscoverTestsShouldCollectTargetDeviceIfTargetDeviceIsDevice() " }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; var mockDiscoveryRegistrar = new Mock(); IRequestData actualRequestData = null; @@ -423,7 +423,7 @@ public void DiscoverTestsShouldCollectTargetDeviceIfTargetDeviceIsEmulator() " }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; var mockDiscoveryRegistrar = new Mock(); IRequestData actualRequestData = null; @@ -467,7 +467,7 @@ public void DiscoverTestsShouldCollectCommands() " }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; var mockDiscoveryRegistrar = new Mock(); IRequestData actualRequestData = null; @@ -523,7 +523,7 @@ public void DiscoverTestsShouldCollectTestSettings() " }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; var mockDiscoveryRegistrar = new Mock(); IRequestData actualRequestData = null; @@ -571,7 +571,7 @@ public void DiscoverTestsShouldCollectVsmdiFile() " }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; var mockDiscoveryRegistrar = new Mock(); IRequestData actualRequestData = null; @@ -619,7 +619,7 @@ public void DiscoverTestsShouldCollectTestRunConfigFile() " }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; var mockDiscoveryRegistrar = new Mock(); IRequestData actualRequestData = null; @@ -914,7 +914,7 @@ public void RunTestsShouldPassSameProtocolConfigInRequestData() Sources = new List() { "a" }, RunSettings = DefaultRunsettings }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; IRequestData actualRequestData = null; var mockDiscoveryRequest = new Mock(); this.mockTestPlatform.Setup(mt => mt.CreateTestRunRequest(It.IsAny(), It.IsAny(), It.IsAny())).Callback( @@ -927,7 +927,7 @@ public void RunTestsShouldPassSameProtocolConfigInRequestData() this.testRequestManager.RunTests(payload, new Mock().Object, new Mock().Object, mockProtocolConfig); // Verify. - Assert.AreEqual(4, actualRequestData.ProtocolConfig.Version); + Assert.AreEqual(5, actualRequestData.ProtocolConfig.Version); } [TestMethod] @@ -941,7 +941,7 @@ public void RunTestsShouldCollectCommands() Sources = new List() { "a" }, RunSettings = DefaultRunsettings }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; IRequestData actualRequestData = null; var mockDiscoveryRequest = new Mock(); this.mockTestPlatform.Setup(mt => mt.CreateTestRunRequest(It.IsAny(), It.IsAny(), It.IsAny())).Callback( @@ -1009,7 +1009,7 @@ public void RunTestsShouldCollectTelemetryForLegacySettings() " }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; IRequestData actualRequestData = null; var mockDiscoveryRequest = new Mock(); this.mockTestPlatform.Setup(mt => mt.CreateTestRunRequest(It.IsAny(), It.IsAny(), It.IsAny())).Callback( @@ -1059,7 +1059,7 @@ public void RunTestsShouldCollectTelemetryForTestSettingsEmbeddedInsideRunSettin " }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; IRequestData actualRequestData = null; var mockDiscoveryRequest = new Mock(); this.mockTestPlatform.Setup(mt => mt.CreateTestRunRequest(It.IsAny(), It.IsAny(), It.IsAny())).Callback( @@ -1107,7 +1107,7 @@ public void RunTestsShouldCollectMetrics() " }; - var mockProtocolConfig = new ProtocolConfig { Version = 4 }; + var mockProtocolConfig = new ProtocolConfig { Version = 5 }; IRequestData actualRequestData = null; var mockDiscoveryRequest = new Mock(); this.mockTestPlatform.Setup(mt => mt.CreateTestRunRequest(It.IsAny(), It.IsAny(), It.IsAny())).Callback(