diff --git a/TestPlatform.sln b/TestPlatform.sln
index 7613c597dd..3d1e2b6080 100644
--- a/TestPlatform.sln
+++ b/TestPlatform.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.26118.0
+VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED0C35EB-7F31-4841-A24F-8EB708FFA959}"
EndProject
@@ -13,8 +13,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.Core
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "datacollector", "src\datacollector\datacollector.csproj", "{2C7CE1F8-E73E-4987-8023-B5A0EBAC86E8}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "datacollector.x86", "src\datacollector.x86\datacollector.x86.csproj", "{2820F090-3F3D-4DA2-8CBA-B8273D695333}"
-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}"
@@ -49,8 +47,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Logger", "Logger", "{020E15
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Performance", "Performance", "{595BE9C1-E10F-4E50-938A-E6C248D3F950}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "datacollector.x86.UnitTests", "test\datacollector.x86.UnitTests\datacollector.x86.UnitTests.csproj", "{F1001A64-974E-461E-B972-1A1330635677}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.Client.UnitTests", "test\Microsoft.TestPlatform.Client.UnitTests\Microsoft.TestPlatform.Client.UnitTests.csproj", "{0D59BA81-6279-4650-AEBB-4EA735C28A1A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.Common.UnitTests", "test\Microsoft.TestPlatform.Common.UnitTests\Microsoft.TestPlatform.Common.UnitTests.csproj", "{DE730F17-7D5C-4D9D-B479-025024BF4F1D}"
@@ -126,6 +122,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleClassLibrary", "test\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleTestProject3", "test\TestAssets\SimpleTestProject3\SimpleTestProject3.csproj", "{9549C1A4-CB57-4689-B3EB-F752F65F863F}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "datacollector.UnitTests", "test\datacollector.UnitTests\datacollector.UnitTests.csproj", "{0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -172,18 +170,6 @@ Global
{2C7CE1F8-E73E-4987-8023-B5A0EBAC86E8}.Release|x64.Build.0 = Release|x64
{2C7CE1F8-E73E-4987-8023-B5A0EBAC86E8}.Release|x86.ActiveCfg = Release|x86
{2C7CE1F8-E73E-4987-8023-B5A0EBAC86E8}.Release|x86.Build.0 = Release|x86
- {2820F090-3F3D-4DA2-8CBA-B8273D695333}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2820F090-3F3D-4DA2-8CBA-B8273D695333}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2820F090-3F3D-4DA2-8CBA-B8273D695333}.Debug|x64.ActiveCfg = Debug|x64
- {2820F090-3F3D-4DA2-8CBA-B8273D695333}.Debug|x64.Build.0 = Debug|x64
- {2820F090-3F3D-4DA2-8CBA-B8273D695333}.Debug|x86.ActiveCfg = Debug|x86
- {2820F090-3F3D-4DA2-8CBA-B8273D695333}.Debug|x86.Build.0 = Debug|x86
- {2820F090-3F3D-4DA2-8CBA-B8273D695333}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2820F090-3F3D-4DA2-8CBA-B8273D695333}.Release|Any CPU.Build.0 = Release|Any CPU
- {2820F090-3F3D-4DA2-8CBA-B8273D695333}.Release|x64.ActiveCfg = Release|x64
- {2820F090-3F3D-4DA2-8CBA-B8273D695333}.Release|x64.Build.0 = Release|x64
- {2820F090-3F3D-4DA2-8CBA-B8273D695333}.Release|x86.ActiveCfg = Release|x86
- {2820F090-3F3D-4DA2-8CBA-B8273D695333}.Release|x86.Build.0 = Release|x86
{6F5EC38C-4A11-40D3-827C-F607B90BEFF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6F5EC38C-4A11-40D3-827C-F607B90BEFF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6F5EC38C-4A11-40D3-827C-F607B90BEFF0}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -340,18 +326,6 @@ Global
{D5C17A3B-A6E6-4FB4-B089-827EECD5EDCB}.Release|x64.Build.0 = Release|Any CPU
{D5C17A3B-A6E6-4FB4-B089-827EECD5EDCB}.Release|x86.ActiveCfg = Release|Any CPU
{D5C17A3B-A6E6-4FB4-B089-827EECD5EDCB}.Release|x86.Build.0 = Release|Any CPU
- {F1001A64-974E-461E-B972-1A1330635677}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F1001A64-974E-461E-B972-1A1330635677}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F1001A64-974E-461E-B972-1A1330635677}.Debug|x64.ActiveCfg = Debug|x64
- {F1001A64-974E-461E-B972-1A1330635677}.Debug|x64.Build.0 = Debug|x64
- {F1001A64-974E-461E-B972-1A1330635677}.Debug|x86.ActiveCfg = Debug|x86
- {F1001A64-974E-461E-B972-1A1330635677}.Debug|x86.Build.0 = Debug|x86
- {F1001A64-974E-461E-B972-1A1330635677}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F1001A64-974E-461E-B972-1A1330635677}.Release|Any CPU.Build.0 = Release|Any CPU
- {F1001A64-974E-461E-B972-1A1330635677}.Release|x64.ActiveCfg = Release|x64
- {F1001A64-974E-461E-B972-1A1330635677}.Release|x64.Build.0 = Release|x64
- {F1001A64-974E-461E-B972-1A1330635677}.Release|x86.ActiveCfg = Release|x86
- {F1001A64-974E-461E-B972-1A1330635677}.Release|x86.Build.0 = Release|x86
{0D59BA81-6279-4650-AEBB-4EA735C28A1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D59BA81-6279-4650-AEBB-4EA735C28A1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D59BA81-6279-4650-AEBB-4EA735C28A1A}.Debug|x64.ActiveCfg = Debug|x64
@@ -700,6 +674,18 @@ Global
{9549C1A4-CB57-4689-B3EB-F752F65F863F}.Release|x64.Build.0 = Release|x64
{9549C1A4-CB57-4689-B3EB-F752F65F863F}.Release|x86.ActiveCfg = Release|x86
{9549C1A4-CB57-4689-B3EB-F752F65F863F}.Release|x86.Build.0 = Release|x86
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Debug|x64.ActiveCfg = Debug|x64
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Debug|x64.Build.0 = Debug|x64
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Debug|x86.ActiveCfg = Debug|x86
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Debug|x86.Build.0 = Debug|x86
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Release|x64.ActiveCfg = Release|x64
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Release|x64.Build.0 = Release|x64
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Release|x86.ActiveCfg = Release|x86
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -708,7 +694,6 @@ Global
{50C00046-0DA3-4B5C-9F6F-7BE1145E156A} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959}
{01409D95-A5F1-4EBE-94B1-909D5D2D0DC3} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6}
{2C7CE1F8-E73E-4987-8023-B5A0EBAC86E8} = {ED0C35EB-7F31-4841-A24F-8EB708FFA959}
- {2820F090-3F3D-4DA2-8CBA-B8273D695333} = {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}
@@ -726,7 +711,6 @@ Global
{46250E12-4CF1-4051-B4A7-80C8C06E0068} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6}
{020E15EA-731F-4667-95AF-226671E0C3AE} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6}
{595BE9C1-E10F-4E50-938A-E6C248D3F950} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6}
- {F1001A64-974E-461E-B972-1A1330635677} = {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}
@@ -758,5 +742,6 @@ Global
{EFA38DEF-C2BB-42AE-8B68-B31D79F3107E} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6}
{0D85D957-6FF2-4620-B766-B708801D97F3} = {8DA7CBD9-F17E-41B6-90C4-CFF55848A25A}
{9549C1A4-CB57-4689-B3EB-F752F65F863F} = {8DA7CBD9-F17E-41B6-90C4-CFF55848A25A}
+ {0C6EFAF9-CE3E-4C11-8DD8-D7DABB206E5C} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6}
EndGlobalSection
EndGlobal
diff --git a/scripts/build.ps1 b/scripts/build.ps1
index 9dd7fd0f94..ae92a084f1 100644
--- a/scripts/build.ps1
+++ b/scripts/build.ps1
@@ -187,7 +187,6 @@ function Publish-Package
$testhostCorePackageDir = $(Join-Path $env:TP_OUT_DIR "$TPB_Configuration\Microsoft.TestPlatform.TestHost\$TPB_TargetFrameworkCore")
$vstestConsoleProject = Join-Path $env:TP_ROOT_DIR "src\vstest.console\vstest.console.csproj"
$dataCollectorProject = Join-Path $env:TP_ROOT_DIR "src\datacollector\datacollector.csproj"
- $dataCollectorx86Project = Join-Path $env:TP_ROOT_DIR "src\datacollector.x86\datacollector.x86.csproj"
Write-Log "Package: Publish package\*.csproj"
@@ -204,7 +203,6 @@ function Publish-Package
Publish-Package-Internal $dataCollectorProject $TPB_TargetFramework $fullCLRPackageDir
Publish-Package-Internal $dataCollectorProject $TPB_TargetFrameworkCore $coreCLRPackageDir
- Write-Log "Package: Publish src\datacollector.x86\datacollector.x86.csproj"
Publish-Package-Internal $dataCollectorx86Project $TPB_TargetFramework $fullCLRPackageDir
# Publish testhost
diff --git a/scripts/build/TestPlatform.targets b/scripts/build/TestPlatform.targets
index 9a1b06940f..bf0af6b762 100644
--- a/scripts/build/TestPlatform.targets
+++ b/scripts/build/TestPlatform.targets
@@ -5,8 +5,8 @@
$(TestPlatformRoot)packages\
-
-
+
+
diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestHandler.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestHandler.cs
index 94c1d04d39..0fbbade8e1 100644
--- a/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestHandler.cs
+++ b/src/Microsoft.TestPlatform.CommunicationUtilities/DataCollectionRequestHandler.cs
@@ -4,30 +4,63 @@
namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection
{
using System;
- using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces;
- using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using System.Collections.ObjectModel;
+
+ using Microsoft.VisualStudio.TestPlatform.Common.DataCollection;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
- using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection.Interfaces;
- using Microsoft.VisualStudio.TestPlatform.Common.DataCollection;
+ using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces;
+ using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+ ///
+ /// The data collection request handler interface.
+ ///
internal class DataCollectionRequestHandler : IDataCollectionRequestHandler, IDisposable
{
private readonly ICommunicationManager communicationManager;
private IDataSerializer dataSerializer;
- public DataCollectionRequestHandler()
+ private static DataCollectionRequestHandler RequestHandler;
+ private static readonly object obj = new object();
+
+ internal DataCollectionRequestHandler()
: this(new SocketCommunicationManager(), JsonDataSerializer.Instance)
{
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ ///
+ ///
+ ///
internal DataCollectionRequestHandler(ICommunicationManager communicationManager, IDataSerializer dataSerializer)
{
this.communicationManager = communicationManager;
this.dataSerializer = dataSerializer;
}
+ ///
+ /// Gets singleton instance of DataCollectionRequestHandler.
+ ///
+ public static DataCollectionRequestHandler Instance
+ {
+ get
+ {
+ lock (obj)
+ {
+ if (RequestHandler == null)
+ {
+ RequestHandler = new DataCollectionRequestHandler();
+ }
+ return RequestHandler;
+ }
+ }
+ }
+
///
/// The dispose.
///
@@ -45,15 +78,13 @@ public void Close()
EqtTrace.Info("Closing the connection !");
}
- ///
- /// Setups client based on port
- ///
- /// port number to connect
+ ///
public void InitializeCommunication(int port)
{
this.communicationManager.SetupClientAsync(port);
}
+ ///
public bool WaitForRequestSenderConnection(int connectionTimeout)
{
return this.communicationManager.WaitForServerConnection(connectionTimeout);
@@ -93,5 +124,14 @@ public void ProcessRequests()
}
while (!isSessionEnd);
}
+
+ ///
+ ///
+ ///
+ ///
+ public void SendDataCollectionMessage(DataCollectionMessageEventArgs args)
+ {
+ this.communicationManager.SendMessage(MessageType.DataCollectionMessage, args);
+ }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Friends.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Friends.cs
index e0d357d537..d9a1f24944 100644
--- a/src/Microsoft.TestPlatform.CommunicationUtilities/Friends.cs
+++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Friends.cs
@@ -8,4 +8,3 @@
[assembly: InternalsVisibleTo("Microsoft.TestPlatform.CrossPlatEngine, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("Microsoft.TestPlatform.CrossPlatEngine.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("datacollector, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
-[assembly: InternalsVisibleTo("datacollector.x86, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs
index 10fc7f3ace..6c2c2780bc 100644
--- a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs
+++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs
@@ -47,7 +47,7 @@ public static class MessageType
/// The discovery started.
///
public const string StartDiscovery = "TestDiscovery.Start";
-
+
///
/// The test cases found.
///
@@ -138,6 +138,11 @@ public static class MessageType
///
public const string LaunchAdapterProcessWithDebuggerAttachedCallback = "TestExecution.LaunchAdapterProcessWithDebuggerAttachedCallback";
+ ///
+ /// Data Collection Message
+ ///
+ public const string DataCollectionMessage = "DataCollection.SendMessage";
+
#region DataCollector messages
///
diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/DataCollectionLauncher.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/DataCollectionLauncher.cs
index 5833fd4287..1f2ef3a45f 100644
--- a/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/DataCollectionLauncher.cs
+++ b/src/Microsoft.TestPlatform.CrossPlatEngine/DataCollection/DataCollectionLauncher.cs
@@ -19,8 +19,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.DataCollection
///
internal class DataCollectionLauncher : IDataCollectionLauncher
{
- private const string X64DataCollectorProcessName = "datacollector.exe";
- private const string X86DataCollectorProcessName = "datacollector.x86.exe";
+ private const string DataCollectorProcessName = "datacollector.exe";
private const string DotnetProcessName = "dotnet.exe";
private const string DotnetProcessNameXPlat = "dotnet";
@@ -54,7 +53,7 @@ internal DataCollectionLauncher(IProcessHelper processHelper)
/// architecture for the host
public void Initialize(Architecture architecture)
{
- this.dataCollectorProcessName = (architecture == Architecture.X86) ? X86DataCollectorProcessName : X64DataCollectorProcessName;
+ this.dataCollectorProcessName = DataCollectorProcessName;
}
///
diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Friends.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Friends.cs
index 1ede604cd1..56385a4fe9 100644
--- a/src/Microsoft.TestPlatform.CrossPlatEngine/Friends.cs
+++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Friends.cs
@@ -5,6 +5,5 @@
[assembly: InternalsVisibleTo("Microsoft.TestPlatform.CrossPlatEngine.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("vstest.console.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
-[assembly: InternalsVisibleTo("datacollector.x86, PublicKey = 002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("datacollector, PublicKey = 002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
\ No newline at end of file
diff --git a/src/Microsoft.TestPlatform.ObjectModel/AttachmentSet.cs b/src/Microsoft.TestPlatform.ObjectModel/AttachmentSet.cs
index ee027e4705..0dae93f17c 100644
--- a/src/Microsoft.TestPlatform.ObjectModel/AttachmentSet.cs
+++ b/src/Microsoft.TestPlatform.ObjectModel/AttachmentSet.cs
@@ -5,8 +5,6 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel
{
using System;
using System.Collections.Generic;
- using System.Linq;
- using System.Text;
using System.Runtime.Serialization;
///
@@ -17,10 +15,8 @@ public class AttachmentSet
{
///
/// URI of the sender.
- ///
/// If a data-collector is sending this set, then it should be uri of the data collector. Also if an
/// executor is sending this attachment, then it should be uri of executor.
- ///
///
[DataMember]
public Uri Uri {get; private set;}
@@ -33,7 +29,6 @@ public class AttachmentSet
///
/// List of data attachments.
- ///
/// These attachments can be things such as files that the collector/adapter wants to make available to the publishers.
///
[DataMember]
diff --git a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Attributes/DataCollectorFriendlyNameAttribute.cs b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Attributes/DataCollectorFriendlyNameAttribute.cs
new file mode 100644
index 0000000000..c9ff1cd1db
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Attributes/DataCollectorFriendlyNameAttribute.cs
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollector
+{
+ using System;
+
+ ///
+ /// Provides a friendly name for the data collector.
+ ///
+ public class DataCollectorFriendlyNameAttribute : Attribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The friendly name.
+ ///
+ public DataCollectorFriendlyNameAttribute(string friendlyName)
+ {
+ this.FriendlyName = friendlyName;
+ }
+
+ ///
+ /// Gets the friendly name.
+ ///
+ public string FriendlyName { get; private set; }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Attributes/DataCollectorTypeUriAttribute.cs b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Attributes/DataCollectorTypeUriAttribute.cs
new file mode 100644
index 0000000000..902c22f63d
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Attributes/DataCollectorTypeUriAttribute.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.DataCollector
+{
+ using System;
+
+ ///
+ /// Provides unique identification of a data collector in the form of a URI.
+ /// Recommended format: 'datacollector://Company/Product/Version'
+ ///
+ public class DataCollectorTypeUriAttribute : Attribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The type uri.
+ ///
+ public DataCollectorTypeUriAttribute(string typeUri)
+ {
+ this.TypeUri = typeUri;
+ }
+
+ ///
+ /// Gets the data collector type uri.
+ ///
+ public string TypeUri { get; private set; }
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/DataCollectionSink.cs b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/DataCollectionSink.cs
index e05646a878..0ba739b967 100644
--- a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/DataCollectionSink.cs
+++ b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/DataCollectionSink.cs
@@ -5,18 +5,16 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection
{
using System;
using System.ComponentModel;
- using System.IO;
///
/// Class used by data collectors to send data to up-stream components
- /// (agent, controller, client, etc).
///
public abstract class DataCollectionSink
{
#region Constructor
///
- /// Creates a DataCollectionSink
+ /// Initializes a new instance of the class.
///
protected DataCollectionSink()
{
@@ -31,11 +29,6 @@ protected DataCollectionSink()
///
public abstract event AsyncCompletedEventHandler SendFileCompleted;
- ///
- /// Called when sending of a stream has completed.
- ///
- public abstract event AsyncCompletedEventHandler SendStreamCompleted;
-
#endregion
#region SendFileAsync
@@ -48,7 +41,7 @@ protected DataCollectionSink()
/// True to automatically have the file removed after sending it.
public void SendFileAsync(DataCollectionContext context, string path, bool deleteFile)
{
- SendFileAsync(context, path, String.Empty, deleteFile);
+ this.SendFileAsync(context, path, string.Empty, deleteFile);
}
///
@@ -63,7 +56,7 @@ public void SendFileAsync(DataCollectionContext context, string path, string des
var fileInfo = new FileTransferInformation(context, path, deleteFile);
fileInfo.Description = description;
- SendFileAsync(fileInfo);
+ this.SendFileAsync(fileInfo);
}
///
@@ -73,43 +66,5 @@ public void SendFileAsync(DataCollectionContext context, string path, string des
public abstract void SendFileAsync(FileTransferInformation fileTransferInformation);
#endregion
-
- #region SendStreamAsync
-
- ///
- /// Sends a stream to up-stream components.
- ///
- /// The context in which the stream is being sent. Cannot be null.
- /// Stream to send.
- /// File name to use for the data on the client.
- /// True to automatically have the stream closed when sending of the contents has completed.
- public void SendStreamAsync(DataCollectionContext context, Stream stream, string fileName, bool closeStream)
- {
- SendStreamAsync(context, stream, fileName, String.Empty, closeStream);
- }
-
- ///
- /// Sends a stream to up-stream components.
- ///
- /// The context in which the stream is being sent. Cannot be null.
- /// Stream to send.
- /// File name to use for the data on the client.
- /// A short description of the data being sent.
- /// True to automatically have the stream closed when sending of the contents has completed.
- public void SendStreamAsync(DataCollectionContext context, Stream stream, string fileName, string description, bool closeStream)
- {
- var streamInfo = new StreamTransferInformation(context, stream, fileName, closeStream);
- streamInfo.Description = description;
-
- SendStreamAsync(streamInfo);
- }
-
- ///
- /// Sends a stream to up-stream components.
- ///
- /// Information about the stream being transferred.
- public abstract void SendStreamAsync(StreamTransferInformation streamTransferInformation);
-
- #endregion
}
}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Events/DataCollectionEvents.cs b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Events/DataCollectionEvents.cs
index fe89153fa6..6295b79a9b 100644
--- a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Events/DataCollectionEvents.cs
+++ b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Events/DataCollectionEvents.cs
@@ -13,7 +13,7 @@ public abstract class DataCollectionEvents
#region Constructor
///
- /// Default constructor.
+ /// Initializes a new instance of the class.
///
protected DataCollectionEvents()
{
@@ -23,8 +23,6 @@ protected DataCollectionEvents()
#region Events
- #region Session events
-
///
/// Raised when a session is starting
///
@@ -35,19 +33,6 @@ protected DataCollectionEvents()
///
public abstract event EventHandler SessionEnd;
- ///
- /// Raised when a session is paused
- ///
- public abstract event EventHandler SessionPause;
-
- ///
- /// Raised when a session is resuming
- ///
- public abstract event EventHandler SessionResume;
- #endregion
-
- #region Test case events
-
///
/// Raised when a test case is starting
///
@@ -58,48 +43,6 @@ protected DataCollectionEvents()
///
public abstract event EventHandler TestCaseEnd;
- ///
- /// Raised when a test case is pausing
- ///
- public abstract event EventHandler TestCasePause;
-
- ///
- /// Raised when a test case is resuming
- ///
- public abstract event EventHandler TestCaseResume;
-
- ///
- /// Raised when a test case is reset
- ///
- public abstract event EventHandler TestCaseReset;
-
- ///
- /// Raised when a test case has failed.
- ///
- ///
- /// This event is only raised for test types which send test failure notifications.
- ///
- public abstract event EventHandler TestCaseFailed;
-
- #endregion
-
- #region Other events
-
- ///
- /// Raised when intermediate data is requested. Can be a test case-specific event, or just
- /// a session event. When sent with a test case-specific context, intermediate data for the
- /// test case is requested, and when sent with only a session-specific context,
- /// intermediate data for a session is requested.
- ///
- public abstract event EventHandler DataRequest;
-
- ///
- /// Raised on a custom notification
- ///
- public abstract event EventHandler CustomNotification;
-
- #endregion
-
#endregion
}
}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Events/SessionEvents.cs b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Events/SessionEvents.cs
index 59e29168ab..8092d34671 100644
--- a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Events/SessionEvents.cs
+++ b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Events/SessionEvents.cs
@@ -16,9 +16,11 @@ public sealed class SessionStartEventArgs : DataCollectionEventArgs
#region Constructor
///
- /// Initializes the instance by storing the given information
+ /// Initializes a new instance of the class.
///
- /// Context information for the session
+ ///
+ /// Context information for the session
+ ///
public SessionStartEventArgs(DataCollectionContext context)
: base(context)
{
@@ -39,60 +41,17 @@ public sealed class SessionEndEventArgs : DataCollectionEventArgs
#region Constructor
///
- /// Initializes the instance by storing the given information
+ /// Initializes a new instance of the class.
///
- /// Context information for the session
+ ///
+ /// Context information for the session
+ ///
public SessionEndEventArgs(DataCollectionContext context)
: base(context)
{
Debug.Assert(!context.HasTestCase, "Session event has test a case context");
}
- #endregion
- }
- ///
- /// Session Pause event arguments
- ///
-#if NET451
- [Serializable]
-#endif
- public sealed class SessionPauseEventArgs : DataCollectionEventArgs
- {
- #region Constructor
-
- ///
- /// Initializes the instance by storing the given information
- ///
- /// Context information for the session
- public SessionPauseEventArgs(DataCollectionContext context)
- : base(context)
- {
- Debug.Assert(!context.HasTestCase, "Session event has test a case context");
- }
-
- #endregion
- }
-
- ///
- /// Session Resume event arguments
- ///
-#if NET451
- [Serializable]
-#endif
- public sealed class SessionResumeEventArgs : DataCollectionEventArgs
- {
- #region Constructor
-
- ///
- /// Initializes the instance by storing the given information
- ///
- /// Context information for the session
- public SessionResumeEventArgs(DataCollectionContext context)
- : base(context)
- {
- Debug.Assert(!context.HasTestCase, "Session event has test a case context");
- }
-
#endregion
}
}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Events/TestCaseEvents.cs b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Events/TestCaseEvents.cs
index 665edae05d..f360e32469 100644
--- a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Events/TestCaseEvents.cs
+++ b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/Events/TestCaseEvents.cs
@@ -9,7 +9,7 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection
///
/// Base class for all test case event arguments.
///
-#if NET451
+#if NET46
[Serializable]
#endif
public abstract class TestCaseEventArgs : DataCollectionEventArgs
@@ -17,46 +17,44 @@ public abstract class TestCaseEventArgs : DataCollectionEventArgs
#region Constructor
///
- /// Initializes the instance by storing the given information.
+ /// Initializes a new instance of the class.
///
- /// Context information for the test case
- /// The test case ID
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
+ ///
+ ///
+ /// The test case ID
+ ///
+ ///
+ /// The test case name
///
- /// The test case name
///
/// True if this is a child test case, false if this is a top-level test case.
///
protected TestCaseEventArgs(
DataCollectionContext context,
Guid testCaseId,
- //TcmInformation tcmInformation,
string testCaseName,
bool isChildTestCase)
: base(context)
{
- TestCaseId = testCaseId;
- //TcmInformation = tcmInformation;
- TestCaseName = testCaseName == null ? string.Empty : testCaseName;
- IsChildTestCase = isChildTestCase;
+ this.TestCaseId = testCaseId;
+ this.TestCaseName = testCaseName == null ? string.Empty : testCaseName;
+ this.IsChildTestCase = isChildTestCase;
}
///
- /// Initializes the instance by storing the given information.
+ /// Initializes a new instance of the class.
///
- /// Context information for the test case
- /// The test element of the test that this event is for.
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
+ ///
+ ///
+ /// The test element of the test that this event is for.
///
protected TestCaseEventArgs(
DataCollectionContext context,
- TestCase testElement
- //TcmInformation tcmInformation
- )
+ TestCase testElement)
: this(context, Guid.Empty, null, false)
{
// NOTE: ONLY USE FOR UNIT TESTING!
@@ -66,14 +64,14 @@ TestCase testElement
// and the Execution Plugin Manager will fill this in for us before the event
// is sent to the data collector when running in a production environment.
- //todo
- //EqtAssert.ParameterNotNull(testElement, "testElement");
+ // todo
+ // EqtAssert.ParameterNotNull(testElement, "testElement");
- TestElement = testElement;
- TestCaseId = testElement.Id;
- TestCaseName = testElement.DisplayName;
- //IsChildTestCase = testElement != null &&
- // !testElement.ParentExecId.Equals(TestExecId.Empty);
+ this.TestElement = testElement;
+ this.TestCaseId = testElement.Id;
+ this.TestCaseName = testElement.DisplayName;
+ // IsChildTestCase = testElement != null &&
+ // !testElement.ParentExecId.Equals(TestExecId.Empty);
}
#endregion
@@ -89,16 +87,6 @@ public Guid TestCaseId
private set;
}
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
- ///
- //public TcmInformation TcmInformation
- //{
- // get;
- // private set;
- //}
-
///
/// Gets the test case name
///
@@ -109,7 +97,7 @@ public string TestCaseName
}
///
- /// True if this is a child test case, false if this is a top-level test case
+ /// Gets a value indicating whether this is a child test case, false if this is a top-level test case
///
public bool IsChildTestCase
{
@@ -118,7 +106,7 @@ public bool IsChildTestCase
}
///
- /// Test element of the test this event is for.
+ /// Gets test element of the test this event is for.
///
public TestCase TestElement
{
@@ -132,30 +120,55 @@ public TestCase TestElement
///
/// Test Case Start event arguments.
///
-#if NET451
+#if NET46
[Serializable]
#endif
public sealed class TestCaseStartEventArgs : TestCaseEventArgs
{
- #region Constructor
+ #region Constructor
+
+ ///
+ /// Initializes a new instance of the class.
+ /// Initializes the instance by storing the given information.
+ ///
+ ///
+ /// Context information for the test case
+ ///
+ ///
+ /// The test element of the test that this event is for.
+ ///
+ public TestCaseStartEventArgs(
+ DataCollectionContext context,
+ TestCase testElement)
+ : base(context, testElement)
+ {
+ // NOTE: ONLY USE FOR UNIT TESTING!
+ // This overload is only here for 3rd parties to use for unit testing
+ // their data collectors. Internally we should not be passing the test element
+ // around in the events as this is extra information that needs to be seralized
+ // and the Execution Plugin Manager will fill this in for us before the event
+ // is sent to the data collector when running in a production environment.
+ }
///
+ /// Initializes a new instance of the class.
/// Initializes the instance by storing the given information
///
- /// Context information for the test case
- /// The test case ID
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
+ ///
+ ///
+ /// The test case ID
+ ///
+ ///
+ /// The test case name
///
- /// The test case name
///
/// True if this is a child test case, false if this is a top-level test case
///
internal TestCaseStartEventArgs(
DataCollectionContext context,
Guid testCaseId,
- //TcmInformation tcmInformation,
string testCaseName,
bool isChildTestCase)
: base(context, testCaseId, testCaseName, isChildTestCase)
@@ -163,19 +176,36 @@ internal TestCaseStartEventArgs(
Debug.Assert(context.HasTestCase, "Context is not for a test case");
}
+ #endregion
+ }
+
+ ///
+ /// Test Case End event arguments.
+ ///
+#if NET46
+ [Serializable]
+#endif
+ public sealed class TestCaseEndEventArgs : TestCaseEventArgs
+ {
+ #region Constructor
+
///
+ /// Initializes a new instance of the class.
/// Initializes the instance by storing the given information.
///
- /// Context information for the test case
- /// The test element of the test that this event is for.
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
///
- public TestCaseStartEventArgs(
+ ///
+ /// The test element of the test that this event is for.
+ ///
+ ///
+ /// The outcome of the test case.
+ ///
+ public TestCaseEndEventArgs(
DataCollectionContext context,
- TestCase testElement)
- //TcmInformation tcmInformation)
+ TestCase testElement,
+ TestOutcome testOutcome)
: base(context, testElement)
{
// NOTE: ONLY USE FOR UNIT TESTING!
@@ -184,38 +214,27 @@ public TestCaseStartEventArgs(
// around in the events as this is extra information that needs to be seralized
// and the Execution Plugin Manager will fill this in for us before the event
// is sent to the data collector when running in a production environment.
+ this.TestOutcome = testOutcome;
}
- #endregion
- }
-
- ///
- /// Test Case End event arguments.
- ///
-#if NET451
- [Serializable]
-#endif
- public sealed class TestCaseEndEventArgs : TestCaseEventArgs
- {
- #region Constructor
-
///
- /// Initializes the instance by storing the given information
+ /// Initializes a new instance of the class.
///
- /// Context information for the test case
- /// The test case ID
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
+ ///
+ ///
+ /// The test case ID
+ ///
+ ///
+ /// The test case name
///
- /// The test case name
///
/// True if this is a child test case, false if this is a top-level test case
///
internal TestCaseEndEventArgs(
DataCollectionContext context,
Guid testCaseId,
- //TcmInformation tcmInformation,
string testCaseName,
bool isChildTestCase)
: this(context, testCaseId, testCaseName, isChildTestCase, TestOutcome.Failed)
@@ -223,23 +242,27 @@ internal TestCaseEndEventArgs(
}
///
+ /// Initializes a new instance of the class.
/// Initializes the instance by storing the given information
///
- /// Context information for the test case
- /// The test case ID
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
+ ///
+ ///
+ /// The test case ID
+ ///
+ ///
+ /// The test case name
///
- /// The test case name
///
/// True if this is a child test case, false if this is a top-level test case
///
- /// The outcome of the test case.
+ ///
+ /// The outcome of the test case.
+ ///
internal TestCaseEndEventArgs(
DataCollectionContext context,
Guid testCaseId,
- //TcmInformation tcmInformation,
string testCaseName,
bool isChildTestCase,
TestOutcome testOutcome)
@@ -247,41 +270,14 @@ internal TestCaseEndEventArgs(
{
Debug.Assert(context.HasTestCase, "Context is not for a test case");
this.TestOutcome = testOutcome;
- }
-
- ///
- /// Initializes the instance by storing the given information.
- ///
- /// Context information for the test case
- /// The test element of the test that this event is for.
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
- ///
- /// The outcome of the test case.
- public TestCaseEndEventArgs(
- DataCollectionContext context,
- TestCase testElement,
- //TcmInformation tcmInformation,
- TestOutcome testOutcome)
- : base(context, testElement)
- {
- // NOTE: ONLY USE FOR UNIT TESTING!
- // This overload is only here for 3rd parties to use for unit testing
- // their data collectors. Internally we should not be passing the test element
- // around in the events as this is extra information that needs to be seralized
- // and the Execution Plugin Manager will fill this in for us before the event
- // is sent to the data collector when running in a production environment.
-
- this.TestOutcome = testOutcome;
- }
+ }
#endregion
#region Properties
///
- /// The outcome of the test.
+ /// Gets the outcome of the test.
///
public TestOutcome TestOutcome
{
@@ -294,7 +290,7 @@ public TestOutcome TestOutcome
///
/// Test Case Pause Event arguments.
///
-#if NET451
+#if NET46
[Serializable]
#endif
public sealed class TestCasePauseEventArgs : TestCaseEventArgs
@@ -302,22 +298,46 @@ public sealed class TestCasePauseEventArgs : TestCaseEventArgs
#region Constructor
///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Context information for the test case
+ ///
+ ///
+ /// The test element of the test that this event is for.
+ ///
+ public TestCasePauseEventArgs(
+ DataCollectionContext context,
+ TestCase testElement)
+ : base(context, testElement)
+ {
+ // NOTE: ONLY USE FOR UNIT TESTING!
+ // This overload is only here for 3rd parties to use for unit testing
+ // their data collectors. Internally we should not be passing the test element
+ // around in the events as this is extra information that needs to be seralized
+ // and the Execution Plugin Manager will fill this in for us before the event
+ // is sent to the data collector when running in a production environment.
+ }
+
+ ///
+ /// Initializes a new instance of the class.
/// Initializes the instance by storing the given information
///
- /// Context information for the test case
- /// The test case ID
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
+ ///
+ ///
+ /// The test case ID
+ ///
+ ///
+ /// The test case name
///
- /// The test case name
///
/// True if this is a child test case, false if this is a top-level test case
///
internal TestCasePauseEventArgs(
DataCollectionContext context,
Guid testCaseId,
- //TcmInformation tcmInformation,
string testCaseName,
bool isChildTestCase)
: base(context, testCaseId, testCaseName, isChildTestCase)
@@ -325,19 +345,32 @@ internal TestCasePauseEventArgs(
Debug.Assert(context.HasTestCase, "Context is not for a test case");
}
+ #endregion
+ }
+
+ ///
+ /// Test Case Resume Event arguments.
+ ///
+#if NET46
+ [Serializable]
+#endif
+ public sealed class TestCaseResumeEventArgs : TestCaseEventArgs
+ {
+ #region Constructor
+
///
+ /// Initializes a new instance of the class.
/// Initializes the instance by storing the given information.
///
- /// Context information for the test case
- /// The test element of the test that this event is for.
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
///
- public TestCasePauseEventArgs(
+ ///
+ /// The test element of the test that this event is for.
+ ///
+ public TestCaseResumeEventArgs(
DataCollectionContext context,
TestCase testElement)
- //TcmInformation tcmInformation)
: base(context, testElement)
{
// NOTE: ONLY USE FOR UNIT TESTING!
@@ -348,56 +381,58 @@ public TestCasePauseEventArgs(
// is sent to the data collector when running in a production environment.
}
- #endregion
- }
-
- ///
- /// Test Case Resume Event arguments.
- ///
-#if NET451
- [Serializable]
-#endif
- public sealed class TestCaseResumeEventArgs : TestCaseEventArgs
- {
- #region Constructor
-
///
+ /// Initializes a new instance of the class.
/// Initializes the instance by storing the given information
///
- /// Context information for the test case
- /// The test case ID
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
+ ///
+ ///
+ /// The test case ID
+ ///
+ ///
+ /// The test case name
///
- /// The test case name
///
/// True if this is a child test case, false if this is a top-level test case
///
internal TestCaseResumeEventArgs(
DataCollectionContext context,
Guid testCaseId,
- //TcmInformation tcmInformation,
string testCaseName,
bool isChildTestCase)
: base(context, testCaseId, testCaseName, isChildTestCase)
{
Debug.Assert(context.HasTestCase, "Context is not for a test case");
- }
+ }
+
+ #endregion
+ }
+
+ ///
+ /// Test Case Reset Event arguments.
+ ///
+#if NET46
+ [Serializable]
+#endif
+ public sealed class TestCaseResetEventArgs : TestCaseEventArgs
+ {
+ #region Constructor
///
+ /// Initializes a new instance of the class.
/// Initializes the instance by storing the given information.
///
- /// Context information for the test case
- /// The test element of the test that this event is for.
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
///
- public TestCaseResumeEventArgs(
+ ///
+ /// The test element of the test that this event is for.
+ ///
+ public TestCaseResetEventArgs(
DataCollectionContext context,
TestCase testElement)
- //TcmInformation tcmInformation)
: base(context, testElement)
{
// NOTE: ONLY USE FOR UNIT TESTING!
@@ -408,56 +443,62 @@ public TestCaseResumeEventArgs(
// is sent to the data collector when running in a production environment.
}
- #endregion
- }
-
- ///
- /// Test Case Reset Event arguments.
- ///
-#if NET451
- [Serializable]
-#endif
- public sealed class TestCaseResetEventArgs : TestCaseEventArgs
- {
- #region Constructor
-
///
+ /// Initializes a new instance of the class.
/// Initializes the instance by storing the given information
///
- /// Context information for the test case
- /// The test case ID
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
+ ///
+ ///
+ /// The test case ID
+ ///
+ ///
+ /// The test case name
///
- /// The test case name
///
/// True if this is a child test case, false if this is a top-level test case
///
internal TestCaseResetEventArgs(
DataCollectionContext context,
Guid testCaseId,
- //TcmInformation tcmInformation,
string testCaseName,
bool isChildTestCase)
: base(context, testCaseId, testCaseName, isChildTestCase)
{
Debug.Assert(context.HasTestCase, "Context is not for a test case");
- }
+ }
+
+ #endregion
+ }
+
+ ///
+ /// Test Case Failed Event arguments.
+ ///
+#if NET46
+ [Serializable]
+#endif
+ public sealed class TestCaseFailedEventArgs : TestCaseEventArgs
+ {
+ #region Constructor
///
+ /// Initializes a new instance of the class.
/// Initializes the instance by storing the given information.
///
- /// Context information for the test case
- /// The test element of the test that this event is for.
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
///
- public TestCaseResetEventArgs(
+ ///
+ /// The test element of the test that this event is for.
+ ///
+ ///
+ /// The type of failure which has occurred.
+ ///
+ public TestCaseFailedEventArgs(
DataCollectionContext context,
- TestCase testElement)
- //TcmInformation tcmInformation)
+ TestCase testElement,
+ TestCaseFailureType failureType)
: base(context, testElement)
{
// NOTE: ONLY USE FOR UNIT TESTING!
@@ -466,39 +507,30 @@ public TestCaseResetEventArgs(
// around in the events as this is extra information that needs to be seralized
// and the Execution Plugin Manager will fill this in for us before the event
// is sent to the data collector when running in a production environment.
+ this.FailureType = failureType;
}
- #endregion
- }
-
- ///
- /// Test Case Failed Event arguments.
- ///
-#if NET451
- [Serializable]
-#endif
- public sealed class TestCaseFailedEventArgs : TestCaseEventArgs
- {
- #region Constructor
-
///
- /// Initializes the instance by storing the given information
+ /// Initializes a new instance of the class.
///
- /// Context information for the test case
- /// The test case ID
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
+ ///
+ /// Context information for the test case
+ ///
+ ///
+ /// The test case ID
+ ///
+ ///
+ /// The test case name
///
- /// The test case name
///
/// True if this is a child test case, false if this is a top-level test case
///
- /// The type of failure which has occured.
+ ///
+ /// The type of failure which has occurred.
+ ///
internal TestCaseFailedEventArgs(
DataCollectionContext context,
Guid testCaseId,
- //TcmInformation tcmInformation,
string testCaseName,
bool isChildTestCase,
TestCaseFailureType failureType)
@@ -508,37 +540,10 @@ internal TestCaseFailedEventArgs(
if (failureType < TestCaseFailureType.None || failureType > TestCaseFailureType.Other)
{
- throw new ArgumentOutOfRangeException("failureType");
+ throw new ArgumentOutOfRangeException(nameof(failureType));
}
- FailureType = failureType;
- }
-
- ///
- /// Initializes the instance by storing the given information.
- ///
- /// Context information for the test case
- /// The test element of the test that this event is for.
- ///
- /// Information used to obtain further data about the test from the Test Case Management (TCM) server,
- /// or null if the test did not originate from TCM.
- ///
- /// The type of failure which has occured.
- public TestCaseFailedEventArgs(
- DataCollectionContext context,
- TestCase testElement,
- //TcmInformation tcmInformation,
- TestCaseFailureType failureType)
- : base(context, testElement)
- {
- // NOTE: ONLY USE FOR UNIT TESTING!
- // This overload is only here for 3rd parties to use for unit testing
- // their data collectors. Internally we should not be passing the test element
- // around in the events as this is extra information that needs to be seralized
- // and the Execution Plugin Manager will fill this in for us before the event
- // is sent to the data collector when running in a production environment.
-
- FailureType = failureType;
+ this.FailureType = failureType;
}
#endregion
@@ -546,7 +551,7 @@ public TestCaseFailedEventArgs(
#region Properties
///
- /// The type of failure which occured.
+ /// Gets the type of failure which occurred.
///
public TestCaseFailureType FailureType { get; private set; }
diff --git a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/ITestExecutionEnvironmentSpecifier.cs b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/ITestExecutionEnvironmentSpecifier.cs
new file mode 100644
index 0000000000..c840a2b0c7
--- /dev/null
+++ b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/ITestExecutionEnvironmentSpecifier.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.DataCollector
+{
+ using System.Collections.Generic;
+
+ ///
+ /// Interface for data collectors add-ins that choose to specify some information about how the test execution environment
+ /// should be set up
+ ///
+ public interface ITestExecutionEnvironmentSpecifier
+ {
+ ///
+ /// Gets environment variables that should be set in the test execution environment
+ ///
+ /// Environment variables that should be set in the test execution environment
+ IEnumerable> GetTestExecutionEnvironmentVariables();
+ }
+}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/TransferInformation/BaseTransferInformation.cs b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/TransferInformation/BaseTransferInformation.cs
index 122c2d14e1..9e42efdde2 100644
--- a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/TransferInformation/BaseTransferInformation.cs
+++ b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/TransferInformation/BaseTransferInformation.cs
@@ -3,8 +3,6 @@
namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection
{
- using System;
-
///
/// Collects the required and optional information needed for requesting a file transfer from a data collector.
///
@@ -19,15 +17,16 @@ public abstract class BasicTransferInformation
#region Constructor
///
- /// Initializes with the data collection context for the transfer.
+ /// Initializes a new instance of the class.
///
- /// The data collection context for the transfer.
+ ///
+ /// The data collection context for the transfer.
+ ///
protected BasicTransferInformation(DataCollectionContext context)
{
//EqtAssert.ParameterNotNull(context, "context");
-
- Context = context;
- Description = String.Empty;
+ this.Context = context;
+ this.Description = string.Empty;
}
#endregion
@@ -35,7 +34,7 @@ protected BasicTransferInformation(DataCollectionContext context)
#region Required Parameters.
///
- /// The data collection context the transfer will be associated with.
+ /// Gets the data collection context the transfer will be associated with.
///
public DataCollectionContext Context { get; private set; }
@@ -44,42 +43,43 @@ protected BasicTransferInformation(DataCollectionContext context)
#region Optional Parameters.
///
- /// A short description of the data being sent.
+ /// Gets or sets a short description of the data being sent.
///
public string Description
{
get
{
- return description;
+ return this.description;
}
+
set
{
// If we don't have a description, use an empty string.
if (value == null)
{
- description = String.Empty;
+ this.description = string.Empty;
}
else
{
- description = value;
+ this.description = value;
}
}
}
///
- /// Token which will be included with the callback to identify this file transfer.
+ /// Gets or sets the token which will be included with the callback to identify this file transfer.
///
public object UserToken { get; set; }
///
- /// The ID of the request that this file should be associated with. This is used
+ /// Gets or sets the ID of the request that this file should be associated with. This is used
/// for sending transient data which will be associated only with this
/// data request and not the session or test cases that are currently running.
///
public RequestId RequestId { get; set; }
///
- /// Indicates if cleanup should be performed after transferring the resource. This
+ /// Gets a value indicating whether cleanup should be performed after transferring the resource. This
/// can be known by different names in the derived classes so it is protected internal
/// so that we can refer to it in a consistent way.
///
@@ -89,11 +89,11 @@ protected internal abstract bool PerformCleanup
}
///
- /// The name of the file to use on the client machine. This
+ /// Gets the name of the file to use on the client machine. This
/// can be known by different names in the derived classes so it is protected internal
/// so that we can refer to it in a consistent way.
///
- protected internal abstract string ClientFileName
+ protected internal abstract string FileName
{
get;
}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/TransferInformation/FileTransferInformation.cs b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/TransferInformation/FileTransferInformation.cs
index 96c4062085..c5c7ae2c3b 100644
--- a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/TransferInformation/FileTransferInformation.cs
+++ b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/TransferInformation/FileTransferInformation.cs
@@ -14,15 +14,21 @@ public class FileTransferInformation : BasicTransferInformation
#region Constructor
///
- /// Initializes with the information required for sending the contents of a file.
+ /// Initializes a new instance of the class.
///
- /// The context in which the file is being sent. Cannot be null.
- /// The path to the file on the local file system
- /// True to automatically have the file removed after sending it.
+ ///
+ /// The context in which the file is being sent. Cannot be null.
+ ///
+ ///
+ /// The path to the file on the local file system
+ ///
+ ///
+ /// True to automatically have the file removed after sending it.
+ ///
public FileTransferInformation(DataCollectionContext context, string path, bool deleteFile)
: base(context)
{
- //EqtAssert.StringNotNullOrEmpty(path, "path");
+ // EqtAssert.StringNotNullOrEmpty(path, "path");
// Expand environment variables in the path
path = Environment.ExpandEnvironmentVariables(path);
@@ -34,9 +40,9 @@ public FileTransferInformation(DataCollectionContext context, string path, bool
}
// Make sure the path we have is a full path (not relative).
- Path = System.IO.Path.GetFullPath(path);
+ this.Path = System.IO.Path.GetFullPath(path);
- PerformCleanup = deleteFile;
+ this.PerformCleanup = deleteFile;
}
#endregion
@@ -44,11 +50,10 @@ public FileTransferInformation(DataCollectionContext context, string path, bool
#region Required Parameters.
///
- /// The path to the file on the local file system.
+ /// Gets the path to the file on the local file system.
///
public string Path { get; private set; }
-
///
/// Indicates if cleanup should be performed after transferring the resource.
///
@@ -57,10 +62,7 @@ public FileTransferInformation(DataCollectionContext context, string path, bool
///
/// The name of the file to use on the client machine.
///
- protected internal override string ClientFileName
- {
- get { return Path; }
- }
+ protected internal override string FileName => this.Path;
#endregion
}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/TransferInformation/StreamTransferInformation.cs b/src/Microsoft.TestPlatform.ObjectModel/DataCollector/TransferInformation/StreamTransferInformation.cs
deleted file mode 100644
index 725c3835c5..0000000000
--- a/src/Microsoft.TestPlatform.ObjectModel/DataCollector/TransferInformation/StreamTransferInformation.cs
+++ /dev/null
@@ -1,90 +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.DataCollection
-{
- using System;
- using System.IO;
-
- ///
- /// Represents required and optional information needed for requesting a stream transfer.
- ///
- public class StreamTransferInformation : BasicTransferInformation
- {
- #region Constructor
-
- ///
- /// Initializes with the with required information for sending the contents of a stream.
- ///
- /// The context in which the file is being sent. Cannot be null.
- /// Stream to send.
- /// File name to use for the data on the client.
- /// True to automatically have the stream closed when sending of the contents has completed.
- public StreamTransferInformation(DataCollectionContext context, Stream stream, string fileName, bool closeStream)
- : base(context)
- {
- //todo
- //EqtAssert.ParameterNotNull(stream, "stream");
-
- // Make sure the trimmed filename is not empty.
- if ((fileName == null) ||
- (fileName = fileName.Trim()).Length == 0)
- {
- throw new ArgumentException(Resources.Resources.Common_CannotBeNullOrEmpty, "fileName");
- }
-
- // Make sure the filename provided is not a reserved filename.
- if (FileHelper.IsReservedFileName(fileName))
- {
- throw new ArgumentException(string.Format(Resources.Resources.DataCollectionSink_ReservedFilenameUsed, new object[] { fileName }), "fileName");
- }
-
- // Make sure just the filename was provided.
- string invalidCharacters;
- if (!FileHelper.IsValidFileName(fileName, out invalidCharacters))
- {
- throw new ArgumentException(string.Format(Resources.Resources.DataCollectionSink_InvalidFileNameCharacters, new object[] { fileName, invalidCharacters }), "fileName");
- }
-
- // If we can not read the stream, throw.
- if (!stream.CanRead)
- {
- throw new InvalidOperationException(Resources.Resources.DataCollectionSink_CanNotReadStream);
- }
-
- Stream = stream;
- FileName = fileName;
- PerformCleanup = closeStream;
- }
-
- #endregion
-
- #region Required Parameters.
-
- ///
- /// Stream to send.
- ///
- public Stream Stream { get; private set; }
-
- ///
- /// File name to use for the data on the client.
- ///
- public string FileName { get; private set; }
-
-
- ///
- /// Indicates if cleanup should be performed after transferring the resource.
- ///
- protected internal override bool PerformCleanup { get; }
-
- ///
- /// The name of the file to use on the client machine.
- ///
- protected internal override string ClientFileName
- {
- get { return FileName; }
- }
-
- #endregion
- }
-}
diff --git a/src/Microsoft.TestPlatform.ObjectModel/Friends.cs b/src/Microsoft.TestPlatform.ObjectModel/Friends.cs
index 93983c499d..8988fc37e9 100644
--- a/src/Microsoft.TestPlatform.ObjectModel/Friends.cs
+++ b/src/Microsoft.TestPlatform.ObjectModel/Friends.cs
@@ -6,5 +6,7 @@
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.Extensions.VSTestIntegration, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.Extensions.MSAppContainerAdapter, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.Extensions.MSPhoneAdapter, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
+[assembly: InternalsVisibleTo("datacollector, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("Microsoft.TestPlatform.ObjectModel.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
+[assembly: InternalsVisibleTo("datacollector.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
diff --git a/src/datacollector.x86/DataCollectionCoordinator.cs b/src/datacollector.x86/DataCollectionCoordinator.cs
deleted file mode 100644
index 98dafdb8b6..0000000000
--- a/src/datacollector.x86/DataCollectionCoordinator.cs
+++ /dev/null
@@ -1,233 +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.DataCollector
-{
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Threading.Tasks;
-
- using Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces;
- using Microsoft.VisualStudio.TestPlatform.Common.DataCollection;
- using Microsoft.VisualStudio.TestPlatform.ObjectModel;
- using Microsoft.VisualStudio.TestPlatform.Common;
- using Microsoft.VisualStudio.TestPlatform.Common.Utilities;
-
- ///
- /// Coordinates the Data Collection for V1 and V2 DataCollectors
- ///
- internal class DataCollectionCoordinator : IDisposable
- {
- private IDataCollectionManager[] dataCollectionManagers;
- private bool disposed;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public DataCollectionCoordinator() : this(default(IDataCollectionManager[]))
- {
- }
-
- ///
- /// Constructor with Dependency injection. Used for unit testing.
- ///
- /// Array of IDataCollectionManagers for handling various versions of DataCollectors (Legacy,V2)
- internal DataCollectionCoordinator(IDataCollectionManager[] dataCollectionManagers)
- {
- this.dataCollectionManagers = dataCollectionManagers;
- }
-
- ///
- /// Invoked before starting of test run.
- ///
- /// Specifies the settings which are being used for the run.
- /// Forces the data collectors to be reset.
- /// Specifies whether run is going to start immediately.
- /// Enivronment variables for the executor.
- public BeforeTestRunStartResult BeforeTestRunStart(string settingsXml, bool resetDataCollectors, bool isRunStartingNow)
- {
- if (this.dataCollectionManagers == null || this.dataCollectionManagers.Length == 0)
- {
- return null;
- }
-
- if (EqtTrace.IsVerboseEnabled)
- {
- EqtTrace.Verbose("DataCollectionCoordinator: BeforeTestRunStart Entering.");
- }
-
- var runSettings = RunSettingsUtilities.CreateAndInitializeRunSettings(settingsXml);
-
- if (EqtTrace.IsVerboseEnabled)
- {
- EqtTrace.Verbose("DataCollectionCoordinator: Loading/Initializing the data collectors");
- }
-
- // Load the collectors and get the environment variables
- var environmentVariables = this.LoadDataCollectors(runSettings);
-
- var areTestCaseLevelEventsRequired = false;
-
- if (isRunStartingNow)
- {
- if (EqtTrace.IsVerboseEnabled)
- {
- EqtTrace.Verbose("DataCollectionCoordinator: Raising session started event.");
- }
-
- // Raise SessionStart event to loaded data collection plugins.
- areTestCaseLevelEventsRequired = this.SessionStarted();
- }
-
- if (EqtTrace.IsVerboseEnabled)
- {
- EqtTrace.Verbose("DataCollectionCoordinator: BeforeTestRunStart Exiting areTestCaseLevelEventsRequired={0}.", areTestCaseLevelEventsRequired);
- }
-
- // todo : Get Data Collection Port here
- return new BeforeTestRunStartResult(environmentVariables, areTestCaseLevelEventsRequired, 0);
- }
-
- ///
- /// Invoked after ending of test run.
- ///
- /// Specified whether the test run is cancelled.
- /// Collection of session attachmentsets.
- public Collection AfterTestRunEnd(bool isCancelled)
- {
- if (this.dataCollectionManagers == null || this.dataCollectionManagers.Length == 0)
- {
- return null;
- }
-
- if (EqtTrace.IsVerboseEnabled)
- {
- EqtTrace.Verbose("DataCollectionCoordinator.AfterTestRunEnd: Entering.");
- }
-
- // Send RunCompleteEvent to data collection plugin manager so it can raise session end event to loaded collector plugins.
- Collection result = this.SessionEnded(isCancelled);
-
- if (EqtTrace.IsVerboseEnabled)
- {
- EqtTrace.Verbose("DataCollectionCoordinator.AfterTestRunEnd: Exiting.");
- }
-
- return result;
- }
-
- ///
- /// The dispose.
- ///
- public void Dispose()
- {
- this.Dispose(true);
-
- // Use SupressFinalize in case a subclass
- // of this type implements a finalizer.
- GC.SuppressFinalize(this);
- }
-
- private void Dispose(bool disposing)
- {
- if (!this.disposed)
- {
- if (disposing)
- {
- if (this.dataCollectionManagers != null && this.dataCollectionManagers.Length > 0)
- {
- var tasks = new List(this.dataCollectionManagers.Length);
-
- foreach (var dataCollectionManager in this.dataCollectionManagers)
- {
- tasks.Add(Task.Factory.StartNew(() => dataCollectionManager.Dispose()));
- }
-
- Task.WaitAll(tasks.ToArray());
- }
- }
-
- this.disposed = true;
- }
- }
-
- private Dictionary LoadDataCollectors(RunSettings runSettings)
- {
- var envVars = new Dictionary();
- var tasks = new List>>(this.dataCollectionManagers.Length);
-
- foreach (var dataCollectionManager in this.dataCollectionManagers)
- {
- tasks.Add(Task>.Factory.StartNew(() => dataCollectionManager.LoadDataCollectors(runSettings)));
- }
-
- Task.WaitAll(tasks.ToArray());
-
- for (var i = 0; i < this.dataCollectionManagers.Length; i++)
- {
- if (tasks[i].Status == TaskStatus.Faulted)
- {
- throw tasks[i].Exception.InnerException;
- }
-
- foreach (var kvp in tasks[i]?.Result)
- {
- if (!envVars.ContainsKey(kvp.Key))
- {
- envVars.Add(kvp.Key, kvp.Value);
- }
- }
- }
-
- return envVars;
- }
-
- private bool SessionStarted()
- {
- var areTestCaseLevelEventsRequired = false;
-
- var tasks = new List>(this.dataCollectionManagers.Length);
-
- foreach (var dataCollectionManager in this.dataCollectionManagers)
- {
- tasks.Add(Task.Factory.StartNew(() => dataCollectionManager.SessionStarted()));
- }
-
- Task.WaitAll(tasks.ToArray());
-
- for (var i = 0; i < this.dataCollectionManagers.Length; i++)
- {
- areTestCaseLevelEventsRequired = areTestCaseLevelEventsRequired || tasks[i].Result;
- }
-
- return areTestCaseLevelEventsRequired;
- }
-
- private Collection SessionEnded(bool isCancelled)
- {
- var attachments = new Collection();
- var tasks = new List>>(this.dataCollectionManagers.Length);
-
- foreach (var dataCollectionManager in this.dataCollectionManagers)
- {
- tasks.Add(Task>.Factory.StartNew(() => dataCollectionManager.SessionEnded(isCancelled)));
- }
-
- Task.WaitAll(tasks.ToArray());
-
- for (var i = 0; i < this.dataCollectionManagers.Length; i++)
- {
- if (tasks[i].Result != null)
- {
- foreach (var attachment in tasks[i].Result)
- {
- attachments.Add(attachment);
- }
- }
- }
-
- return attachments;
- }
- }
-}
diff --git a/src/datacollector.x86/Friends.cs b/src/datacollector.x86/Friends.cs
deleted file mode 100644
index 43c78eeea2..0000000000
--- a/src/datacollector.x86/Friends.cs
+++ /dev/null
@@ -1,10 +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.Runtime.CompilerServices;
-
-#region Test Assemblies
-
-[assembly: InternalsVisibleTo("datacollector.x86.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
-
-#endregion
diff --git a/src/datacollector.x86/Properties/AssemblyInfo.cs b/src/datacollector.x86/Properties/AssemblyInfo.cs
deleted file mode 100644
index beb7cd70f9..0000000000
--- a/src/datacollector.x86/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,22 +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.CompilerServices;
-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.x86")]
-[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("00dfb5c7-3850-4a65-986b-713f200482d4")]
diff --git a/src/datacollector.x86/app.config b/src/datacollector.x86/app.config
deleted file mode 100644
index 8846256c18..0000000000
--- a/src/datacollector.x86/app.config
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/datacollector.x86/datacollector.x86.csproj b/src/datacollector.x86/datacollector.x86.csproj
deleted file mode 100644
index 12c7cad25b..0000000000
--- a/src/datacollector.x86/datacollector.x86.csproj
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
- ..\..\
-
-
-
- datacollector.x86
- netcoreapp1.0;net46
- true
- x86
- Exe
- $(PackageTargetFallback);dnxcore50;netstandardapp1.0;portable-net45+win8;portable-net45+wp80+win8+wpa81+dnxcore50
-
-
- win7-x64
-
-
-
-
-
-
-
-
-
- true
-
-
- true
-
-
-
-
- 1.0.0
-
-
-
-
-
-
-
-
diff --git a/src/datacollector/DataCollectionAttachmentManager.cs b/src/datacollector/DataCollectionAttachmentManager.cs
new file mode 100644
index 0000000000..7126c79815
--- /dev/null
+++ b/src/datacollector/DataCollectionAttachmentManager.cs
@@ -0,0 +1,319 @@
+// 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.DataCollector
+{
+ using System;
+ using System.Collections.Generic;
+ using System.ComponentModel;
+ using System.Diagnostics;
+ using System.Globalization;
+ using System.IO;
+ using System.Linq;
+ using System.Threading.Tasks;
+
+ using Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+
+ ///
+ /// Manages file transfer from data collector to test runner service.
+ ///
+ internal class DataCollectionAttachmentManager : IDataCollectionAttachmentManager
+ {
+ #region Fields
+
+ ///
+ /// Default results directory to be used when user didn't specify.
+ ///
+ private const string DefaultOutputDirectoryName = "TestResults";
+
+ ///
+ /// Logger for data collection messages
+ ///
+ private IMessageSink messageSink;
+
+ ///
+ /// Attachment transfer tasks.
+ ///
+ private List attachmentTasks;
+
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public DataCollectionAttachmentManager()
+ {
+ this.attachmentTasks = new List();
+ this.AttachmentSets = new Dictionary();
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets the session output directory.
+ ///
+ internal string SessionOutputDirectory { get; private set; }
+
+ ///
+ /// Gets the attachment sets for the session.
+ ///
+ internal Dictionary AttachmentSets
+ {
+ get; private set;
+ }
+ #endregion
+
+ #region public methods
+
+ ///
+ public void Initialize(SessionId id, string outputDirectory, IMessageSink messageSink)
+ {
+ ValidateArg.NotNull(id, nameof(id));
+ ValidateArg.NotNull(messageSink, nameof(messageSink));
+
+ this.messageSink = messageSink;
+
+ if (string.IsNullOrEmpty(outputDirectory))
+ {
+ this.SessionOutputDirectory = Path.Combine(Path.GetTempPath(), DefaultOutputDirectoryName, id.Id.ToString());
+ }
+ else
+ {
+ // Create a session specific directory under base output directory.
+ var expandedOutputDirectory = Environment.ExpandEnvironmentVariables(outputDirectory);
+ var absolutePath = Path.GetFullPath(expandedOutputDirectory);
+ this.SessionOutputDirectory = Path.Combine(absolutePath, id.Id.ToString());
+ }
+
+ // Create the output directory if it doesn't exist.
+ if (!Directory.Exists(this.SessionOutputDirectory))
+ {
+ Directory.CreateDirectory(this.SessionOutputDirectory);
+ }
+ }
+
+ ///
+ public List GetAttachments(DataCollectionContext dataCollectionContext)
+ {
+ Task.WhenAll(this.attachmentTasks.ToArray()).Wait();
+ return this.AttachmentSets.Values.ToList();
+ }
+
+ ///
+ public void AddAttachment(FileTransferInformation fileTransferInfo, AsyncCompletedEventHandler sendFileCompletedCallback, Uri uri, string friendlyName)
+ {
+ ValidateArg.NotNull(fileTransferInfo, nameof(fileTransferInfo));
+
+ if (string.IsNullOrEmpty(this.SessionOutputDirectory))
+ {
+ if (EqtTrace.IsErrorEnabled)
+ {
+ EqtTrace.Error(
+ "DataCollectionAttachmentManager.AddAttachment: Initialize not invoked.");
+ }
+
+ return;
+ }
+
+ if (!this.AttachmentSets.ContainsKey(uri))
+ {
+ this.AttachmentSets.Add(uri, new AttachmentSet(uri, friendlyName));
+ }
+
+ if (fileTransferInfo != null)
+ {
+ this.AddNewFileTransfer(fileTransferInfo, sendFileCompletedCallback, uri, friendlyName);
+ }
+ else
+ {
+ if (EqtTrace.IsErrorEnabled)
+ {
+ EqtTrace.Error("DataCollectionAttachmentManager.AddAttachment: Got unexpected message of type FileTransferInformationExtension.");
+ }
+ }
+ }
+
+ #endregion
+
+ #region private methods
+
+ ///
+ /// Sanity checks on CopyRequestData
+ ///
+ ///
+ /// The file Transfer Info.
+ ///
+ ///
+ /// The local File Path.
+ ///
+ private static void Validate(FileTransferInformation fileTransferInfo, string localFilePath)
+ {
+ if (!File.Exists(fileTransferInfo.FileName))
+ {
+ throw new FileNotFoundException(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ "Could not find source file '{0}'.",
+ fileTransferInfo.FileName));
+ }
+
+ var directoryName = Path.GetDirectoryName(localFilePath);
+
+ if (!Directory.Exists(directoryName))
+ {
+ Directory.CreateDirectory(directoryName);
+ }
+ else if (File.Exists(localFilePath))
+ {
+ File.Delete(localFilePath);
+ }
+ }
+
+ ///
+ /// Add a new file transfer (either copy/move) request.
+ ///
+ ///
+ /// The file Transfer Info.
+ ///
+ ///
+ /// The send File Completed Callback.
+ ///
+ ///
+ /// The uri.
+ ///
+ ///
+ /// The friendly Name.
+ ///
+ private void AddNewFileTransfer(FileTransferInformation fileTransferInfo, AsyncCompletedEventHandler sendFileCompletedCallback, Uri uri, string friendlyName)
+ {
+ var context = fileTransferInfo.Context;
+ Debug.Assert(
+ context != null,
+ "DataCollectionManager.AddNewFileTransfer: FileDataHeaderMessage with null context.");
+
+ var testCaseId = fileTransferInfo.Context.HasTestCase
+ ? fileTransferInfo.Context.TestExecId.Id.ToString()
+ : string.Empty;
+
+ var directoryPath = Path.Combine(
+ this.SessionOutputDirectory,
+ testCaseId);
+ var localFilePath = Path.Combine(directoryPath, Path.GetFileName(fileTransferInfo.FileName));
+
+ // todo : add cancellation token for cancelling file operations test run is cancelled or there is a crash.
+ var task = new Task(() =>
+ {
+ Validate(fileTransferInfo, localFilePath);
+
+ try
+ {
+ if (fileTransferInfo.PerformCleanup)
+ {
+ if (EqtTrace.IsInfoEnabled)
+ {
+ EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Moving file {0} to {1}", fileTransferInfo.FileName, localFilePath);
+ }
+
+ File.Move(fileTransferInfo.FileName, localFilePath);
+
+ if (EqtTrace.IsInfoEnabled)
+ {
+ EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Moved file {0} to {1}", fileTransferInfo.FileName, localFilePath);
+ }
+ }
+ else
+ {
+ if (EqtTrace.IsInfoEnabled)
+ {
+ EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Copying file {0} to {1}", fileTransferInfo.FileName, localFilePath);
+ }
+
+ File.Copy(fileTransferInfo.FileName, localFilePath);
+
+ if (EqtTrace.IsInfoEnabled)
+ {
+ EqtTrace.Info("DataCollectionAttachmentManager.AddNewFileTransfer : Copied file {0} to {1}", fileTransferInfo.FileName, localFilePath);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ this.LogError(
+ ex.Message,
+ uri,
+ friendlyName,
+ Guid.Parse(testCaseId));
+
+ throw;
+ }
+ });
+
+ var continuationTask = task.ContinueWith((t) =>
+ {
+ try
+ {
+ if (t.Exception == null)
+ {
+ this.AttachmentSets[uri].Attachments.Add(new UriDataAttachment(new Uri(localFilePath), fileTransferInfo.Description));
+ }
+
+ sendFileCompletedCallback(this, new AsyncCompletedEventArgs(t.Exception, false, fileTransferInfo.UserToken));
+ }
+ catch (Exception e)
+ {
+ if (EqtTrace.IsErrorEnabled)
+ {
+ EqtTrace.Error(
+ "DataCollectionAttachmentManager.TriggerCallBack: Error occurred while raising the file transfer completed callback for {0}. Error: {1}",
+ localFilePath,
+ e.ToString());
+ }
+ }
+ });
+
+ this.attachmentTasks.Add(task);
+ this.attachmentTasks.Add(continuationTask);
+ task.Start();
+ }
+
+ ///
+ /// Logs an error message.
+ ///
+ ///
+ /// The error message.
+ ///
+ ///
+ /// The collector uri.
+ ///
+ ///
+ /// The collector friendly name.
+ ///
+ ///
+ /// Id of testCase if available, null otherwise.
+ ///
+ private void LogError(string errorMessage, Uri collectorUri, string collectorFriendlyName, Guid testCaseId)
+ {
+ var args = new DataCollectionMessageEventArgs(TestMessageLevel.Error, errorMessage)
+ {
+ Uri = collectorUri,
+ FriendlyName = collectorFriendlyName
+ };
+
+ if (!testCaseId.Equals(Guid.Empty))
+ {
+ args.TestCaseId = testCaseId;
+ }
+
+ this.messageSink.SendMessage(args);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/datacollector/DataCollectionEnvironmentVariable.cs b/src/datacollector/DataCollectionEnvironmentVariable.cs
new file mode 100644
index 0000000000..92cbde0a5b
--- /dev/null
+++ b/src/datacollector/DataCollectionEnvironmentVariable.cs
@@ -0,0 +1,107 @@
+// 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.DataCollector
+{
+ using System.Collections.Generic;
+
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+
+ ///
+ /// An environment variable requested to be set in the test execution environment by a data collector, including the
+ /// friendly names of data collectors that requested it.
+ /// This is needed to find list of environment variables needed for test run after eliminating the duplicate name and keys.
+ /// For details check DataCollectionPluginManager.AddCollectorEnvironmentVariables() method.
+ ///
+ internal class DataCollectionEnvironmentVariable
+ {
+ #region Fields
+
+ ///
+ /// Variable name and requested value
+ ///
+ private readonly KeyValuePair variable;
+
+ ///
+ /// Friendly names of data collectors that requested this environment variable
+ ///
+ private List dataCollectorsThatRequested;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Variable name and requested value.
+ ///
+ ///
+ /// Friendly name of the data collector requesting it.
+ ///
+ public DataCollectionEnvironmentVariable(
+ KeyValuePair variable,
+ string requestingDataCollectorFriendlyName)
+ {
+ ValidateArg.NotNullOrEmpty(variable.Key, nameof(variable.Key));
+ ValidateArg.NotNullOrEmpty(requestingDataCollectorFriendlyName, nameof(requestingDataCollectorFriendlyName));
+
+ this.variable = variable;
+ this.dataCollectorsThatRequested = new List { requestingDataCollectorFriendlyName };
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets variable name.
+ ///
+ public string Name
+ {
+ get
+ {
+ return this.variable.Key;
+ }
+ }
+
+ ///
+ /// Gets requested value
+ ///
+ public string Value
+ {
+ get
+ {
+ return this.variable.Value;
+ }
+ }
+
+ ///
+ /// Gets friendly name of the first data collector that requested this environment variable
+ ///
+ public string FirstDataCollectorThatRequested
+ {
+ get
+ {
+ return this.dataCollectorsThatRequested[0];
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Adds the data collector to the list of data collectors that requested this variable.
+ ///
+ /// Friendly name of requesting data collector.
+ public void AddRequestingDataCollector(string requestingDataCollectorFriendlyName)
+ {
+ ValidateArg.NotNullOrEmpty(requestingDataCollectorFriendlyName, nameof(requestingDataCollectorFriendlyName));
+ this.dataCollectorsThatRequested.Add(requestingDataCollectorFriendlyName);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/datacollector/DataCollectionManager.cs b/src/datacollector/DataCollectionManager.cs
new file mode 100644
index 0000000000..660bc284e2
--- /dev/null
+++ b/src/datacollector/DataCollectionManager.cs
@@ -0,0 +1,552 @@
+// 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.DataCollector
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Diagnostics;
+ using System.Globalization;
+ using System.IO;
+ using System.Linq;
+ using System.Reflection;
+
+ using Microsoft.VisualStudio.TestPlatform.Common.Utilities;
+ using Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
+
+ ///
+ /// Manages data collection.
+ ///
+ internal class DataCollectionManager : IDataCollectionManager
+ {
+ ///
+ /// The source directory.
+ ///
+ private static string sourceDirectory;
+
+ ///
+ /// Value indicating whether data collection is currently enabled.
+ ///
+ private bool isDataCollectionEnabled;
+
+ ///
+ /// Data collection environment context.
+ ///
+ private DataCollectionEnvironmentContext dataCollectionEnvironmentContext;
+
+ ///
+ /// Attachment manager for performing file transfer from datacollector.
+ ///
+ private IDataCollectionAttachmentManager attachmentManager;
+
+ ///
+ /// Message sink for sending data collection messages to client..
+ ///
+ private IMessageSink messageSink;
+
+ ///
+ /// Events that can be subscribed by datacollectors.
+ ///
+ private TestPlatformDataCollectionEvents events;
+
+ ///
+ /// Specifies whether the object is disposed or not.
+ ///
+ private bool disposed;
+
+ ///
+ /// Loads datacollector.
+ ///
+ private IDataCollectorLoader dataCollectorLoader;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ internal DataCollectionManager() : this(new DataCollectionAttachmentManager(), new MessageSink(), new DataCollectorLoader())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The datacollection Attachment Manager.
+ ///
+ ///
+ /// The message Sink.
+ ///
+ ///
+ /// The data Collector Loader.
+ ///
+ internal DataCollectionManager(IDataCollectionAttachmentManager datacollectionAttachmentManager, IMessageSink messageSink, IDataCollectorLoader dataCollectorLoader)
+ {
+ this.attachmentManager = datacollectionAttachmentManager;
+ this.messageSink = messageSink;
+ this.dataCollectorLoader = dataCollectorLoader;
+ this.events = new TestPlatformDataCollectionEvents();
+
+ this.RunDataCollectors = new Dictionary();
+ }
+
+ ///
+ /// Gets cache of data collectors associated with the run.
+ ///
+ internal Dictionary RunDataCollectors { get; private set; }
+
+ ///
+ public IDictionary InitializeDataCollectors(string settingsXml)
+ {
+ if (string.IsNullOrEmpty(settingsXml) && EqtTrace.IsInfoEnabled)
+ {
+ EqtTrace.Info("DataCollectionManager.InitializeDataCollectors : Runsettings is null or empty.");
+ }
+
+ ValidateArg.NotNull(settingsXml, "settingsXml");
+
+ var sessionId = new SessionId(Guid.NewGuid());
+ var dataCollectionContext = new DataCollectionContext(sessionId);
+ this.dataCollectionEnvironmentContext = DataCollectionEnvironmentContext.CreateForLocalEnvironment(dataCollectionContext);
+
+ this.attachmentManager.Initialize(sessionId, sourceDirectory, this.messageSink);
+
+ // Enviornment variables are passed to testhost process, through ProcessStartInfo.EnvironmentVariables, which handles the key in a case-insensitive manner, which is translated to lowercase.
+ // Therefore, using StringComparer.OrdinalIgnoreCase so that same keys with different cases are treated as same.
+ var executionEnvironmentVariables = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(settingsXml);
+ sourceDirectory = RunSettingsUtilities.GetTestResultsDirectory(runConfiguration);
+
+ var dataCollectionRunSettings = XmlRunSettingsUtilities.GetDataCollectionRunSettings(settingsXml);
+
+ this.isDataCollectionEnabled = dataCollectionRunSettings.IsCollectionEnabled;
+
+ // If dataCollectionRunSettings is null, that means datacollectors are not configured.
+ if (dataCollectionRunSettings == null || !dataCollectionRunSettings.IsCollectionEnabled)
+ {
+ return executionEnvironmentVariables;
+ }
+
+ // Get settings for each data collector, load and initialize the data collectors.
+ var enabledDataCollectorsSettings = this.GetDataCollectorsEnabledForRun(dataCollectionRunSettings);
+ if (enabledDataCollectorsSettings == null || enabledDataCollectorsSettings.Count == 0)
+ {
+ return executionEnvironmentVariables;
+ }
+
+ foreach (var dataCollectorSettings in enabledDataCollectorsSettings)
+ {
+ this.LoadAndInitialize(dataCollectorSettings);
+ }
+
+ // Once all data collectors have been initialized, query for environment variables
+ bool unloadedAnyCollector;
+ var dataCollectorEnvironmentVariables = this.GetEnvironmentVariables(out unloadedAnyCollector);
+
+ foreach (var variable in dataCollectorEnvironmentVariables.Values)
+ {
+ executionEnvironmentVariables.Add(variable.Name, variable.Value);
+ }
+
+ return executionEnvironmentVariables;
+ }
+
+ ///
+ public void Dispose()
+ {
+ this.Dispose(true);
+
+ // Use SupressFinalize in case a subclass
+ // of this type implements a finalizer.
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ public Collection SessionEnded()
+ {
+ // Return null if datacollection is not enabled.
+ if (!this.isDataCollectionEnabled)
+ {
+ return new Collection();
+ }
+
+ var endEvent = new SessionEndEventArgs(this.dataCollectionEnvironmentContext.SessionDataCollectionContext);
+ this.SendEvent(endEvent);
+
+ List result = new List();
+ try
+ {
+ result = this.attachmentManager.GetAttachments(endEvent.Context);
+ }
+ catch (Exception ex)
+ {
+ if (EqtTrace.IsErrorEnabled)
+ {
+ EqtTrace.Error("DataCollectionManager.SessionEnded: Failed to get attachments : {0}", ex.Message);
+ }
+
+ return new Collection(result);
+ }
+
+ foreach (var entry in result)
+ {
+ foreach (var file in entry.Attachments)
+ {
+ if (EqtTrace.IsVerboseEnabled)
+ {
+ EqtTrace.Verbose(
+ "Run Attachment Description: Collector:'{0}' Uri:'{1}' Description:'{2}' Uri:'{3}' ",
+ entry.DisplayName,
+ entry.Uri,
+ file.Description,
+ file.Uri);
+ }
+ }
+ }
+
+ return new Collection(result);
+ }
+
+ ///
+ public bool SessionStarted()
+ {
+ // If datacollectors are not configured or datacollection is not enabled, return false.
+ if (!this.isDataCollectionEnabled || this.RunDataCollectors.Count == 0)
+ {
+ return false;
+ }
+
+ this.SendEvent(new SessionStartEventArgs(this.dataCollectionEnvironmentContext.SessionDataCollectionContext));
+
+ return true;
+ }
+
+ ///
+ public Collection TestCaseEnded(TestCase testCase, TestOutcome testOutcome)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ public void TestCaseStarted(TestCaseStartEventArgs testCaseStartEventArgs)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// The dispose.
+ ///
+ ///
+ /// The disposing.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!this.disposed)
+ {
+ if (disposing)
+ {
+ }
+
+ this.disposed = true;
+ }
+ }
+
+ #region Load and Initialize DataCollectors
+
+ ///
+ /// Loads and initializes datacollector using datacollector settings.
+ ///
+ ///
+ /// The data collector settings.
+ ///
+ private void LoadAndInitialize(DataCollectorSettings dataCollectorSettings)
+ {
+ var collectorTypeName = dataCollectorSettings.AssemblyQualifiedName;
+ DataCollectorInformation dataCollectorInfo;
+ DataCollectorConfig dataCollectorConfig;
+
+ try
+ {
+ var dataCollector = this.dataCollectorLoader.Load(dataCollectorSettings.CodeBase, dataCollectorSettings.AssemblyQualifiedName);
+
+ if (dataCollector == null)
+ {
+ this.LogWarning(string.Format(CultureInfo.CurrentUICulture, Resources.Resources.DataCollectorNotFound, collectorTypeName, string.Empty));
+ return;
+ }
+
+ if (this.RunDataCollectors.ContainsKey(dataCollector.GetType()))
+ {
+ // Collector is already loaded (may be configured twice). Ignore duplicates and return.
+ return;
+ }
+
+ dataCollectorConfig = new DataCollectorConfig(dataCollector.GetType());
+
+ // Attempt to get the data collector information verifying that all of the required metadata for the collector is available.
+ dataCollectorInfo = new DataCollectorInformation(
+ dataCollector,
+ dataCollectorSettings.Configuration,
+ dataCollectorConfig,
+ this.dataCollectionEnvironmentContext,
+ this.attachmentManager,
+ this.events,
+ this.messageSink);
+
+ if (!dataCollectorInfo.DataCollectorConfig.TypeUri.Equals(dataCollectorSettings.Uri))
+ {
+ // If the data collector was not found, send an error.
+ this.LogWarning(string.Format(CultureInfo.CurrentCulture, Resources.Resources.DataCollectorNotFound, dataCollectorConfig.DataCollectorType.FullName, dataCollectorSettings.Uri));
+ return;
+ }
+ }
+ catch (Exception ex)
+ {
+ if (EqtTrace.IsErrorEnabled)
+ {
+ EqtTrace.Error("DataCollectionManager.LoadAndInitialize: exception while creating data collector {0} : {1}", collectorTypeName, ex);
+ }
+
+ // No data collector info, so send the error with no direct association to the collector.
+ this.LogWarning(string.Format(CultureInfo.CurrentUICulture, Resources.Resources.DataCollectorInitializationError, collectorTypeName, ex.Message));
+ return;
+ }
+
+ try
+ {
+ dataCollectorInfo.InitializeDataCollector();
+ lock (this.RunDataCollectors)
+ {
+ // Add data collectors to run cache.
+ this.RunDataCollectors[dataCollectorConfig.DataCollectorType] = dataCollectorInfo;
+ }
+ }
+ catch (Exception ex)
+ {
+ if (EqtTrace.IsErrorEnabled)
+ {
+ EqtTrace.Error("DataCollectionManager.LoadAndInitialize: exception while initializing data collector {0}: " + ex, collectorTypeName);
+ }
+
+ // Log error.
+ dataCollectorInfo.Logger.LogError(this.dataCollectionEnvironmentContext.SessionDataCollectionContext, string.Format(CultureInfo.CurrentCulture, Resources.Resources.DataCollectorInitializationError, dataCollectorConfig.FriendlyName, ex.Message));
+
+ // Dispose datacollector.
+ dataCollectorInfo.DisposeDataCollector();
+ }
+ }
+
+ ///
+ /// Finds data collector enabled for the run in data collection settings.
+ ///
+ /// data collection settings
+ /// List of enabled data collectors
+ private List GetDataCollectorsEnabledForRun(DataCollectionRunSettings dataCollectionSettings)
+ {
+ var runEnabledDataCollectors = new List();
+ foreach (var settings in dataCollectionSettings.DataCollectorSettingsList)
+ {
+ if (settings.IsEnabled)
+ {
+ if (runEnabledDataCollectors.Any(dcSettings => dcSettings.Uri.Equals(settings.Uri)
+ || string.Equals(dcSettings.AssemblyQualifiedName, settings.AssemblyQualifiedName, StringComparison.OrdinalIgnoreCase)))
+ {
+ // If Uri or assembly qualified type name is repeated, consider data collector as duplicate and ignore it.
+ this.LogWarning(string.Format(CultureInfo.CurrentUICulture, Resources.Resources.IgnoredDuplicateConfiguration, settings.AssemblyQualifiedName, settings.Uri));
+ continue;
+ }
+
+ runEnabledDataCollectors.Add(settings);
+ }
+ }
+
+ return runEnabledDataCollectors;
+ }
+
+ #endregion
+
+ ///
+ /// Sends a warning message against the session which is not associated with a data collector.
+ ///
+ ///
+ /// This should only be used when we do not have the data collector info yet. After we have the data
+ /// collector info we can use the data collectors logger for errors.
+ ///
+ /// The message to be logged.
+ private void LogWarning(string warningMessage)
+ {
+ this.messageSink.SendMessage(new DataCollectionMessageEventArgs(TestMessageLevel.Warning, warningMessage));
+ }
+
+ ///
+ /// Sends the event to all data collectors and fires a callback on the sender, letting it
+ /// know when all plugins have completed processing the event
+ ///
+ /// The context information for the event
+ private void SendEvent(DataCollectionEventArgs args)
+ {
+ ValidateArg.NotNull(args, nameof(args));
+
+ if (!this.isDataCollectionEnabled)
+ {
+ if (EqtTrace.IsErrorEnabled)
+ {
+ EqtTrace.Error("DataCollectionManger:SendEvent: SendEvent called when no collection is enabled.");
+ }
+
+ return;
+ }
+
+ foreach (var dataCollectorInfo in this.RunDataCollectors.Values)
+ {
+ if (EqtTrace.IsVerboseEnabled)
+ {
+ EqtTrace.Verbose("DataCollectionManger:SendEvent: Raising event {0} to collector {1}", args.GetType(), dataCollectorInfo.DataCollectorConfig.FriendlyName);
+ }
+
+ try
+ {
+ this.events.RaiseEvent(args);
+ }
+ catch (Exception ex)
+ {
+ if (EqtTrace.IsErrorEnabled)
+ {
+ EqtTrace.Error("DataCollectionManger:SendEvent: Error while RaiseEvent {0} to datacollector {1} : {2}.", args.GetType(), dataCollectorInfo.DataCollectorConfig.FriendlyName, ex.Message);
+ }
+ }
+ }
+ }
+
+ ///
+ /// The get environment variables.
+ ///
+ ///
+ /// The unloaded any collector.
+ ///
+ ///
+ /// Dictionary of variable name as key and collector requested environment variable as value.
+ ///
+ private Dictionary GetEnvironmentVariables(out bool unloadedAnyCollector)
+ {
+ var failedCollectors = new List();
+ unloadedAnyCollector = false;
+ var dataCollectorEnvironmentVariable = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ foreach (var dataCollectorInfo in this.RunDataCollectors.Values)
+ {
+ try
+ {
+ this.AddCollectorEnvironmentVariables(dataCollectorInfo, dataCollectorEnvironmentVariable);
+ }
+ catch (Exception ex)
+ {
+ unloadedAnyCollector = true;
+
+ var dataCollectorType = dataCollectorInfo.DataCollector.GetType();
+ failedCollectors.Add(dataCollectorInfo);
+ dataCollectorInfo.Logger.LogError(
+ this.dataCollectionEnvironmentContext.SessionDataCollectionContext,
+ string.Format(CultureInfo.CurrentCulture, Resources.Resources.DataCollectorErrorOnGetVariable, dataCollectorType, ex.ToString()));
+
+ if (EqtTrace.IsErrorEnabled)
+ {
+ EqtTrace.Error("DataCollectionManager.GetEnvironmentVariables: Failed to get variable for Collector '{0}': {1}", dataCollectorType, ex);
+ }
+ }
+ }
+
+ this.RemoveDataCollectors(failedCollectors);
+ return dataCollectorEnvironmentVariable;
+ }
+
+ ///
+ /// Collects environment variable to be set in test process by avoiding duplicates
+ /// and detecting override of variable value by multiple adapters.
+ ///
+ ///
+ /// The data Collection Wrapper.
+ ///
+ ///
+ /// Environment variables required for already loaded plugin.
+ ///
+ private void AddCollectorEnvironmentVariables(
+ DataCollectorInformation dataCollectionWrapper,
+ Dictionary dataCollectorEnvironmentVariables)
+ {
+ if (dataCollectionWrapper.TestExecutionEnvironmentVariables != null)
+ {
+ var collectorFriendlyName = dataCollectionWrapper.DataCollectorConfig.FriendlyName;
+ foreach (var namevaluepair in dataCollectionWrapper.TestExecutionEnvironmentVariables)
+ {
+ DataCollectionEnvironmentVariable alreadyRequestedVariable;
+ if (dataCollectorEnvironmentVariables.TryGetValue(namevaluepair.Key, out alreadyRequestedVariable))
+ {
+ // Dev10 behavior is to consider environment variables values as case sensitive.
+ if (string.Equals(namevaluepair.Value, alreadyRequestedVariable.Value, StringComparison.Ordinal))
+ {
+ alreadyRequestedVariable.AddRequestingDataCollector(collectorFriendlyName);
+ }
+ else
+ {
+ // Data collector is overriding an already requested variable, possibly an error.
+ dataCollectionWrapper.Logger.LogError(
+ this.dataCollectionEnvironmentContext.SessionDataCollectionContext,
+ string.Format(
+ CultureInfo.CurrentUICulture,
+ Resources.Resources.DataCollectorRequestedDuplicateEnvironmentVariable,
+ collectorFriendlyName,
+ namevaluepair.Key,
+ namevaluepair.Value,
+ alreadyRequestedVariable.FirstDataCollectorThatRequested,
+ alreadyRequestedVariable.Value));
+ }
+ }
+ else
+ {
+ if (EqtTrace.IsVerboseEnabled)
+ {
+ // new variable, add to the list.
+ EqtTrace.Verbose("DataCollectionManager.AddCollectionEnvironmentVariables: Adding Environment variable '{0}' value '{1}'", namevaluepair.Key, namevaluepair.Value);
+ }
+
+ dataCollectorEnvironmentVariables.Add(
+ namevaluepair.Key,
+ new DataCollectionEnvironmentVariable(namevaluepair, collectorFriendlyName));
+ }
+ }
+ }
+ }
+
+ ///
+ /// The remove data collectors.
+ ///
+ ///
+ /// The data collectors to remove.
+ ///
+ private void RemoveDataCollectors(IReadOnlyCollection dataCollectorsToRemove)
+ {
+ if (dataCollectorsToRemove == null || !dataCollectorsToRemove.Any())
+ {
+ return;
+ }
+
+ lock (this.RunDataCollectors)
+ {
+ foreach (var dataCollectorToRemove in dataCollectorsToRemove)
+ {
+ dataCollectorToRemove.DisposeDataCollector();
+ this.RunDataCollectors.Remove(dataCollectorToRemove.DataCollector.GetType());
+ }
+
+ if (this.RunDataCollectors.Count == 0)
+ {
+ this.isDataCollectionEnabled = false;
+ }
+ }
+ }
+ }
+}
diff --git a/src/datacollector/DataCollectorConfig.cs b/src/datacollector/DataCollectorConfig.cs
new file mode 100644
index 0000000000..6af3e824ff
--- /dev/null
+++ b/src/datacollector/DataCollectorConfig.cs
@@ -0,0 +1,130 @@
+// 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.DataCollector
+{
+ using System;
+ using System.Diagnostics;
+ using System.Globalization;
+ using System.Linq;
+ using System.Reflection;
+
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollector;
+
+ ///
+ /// The data collector config.
+ ///
+ public class DataCollectorConfig
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The type.
+ ///
+ public DataCollectorConfig(Type type)
+ {
+ ValidateArg.NotNull(type, nameof(type));
+
+ this.DataCollectorType = type;
+ this.TypeUri = GetTypeUri(type);
+ this.FriendlyName = GetFriendlyName(type);
+ }
+
+ ///
+ /// Gets the data collector type.
+ ///
+ public Type DataCollectorType { get; private set; }
+
+ ///
+ /// Gets the type uri.
+ ///
+ public Uri TypeUri { get; private set; }
+
+ ///
+ /// Gets the friendly name.
+ ///
+ public string FriendlyName { get; private set; }
+
+ ///
+ /// Gets the Type Uri for the data collector.
+ ///
+ /// The data collector to get the Type URI for.
+ /// Type Uri of the data collector.
+ private static Uri GetTypeUri(Type dataCollectorType)
+ {
+ DataCollectorTypeUriAttribute typeUriAttribute = null;
+ try
+ {
+ var typeUriAttributes = GetAttributes(dataCollectorType, typeof(DataCollectorTypeUriAttribute));
+ typeUriAttribute = (DataCollectorTypeUriAttribute)typeUriAttributes[0];
+ }
+ catch (Exception)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Resources.DataCollector_TypeIsNull, dataCollectorType.FullName));
+ }
+
+ // The type uri can not be null or empty.
+ if (string.IsNullOrEmpty(typeUriAttribute.TypeUri))
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Resources.DataCollector_TypeIsNull, dataCollectorType.FullName));
+ }
+
+ return new Uri(typeUriAttribute.TypeUri);
+ }
+
+ ///
+ /// Gets the friendly name for the data collector.
+ ///
+ /// The data collector to get the Type URI for.
+ /// Friendly name of the data collector.
+ private static string GetFriendlyName(Type dataCollectorType)
+ {
+ Debug.Assert(dataCollectorType != null, "null dataCollectorType");
+
+ DataCollectorFriendlyNameAttribute friendlyNameAttribute = null;
+
+ // Get the friendly name from the attribute.
+ try
+ {
+ var friendlyNameAttributes = GetAttributes(dataCollectorType, typeof(DataCollectorFriendlyNameAttribute));
+ friendlyNameAttribute = (DataCollectorFriendlyNameAttribute)friendlyNameAttributes[0];
+ }
+ catch (Exception)
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Resources.FriendlyNameIsNullOrEmpty, dataCollectorType.FullName));
+ }
+
+ // Verify that the friendly name provided is not null or empty.
+ if (string.IsNullOrEmpty(friendlyNameAttribute.FriendlyName))
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Resources.FriendlyNameIsNullOrEmpty, dataCollectorType.FullName));
+ }
+
+ return friendlyNameAttribute.FriendlyName;
+ }
+
+ ///
+ /// Gets the attributes of the specified type from the data collector type.
+ ///
+ ///
+ /// Data collector type to get attribute from.
+ ///
+ ///
+ /// The type of attribute to look for.
+ ///
+ ///
+ /// Array of attributes matching the type provided. Will be an empty array if none were found.
+ ///
+ private static object[] GetAttributes(Type dataCollectorType, Type attributeType)
+ {
+ Debug.Assert(dataCollectorType != null, "null dataCollectorType");
+ Debug.Assert(attributeType != null, "null attributeType");
+
+ // If any attribute constructor on the type throws, the exception will bubble up through
+ // the "GetCustomAttributes" method.
+ return dataCollectorType.GetTypeInfo().GetCustomAttributes(attributeType, true).ToArray
/// Run Settings which has DataCollector configuration.
/// Environment variables.
- Dictionary LoadDataCollectors(RunSettings settingsXml);
+ IDictionary InitializeDataCollectors(string settingsXml);
///
/// Raises TestCaseStart event to all data collectors configured for run.
@@ -48,8 +45,7 @@ internal interface IDataCollectionManager : IDisposable
///
/// Raises SessionEnd event to all data collectors configured for run.
///
- /// Specified whether the run is cancelled or not.
/// Collection of session attachmentSet.
- Collection SessionEnded(bool isCancelled);
+ Collection SessionEnded();
}
}
\ No newline at end of file
diff --git a/src/datacollector/Interfaces/IDataCollectorLoader.cs b/src/datacollector/Interfaces/IDataCollectorLoader.cs
new file mode 100644
index 0000000000..0040750cf0
--- /dev/null
+++ b/src/datacollector/Interfaces/IDataCollectorLoader.cs
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces
+{
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+
+ ///
+ /// Loads datacollector.
+ ///
+ internal interface IDataCollectorLoader
+ {
+ ///
+ /// Loads datacollector from specified assembly using assembly qualified name.
+ ///
+ ///
+ /// Location of datacollector assembly.
+ ///
+ ///
+ /// The assembly qualified name of datacollector.
+ ///
+ ///
+ /// The .
+ ///
+ DataCollector Load(string location, string assemblyQualifiedName);
+ }
+}
diff --git a/src/datacollector/Interfaces/IMessageSink.cs b/src/datacollector/Interfaces/IMessageSink.cs
new file mode 100644
index 0000000000..56c6ab703b
--- /dev/null
+++ b/src/datacollector/Interfaces/IMessageSink.cs
@@ -0,0 +1,19 @@
+// 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.DataCollector.Interfaces
+{
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+
+ ///
+ /// Expose methods to be used by data collection process to send messages to Test Platform Client.
+ ///
+ internal interface IMessageSink
+ {
+ ///
+ /// Data collection message as sent by DataCollectionLogger.
+ ///
+ /// Data collection message event args.
+ void SendMessage(DataCollectionMessageEventArgs args);
+ }
+}
diff --git a/src/datacollector/MessageSink.cs b/src/datacollector/MessageSink.cs
new file mode 100644
index 0000000000..03ec0ef8dc
--- /dev/null
+++ b/src/datacollector/MessageSink.cs
@@ -0,0 +1,22 @@
+// 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.DataCollector
+{
+ using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection;
+ using Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+
+ ///
+ internal class MessageSink : IMessageSink
+ {
+ ///
+ /// Data collection message as sent by DataCollectionLogger.
+ ///
+ /// Data collection message event args.
+ public void SendMessage(DataCollectionMessageEventArgs args)
+ {
+ DataCollectionRequestHandler.Instance.SendDataCollectionMessage(args);
+ }
+ }
+}
diff --git a/src/datacollector.x86/Program.cs b/src/datacollector/Program.cs
similarity index 97%
rename from src/datacollector.x86/Program.cs
rename to src/datacollector/Program.cs
index c80e39780a..e1abf1e82d 100644
--- a/src/datacollector.x86/Program.cs
+++ b/src/datacollector/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.VisualStudio.TestPlatform.DataCollector.x86
+namespace Microsoft.VisualStudio.TestPlatform.DataCollector
{
using System;
diff --git a/src/datacollector/Properties/AssemblyInfo.cs b/src/datacollector/Properties/AssemblyInfo.cs
index 1a156307ed..0a9e15abc2 100644
--- a/src/datacollector/Properties/AssemblyInfo.cs
+++ b/src/datacollector/Properties/AssemblyInfo.cs
@@ -19,4 +19,4 @@
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("3572e78c-5aa5-4f68-876d-fc5322677263")]
+[assembly: Guid("00dfb5c7-3850-4a65-986b-713f200482d4")]
diff --git a/src/datacollector/Resources/Resources.Designer.cs b/src/datacollector/Resources/Resources.Designer.cs
new file mode 100644
index 0000000000..0e6684ddce
--- /dev/null
+++ b/src/datacollector/Resources/Resources.Designer.cs
@@ -0,0 +1,199 @@
+//------------------------------------------------------------------------------
+//
+// 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.DataCollector.Resources {
+ using System;
+ 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", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ 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 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.DataCollector.Resources.Resources", typeof(Resources).GetTypeInfo().Assembly);
+ 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 {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to An error occurred while retrieving the attributes for the diagnostic data adapter of type '{0}'..
+ ///
+ internal static string AttributeRetrievalError {
+ get {
+ return ResourceManager.GetString("AttributeRetrievalError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Diagnostic data adapter type URI cannot be null or empty. The type URI for the diagnostic data adapter of type '{0}' is null or empty..
+ ///
+ internal static string DataCollector_TypeIsNull {
+ get {
+ return ResourceManager.GetString("DataCollector_TypeIsNull", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Could not find diagnostic data adapter '{0}'. Make sure diagnostic data adapter is installed and try again..
+ ///
+ internal static string DataCollectorAssemblyNotFound {
+ get {
+ return ResourceManager.GetString("DataCollectorAssemblyNotFound", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Diagnostic data adapter '{0}' failed to provide intialization information. Error: {1}.
+ ///
+ internal static string DataCollectorErrorOnGetVariable {
+ get {
+ return ResourceManager.GetString("DataCollectorErrorOnGetVariable", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The diagnostic data adapter '{0}' threw an exception during type loading, construction, or initialization: {1}..
+ ///
+ internal static string DataCollectorInitializationError {
+ get {
+ return ResourceManager.GetString("DataCollectorInitializationError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Could not find diagnostic data adapter of type '{0}' and Uri '{1}'.
+ ///
+ internal static string DataCollectorNotFound {
+ get {
+ return ResourceManager.GetString("DataCollectorNotFound", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The diagnostic data adapter '{0}' requested environment variable '{1}' with value '{2}' to be set in test execution environment, but another diagnostic data adapter '{3}' has already requested same environment variable with different value '{4}'..
+ ///
+ internal static string DataCollectorRequestedDuplicateEnvironmentVariable {
+ get {
+ return ResourceManager.GetString("DataCollectorRequestedDuplicateEnvironmentVariable", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The required diagnostic data adapter attribute '{0}' is missing for the diagnostic data adapter of type '{1}'..
+ ///
+ internal static string DataCollectorRequiredAttributeMissing {
+ get {
+ return ResourceManager.GetString("DataCollectorRequiredAttributeMissing", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Failed to get type for diagnostic data adapter '{0}'. Error: {1}..
+ ///
+ internal static string DataCollectorTypeNotFound {
+ get {
+ return ResourceManager.GetString("DataCollectorTypeNotFound", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Invalid URI format. The URI '{0}' provided for the diagnostic data adapter of type '{1}' is not a valid URI..
+ ///
+ internal static string DataCollectorTypeUriFormatInvalid {
+ get {
+ return ResourceManager.GetString("DataCollectorTypeUriFormatInvalid", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Sending message of Message Type '{0}' is not supported..
+ ///
+ internal static string DataCollectorUnsupportedMessageType {
+ get {
+ return ResourceManager.GetString("DataCollectorUnsupportedMessageType", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Diagnostic data adapter friendly names cannot be null or empty. The friendly name for the diagnostic data adapter of type '{0}' is null or empty..
+ ///
+ internal static string FriendlyNameIsNullOrEmpty {
+ get {
+ return ResourceManager.GetString("FriendlyNameIsNullOrEmpty", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to There are multiple configurations that have diagnostic data adapter type '{0}' or Uri '{1}'. Duplicate configurations will be ignored in the test run..
+ ///
+ internal static string IgnoredDuplicateConfiguration {
+ get {
+ return ResourceManager.GetString("IgnoredDuplicateConfiguration", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Diagnostic data adapter caught an exception of type '{0}': '{1}'. More details: {2}..
+ ///
+ internal static string ReportDataCollectorException {
+ get {
+ return ResourceManager.GetString("ReportDataCollectorException", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Types deriving from the data collection context cannot be used for sending data and messages. The DataCollectionContext used for sending data and messages must come from one of the events raised to the data collector..
+ ///
+ internal static string WrongDataCollectionContextType {
+ get {
+ return ResourceManager.GetString("WrongDataCollectionContextType", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/datacollector/Resources/Resources.resx b/src/datacollector/Resources/Resources.resx
new file mode 100644
index 0000000000..69f7c7248f
--- /dev/null
+++ b/src/datacollector/Resources/Resources.resx
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ An error occurred while retrieving the attributes for the diagnostic data adapter of type '{0}'.
+
+
+ Could not find diagnostic data adapter '{0}'. Make sure diagnostic data adapter is installed and try again.
+
+
+ The diagnostic data adapter '{0}' threw an exception during type loading, construction, or initialization: {1}.
+
+
+ Could not find diagnostic data adapter of type '{0}' and Uri '{1}'
+
+
+ The required diagnostic data adapter attribute '{0}' is missing for the diagnostic data adapter of type '{1}'.
+
+
+ Failed to get type for diagnostic data adapter '{0}'. Error: {1}.
+
+
+ Invalid URI format. The URI '{0}' provided for the diagnostic data adapter of type '{1}' is not a valid URI.
+
+
+ Sending message of Message Type '{0}' is not supported.
+
+
+ Diagnostic data adapter type URI cannot be null or empty. The type URI for the diagnostic data adapter of type '{0}' is null or empty.
+
+
+ There are multiple configurations that have diagnostic data adapter type '{0}' or Uri '{1}'. Duplicate configurations will be ignored in the test run.
+
+
+ Diagnostic data adapter caught an exception of type '{0}': '{1}'. More details: {2}.
+
+
+ Types deriving from the data collection context cannot be used for sending data and messages. The DataCollectionContext used for sending data and messages must come from one of the events raised to the data collector.
+
+
+ Diagnostic data adapter friendly names cannot be null or empty. The friendly name for the diagnostic data adapter of type '{0}' is null or empty.
+
+
+ Diagnostic data adapter '{0}' failed to provide intialization information. Error: {1}
+
+
+ The diagnostic data adapter '{0}' requested environment variable '{1}' with value '{2}' to be set in test execution environment, but another diagnostic data adapter '{3}' has already requested same environment variable with different value '{4}'.
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.cs.xlf b/src/datacollector/Resources/xlf/Resources.cs.xlf
new file mode 100644
index 0000000000..d5b50f8278
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.cs.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.de.xlf b/src/datacollector/Resources/xlf/Resources.de.xlf
new file mode 100644
index 0000000000..499162759f
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.de.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.es.xlf b/src/datacollector/Resources/xlf/Resources.es.xlf
new file mode 100644
index 0000000000..d5b50f8278
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.es.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.fr.xlf b/src/datacollector/Resources/xlf/Resources.fr.xlf
new file mode 100644
index 0000000000..605666ca79
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.fr.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.it.xlf b/src/datacollector/Resources/xlf/Resources.it.xlf
new file mode 100644
index 0000000000..ec1d98950c
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.it.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.ja.xlf b/src/datacollector/Resources/xlf/Resources.ja.xlf
new file mode 100644
index 0000000000..458f62285c
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.ja.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.ko.xlf b/src/datacollector/Resources/xlf/Resources.ko.xlf
new file mode 100644
index 0000000000..a01458d86b
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.ko.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.pl.xlf b/src/datacollector/Resources/xlf/Resources.pl.xlf
new file mode 100644
index 0000000000..56a4238785
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.pl.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.pt-BR.xlf b/src/datacollector/Resources/xlf/Resources.pt-BR.xlf
new file mode 100644
index 0000000000..b86ed4d5f4
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.pt-BR.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.ru.xlf b/src/datacollector/Resources/xlf/Resources.ru.xlf
new file mode 100644
index 0000000000..d433d1be53
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.ru.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.tr.xlf b/src/datacollector/Resources/xlf/Resources.tr.xlf
new file mode 100644
index 0000000000..0008b20fa6
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.tr.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.xlf b/src/datacollector/Resources/xlf/Resources.xlf
new file mode 100644
index 0000000000..c72b0209b2
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.xlf
@@ -0,0 +1,15 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.zh-Hans.xlf b/src/datacollector/Resources/xlf/Resources.zh-Hans.xlf
new file mode 100644
index 0000000000..4d6d84d4dc
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.zh-Hans.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/Resources/xlf/Resources.zh-Hant.xlf b/src/datacollector/Resources/xlf/Resources.zh-Hant.xlf
new file mode 100644
index 0000000000..975d46faac
--- /dev/null
+++ b/src/datacollector/Resources/xlf/Resources.zh-Hant.xlf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ The test run could not be executed because the initial state was invalid.
+ The test run could not be executed because the initial state was invalid.
+
+
+
+ Wait for completion operation is not allowed when there is no active test run.
+ Wait for completion operation is not allowed when there is no active test run.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/datacollector/TestPlatformDataCollectionEvents.cs b/src/datacollector/TestPlatformDataCollectionEvents.cs
new file mode 100644
index 0000000000..d111418d12
--- /dev/null
+++ b/src/datacollector/TestPlatformDataCollectionEvents.cs
@@ -0,0 +1,131 @@
+// 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.DataCollector
+{
+ using System;
+ using System.Collections.Generic;
+
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+ using Microsoft.VisualStudio.TestPlatform.Utilities;
+
+ ///
+ /// The test platform data collection events.
+ ///
+ internal sealed class TestPlatformDataCollectionEvents : DataCollectionEvents
+ {
+ ///
+ /// Maps the type of event args to the multicast delegate for that event
+ ///
+ private Dictionary eventArgsToEventInvokerMap;
+
+ ///
+ /// Initializes a new instance of the class by mapping the types of expected event args to the multicast
+ /// delegate that invokes the event on registered targets
+ ///
+ internal TestPlatformDataCollectionEvents()
+ {
+ this.eventArgsToEventInvokerMap = new Dictionary(4);
+
+ this.eventArgsToEventInvokerMap[typeof(SessionStartEventArgs)] = this.OnSessionStart;
+ this.eventArgsToEventInvokerMap[typeof(SessionEndEventArgs)] = this.OnSessionEnd;
+ this.eventArgsToEventInvokerMap[typeof(TestCaseStartEventArgs)] = this.OnTestCaseStart;
+ this.eventArgsToEventInvokerMap[typeof(TestCaseEndEventArgs)] = this.OnTestCaseEnd;
+ }
+
+ ///
+ /// Delegate for the event invoker methods (OnSessionStart, OnTestCaseResume, etc.)
+ ///
+ ///
+ /// Contains the event data
+ ///
+ private delegate void EventInvoker(DataCollectionEventArgs e);
+
+ ///
+ /// Raised when a session is starting
+ ///
+ public override event EventHandler SessionStart;
+
+ ///
+ /// Raised when a session is ending
+ ///
+ public override event EventHandler SessionEnd;
+
+ ///
+ /// Raised when a test case is starting
+ ///
+ public override event EventHandler TestCaseStart;
+
+ ///
+ /// Raised when a test case is ending
+ ///
+ public override event EventHandler TestCaseEnd;
+
+ ///
+ /// Raises the event corresponding to the event arguments to all registered handlers
+ ///
+ ///
+ /// Contains the event data
+ ///
+ internal void RaiseEvent(DataCollectionEventArgs e)
+ {
+ ValidateArg.NotNull(e, "DataCollectionEventArgs");
+
+ EventInvoker onEvent;
+
+ if (this.eventArgsToEventInvokerMap.TryGetValue(e.GetType(), out onEvent))
+ {
+ onEvent(e);
+ }
+ else
+ {
+ EqtTrace.Fail("TestPlatformDataCollectionEvents.RaiseEvent: Unrecognized data collection event of type {0}.", e.GetType().FullName);
+ }
+ }
+
+ ///
+ /// Raises the SessionStart event
+ ///
+ ///
+ /// Contains the event data
+ ///
+ private void OnSessionStart(DataCollectionEventArgs e)
+ {
+ this.SessionStart.SafeInvoke(this, e, "DataCollectionEvents.SessionStart");
+ }
+
+ ///
+ /// Raises the SessionEnd event
+ ///
+ ///
+ /// Contains the event data
+ ///
+ private void OnSessionEnd(DataCollectionEventArgs e)
+ {
+ this.SessionEnd.SafeInvoke(this, e, "DataCollectionEvents.SessionEnd");
+ }
+
+ ///
+ /// Raises the TestCaseStart event
+ ///
+ ///
+ /// Contains the event data
+ ///
+ private void OnTestCaseStart(DataCollectionEventArgs e)
+ {
+ this.TestCaseStart.SafeInvoke(this, e, "DataCollectionEvents.TestCaseStart");
+ }
+
+ ///
+ /// Raises the TestCaseEnd event
+ ///
+ ///
+ /// Contains the event data
+ ///
+ private void OnTestCaseEnd(DataCollectionEventArgs e)
+ {
+ this.TestCaseEnd.SafeInvoke(this, e, "DataCollectionEvents.TestCaseEnd");
+ }
+ }
+}
diff --git a/src/datacollector/TestPlatformDataCollectionLogger.cs b/src/datacollector/TestPlatformDataCollectionLogger.cs
new file mode 100644
index 0000000000..7c9ccd755f
--- /dev/null
+++ b/src/datacollector/TestPlatformDataCollectionLogger.cs
@@ -0,0 +1,157 @@
+// 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.DataCollector
+{
+ using System;
+ using System.Diagnostics;
+ using System.Globalization;
+
+ using Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+
+ ///
+ /// Class used by data collectors to send messages to the client
+ ///
+ internal class TestPlatformDataCollectionLogger : DataCollectionLogger
+ {
+ ///
+ /// DataCollector's config info.
+ ///
+ private readonly DataCollectorConfig dataCollectorConfig;
+
+ ///
+ /// Message sink.
+ ///
+ private readonly IMessageSink sink;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The underlying raw IMessageSink. Cannot be null.
+ ///
+ ///
+ /// The data Collector Information.
+ ///
+ internal TestPlatformDataCollectionLogger(IMessageSink sink, DataCollectorConfig dataCollectorConfig)
+ {
+ ValidateArg.NotNull(dataCollectorConfig, "dataCollectorInformation");
+ ValidateArg.NotNull(sink, "sink");
+ this.dataCollectorConfig = dataCollectorConfig;
+ this.sink = sink;
+ }
+
+ ///
+ public override void LogError(DataCollectionContext context, string text)
+ {
+ ValidateArg.NotNull(context, "context");
+ ValidateArg.NotNull(text, "text");
+
+ if (EqtTrace.IsErrorEnabled)
+ {
+ EqtTrace.Error(
+ "Data collector '{0}' logged the following error: {1}",
+ this.dataCollectorConfig.TypeUri,
+ text);
+ }
+
+ this.SendTextMessage(context, text, TestMessageLevel.Error);
+ }
+
+ ///
+ public override void LogError(DataCollectionContext context, string text, Exception exception)
+ {
+ ValidateArg.NotNull(context, "context");
+ ValidateArg.NotNull(text, "text");
+ ValidateArg.NotNull(exception, "exception");
+
+ // Make sure the data collection context is not a derived data collection context. This
+ // is done to safeguard from 3rd parties creating their own data collection contexts.
+ if (context.GetType() != typeof(DataCollectionContext))
+ {
+ throw new InvalidOperationException(Resources.Resources.WrongDataCollectionContextType);
+ }
+
+ if (EqtTrace.IsErrorEnabled)
+ {
+ EqtTrace.Error(
+ "Data collector '{0}' logged the following error:" + Environment.NewLine +
+ "Description: {1}" + Environment.NewLine +
+ "Exception type: {2}" + Environment.NewLine + "Exception message: {3}"
+ + Environment.NewLine + "Exception stack trace: {4}",
+ this.dataCollectorConfig.TypeUri,
+ text,
+ exception.GetType(),
+ exception.Message,
+ exception.StackTrace);
+ }
+
+ // Currently there is one type of DataCollectionMessage sent accross client for all message kind.
+ // If required new type can be created for different message type.
+ var message = string.Format(
+ CultureInfo.CurrentCulture,
+ Resources.Resources.ReportDataCollectorException,
+ exception.GetType(),
+ exception.Message,
+ text);
+ this.SendTextMessage(context, message, TestMessageLevel.Error);
+ }
+
+ ///
+ public override void LogWarning(DataCollectionContext context, string text)
+ {
+ ValidateArg.NotNull(context, "context");
+ ValidateArg.NotNull(text, "text");
+ EqtTrace.Warning(
+ "Data collector '{0}' logged the following warning: {1}",
+ this.dataCollectorConfig.TypeUri,
+ text);
+
+ this.SendTextMessage(context, text, TestMessageLevel.Warning);
+ }
+
+ ///
+ /// Sends text to message sink.
+ ///
+ ///
+ /// The context.
+ ///
+ ///
+ /// The text.
+ ///
+ ///
+ /// The level.
+ ///
+ /// Throws InvalidOperationException.
+ ///
+ private void SendTextMessage(DataCollectionContext context, string text, TestMessageLevel level)
+ {
+ ValidateArg.NotNull(context, "context");
+ ValidateArg.NotNull(text, "text");
+
+ Debug.Assert(
+ level >= TestMessageLevel.Informational && level <= TestMessageLevel.Error,
+ "Invalid level: " + level);
+
+ // Make sure the data collection context is not a derived data collection context. This
+ // is done to safeguard from 3rd parties creating their own data collection contexts.
+ if (context.GetType() != typeof(DataCollectionContext))
+ {
+ throw new InvalidOperationException(Resources.Resources.WrongDataCollectionContextType);
+ }
+
+ var args = new DataCollectionMessageEventArgs(level, text);
+ args.Uri = this.dataCollectorConfig.TypeUri;
+ args.FriendlyName = this.dataCollectorConfig.FriendlyName;
+ if (context.HasTestCase)
+ {
+ args.TestCaseId = context.TestExecId.Id;
+ }
+
+ this.sink.SendMessage(args);
+ }
+ }
+}
diff --git a/src/datacollector/TestPlatformDataCollectionSink.cs b/src/datacollector/TestPlatformDataCollectionSink.cs
new file mode 100644
index 0000000000..023b4c88ed
--- /dev/null
+++ b/src/datacollector/TestPlatformDataCollectionSink.cs
@@ -0,0 +1,71 @@
+// 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.DataCollector
+{
+ using System.ComponentModel;
+ using System.Diagnostics;
+
+ using Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+
+ ///
+ /// The test platform data collection sink.
+ ///
+ internal class TestPlatformDataCollectionSink : DataCollectionSink
+ {
+ ///
+ /// Initializes a new instance of the class.
+ /// Creates a data collector sink for data transfer.
+ ///
+ ///
+ /// The attachment Manager.
+ ///
+ ///
+ /// Data collector info.
+ ///
+ internal TestPlatformDataCollectionSink(IDataCollectionAttachmentManager attachmentManager, DataCollectorConfig dataCollectorConfig)
+ {
+ ValidateArg.NotNull(attachmentManager, nameof(attachmentManager));
+ ValidateArg.NotNull(dataCollectorConfig, nameof(dataCollectorConfig));
+
+ this.DataCollectorConfig = dataCollectorConfig;
+ this.AttachmentManager = attachmentManager;
+ }
+
+ ///
+ /// Event handler for handling file transfer completed event.
+ ///
+ public override event AsyncCompletedEventHandler SendFileCompleted;
+
+ ///
+ /// Gets or sets message sink to transfer collection message.
+ ///
+ private IDataCollectionAttachmentManager AttachmentManager
+ {
+ get; set;
+ }
+
+ ///
+ /// Gets or sets dataCollector with which this data sink is associated.
+ ///
+ private DataCollectorConfig DataCollectorConfig
+ {
+ get; set;
+ }
+
+ ///
+ /// Sends a file asynchronously.
+ ///
+ /// Information about the file being transferred.
+ public override void SendFileAsync(FileTransferInformation fileTransferInformation)
+ {
+ ValidateArg.NotNull(fileTransferInformation, "fileTransferInformation");
+
+ Debug.Assert(System.IO.File.Exists(fileTransferInformation.Path), "DataCollector file '" + fileTransferInformation.Path + "' does not exist!");
+
+ this.AttachmentManager.AddAttachment(fileTransferInformation, this.SendFileCompleted, this.DataCollectorConfig.TypeUri, this.DataCollectorConfig.FriendlyName);
+ }
+ }
+}
diff --git a/src/datacollector/app.config b/src/datacollector/app.config
deleted file mode 100644
index 49ee151f08..0000000000
--- a/src/datacollector/app.config
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/datacollector/datacollector.csproj b/src/datacollector/datacollector.csproj
index 0e4a9dd37a..29fbc35f33 100644
--- a/src/datacollector/datacollector.csproj
+++ b/src/datacollector/datacollector.csproj
@@ -1,13 +1,17 @@
-
+
..\..\
+
+ Microsoft.VisualStudio.TestPlatform.DataCollector
+ datacollectornetcoreapp1.0;net46true
+ AnyCPUExe$(PackageTargetFallback);dnxcore50;netstandardapp1.0;portable-net45+win8;portable-net45+wp80+win8+wpa81+dnxcore50
@@ -15,8 +19,10 @@
win7-x64
-
-
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
@@ -33,13 +39,32 @@
1.0.0
-
- 4.3.0
+
+ 4.0.0
+
+
+
+
+ 4.1.0
+
+
+ 4.0.1
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
-
+
\ No newline at end of file
diff --git a/src/package/sign/sign.proj b/src/package/sign/sign.proj
index c700d40164..40dd16478a 100644
--- a/src/package/sign/sign.proj
+++ b/src/package/sign/sign.proj
@@ -70,7 +70,6 @@
-
diff --git a/test/datacollector.UnitTests/DataCollectionAttachmentManagerTests.cs b/test/datacollector.UnitTests/DataCollectionAttachmentManagerTests.cs
new file mode 100644
index 0000000000..df7a69bd43
--- /dev/null
+++ b/test/datacollector.UnitTests/DataCollectionAttachmentManagerTests.cs
@@ -0,0 +1,192 @@
+// 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.DataCollector.UnitTests
+{
+ using System;
+ using System.ComponentModel;
+ using System.IO;
+ using System.Threading;
+
+ using Microsoft.VisualStudio.TestPlatform.DataCollector;
+ using Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ using Moq;
+
+ [TestClass]
+ public class DataCollectionAttachmentManagerTests
+ {
+ private DataCollectionAttachmentManager attachmentManager;
+ private Mock messageSink;
+ private SessionId sessionId;
+
+ public DataCollectionAttachmentManagerTests()
+ {
+ this.attachmentManager = new DataCollectionAttachmentManager();
+ this.messageSink = new Mock();
+ var guid = Guid.NewGuid();
+ this.sessionId = new SessionId(guid);
+ }
+
+ [TestCleanup]
+ public void Cleanup()
+ {
+ File.Delete(Path.Combine(AppContext.BaseDirectory, "filename.txt"));
+ File.Delete(Path.Combine(AppContext.BaseDirectory, "filename1.txt"));
+ }
+
+ [TestMethod]
+ public void InitializeShouldThrowExceptionIfSessionIdIsNull()
+ {
+ Assert.ThrowsException(() =>
+ {
+ this.attachmentManager.Initialize((SessionId)null, string.Empty, this.messageSink.Object);
+ });
+ }
+
+ [TestMethod]
+ public void InitializeShouldThrowExceptionIfMessageSinkIsNull()
+ {
+ Assert.ThrowsException(() =>
+ {
+ this.attachmentManager.Initialize(this.sessionId, string.Empty, null);
+ });
+ }
+
+ [TestMethod]
+ public void InitializeShouldSetDefaultPathIfOutputDirectoryPathIsNull()
+ {
+ this.attachmentManager.Initialize(this.sessionId, string.Empty, this.messageSink.Object);
+
+ Assert.AreEqual(this.attachmentManager.SessionOutputDirectory, Path.Combine(Path.GetTempPath(), "TestResults", this.sessionId.Id.ToString()));
+ }
+
+ [TestMethod]
+ public void InitializeShouldSetCorrectGuidAndOutputPath()
+ {
+ this.attachmentManager.Initialize(this.sessionId, System.AppContext.BaseDirectory, this.messageSink.Object);
+
+ Assert.AreEqual(Path.Combine(System.AppContext.BaseDirectory, this.sessionId.Id.ToString()), this.attachmentManager.SessionOutputDirectory);
+ }
+
+ [TestMethod]
+ public void AddAttachmentShouldNotAddNewFileTransferIfSessionIsNotConfigured()
+ {
+ var filename = "filename.txt";
+ File.WriteAllText(Path.Combine(AppContext.BaseDirectory, filename), string.Empty);
+
+ var datacollectioncontext = new DataCollectionContext(this.sessionId);
+ var friendlyName = "TestDataCollector";
+ var uri = new Uri("datacollector://Company/Product/Version");
+
+ var dataCollectorDataMessage = new FileTransferInformation(datacollectioncontext, Path.Combine(AppContext.BaseDirectory, filename), false);
+
+ this.attachmentManager.AddAttachment(dataCollectorDataMessage, null, uri, friendlyName);
+
+ Assert.AreEqual(this.attachmentManager.AttachmentSets.Count, 0);
+ }
+
+ [TestMethod]
+ public void AddAttachmentShouldAddNewFileTransferAndCopyFileToOutputDirectoryIfDeleteFileIsFalse()
+ {
+ var filename = "filename.txt";
+ File.WriteAllText(Path.Combine(AppContext.BaseDirectory, filename), string.Empty);
+
+
+ this.attachmentManager.Initialize(this.sessionId, AppContext.BaseDirectory, this.messageSink.Object);
+
+ var datacollectioncontext = new DataCollectionContext(this.sessionId);
+ var friendlyName = "TestDataCollector";
+ var uri = new Uri("datacollector://Company/Product/Version");
+
+ EventWaitHandle waitHandle = new AutoResetEvent(false);
+ var handler = new AsyncCompletedEventHandler((a, e) => { waitHandle.Set(); });
+ var dataCollectorDataMessage = new FileTransferInformation(datacollectioncontext, Path.Combine(AppContext.BaseDirectory, filename), false);
+
+
+ this.attachmentManager.AddAttachment(dataCollectorDataMessage, handler, uri, friendlyName);
+
+ // Wait for file operations to complete
+ waitHandle.WaitOne();
+
+ Assert.IsTrue(File.Exists(Path.Combine(System.AppContext.BaseDirectory, filename)));
+ Assert.IsTrue(File.Exists(Path.Combine(AppContext.BaseDirectory, this.sessionId.Id.ToString(), filename)));
+ Assert.AreEqual(1, this.attachmentManager.AttachmentSets[uri].Attachments.Count);
+ }
+
+ [TestMethod]
+ public void AddAttachmentShouldAddNewFileTransferAndMoveFileToOutputDirectoryIfDeleteFileIsTrue()
+ {
+ var filename = "filename1.txt";
+ File.WriteAllText(Path.Combine(AppContext.BaseDirectory, filename), string.Empty);
+
+
+ this.attachmentManager.Initialize(this.sessionId, System.AppContext.BaseDirectory, this.messageSink.Object);
+
+ var datacollectioncontext = new DataCollectionContext(this.sessionId);
+ var friendlyName = "TestDataCollector";
+ var uri = new Uri("datacollector://Company/Product/Version");
+
+ var waitHandle = new AutoResetEvent(false);
+ var handler = new AsyncCompletedEventHandler((a, e) => { waitHandle.Set(); });
+ var dataCollectorDataMessage = new FileTransferInformation(datacollectioncontext, Path.Combine(AppContext.BaseDirectory, filename), true);
+
+ this.attachmentManager.AddAttachment(dataCollectorDataMessage, handler, uri, friendlyName);
+
+ // Wait for file operations to complete
+ waitHandle.WaitOne();
+
+ Assert.AreEqual(1, this.attachmentManager.AttachmentSets[uri].Attachments.Count);
+ Assert.IsTrue(File.Exists(Path.Combine(AppContext.BaseDirectory, this.sessionId.Id.ToString(), filename)));
+ Assert.IsFalse(File.Exists(Path.Combine(AppContext.BaseDirectory, filename)));
+ }
+
+ [TestMethod]
+ public void AddAttachmentShouldNotAddNewFileTransferIfNullIsPassed()
+ {
+ Assert.ThrowsException(() =>
+ {
+ this.attachmentManager.AddAttachment(null, null, null, null);
+ });
+ }
+
+ [TestMethod]
+ public void GetAttachmentsShouldReturnAllAttachmets()
+ {
+ var filename = "filename1.txt";
+ File.WriteAllText(Path.Combine(AppContext.BaseDirectory, filename), string.Empty);
+
+ this.attachmentManager.Initialize(this.sessionId, AppContext.BaseDirectory, this.messageSink.Object);
+
+ var datacollectioncontext = new DataCollectionContext(this.sessionId);
+ var friendlyName = "TestDataCollector";
+ var uri = new Uri("datacollector://Company/Product/Version");
+
+ var dataCollectorDataMessage = new FileTransferInformation(datacollectioncontext, Path.Combine(AppContext.BaseDirectory, filename), true);
+
+ this.attachmentManager.AddAttachment(dataCollectorDataMessage, null, uri, friendlyName);
+
+ Assert.AreEqual(1, this.attachmentManager.AttachmentSets.Count);
+ var result = this.attachmentManager.GetAttachments(datacollectioncontext);
+
+ Assert.AreEqual(1, this.attachmentManager.AttachmentSets.Count);
+ Assert.AreEqual(1, result.Count);
+ Assert.AreEqual(friendlyName, result[0].DisplayName);
+ Assert.AreEqual(uri, result[0].Uri);
+ Assert.AreEqual(1, result[0].Attachments.Count);
+ }
+
+ [TestMethod]
+ public void GetAttachmentsShouldNotReutrnAnyDataWhenActiveFileTransferAreNotPresent()
+ {
+ this.attachmentManager.Initialize(this.sessionId, AppContext.BaseDirectory, this.messageSink.Object);
+
+ var datacollectioncontext = new DataCollectionContext(this.sessionId);
+
+ var result = this.attachmentManager.GetAttachments(datacollectioncontext);
+ Assert.AreEqual(0, result.Count);
+ }
+ }
+}
diff --git a/test/datacollector.UnitTests/DataCollectionEnvironmentVariableTests.cs b/test/datacollector.UnitTests/DataCollectionEnvironmentVariableTests.cs
new file mode 100644
index 0000000000..d65381b643
--- /dev/null
+++ b/test/datacollector.UnitTests/DataCollectionEnvironmentVariableTests.cs
@@ -0,0 +1,46 @@
+// 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.DataCollector.UnitTests
+{
+ using System;
+ using System.Collections.Generic;
+ using Microsoft.VisualStudio.TestPlatform.DataCollector;
+
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ [TestClass]
+ public class DataCollectionEnvironmentVariableTests
+ {
+ [TestMethod]
+ public void ConstructorShouldThrowExceptionIfKeyValueIsNull()
+ {
+ Assert.ThrowsException(
+ () =>
+ {
+ var envvariable = new DataCollectionEnvironmentVariable(default(KeyValuePair), null);
+ });
+ }
+
+ [TestMethod]
+ public void FirstDataCollectorThatRequestedShouldReturnTheFirstdataCollectorRequestingThatEnvVariable()
+ {
+ var envValPair = new KeyValuePair("key", "value");
+ var envvariable = new DataCollectionEnvironmentVariable(envValPair, "datacollector");
+ envvariable.AddRequestingDataCollector("datacollector1");
+
+ Assert.AreEqual("datacollector", envvariable.FirstDataCollectorThatRequested);
+ }
+
+ [TestMethod]
+ public void FirstDataCollectorThatRequestedShouldSetNameAndValue()
+ {
+ var envValPair = new KeyValuePair("key", "value");
+ var envvariable = new DataCollectionEnvironmentVariable(envValPair, "datacollector");
+ envvariable.AddRequestingDataCollector("datacollector1");
+
+ Assert.AreEqual("key", envvariable.Name);
+ Assert.AreEqual("value", envvariable.Value);
+ }
+ }
+}
diff --git a/test/datacollector.UnitTests/DataCollectionManagerTests.cs b/test/datacollector.UnitTests/DataCollectionManagerTests.cs
new file mode 100644
index 0000000000..5155ca3c0c
--- /dev/null
+++ b/test/datacollector.UnitTests/DataCollectionManagerTests.cs
@@ -0,0 +1,340 @@
+// 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.DataCollector.UnitTests
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Reflection;
+ using System.Xml;
+
+
+ using Microsoft.VisualStudio.TestPlatform.DataCollector;
+ using Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollector;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ using Moq;
+
+ [TestClass]
+ public class DataCollectionManagerTests
+ {
+ private DataCollectionManager dataCollectionManager;
+ private string defaultRunSettings = "\r\n\r\n \r\n {0}\r\n \r\n";
+ private string defaultDataCollectionSettings = "";
+ private string dataCollectorSettings;
+
+ private string dataCollectorSettingsWithWrongUri, dataCollectorSettingsWithoutUri, dataCollectorSettingsEnabled, dataCollectorSettingsDisabled;
+
+ private Mock mockMessageSink;
+ private Mock dataCollectorLoader;
+ private Mock mockDataCollector;
+ private List> envVarList;
+
+ public DataCollectionManagerTests()
+ {
+ var friendlyName = "CustomDataCollector";
+ var uri = "my://custom/datacollector";
+
+ this.envVarList = new List>();
+ this.mockDataCollector = new Mock();
+ this.mockDataCollector.As().Setup(x => x.GetTestExecutionEnvironmentVariables()).Returns(this.envVarList);
+
+ this.dataCollectorSettings = string.Format(this.defaultDataCollectionSettings, friendlyName, uri, this.mockDataCollector.Object.GetType().AssemblyQualifiedName, typeof(DataCollectionManagerTests).GetTypeInfo().Assembly.Location, string.Empty);
+ this.dataCollectorSettingsWithWrongUri = string.Format(this.defaultDataCollectionSettings, friendlyName, "my://custom1/datacollector", this.mockDataCollector.Object.GetType().AssemblyQualifiedName, typeof(DataCollectionManagerTests).GetTypeInfo().Assembly.Location, string.Empty);
+ this.dataCollectorSettingsWithoutUri = string.Format(this.defaultDataCollectionSettings, friendlyName, string.Empty, this.mockDataCollector.Object.GetType().AssemblyQualifiedName, typeof(DataCollectionManagerTests).GetTypeInfo().Assembly.Location, string.Empty).Replace("uri=\"\"", string.Empty);
+ this.dataCollectorSettingsEnabled = string.Format(this.defaultDataCollectionSettings, friendlyName, uri, this.mockDataCollector.Object.GetType().AssemblyQualifiedName, typeof(DataCollectionManagerTests).GetTypeInfo().Assembly.Location, "enabled=\"true\"");
+ this.dataCollectorSettingsDisabled = string.Format(this.defaultDataCollectionSettings, friendlyName, uri, this.mockDataCollector.Object.GetType().AssemblyQualifiedName, typeof(DataCollectionManagerTests).GetTypeInfo().Assembly.Location, "enabled=\"false\"");
+
+ this.mockMessageSink = new Mock();
+ this.dataCollectorLoader = new Mock();
+
+ this.dataCollectorLoader.Setup(x => x.Load(typeof(DataCollectionManagerTests).GetTypeInfo().Assembly.Location, this.mockDataCollector.Object.GetType().AssemblyQualifiedName)).Returns(this.mockDataCollector.Object);
+ this.dataCollectionManager = new DataCollectionManager(new DataCollectionAttachmentManager(), this.mockMessageSink.Object, this.dataCollectorLoader.Object);
+ }
+
+ [TestMethod]
+ public void InitializeDataCollectorsShouldThrowExceptionIfSettingsXmlIsNull()
+ {
+ Assert.ThrowsException(() =>
+ {
+ this.dataCollectionManager.InitializeDataCollectors(null);
+ });
+ }
+
+ [TestMethod]
+ public void InitializeDataCollectorsShouldReturnEmptyDictionaryIfDataCollectorsAreNotConfigured()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, string.Empty);
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ Assert.AreEqual(0, this.dataCollectionManager.RunDataCollectors.Count);
+ }
+
+ [TestMethod]
+ public void InitializeDataCollectorsShouldLoadDataCollector()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettings);
+
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ Assert.IsTrue(this.dataCollectionManager.RunDataCollectors.ContainsKey(this.mockDataCollector.Object.GetType()));
+ this.dataCollectorLoader.Verify();
+ this.mockDataCollector.Verify(x => x.Initialize(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once);
+ }
+
+ [TestMethod]
+ public void InitializeShouldNotAddDataCollectorIfItIsDisabled()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettingsDisabled);
+
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ Assert.AreEqual(0, this.dataCollectionManager.RunDataCollectors.Count);
+ this.mockDataCollector.Verify(x => x.Initialize(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never);
+ }
+
+ [TestMethod]
+ public void InitializeShouldAddDataCollectorIfItIsEnabled()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettingsEnabled);
+
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ Assert.IsTrue(this.dataCollectionManager.RunDataCollectors.ContainsKey(this.mockDataCollector.Object.GetType()));
+ this.mockDataCollector.Verify(x => x.Initialize(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once);
+ }
+
+
+ [TestMethod]
+ public void InitializeDataCollectorsShouldNotLoadDataCollectorIfUriIsNotCorrect()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettingsWithWrongUri);
+
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ Assert.AreEqual(0, this.dataCollectionManager.RunDataCollectors.Count);
+ this.mockDataCollector.Verify(x => x.Initialize(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never);
+ }
+
+ public void InitializeDataCollectorsShouldNotAddSameDataCollectorMoreThanOnce()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettings + this.dataCollectorSettings);
+
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ Assert.IsTrue(this.dataCollectionManager.RunDataCollectors.ContainsKey(this.mockDataCollector.Object.GetType()));
+ this.mockDataCollector.Verify(x => x.Initialize(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once);
+ }
+
+ [TestMethod]
+ public void InitializeDataCollectorsShouldNotAddDataCollectorIfUriIsNotSpecifiedByDataCollector()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettingsWithoutUri);
+
+ Assert.ThrowsException(() =>
+ {
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+ });
+ }
+
+ [TestMethod]
+ public void InitializeDataCollectorsShouldLoadDataCollectorAndReturnEnvironmentVariables()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettings);
+
+ this.envVarList.Add(new KeyValuePair("key", "value"));
+
+ var result = this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ Assert.AreEqual("value", result["key"]);
+ }
+
+ [TestMethod]
+ public void InitializeDataCollectorsShouldLogExceptionToMessageSinkIfInitializationFails()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettings);
+ this.mockDataCollector.Setup(
+ x =>
+ x.Initialize(
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny())).Throws();
+
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ Assert.AreEqual(0, this.dataCollectionManager.RunDataCollectors.Count);
+ this.mockMessageSink.Verify(x => x.SendMessage(It.IsAny()), Times.Once);
+ }
+
+ [TestMethod]
+ public void InitializeDataCollectorsShouldReturnFirstEnvironmentVariableIfMoreThanOneVariablesWithSameKeyIsSpecified()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettings);
+ this.envVarList.Add(new KeyValuePair("key", "value"));
+ this.envVarList.Add(new KeyValuePair("key", "value1"));
+
+ var result = this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ Assert.AreEqual("value", result["key"]);
+ }
+
+ [TestMethod]
+ public void SessionStartedShouldReturnFalseIfDataCollectionIsNotConfiguredInRunSettings()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, string.Empty);
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ var result = this.dataCollectionManager.SessionStarted();
+
+ Assert.IsFalse(result);
+ }
+
+ [TestMethod]
+ public void SessionStartedShouldSendEventToDataCollector()
+ {
+ var isStartInvoked = false;
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettings);
+ this.mockDataCollector.Setup(
+ x =>
+ x.Initialize(
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny())).Callback((a, b, c, d, e) =>
+ {
+ b.SessionStart += (sender, eventArgs) => isStartInvoked = true;
+ });
+
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ this.dataCollectionManager.SessionStarted();
+
+ Assert.IsTrue(isStartInvoked);
+ }
+
+ [TestMethod]
+ public void SessionStaretedShouldContinueDataCollectionIfExceptionIsThrownWhileSendingEventsToDataCollector()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettings);
+ this.mockDataCollector.Setup(
+ x =>
+ x.Initialize(
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny())).Callback((a, b, c, d, e) =>
+ {
+ b.SessionStart += (sender, eventArgs) => throw new Exception();
+ });
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ var result = this.dataCollectionManager.SessionStarted();
+
+ Assert.IsTrue(result);
+ }
+
+ [TestMethod]
+ public void SessionStartedShouldReturnFalseIfDataCollectorsAreNotInitialized()
+ {
+ var result = this.dataCollectionManager.SessionStarted();
+
+ Assert.IsFalse(result);
+ }
+
+ [TestMethod]
+ public void SessionEndedShouldReturnEmptyCollectionIfDataCollectionIsNotEnabled()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, string.Empty);
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ var result = this.dataCollectionManager.SessionEnded();
+
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [TestMethod]
+ public void SessionEndedShouldReturnAttachments()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettings);
+ this.mockDataCollector.Setup(
+ x =>
+ x.Initialize(
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny())).Callback((a, b, c, d, e) =>
+ {
+ b.SessionEnd += (sender, ev) =>
+ {
+ var filename = Path.Combine(AppContext.BaseDirectory, "filename.txt");
+ File.WriteAllText(filename, string.Empty);
+ c.SendFileAsync(e.SessionDataCollectionContext, filename, true);
+ };
+ });
+
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+ this.dataCollectionManager.SessionStarted();
+
+ var result = this.dataCollectionManager.SessionEnded();
+
+ Assert.IsTrue(result[0].Attachments[0].Uri.ToString().Contains("filename.txt"));
+ }
+
+ [TestMethod]
+ public void SessionEndedShouldNotReturnAttachmentsIfExceptionIsThrownWhileGettingAttachments()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettings);
+ var mockDataCollectionAttachmentManager = new Mock();
+ mockDataCollectionAttachmentManager.Setup(x => x.GetAttachments(It.IsAny())).Throws();
+ this.dataCollectionManager = new DataCollectionManager(mockDataCollectionAttachmentManager.Object, this.mockMessageSink.Object, new Mock().Object);
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+
+ var result = this.dataCollectionManager.SessionEnded();
+
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [TestMethod]
+ public void SessionEndedShouldContinueDataCollectionIfExceptionIsThrownWhileSendingSessionEndEventToDataCollector()
+ {
+ var runSettings = string.Format(this.defaultRunSettings, this.dataCollectorSettings);
+ this.mockDataCollector.Setup(
+ x =>
+ x.Initialize(
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny())).Callback(
+ (a, b, c, d, e) =>
+ {
+ b.SessionEnd += (sender, ev) =>
+ { throw new Exception(); };
+ });
+
+ this.dataCollectionManager.InitializeDataCollectors(runSettings);
+ this.dataCollectionManager.SessionStarted();
+
+ var result = this.dataCollectionManager.SessionEnded();
+
+ Assert.AreEqual(0, result.Count);
+ }
+ }
+
+ [DataCollectorFriendlyName("CustomDataCollector")]
+ [DataCollectorTypeUri("my://custom/datacollector")]
+ public abstract class DataCollector2 : DataCollector
+ {
+
+ }
+}
diff --git a/test/datacollector.UnitTests/DataCollectorConfigTests.cs b/test/datacollector.UnitTests/DataCollectorConfigTests.cs
new file mode 100644
index 0000000000..0e482d19e8
--- /dev/null
+++ b/test/datacollector.UnitTests/DataCollectorConfigTests.cs
@@ -0,0 +1,78 @@
+// 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.DataCollector.UnitTests
+{
+ using System;
+ using System.Globalization;
+
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ [TestClass]
+ public class DataCollectorConfigTests
+ {
+ [TestMethod]
+ public void ConstructorShouldSetCorrectFriendlyNameAndUri()
+ {
+ var dataCollectorConfig = new DataCollectorConfig(typeof(CustomDataCollector));
+
+ Assert.AreEqual("CustomDataCollector", dataCollectorConfig.FriendlyName);
+ Assert.AreEqual("my://custom/datacollector", dataCollectorConfig.TypeUri.ToString());
+ }
+
+ [TestMethod]
+ public void ConstructorShouldThrowExceptionIfTypeIsNull()
+ {
+ Assert.ThrowsException(
+ () =>
+ {
+ new DataCollectorConfig(null);
+ });
+ }
+
+ [TestMethod]
+ public void ConstructorShouldThrowExceptionIfUriIsNotSpecifiedInDataCollector()
+ {
+ ThrowsExceptionWithMessage(() =>
+ {
+ new DataCollectorConfig(typeof(CustomDataCollectorWithoutUri));
+ },
+ string.Format(
+ CultureInfo.CurrentCulture,
+ Resources.Resources.DataCollector_TypeIsNull,
+ typeof(CustomDataCollectorWithoutUri).FullName));
+ }
+
+ [TestMethod]
+ public void ConstructorShouldThrowExceptionIfFriendlyNameIsEmpty()
+ {
+ ThrowsExceptionWithMessage(() =>
+ {
+ new DataCollectorConfig(typeof(CustomDataCollectorWithEmptyFriendlyName));
+ },
+ string.Format(
+ CultureInfo.CurrentCulture,
+ Resources.Resources.FriendlyNameIsNullOrEmpty,
+ typeof(CustomDataCollectorWithEmptyFriendlyName).FullName));
+ }
+
+ [TestMethod]
+ public void ConstructorShouldThrowExceptionIfFriendlyNameIsNotSpecified()
+ {
+ ThrowsExceptionWithMessage(() =>
+ {
+ new DataCollectorConfig(typeof(CustomDataCollectorWithoutFriendlyName));
+ },
+ string.Format(
+ CultureInfo.CurrentCulture,
+ Resources.Resources.FriendlyNameIsNullOrEmpty,
+ typeof(CustomDataCollectorWithoutFriendlyName).FullName));
+ }
+
+ public static void ThrowsExceptionWithMessage(Action action, string message) where T : Exception
+ {
+ var exception = Assert.ThrowsException(action);
+ StringAssert.Contains(exception.Message, message);
+ }
+ }
+}
diff --git a/test/datacollector.UnitTests/DataCollectorInformationTests.cs b/test/datacollector.UnitTests/DataCollectorInformationTests.cs
new file mode 100644
index 0000000000..4ba3389d65
--- /dev/null
+++ b/test/datacollector.UnitTests/DataCollectorInformationTests.cs
@@ -0,0 +1,62 @@
+// 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.DataCollector.UnitTests
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ using Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollector;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ using Moq;
+ using Moq.Protected;
+
+ [TestClass]
+ public class DataCollectorInformationTests
+ {
+ private DataCollectorInformation dataCollectorInfo;
+
+ private List> envVarList;
+
+ private Mock mockDataCollector;
+
+ public DataCollectorInformationTests()
+ {
+ this.envVarList = new List>();
+ this.mockDataCollector = new Mock();
+ this.mockDataCollector.As().Setup(x => x.GetTestExecutionEnvironmentVariables()).Returns(this.envVarList);
+ this.mockDataCollector.Protected().Setup("Dispose", true);
+ var mockMessageSink = new Mock();
+ this.dataCollectorInfo = new DataCollectorInformation(
+ this.mockDataCollector.Object,
+ null,
+ new DataCollectorConfig(typeof(CustomDataCollector)),
+ null,
+ new Mock().Object,
+ new TestPlatformDataCollectionEvents(),
+ mockMessageSink.Object);
+ }
+
+ [TestMethod]
+ public void InitializeDataCollectorShouldInitializeDataCollector()
+ {
+ this.envVarList.Add(new KeyValuePair("key", "value"));
+
+ this.dataCollectorInfo.InitializeDataCollector();
+
+ CollectionAssert.AreEqual(this.envVarList, this.dataCollectorInfo.TestExecutionEnvironmentVariables.ToList());
+ }
+
+ [TestMethod]
+ public void DisposeShouldInvokeDisposeOfDatacollector()
+ {
+ this.dataCollectorInfo.InitializeDataCollector();
+ this.dataCollectorInfo.DisposeDataCollector();
+
+ this.mockDataCollector.Protected().Verify("Dispose", Times.Once(), true);
+ }
+ }
+}
diff --git a/test/datacollector.UnitTests/DataCollectorLoaderTests.cs b/test/datacollector.UnitTests/DataCollectorLoaderTests.cs
new file mode 100644
index 0000000000..fcb7061892
--- /dev/null
+++ b/test/datacollector.UnitTests/DataCollectorLoaderTests.cs
@@ -0,0 +1,86 @@
+// 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.DataCollector.UnitTests
+{
+ using System;
+ using System.Reflection;
+ using System.Xml;
+
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollector;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ [TestClass]
+ public class DataCollectorLoaderTests
+ {
+ private readonly DataCollectorLoader dataCollectionLoader;
+
+ private readonly string dummyDataCollectorLocation;
+
+ private readonly string dummyDataCollectorTypeName;
+
+ public DataCollectorLoaderTests()
+ {
+ this.dataCollectionLoader = new DataCollectorLoader();
+ this.dummyDataCollectorLocation = typeof(DummyDataCollector1).GetTypeInfo().Assembly.Location;
+ this.dummyDataCollectorTypeName = typeof(DummyDataCollector1).AssemblyQualifiedName;
+ }
+
+ [TestMethod]
+ public void LoadShouldLoadTheDataCollectorIfTypeIsAvailable()
+ {
+ var collector = this.dataCollectionLoader.Load(
+ this.dummyDataCollectorLocation,
+ this.dummyDataCollectorTypeName);
+
+ Assert.IsNotNull(collector);
+ Assert.IsInstanceOfType(collector, typeof(DataCollector));
+ }
+
+ [TestMethod]
+ public void LoadShouldReturnNullDataCollectorIfTypeIsNotAvailable()
+ {
+ var collector = this.dataCollectionLoader.Load(
+ this.dummyDataCollectorLocation,
+ this.dummyDataCollectorTypeName.Replace("DataCollector1", "DataCollectorNotExist"));
+
+ Assert.IsNull(collector);
+ }
+
+ [TestMethod]
+ public void LoadShouldReturnNullDataCollectorIfTypeIsNotInstanceOfDataCollector()
+ {
+ var collector = this.dataCollectionLoader.Load(
+ this.dummyDataCollectorLocation.Replace("Tests", "UnitTests"),
+ this.dummyDataCollectorTypeName.Replace("DataCollector1", "DataCollector2"));
+
+ Assert.IsNull(collector);
+ }
+
+ public void LoadShouldReturnNullDataCollectorIfAssemblyIsNotPresent()
+ {
+ var collector = this.dataCollectionLoader.Load(
+ this.dummyDataCollectorLocation,
+ this.dummyDataCollectorTypeName.Replace("DataCollector1", "DataCollector2"));
+
+ Assert.IsNull(collector);
+ }
+
+ [DataCollectorFriendlyName("mymockeddatacollector")]
+ [DataCollectorTypeUri("my://mocked/datacollector")]
+ public class DummyDataCollector1 : DataCollector
+ {
+ public override void Initialize(XmlElement configurationElement, DataCollectionEvents events, DataCollectionSink dataSink, DataCollectionLogger logger, DataCollectionEnvironmentContext environmentContext)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ [DataCollectorFriendlyName("mymockeddatacollector")]
+ [DataCollectorTypeUri("my://mocked/datacollector")]
+ public class DummyDataCollector2
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/datacollector.UnitTests/DummyDataCollectors.cs b/test/datacollector.UnitTests/DummyDataCollectors.cs
new file mode 100644
index 0000000000..19f8c67a40
--- /dev/null
+++ b/test/datacollector.UnitTests/DummyDataCollectors.cs
@@ -0,0 +1,80 @@
+// 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.DataCollector.UnitTests
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Xml;
+
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollector;
+
+ [DataCollectorFriendlyName("CustomDataCollector")]
+ [DataCollectorTypeUri("my://custom/datacollector")]
+ public class CustomDataCollector : DataCollector, ITestExecutionEnvironmentSpecifier
+ {
+ public DataCollectionEnvironmentContext dataCollectionEnvironmentContext { get; set; }
+
+ public DataCollectionSink dataSink { get; set; }
+
+ public override void Initialize(
+ XmlElement configurationElement,
+ DataCollectionEvents events,
+ DataCollectionSink dataSink,
+ DataCollectionLogger logger,
+ DataCollectionEnvironmentContext environmentContext)
+ {
+ }
+
+ public IEnumerable> GetTestExecutionEnvironmentVariables()
+ {
+ return default(IEnumerable>);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ }
+ }
+
+ [DataCollectorFriendlyName("CustomDataCollector")]
+ public class CustomDataCollectorWithoutUri : DataCollector
+ {
+ public override void Initialize(
+ XmlElement configurationElement,
+ DataCollectionEvents events,
+ DataCollectionSink dataSink,
+ DataCollectionLogger logger,
+ DataCollectionEnvironmentContext environmentContext)
+ {
+ }
+ }
+
+ [DataCollectorTypeUri("my://custom/datacollector")]
+ public class CustomDataCollectorWithoutFriendlyName : DataCollector
+ {
+ public override void Initialize(
+ XmlElement configurationElement,
+ DataCollectionEvents events,
+ DataCollectionSink dataSink,
+ DataCollectionLogger logger,
+ DataCollectionEnvironmentContext environmentContext)
+ {
+ }
+ }
+
+ [DataCollectorFriendlyName("")]
+ [DataCollectorTypeUri("my://custom/datacollector")]
+ public class CustomDataCollectorWithEmptyFriendlyName : DataCollector
+ {
+ public override void Initialize(
+ XmlElement configurationElement,
+ DataCollectionEvents events,
+ DataCollectionSink dataSink,
+ DataCollectionLogger logger,
+ DataCollectionEnvironmentContext environmentContext)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/datacollector.x86.UnitTests/Program.cs b/test/datacollector.UnitTests/Program.cs
similarity index 85%
rename from test/datacollector.x86.UnitTests/Program.cs
rename to test/datacollector.UnitTests/Program.cs
index 2b0a2502e7..b6e8af2a8b 100644
--- a/test/datacollector.x86.UnitTests/Program.cs
+++ b/test/datacollector.UnitTests/Program.cs
@@ -7,7 +7,7 @@ namespace Microsoft.VisualStudio.TestPlatform.DataCollector.UnitTests
///
public static class Program
{
- public static void Main(string[] args)
+ public static void Main(string[] args)
{
}
}
diff --git a/test/datacollector.x86.UnitTests/Properties/AssemblyInfo.cs b/test/datacollector.UnitTests/Properties/AssemblyInfo.cs
similarity index 94%
rename from test/datacollector.x86.UnitTests/Properties/AssemblyInfo.cs
rename to test/datacollector.UnitTests/Properties/AssemblyInfo.cs
index 593e9f1e68..f0ec08dd62 100644
--- a/test/datacollector.x86.UnitTests/Properties/AssemblyInfo.cs
+++ b/test/datacollector.UnitTests/Properties/AssemblyInfo.cs
@@ -10,7 +10,7 @@
// associated with an assembly.
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("datacollector.x86.UnitTests")]
+[assembly: AssemblyProduct("datacollector.UnitTests")]
[assembly: AssemblyTrademark("")]
// Setting ComVisible to false makes the types in this assembly not visible
diff --git a/test/datacollector.UnitTests/TestPlatformDataCollectionEventsTests.cs b/test/datacollector.UnitTests/TestPlatformDataCollectionEventsTests.cs
new file mode 100644
index 0000000000..9b67141710
--- /dev/null
+++ b/test/datacollector.UnitTests/TestPlatformDataCollectionEventsTests.cs
@@ -0,0 +1,140 @@
+// 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.DataCollector.UnitTests
+{
+ using System;
+
+ using Microsoft.VisualStudio.TestPlatform.DataCollector;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ [TestClass]
+ public class TestPlatformDataCollectionEventsTests
+ {
+ private TestPlatformDataCollectionEvents events;
+
+ private DataCollectionContext context;
+
+ private bool isEventRaised;
+
+ public TestPlatformDataCollectionEventsTests()
+ {
+ this.events = new TestPlatformDataCollectionEvents();
+ }
+
+ [TestMethod]
+ public void RaiseEventsShouldThrowExceptionIfEventArgsIsNull()
+ {
+ Assert.ThrowsException(() =>
+ {
+ this.events.RaiseEvent(null);
+ });
+ }
+
+ [TestMethod]
+ public void RaiseEventsShouldRaiseEventsIfSessionStartEventArgsIsPassed()
+ {
+ this.isEventRaised = false;
+ var testCase = new TestCase();
+ this.context = new DataCollectionContext(testCase);
+
+ this.events.SessionStart += this.SessionStartMessageHandler;
+ var eventArgs = new SessionStartEventArgs(this.context);
+ this.events.RaiseEvent(eventArgs);
+
+ Assert.IsTrue(this.isEventRaised);
+ }
+
+ [TestMethod]
+ public void RaiseEventsShouldNotRaiseEventsIfEventIsNotRegisterd()
+ {
+ this.isEventRaised = false;
+ var testCase = new TestCase();
+ this.context = new DataCollectionContext(testCase);
+
+ var eventArgs = new SessionStartEventArgs(this.context);
+ this.events.RaiseEvent(eventArgs);
+
+ Assert.IsFalse(this.isEventRaised);
+ }
+
+ [TestMethod]
+ public void RaiseEventsShouldNotRaiseEventsIfEventIsUnRegisterd()
+ {
+ this.isEventRaised = false;
+ var testCase = new TestCase();
+ this.context = new DataCollectionContext(testCase);
+
+ this.events.SessionStart += this.SessionStartMessageHandler;
+ this.events.SessionStart -= this.SessionStartMessageHandler;
+ var eventArgs = new SessionStartEventArgs(this.context);
+ this.events.RaiseEvent(eventArgs);
+
+ Assert.IsFalse(this.isEventRaised);
+ }
+
+ [TestMethod]
+ public void RaiseEventsShouldRaiseEventsIfSessionEndEventArgsIsPassed()
+ {
+ this.isEventRaised = false;
+ var testCase = new TestCase();
+ this.context = new DataCollectionContext(testCase);
+
+ this.events.SessionEnd += this.SessionEndMessageHandler;
+ var eventArgs = new SessionEndEventArgs(this.context);
+ this.events.RaiseEvent(eventArgs);
+
+ Assert.IsTrue(this.isEventRaised);
+ }
+
+ [TestMethod]
+ public void RaiseEventsShouldRaiseEventsIfTestCaseStartEventArgsIsPassed()
+ {
+ this.isEventRaised = false;
+ var testCase = new TestCase();
+ this.context = new DataCollectionContext(testCase);
+
+ this.events.TestCaseStart += this.TestCaseStartMessageHandler;
+ var eventArgs = new TestCaseStartEventArgs(this.context, testCase);
+ this.events.RaiseEvent(eventArgs);
+
+ Assert.IsTrue(this.isEventRaised);
+ }
+
+ [TestMethod]
+ public void RaiseEventsShouldRaiseEventsIfTestCaseEndEventArgsIsPassed()
+ {
+ this.isEventRaised = false;
+ var testCase = new TestCase();
+ this.context = new DataCollectionContext(testCase);
+
+ this.events.TestCaseEnd += this.TestCaseEndMessageHandler;
+ var eventArgs = new TestCaseEndEventArgs(this.context, testCase, TestOutcome.Passed);
+ this.events.RaiseEvent(eventArgs);
+
+ Assert.IsTrue(this.isEventRaised);
+ }
+
+ private void SessionStartMessageHandler(object sender, SessionStartEventArgs e)
+ {
+ this.isEventRaised = true;
+ }
+
+ private void SessionEndMessageHandler(object sender, SessionEndEventArgs e)
+ {
+ this.isEventRaised = true;
+ }
+
+ private void TestCaseStartMessageHandler(object sender, TestCaseStartEventArgs e)
+ {
+ this.isEventRaised = true;
+ }
+
+ private void TestCaseEndMessageHandler(object sender, TestCaseEndEventArgs e)
+ {
+ this.isEventRaised = true;
+ }
+ }
+}
diff --git a/test/datacollector.UnitTests/TestPlatformDataCollectionLoggerTests.cs b/test/datacollector.UnitTests/TestPlatformDataCollectionLoggerTests.cs
new file mode 100644
index 0000000000..d7d3e02263
--- /dev/null
+++ b/test/datacollector.UnitTests/TestPlatformDataCollectionLoggerTests.cs
@@ -0,0 +1,105 @@
+// 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.DataCollector.UnitTests
+{
+ using System;
+
+ using Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ using Moq;
+
+ [TestClass]
+ public class TestPlatformDataCollectionLoggerTests
+ {
+ private TestPlatformDataCollectionLogger logger;
+ private Mock messageSink;
+ private DataCollectorConfig dataCollectorConfig;
+ private DataCollectionContext context;
+
+ public TestPlatformDataCollectionLoggerTests()
+ {
+ this.messageSink = new Mock();
+ this.dataCollectorConfig = new DataCollectorConfig(typeof(CustomDataCollector));
+ this.logger = new TestPlatformDataCollectionLogger(this.messageSink.Object, this.dataCollectorConfig);
+
+ var guid = Guid.NewGuid();
+ var sessionId = new SessionId(guid);
+ this.context = new DataCollectionContext(sessionId);
+ }
+
+ [TestMethod]
+ public void LogErrorShouldThrowExceptionIfContextIsNull()
+ {
+ Assert.ThrowsException(() =>
+ {
+ this.logger.LogError(null, string.Empty);
+ });
+
+ Assert.ThrowsException(() =>
+ {
+ this.logger.LogError(null, new Exception());
+ });
+
+ Assert.ThrowsException(() =>
+ {
+ this.logger.LogError(null, string.Empty, new Exception());
+ });
+ }
+
+ [TestMethod]
+ public void LogErrorShouldThrowExceptionIfTextIsNull()
+ {
+ Assert.ThrowsException(() =>
+ {
+ this.logger.LogError(this.context, (string)null);
+ });
+
+ Assert.ThrowsException(() =>
+ {
+ this.logger.LogError(this.context, null, new Exception());
+ });
+ }
+
+ [TestMethod]
+ public void LogErrorShouldThrowExceptionIfExceptionIsNull()
+ {
+ Assert.ThrowsException(() =>
+ {
+ this.logger.LogError(this.context, (Exception)null);
+ });
+
+ Assert.ThrowsException(() =>
+ {
+ this.logger.LogError(this.context, string.Empty, (Exception)null);
+ });
+ }
+
+ [TestMethod]
+ public void LogErrorShouldSendMessageToMessageSink()
+ {
+ var text = "customtext";
+ this.logger.LogError(this.context, text);
+
+ this.messageSink.Verify(x => x.SendMessage(It.IsAny()), Times.Once());
+
+ this.logger.LogError(this.context, new Exception(text));
+ this.messageSink.Verify(x => x.SendMessage(It.IsAny()), Times.Exactly(2));
+
+ this.logger.LogError(this.context, text, new Exception(text));
+ this.messageSink.Verify(x => x.SendMessage(It.IsAny()), Times.Exactly(3));
+ }
+
+ [TestMethod]
+ public void LogWarningShouldSendMessageToMessageSink()
+ {
+ var text = "customtext";
+ this.logger.LogWarning(this.context, text);
+
+ this.messageSink.Verify(x => x.SendMessage(It.IsAny()), Times.Once());
+ }
+ }
+}
diff --git a/test/datacollector.UnitTests/TestPlatformDataCollectionSinkTests.cs b/test/datacollector.UnitTests/TestPlatformDataCollectionSinkTests.cs
new file mode 100644
index 0000000000..e24e3b3bac
--- /dev/null
+++ b/test/datacollector.UnitTests/TestPlatformDataCollectionSinkTests.cs
@@ -0,0 +1,128 @@
+// 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.DataCollector.UnitTests
+{
+ using System;
+ using System.ComponentModel;
+ using System.IO;
+
+ using Microsoft.VisualStudio.TestPlatform.DataCollector;
+ using Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ using Moq;
+
+ [TestClass]
+ public class TestPlatformDataCollectionSinkTests
+ {
+ private Mock attachmentManager;
+
+ private DataCollectorConfig dataCollectorConfig;
+
+ private TestPlatformDataCollectionSink dataCollectionSink;
+
+ private bool isEventHandlerInvoked = false;
+
+ public TestPlatformDataCollectionSinkTests()
+ {
+ this.attachmentManager = new Mock();
+ this.dataCollectorConfig = new DataCollectorConfig(typeof(CustomDataCollector));
+ this.dataCollectionSink = new TestPlatformDataCollectionSink(this.attachmentManager.Object, this.dataCollectorConfig);
+ this.isEventHandlerInvoked = false;
+ }
+
+ [TestCleanup]
+ public void Cleanup()
+ {
+ File.Delete(Path.Combine(AppContext.BaseDirectory, "filename.txt"));
+ }
+
+ [TestMethod]
+ public void SendFileAsyncShouldThrowExceptionIfFileTransferInformationIsNull()
+ {
+ Assert.ThrowsException(() =>
+ {
+ this.dataCollectionSink.SendFileAsync(default(FileTransferInformation));
+ });
+ }
+
+ [TestMethod]
+ public void SendFileAsyncShouldInvokeAttachmentManagerWithValidFileTransferInfo()
+ {
+ var filename = Path.Combine(AppContext.BaseDirectory, "filename.txt");
+ File.WriteAllText(filename, string.Empty);
+
+ var guid = Guid.NewGuid();
+ var sessionId = new SessionId(guid);
+ var context = new DataCollectionContext(sessionId);
+
+ var fileTransferInfo = new FileTransferInformation(context, filename, false);
+
+ this.dataCollectionSink.SendFileAsync(fileTransferInfo);
+
+ this.attachmentManager.Verify(x => x.AddAttachment(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once());
+ }
+
+ [TestMethod]
+ public void SendFileAsyncShouldInvokeSendFileCompletedIfRegistered()
+ {
+ var filename = Path.Combine(AppContext.BaseDirectory, "filename.txt");
+ File.WriteAllText(filename, string.Empty);
+
+ var guid = Guid.NewGuid();
+ var sessionId = new SessionId(guid);
+ var context = new DataCollectionContext(sessionId);
+
+ var fileTransferInfo = new FileTransferInformation(context, filename, false);
+
+ var attachmentManager = new DataCollectionAttachmentManager();
+ attachmentManager.Initialize(sessionId, AppContext.BaseDirectory, new Mock().Object);
+
+ this.dataCollectionSink = new TestPlatformDataCollectionSink(attachmentManager, this.dataCollectorConfig);
+ this.dataCollectionSink.SendFileCompleted += SendFileCompleted_Handler;
+ this.dataCollectionSink.SendFileAsync(fileTransferInfo);
+
+ var result = attachmentManager.GetAttachments(context);
+
+ Assert.IsNotNull(result);
+ Assert.IsTrue(this.isEventHandlerInvoked);
+ }
+
+ [TestMethod]
+ public void SendFileAsyncShouldInvokeAttachmentManagerWithValidFileTransferInfoOverLoaded1()
+ {
+ var filename = Path.Combine(AppContext.BaseDirectory, "filename.txt");
+ File.WriteAllText(filename, string.Empty);
+
+ var guid = Guid.NewGuid();
+ var sessionId = new SessionId(guid);
+ var context = new DataCollectionContext(sessionId);
+
+ this.dataCollectionSink.SendFileAsync(context, filename, false);
+
+ this.attachmentManager.Verify(x => x.AddAttachment(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once());
+ }
+
+ [TestMethod]
+ public void SendFileAsyncShouldInvokeAttachmentManagerWithValidFileTransferInfoOverLoaded2()
+ {
+ var filename = Path.Combine(AppContext.BaseDirectory, "filename.txt");
+ File.WriteAllText(filename, string.Empty);
+
+ var guid = Guid.NewGuid();
+ var sessionId = new SessionId(guid);
+ var context = new DataCollectionContext(sessionId);
+
+ this.dataCollectionSink.SendFileAsync(context, filename, string.Empty, false);
+
+ this.attachmentManager.Verify(x => x.AddAttachment(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once());
+ }
+
+ void SendFileCompleted_Handler(object sender, AsyncCompletedEventArgs e)
+ {
+ this.isEventHandlerInvoked = true;
+ }
+ }
+}
diff --git a/test/datacollector.x86.UnitTests/datacollector.x86.UnitTests.csproj b/test/datacollector.UnitTests/datacollector.UnitTests.csproj
similarity index 81%
rename from test/datacollector.x86.UnitTests/datacollector.x86.UnitTests.csproj
rename to test/datacollector.UnitTests/datacollector.UnitTests.csproj
index 91cc734af8..a7dbc25a9e 100644
--- a/test/datacollector.x86.UnitTests/datacollector.x86.UnitTests.csproj
+++ b/test/datacollector.UnitTests/datacollector.UnitTests.csproj
@@ -1,16 +1,18 @@
-
+
..\..\true
+
+ Microsoft.VisualStudio.TestPlatform.DataCollector.UnitTests
+ Exenetcoreapp1.0;net46
- datacollector.x86.UnitTests
+ datacollector.UnitTests$(PackageTargetFallback);dnxcore50;portable-net45+win8
- x64
@@ -34,9 +36,15 @@
+
+
+
+
+ 4.0.1
+
-
+
\ No newline at end of file
diff --git a/test/datacollector.x86.UnitTests/DataCollectionCoordinatorTests.cs b/test/datacollector.x86.UnitTests/DataCollectionCoordinatorTests.cs
deleted file mode 100644
index db0130cbf1..0000000000
--- a/test/datacollector.x86.UnitTests/DataCollectionCoordinatorTests.cs
+++ /dev/null
@@ -1,231 +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.DataCollector.UnitTests
-{
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Diagnostics;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
-
- using Microsoft.VisualStudio.TestPlatform.Common;
- using Microsoft.VisualStudio.TestPlatform.DataCollector.Interfaces;
- using Microsoft.VisualStudio.TestPlatform.DataCollector.x86;
- using Microsoft.VisualStudio.TestPlatform.ObjectModel;
- using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
-
- [TestClass]
- public class DataCollectionCoordinatorTests
- {
- private DummyDataCollectionManager dummyDataCollectionManagerV1, dummyDataCollectionManagerV2;
- private DataCollectionCoordinator dataCollectionCoordinator;
-
- [TestInitialize]
- public void Initialize()
- {
- this.dummyDataCollectionManagerV1 = new DummyDataCollectionManager();
- this.dummyDataCollectionManagerV2 = new DummyDataCollectionManager();
- this.dataCollectionCoordinator = new DataCollectionCoordinator(new IDataCollectionManager[] { dummyDataCollectionManagerV1, dummyDataCollectionManagerV2 });
- }
-
- [TestMethod]
- public void BeforeTestRunStartShouldReturnBeforeTestRunStartResult()
- {
- var envVars = new Dictionary();
- envVars.Add("key", "value");
- this.dummyDataCollectionManagerV1.EnvVariables = envVars;
- this.dummyDataCollectionManagerV2.EnvVariables = new Dictionary();
-
- var result = this.dataCollectionCoordinator.BeforeTestRunStart(settingsXml: string.Empty, resetDataCollectors: true, isRunStartingNow: true);
-
- Assert.IsTrue(this.dummyDataCollectionManagerV1.IsLoadCollectorsInvoked);
- Assert.IsTrue(this.dummyDataCollectionManagerV2.IsLoadCollectorsInvoked);
- Assert.IsTrue(this.dummyDataCollectionManagerV1.IsSessionStartedInvoked);
- Assert.IsTrue(this.dummyDataCollectionManagerV2.IsSessionStartedInvoked);
- Assert.AreEqual(1, result.EnvironmentVariables.Count);
- Assert.AreEqual(envVars.Keys.First(), result.EnvironmentVariables.Keys.First());
- Assert.AreEqual(envVars.Values.First(), result.EnvironmentVariables.Values.First());
- }
-
- [TestMethod]
- public void BeforeTestRunStartShouldLoadTwoDataCollectorsInParallel()
- {
- var envVars = new Dictionary();
- envVars.Add("key", "value");
- this.dummyDataCollectionManagerV1.EnvVariables = envVars;
- this.dummyDataCollectionManagerV2.EnvVariables = new Dictionary();
-
- var result = this.dataCollectionCoordinator.BeforeTestRunStart(settingsXml: string.Empty, resetDataCollectors: true, isRunStartingNow: true);
-
- // Verify the two collectors are invoked in parallel
- Assert.IsTrue(this.dummyDataCollectionManagerV1.TaskId > 0);
- Assert.IsTrue(this.dummyDataCollectionManagerV2.TaskId > 0);
- Assert.AreNotEqual(this.dummyDataCollectionManagerV1.TaskId, this.dummyDataCollectionManagerV2.TaskId);
- }
-
- [TestMethod]
- public void BeforeTestRunStartShouldReturnNullIfNoDataCollectorManagersAreProvided()
- {
- this.dataCollectionCoordinator = new DataCollectionCoordinator(null);
-
- var result = this.dataCollectionCoordinator.BeforeTestRunStart(settingsXml: string.Empty, resetDataCollectors: true, isRunStartingNow: true);
-
- Assert.IsNull(result);
- }
-
- [TestMethod]
- public void BeforeTestRunStartShouldThrowExceptionIfExceptionIsThrownByDataCollectionManager()
- {
- this.dummyDataCollectionManagerV1.LoadDataCollectorsThrowException = true;
-
- Assert.ThrowsException(
- () =>
- {
- var result = this.dataCollectionCoordinator.BeforeTestRunStart(settingsXml: string.Empty, resetDataCollectors: true, isRunStartingNow: true);
- });
- }
-
- [TestMethod]
- public void AfterTestRunEndShouldReturnAttachments()
- {
- Collection attachments1 = new Collection();
- AttachmentSet attachmentset1 = new AttachmentSet(new Uri("DataCollection://Attachment/v1"), "AttachmentV1");
- attachmentset1.Attachments.Add(new UriDataAttachment(new Uri("DataCollection://Attachment/v11"), "AttachmentV1-Attachment1"));
- attachments1.Add(attachmentset1);
-
- this.dummyDataCollectionManagerV1.Attachments = attachments1;
- this.dummyDataCollectionManagerV2.Attachments = attachments1;
-
- var result = this.dataCollectionCoordinator.AfterTestRunEnd(isCancelled: false);
-
- Assert.IsNotNull(result);
- Assert.IsTrue(this.dummyDataCollectionManagerV1.IsSessionEndedInvoked);
- Assert.IsTrue(this.dummyDataCollectionManagerV2.IsSessionEndedInvoked);
- Assert.AreEqual(2, result.Count());
- }
-
- [TestMethod]
- public void AfterTestRunEndShouldGetAttachmentsFromDataCollectorManagersInParallel()
- {
- Collection attachments1 = new Collection();
- AttachmentSet attachmentset1 = new AttachmentSet(new Uri("DataCollection://Attachment/v1"), "AttachmentV1");
- attachmentset1.Attachments.Add(new UriDataAttachment(new Uri("DataCollection://Attachment/v11"), "AttachmentV1-Attachment1"));
- attachments1.Add(attachmentset1);
-
- this.dummyDataCollectionManagerV1.Attachments = attachments1;
- this.dummyDataCollectionManagerV2.Attachments = attachments1;
-
- var result = this.dataCollectionCoordinator.AfterTestRunEnd(isCancelled: false);
-
- // Verify the two collectors are invoked in parallel
- Assert.IsTrue(this.dummyDataCollectionManagerV1.TaskId > 0);
- Assert.IsTrue(this.dummyDataCollectionManagerV2.TaskId > 0);
- Assert.AreNotEqual(this.dummyDataCollectionManagerV1.TaskId, this.dummyDataCollectionManagerV2.TaskId);
- }
-
- [TestMethod]
- public void AfterTestRunEndShouldReturnNullIfNoDataCollectorManagersAreProvided()
- {
- this.dataCollectionCoordinator = new DataCollectionCoordinator(null);
-
- var result = this.dataCollectionCoordinator.AfterTestRunEnd(isCancelled: true);
-
- Assert.IsNull(result);
- }
-
- [TestMethod]
- public void AfterTestRunEndShouldThrowExceptionIfExceptionIsThrownByDataCollectionManager()
- {
- this.dummyDataCollectionManagerV1.SessionEndedThrowsException = true;
-
- Assert.ThrowsException(
- () =>
- {
- var result = this.dataCollectionCoordinator.AfterTestRunEnd(isCancelled: false);
- });
- }
-
- [TestMethod]
- public void DisposeShouldCallDisposeOfDataCollectionManagers()
- {
- this.dataCollectionCoordinator.Dispose();
-
- Assert.IsTrue(this.dummyDataCollectionManagerV1.IsDisposedInvoked);
- Assert.IsTrue(this.dummyDataCollectionManagerV2.IsDisposedInvoked);
- }
-
- [TestMethod]
- public void DisposeShouldDisposeResourcesIfNoDataCollectionManagersAreProvided()
- {
- this.dataCollectionCoordinator = new DataCollectionCoordinator(null);
-
- this.dataCollectionCoordinator.Dispose();
- }
- }
-
- internal class DummyDataCollectionManager : IDataCollectionManager
- {
- public bool IsLoadCollectorsInvoked;
- public bool IsSessionStartedInvoked;
- public bool IsSessionEndedInvoked;
- public Dictionary EnvVariables;
- public bool LoadDataCollectorsThrowException;
- public Collection Attachments;
- public bool SessionEndedThrowsException;
- public bool IsDisposedInvoked;
- public int TaskId;
-
- public void Dispose()
- {
- this.IsDisposedInvoked = true;
- }
-
- public Dictionary LoadDataCollectors(RunSettings settingsXml)
- {
- this.TaskId = Task.CurrentId.Value;
-
- if (this.LoadDataCollectorsThrowException)
- {
- throw new Exception("DataCollectionManagerException");
- }
-
- this.IsLoadCollectorsInvoked = true;
- return this.EnvVariables;
-
- }
-
- public void TestCaseStarted(TestCaseStartEventArgs testCaseStartEventArgs)
- {
- throw new NotImplementedException();
- }
-
- public Collection SessionEnded(bool isCancelled)
- {
- this.TaskId = Task.CurrentId.Value;
-
- if (this.SessionEndedThrowsException)
- {
- throw new Exception("DataCollectionManagerException");
- }
-
- this.IsSessionEndedInvoked = true;
- return this.Attachments;
- }
-
- public bool SessionStarted()
- {
- this.TaskId = Task.CurrentId.Value;
- this.IsSessionStartedInvoked = true;
- return true;
- }
-
- public Collection TestCaseEnded(TestCase testCase, TestOutcome testOutcome)
- {
- throw new NotImplementedException();
- }
- }
-}