diff --git a/TestPlatform.sln b/TestPlatform.sln
index eac26bc1ef..67d17fdcdb 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.26005.1
+VisualStudioVersion = 15.0.26014.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED0C35EB-7F31-4841-A24F-8EB708FFA959}"
EndProject
@@ -118,6 +118,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerfTestProject", "test\Tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleDataCollector", "test\TestAssets\SimpleDataCollector\SimpleDataCollector.csproj", "{D62D754C-8F0A-406F-8BA7-E96C6FFA7C7C}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.Protocol", "samples\Microsoft.TestPlatform.Protocol\Microsoft.TestPlatform.Protocol.csproj", "{97DD9467-B011-4736-AAC4-2C21BF554349}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleTestProject3", "test\TestAssets\SimpleTestProject3\SimpleTestProject3.csproj", "{82E75225-FA92-4F87-909D-039D62F96BFF}"
EndProject
Global
@@ -646,6 +648,18 @@ Global
{D62D754C-8F0A-406F-8BA7-E96C6FFA7C7C}.Release|x64.Build.0 = Release|Any CPU
{D62D754C-8F0A-406F-8BA7-E96C6FFA7C7C}.Release|x86.ActiveCfg = Release|Any CPU
{D62D754C-8F0A-406F-8BA7-E96C6FFA7C7C}.Release|x86.Build.0 = Release|Any CPU
+ {97DD9467-B011-4736-AAC4-2C21BF554349}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {97DD9467-B011-4736-AAC4-2C21BF554349}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {97DD9467-B011-4736-AAC4-2C21BF554349}.Debug|x64.ActiveCfg = Debug|x64
+ {97DD9467-B011-4736-AAC4-2C21BF554349}.Debug|x64.Build.0 = Debug|x64
+ {97DD9467-B011-4736-AAC4-2C21BF554349}.Debug|x86.ActiveCfg = Debug|x86
+ {97DD9467-B011-4736-AAC4-2C21BF554349}.Debug|x86.Build.0 = Debug|x86
+ {97DD9467-B011-4736-AAC4-2C21BF554349}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {97DD9467-B011-4736-AAC4-2C21BF554349}.Release|Any CPU.Build.0 = Release|Any CPU
+ {97DD9467-B011-4736-AAC4-2C21BF554349}.Release|x64.ActiveCfg = Release|x64
+ {97DD9467-B011-4736-AAC4-2C21BF554349}.Release|x64.Build.0 = Release|x64
+ {97DD9467-B011-4736-AAC4-2C21BF554349}.Release|x86.ActiveCfg = Release|x86
+ {97DD9467-B011-4736-AAC4-2C21BF554349}.Release|x86.Build.0 = Release|x86
{82E75225-FA92-4F87-909D-039D62F96BFF}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{82E75225-FA92-4F87-909D-039D62F96BFF}.Debug|Any CPU.Build.0 = Release|Any CPU
{82E75225-FA92-4F87-909D-039D62F96BFF}.Debug|x64.ActiveCfg = Release|Any CPU
@@ -712,6 +726,7 @@ Global
{A23E3408-D569-488E-A071-E1B3625C5F09} = {8DA7CBD9-F17E-41B6-90C4-CFF55848A25A}
{57B182B8-9014-4C6D-B966-B464DE3127D5} = {8DA7CBD9-F17E-41B6-90C4-CFF55848A25A}
{D62D754C-8F0A-406F-8BA7-E96C6FFA7C7C} = {8DA7CBD9-F17E-41B6-90C4-CFF55848A25A}
+ {97DD9467-B011-4736-AAC4-2C21BF554349} = {B9AB7A3D-4F63-48D2-86C0-70F52F6509AB}
{82E75225-FA92-4F87-909D-039D62F96BFF} = {8DA7CBD9-F17E-41B6-90C4-CFF55848A25A}
EndGlobalSection
EndGlobal
diff --git a/samples/Microsoft.TestPlatform.Protocol/Communication/JsonDataSerializer.cs b/samples/Microsoft.TestPlatform.Protocol/Communication/JsonDataSerializer.cs
new file mode 100644
index 0000000000..b5800254a5
--- /dev/null
+++ b/samples/Microsoft.TestPlatform.Protocol/Communication/JsonDataSerializer.cs
@@ -0,0 +1,152 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.TestPlatform.Protocol
+{
+ using System.IO;
+
+ using Newtonsoft.Json;
+ using Newtonsoft.Json.Linq;
+ using Newtonsoft.Json.Serialization;
+
+ ///
+ /// JsonDataSerializes serializes and deserializes data using Json format
+ ///
+ public class JsonDataSerializer
+ {
+ private static JsonDataSerializer instance;
+
+ private static JsonSerializer serializer;
+
+ ///
+ /// Prevents a default instance of the class from being created.
+ ///
+ private JsonDataSerializer()
+ {
+ serializer = JsonSerializer.Create(
+ new JsonSerializerSettings
+ {
+ DateFormatHandling = DateFormatHandling.IsoDateFormat,
+ DateParseHandling = DateParseHandling.DateTimeOffset,
+ DateTimeZoneHandling = DateTimeZoneHandling.Utc,
+ TypeNameHandling = TypeNameHandling.None
+ });
+#if DEBUG
+ // MemoryTraceWriter can help diagnose serialization issues. Enable it for
+ // debug builds only.
+ serializer.TraceWriter = new MemoryTraceWriter();
+#endif
+ }
+
+ ///
+ /// Gets the JSON Serializer instance.
+ ///
+ public static JsonDataSerializer Instance
+ {
+ get
+ {
+ return instance ?? (instance = new JsonDataSerializer());
+ }
+ }
+
+ ///
+ /// Deserialize a from raw JSON text.
+ ///
+ /// JSON string.
+ /// A instance.
+ public Message DeserializeMessage(string rawMessage)
+ {
+ return JsonConvert.DeserializeObject(rawMessage);
+ }
+
+ ///
+ /// Deserialize the for a message.
+ ///
+ /// A object.
+ /// Payload type.
+ /// The deserialized payload.
+ public T DeserializePayload(Message message)
+ {
+ T retValue = default(T);
+
+ // TODO: Currently we use json serializer auto only for non-testmessage types
+ // CHECK: Can't we just use auto for everything
+ if (Microsoft.TestPlatform.Protocol.MessageType.TestMessage.Equals(message.MessageType))
+ {
+ retValue = message.Payload.ToObject();
+ }
+ else
+ {
+ retValue = message.Payload.ToObject(serializer);
+ }
+
+ return retValue;
+ }
+
+ ///
+ /// Deserialize raw JSON to an object using the default serializer.
+ ///
+ /// JSON string.
+ /// Target type to deserialize.
+ /// An instance of .
+ public T Deserialize(string json)
+ {
+ using (var stringReader = new StringReader(json))
+ using (var jsonReader = new JsonTextReader(stringReader))
+ {
+ return serializer.Deserialize(jsonReader);
+ }
+ }
+
+ ///
+ /// Serialize an empty message.
+ ///
+ /// Type of the message.
+ /// Serialized message.
+ public string SerializeMessage(string messageType)
+ {
+ return JsonConvert.SerializeObject(new Message { MessageType = messageType });
+ }
+
+ ///
+ /// Serialize a message with payload.
+ ///
+ /// Type of the message.
+ /// Payload for the message.
+ /// Serialized message.
+ public string SerializePayload(string messageType, object payload)
+ {
+ JToken serializedPayload = null;
+
+ // TODO: Currently we use json serializer auto only for non-testmessage types
+ // CHECK: Can't we just use auto for everything
+ if (MessageType.TestMessage.Equals(messageType))
+ {
+ serializedPayload = JToken.FromObject(payload);
+ }
+ else
+ {
+ serializedPayload = JToken.FromObject(payload, serializer);
+ }
+
+ return JsonConvert.SerializeObject(new Message { MessageType = messageType, Payload = serializedPayload });
+ }
+
+ ///
+ /// Serialize an object to JSON using default serialization settings.
+ ///
+ /// Type of object to serialize.
+ /// Instance of the object to serialize.
+ /// JSON string.
+ public string Serialize(T data)
+ {
+ using (var stringWriter = new StringWriter())
+ using (var jsonWriter = new JsonTextWriter(stringWriter))
+ {
+ serializer.Serialize(jsonWriter, data);
+
+ return stringWriter.ToString();
+ }
+ }
+ }
+}
diff --git a/samples/Microsoft.TestPlatform.Protocol/Communication/Message.cs b/samples/Microsoft.TestPlatform.Protocol/Communication/Message.cs
new file mode 100644
index 0000000000..732db13beb
--- /dev/null
+++ b/samples/Microsoft.TestPlatform.Protocol/Communication/Message.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.TestPlatform.Protocol
+{
+ using Newtonsoft.Json;
+ using Newtonsoft.Json.Linq;
+
+ public class Message
+ {
+ ///
+ /// Gets or sets the message type.
+ ///
+ public string MessageType { get; set; }
+
+ ///
+ /// Gets or sets the payload.
+ ///
+ public JToken Payload { get; set; }
+
+ ///
+ /// To string implementation.
+ ///
+ /// The .
+ public override string ToString()
+ {
+ return "(" + MessageType + ") -> " + (Payload == null ? "null" : Payload.ToString(Formatting.Indented));
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/Microsoft.TestPlatform.Protocol/Communication/MessageType.cs b/samples/Microsoft.TestPlatform.Protocol/Communication/MessageType.cs
new file mode 100644
index 0000000000..b37d567cd7
--- /dev/null
+++ b/samples/Microsoft.TestPlatform.Protocol/Communication/MessageType.cs
@@ -0,0 +1,142 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.TestPlatform.Protocol
+{
+ ///
+ /// The message type.
+ ///
+ public static class MessageType
+ {
+ ///
+ /// The session start.
+ ///
+ public const string SessionStart = "TestSession.Start";
+
+ ///
+ /// The session end.
+ ///
+ public const string SessionEnd = "TestSession.Terminate";
+
+ ///
+ /// The is aborted.
+ ///
+ public const string SessionAbort = "TestSession.Abort";
+
+ ///
+ /// The session connected.
+ ///
+ public const string SessionConnected = "TestSession.Connected";
+
+ ///
+ /// Test Message
+ ///
+ public const string TestMessage = "TestSession.Message";
+
+ ///
+ /// Protocol Version
+ ///
+ public const string VersionCheck = "ProtocolVersion";
+
+ ///
+ /// The session start.
+ ///
+ public const string DiscoveryInitialize = "TestDiscovery.Initialize";
+
+ ///
+ /// The discovery started.
+ ///
+ public const string StartDiscovery = "TestDiscovery.Start";
+
+ ///
+ /// The test cases found.
+ ///
+ public const string TestCasesFound = "TestDiscovery.TestFound";
+
+ ///
+ /// The discovery complete.
+ ///
+ public const string DiscoveryComplete = "TestDiscovery.Completed";
+
+ ///
+ /// The session start.
+ ///
+ public const string ExecutionInitialize = "TestExecution.Initialize";
+
+ ///
+ /// Cancel the current test run
+ ///
+ public const string CancelTestRun = "TestExecution.Cancel";
+
+ ///
+ /// Cancel the current test run
+ ///
+ public const string AbortTestRun = "TestExecution.Abort";
+
+ ///
+ /// Start test execution.
+ ///
+ public const string StartTestExecutionWithSources = "TestExecution.StartWithSources";
+
+ ///
+ /// Start test execution.
+ ///
+ public const string StartTestExecutionWithTests = "TestExecution.StartWithTests";
+
+ ///
+ /// The test run stats change.
+ ///
+ public const string TestRunStatsChange = "TestExecution.StatsChange";
+
+ ///
+ /// The execution complete.
+ ///
+ public const string ExecutionComplete = "TestExecution.Completed";
+
+ ///
+ /// The message to get runner process startInfo for run all tests in given sources
+ ///
+ public const string GetTestRunnerProcessStartInfoForRunAll = "TestExecution.GetTestRunnerProcessStartInfoForRunAll";
+
+ ///
+ /// The message to get runner process startInfo for run selected tests
+ ///
+ public const string GetTestRunnerProcessStartInfoForRunSelected = "TestExecution.GetTestRunnerProcessStartInfoForRunSelected";
+
+ ///
+ /// CustomTestHostLaunch
+ ///
+ public const string CustomTestHostLaunch = "TestExecution.CustomTestHostLaunch";
+
+ ///
+ /// Custom Test Host launch callback
+ ///
+ public const string CustomTestHostLaunchCallback = "TestExecution.CustomTestHostLaunchCallback";
+
+ ///
+ /// Extensions Initialization
+ ///
+ public const string ExtensionsInitialize = "Extensions.Initialize";
+
+ ///
+ /// Start Test Run All Sources
+ ///
+ public const string TestRunAllSourcesWithDefaultHost = "TestExecution.RunAllWithDefaultHost";
+
+ ///
+ /// Start Test Run - Testcases
+ ///
+ public const string TestRunSelectedTestCasesDefaultHost = "TestExecution.RunSelectedWithDefaultHost";
+
+ ///
+ /// Launch Adapter Process With DebuggerAttached
+ ///
+ public const string LaunchAdapterProcessWithDebuggerAttached = "TestExecution.LaunchAdapterProcessWithDebuggerAttached";
+
+ ///
+ /// Launch Adapter Process With DebuggerAttached
+ ///
+ public const string LaunchAdapterProcessWithDebuggerAttachedCallback = "TestExecution.LaunchAdapterProcessWithDebuggerAttachedCallback";
+
+ }
+}
diff --git a/samples/Microsoft.TestPlatform.Protocol/Communication/SocketCommunicationManager.cs b/samples/Microsoft.TestPlatform.Protocol/Communication/SocketCommunicationManager.cs
new file mode 100644
index 0000000000..0cc1b5a3ae
--- /dev/null
+++ b/samples/Microsoft.TestPlatform.Protocol/Communication/SocketCommunicationManager.cs
@@ -0,0 +1,213 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.TestPlatform.Protocol
+{
+ using System;
+ using System.IO;
+ using System.Net;
+ using System.Net.Sockets;
+ using System.Threading;
+ using System.Threading.Tasks;
+
+ ///
+ /// Facilitates communication using sockets
+ ///
+ public class SocketCommunicationManager
+ {
+ ///
+ /// TCP Listener to host TCP channel and listen
+ ///
+ private TcpListener tcpListener;
+
+ ///
+ /// Binary Writer to write to channel stream
+ ///
+ private BinaryWriter binaryWriter;
+
+ ///
+ /// Binary reader to read from channel stream
+ ///
+ private BinaryReader binaryReader;
+
+ ///
+ /// Serializer for the data objects
+ ///
+ private JsonDataSerializer dataSerializer;
+
+ ///
+ /// Event used to maintain client connection state
+ ///
+ private ManualResetEvent clientConnectedEvent = new ManualResetEvent(false);
+
+ ///
+ /// Sync object for sending messages
+ /// SendMessage over socket channel is NOT thread-safe
+ ///
+ private object sendSyncObject = new object();
+
+ ///
+ /// Stream to use read timeout
+ ///
+ private NetworkStream stream;
+
+ private Socket socket;
+
+ ///
+ /// The server stream read timeout constant (in microseconds).
+ ///
+ private const int StreamReadTimeout = 1000 * 1000;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SocketCommunicationManager() : this(JsonDataSerializer.Instance)
+ {
+ }
+
+ internal SocketCommunicationManager(JsonDataSerializer dataSerializer)
+ {
+ this.dataSerializer = dataSerializer;
+ }
+
+ #region ServerMethods
+
+ ///
+ /// Host TCP Socket Server and start listening
+ ///
+ ///
+ public int HostServer()
+ {
+ var endpoint = new IPEndPoint(IPAddress.Loopback, 0);
+ this.tcpListener = new TcpListener(endpoint);
+
+ this.tcpListener.Start();
+ var portNumber = ((IPEndPoint)this.tcpListener.LocalEndpoint).Port;
+ Console.WriteLine("Server started. Listening at port : {0}", portNumber);
+ return portNumber;
+ }
+
+ ///
+ /// Accepts client async
+ ///
+ public async Task AcceptClientAsync()
+ {
+ if (this.tcpListener != null)
+ {
+ this.clientConnectedEvent.Reset();
+
+ var client = await this.tcpListener.AcceptTcpClientAsync();
+ this.socket = client.Client;
+ this.stream = client.GetStream();
+ this.binaryReader = new BinaryReader(this.stream);
+ this.binaryWriter = new BinaryWriter(this.stream);
+
+ this.clientConnectedEvent.Set();
+
+ Console.WriteLine("Accepted Client request and set the flag");
+ }
+ }
+
+ ///
+ /// Waits for Client Connection
+ ///
+ /// Time to Wait for the connection
+ /// True if Client is connected, false otherwise
+ public bool WaitForClientConnection(int clientConnectionTimeout)
+ {
+ return this.clientConnectedEvent.WaitOne(clientConnectionTimeout);
+ }
+
+ ///
+ /// Stop Listener
+ ///
+ public void StopServer()
+ {
+ this.tcpListener?.Stop();
+ this.tcpListener = null;
+ this.binaryReader?.Dispose();
+ this.binaryWriter?.Dispose();
+ }
+
+ #endregion
+
+ ///
+ /// Writes message to the binary writer.
+ ///
+ /// Type of Message to be sent, for instance TestSessionStart
+ public void SendMessage(string messageType)
+ {
+ var serializedObject = this.dataSerializer.SerializeMessage(messageType);
+ this.WriteAndFlushToChannel(serializedObject);
+ }
+
+ ///
+ /// Reads message from the binary reader
+ ///
+ /// Returns message read from the binary reader
+ public Message ReceiveMessage()
+ {
+ var rawMessage = this.ReceiveRawMessage();
+ return this.dataSerializer.DeserializeMessage(rawMessage);
+ }
+
+ ///
+ /// Writes message to the binary writer with payload
+ ///
+ /// Type of Message to be sent, for instance TestSessionStart
+ /// payload to be sent
+ public void SendMessage(string messageType, object payload)
+ {
+ var rawMessage = this.dataSerializer.SerializePayload(messageType, payload);
+ this.WriteAndFlushToChannel(rawMessage);
+ }
+
+ ///
+ /// The send hand shake message.
+ ///
+ public void SendHandShakeMessage()
+ {
+ this.SendMessage(MessageType.SessionStart);
+ }
+
+ ///
+ /// Reads message from the binary reader
+ ///
+ /// Raw message string
+ public string ReceiveRawMessage()
+ {
+ var rawMessage = this.binaryReader.ReadString();
+ Console.WriteLine("\n=========== Receiving Message ===========");
+ Console.WriteLine(rawMessage);
+ return rawMessage;
+ }
+
+ ///
+ /// Deserializes the Message into actual TestPlatform objects
+ ///
+ /// The type of object to deserialize to.
+ /// Message object
+ /// TestPlatform object
+ public T DeserializePayload(Message message)
+ {
+ return this.dataSerializer.DeserializePayload(message);
+ }
+
+ ///
+ /// Writes the data on socket and flushes the buffer
+ ///
+ /// message to write
+ private void WriteAndFlushToChannel(string rawMessage)
+ {
+ // Writing Message on binarywriter is not Thread-Safe
+ // Need to sync one by one to avoid buffer corruption
+ lock (this.sendSyncObject)
+ {
+ Console.WriteLine("\n=========== Sending Message ===========");
+ Console.WriteLine(rawMessage);
+ this.binaryWriter?.Write(rawMessage);
+ this.binaryWriter?.Flush();
+ }
+ }
+ }
+}
diff --git a/samples/Microsoft.TestPlatform.Protocol/Microsoft.TestPlatform.Protocol.csproj b/samples/Microsoft.TestPlatform.Protocol/Microsoft.TestPlatform.Protocol.csproj
new file mode 100644
index 0000000000..2f1e4d453c
--- /dev/null
+++ b/samples/Microsoft.TestPlatform.Protocol/Microsoft.TestPlatform.Protocol.csproj
@@ -0,0 +1,42 @@
+
+
+
+ net46
+ Microsoft.TestPlatform.Protocol
+ Exe
+ win7-x64
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+ 4.1.1
+
+
+
+
+ 8.0.3
+
+
+
+
+
+
+
+
+
+ 1.0.0-alpha-20161104-2
+ All
+
+
+
+ $(DefineConstants);RELEASE
+
+
+
\ No newline at end of file
diff --git a/samples/Microsoft.TestPlatform.Protocol/Payload/DiscoveryRequestPayload.cs b/samples/Microsoft.TestPlatform.Protocol/Payload/DiscoveryRequestPayload.cs
new file mode 100644
index 0000000000..e2a360e745
--- /dev/null
+++ b/samples/Microsoft.TestPlatform.Protocol/Payload/DiscoveryRequestPayload.cs
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.TestPlatform.Protocol
+{
+ using System.Collections.Generic;
+ using System.Runtime.Serialization;
+
+ ///
+ /// Class used to define the DiscoveryRequestPayload sent by the Vstest.console translation layers into design mode
+ ///
+ public class DiscoveryRequestPayload
+ {
+ ///
+ /// Settings used for the discovery request.
+ ///
+ [DataMember]
+ public IEnumerable Sources { get; set; }
+
+ ///
+ /// Settings used for the discovery request.
+ ///
+ [DataMember]
+ public string RunSettings { get; set; }
+ }
+}
diff --git a/samples/Microsoft.TestPlatform.Protocol/Payload/TestRunRequestPayload.cs b/samples/Microsoft.TestPlatform.Protocol/Payload/TestRunRequestPayload.cs
new file mode 100644
index 0000000000..5cebd391c6
--- /dev/null
+++ b/samples/Microsoft.TestPlatform.Protocol/Payload/TestRunRequestPayload.cs
@@ -0,0 +1,44 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.TestPlatform.Protocol
+{
+ using System.Collections.Generic;
+ using System.Runtime.Serialization;
+
+ ///
+ /// Class used to define the TestRunRequestPayload sent to Vstest.console in design mode
+ ///
+ public class TestRunRequestPayload
+ {
+ ///
+ /// Gets or sets the sources for the test run request.
+ ///
+ [DataMember]
+ public List Sources { get; set; }
+
+ ///
+ /// Gets or sets the test cases for the test run request.
+ ///
+ [DataMember]
+ public dynamic TestCases { get; set; }
+
+ ///
+ /// Gets or sets the settings used for the test run request.
+ ///
+ [DataMember]
+ public string RunSettings { get; set; }
+
+ ///
+ /// Settings used for the Run request.
+ ///
+ [DataMember]
+ public bool KeepAlive { get; set; }
+
+ ///
+ /// Is Debugging enabled
+ ///
+ [DataMember]
+ public bool DebuggingEnabled { get; set; }
+ }
+}
diff --git a/samples/Microsoft.TestPlatform.Protocol/Program.cs b/samples/Microsoft.TestPlatform.Protocol/Program.cs
new file mode 100644
index 0000000000..938013dc08
--- /dev/null
+++ b/samples/Microsoft.TestPlatform.Protocol/Program.cs
@@ -0,0 +1,201 @@
+//// Copyright (c) Microsoft Corporation. All rights reserved.
+//// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.TestPlatform.Protocol
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Globalization;
+ using System.IO;
+ using System.Threading;
+
+ public class Program
+ {
+ private const string PORT_ARGUMENT = "/port:{0}";
+ private const string PARENT_PROCESSID_ARGUMENT = "/parentprocessid:{0}";
+
+ private static SocketCommunicationManager communicationManager;
+ private static JsonDataSerializer dataSerializer = JsonDataSerializer.Instance;
+
+ public static void Main(string[] args)
+ {
+ if(args == null || args.Length < 1)
+ {
+ Console.WriteLine("Please provide appropriate arguments. Arguments can be passed as following:");
+ Console.WriteLine("Microsoft.TestPlatform.Protocol.exe --testassembly:\"[assemblyPath]\" --operation:\"[RunAll|RunSelected|Discovery]\" --testadapterpath:\"[path]\"");
+ Console.WriteLine("or Microsoft.TestPlatform.Protocol.exe -a:\"[assemblyPath]\" -o:\"[RunAll|RunSelected|Discovery]\" -p:\"[path]\" \n");
+ }
+
+ var executingLocation = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
+
+ // Default values
+ var testAssembly = Path.Combine(executingLocation, "UnitTestProject.dll");
+ string testadapterPath = null;
+ string operation = "Discovery";
+ var separator = new char[] { ':' };
+ foreach (var arg in args)
+ {
+ if (arg.StartsWith("-p:") || arg.StartsWith("--testadapterpath:"))
+ {
+ testadapterPath = arg.Split(separator, 2)[1];
+ }
+ else if (arg.StartsWith("-a:") || arg.StartsWith("--testassembly:"))
+ {
+ testAssembly = arg.Split(separator,2)[1];
+ }
+ else if (arg.StartsWith("-o:") || arg.StartsWith("--operation:"))
+ {
+ operation = arg.Split(separator, 2)[1];
+ }
+ }
+
+ Console.WriteLine("TestAdapter Path : {0}", testadapterPath);
+ Console.WriteLine("TestAssembly Path : {0}", testAssembly);
+ Console.WriteLine("Operation : {0}", operation);
+
+ var processManager = new RunnerProcessManager();
+ communicationManager = new SocketCommunicationManager();
+
+ // Start the server
+ var port = communicationManager.HostServer();
+
+ //Start runner exe and wait for the connection
+ string parentProcessIdArgs = string.Format(CultureInfo.InvariantCulture, PARENT_PROCESSID_ARGUMENT, Process.GetCurrentProcess().Id);
+ string portArgs = string.Format(CultureInfo.InvariantCulture, PORT_ARGUMENT, port);
+ processManager.StartProcess(new string[2] { parentProcessIdArgs, portArgs });
+
+ communicationManager.AcceptClientAsync();
+ communicationManager.WaitForClientConnection(Timeout.Infinite);
+ HandShakeWithVsTestConsole();
+
+ //Actual operation
+ dynamic discoveredTestCases;
+ switch (operation.ToLower())
+ {
+ case "discovery":
+ discoveredTestCases = DiscoverTests(testadapterPath, testAssembly);
+ break;
+
+ case "runselected":
+ discoveredTestCases = DiscoverTests(testadapterPath, testAssembly);
+ RunSelectedTests(discoveredTestCases);
+ break;
+
+ case "runall":
+ default:
+ RunAllTests(new List() { testAssembly });
+ break;
+ }
+ }
+
+ static void HandShakeWithVsTestConsole()
+ {
+ //HandShake with vstest.console
+ Console.WriteLine("=========== HandShake with vstest.console ==========");
+ var message = communicationManager.ReceiveMessage();
+ if (message.MessageType == MessageType.SessionConnected)
+ {
+ //Version Check
+ communicationManager.SendMessage(MessageType.VersionCheck);
+ message = communicationManager.ReceiveMessage();
+
+ if (message.MessageType == MessageType.VersionCheck)
+ {
+ var version = JsonDataSerializer.Instance.DeserializePayload(message);
+
+ var success = version == 1;
+ Console.WriteLine("Version Success: {0}", success);
+ }
+ }
+ }
+
+ static dynamic DiscoverTests(string testadapterPath, string testAssembly)
+ {
+ Console.WriteLine("Starting Operation : Discovery");
+
+ // Intialize the extensions
+ if (testadapterPath != null)
+ {
+ communicationManager.SendMessage(MessageType.ExtensionsInitialize, new List() { testadapterPath });
+ }
+
+ // Start Discovery
+ communicationManager.SendMessage(
+ MessageType.StartDiscovery,
+ new DiscoveryRequestPayload() { Sources = new List() { testAssembly }, RunSettings = null });
+ var isDiscoveryComplete = false;
+
+ dynamic testCases = null;
+
+ while (!isDiscoveryComplete)
+ {
+ var message = communicationManager.ReceiveMessage();
+
+ if (string.Equals(MessageType.TestCasesFound, message.MessageType))
+ {
+ // Handle discovered tests here.
+ testCases = (JsonDataSerializer.Instance.DeserializePayload(message));
+ }
+ else if (string.Equals(MessageType.DiscoveryComplete, message.MessageType))
+ {
+ dynamic discoveryCompletePayload =
+ JsonDataSerializer.Instance.DeserializePayload(message);
+
+ //Handle discovery complete here
+ isDiscoveryComplete = true;
+ }
+ else if (string.Equals(MessageType.TestMessage, message.MessageType))
+ {
+ var testMessagePayload = dataSerializer.DeserializePayload(message);
+ // Handle messages here.
+ }
+ }
+
+ return testCases;
+ }
+
+ static void RunAllTests(List sources)
+ {
+ Console.WriteLine("Starting Operation: RunAll");
+ communicationManager.SendMessage(MessageType.TestRunAllSourcesWithDefaultHost, new TestRunRequestPayload() { Sources = sources, RunSettings = null });
+ RecieveRunMesagesAndHandleRunComplete();
+ }
+
+ static void RunSelectedTests(dynamic testCases)
+ {
+ Console.WriteLine("Starting Operation: RunSelected");
+ communicationManager.SendMessage(MessageType.TestRunSelectedTestCasesDefaultHost, new TestRunRequestPayload() { TestCases = testCases, RunSettings = null });
+ RecieveRunMesagesAndHandleRunComplete();
+ }
+
+ static void RecieveRunMesagesAndHandleRunComplete()
+ {
+ var isTestRunComplete = false;
+
+ while (!isTestRunComplete)
+ {
+ var message = communicationManager.ReceiveMessage();
+
+ if (string.Equals(MessageType.TestRunStatsChange, message.MessageType))
+ {
+ var testRunChangedArgs = dataSerializer.DeserializePayload(message);
+ // Handle TestRunStatsChange here
+ }
+ else if (string.Equals(MessageType.ExecutionComplete, message.MessageType))
+ {
+ var testRunCompletePayload = dataSerializer.DeserializePayload(message);
+
+ // Handle TestRunComplete here
+ // Set the flag, to end the loop.
+ isTestRunComplete = true;
+ }
+ else if (string.Equals(MessageType.TestMessage, message.MessageType))
+ {
+ var testMessagePayload = dataSerializer.DeserializePayload(message);
+ // Handle log messages here
+ }
+ }
+ }
+ }
+}
diff --git a/samples/Microsoft.TestPlatform.Protocol/Properties/AssemblyInfo.cs b/samples/Microsoft.TestPlatform.Protocol/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..ecbfce1cf0
--- /dev/null
+++ b/samples/Microsoft.TestPlatform.Protocol/Properties/AssemblyInfo.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.
+
+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("Microsoft.TestPlatform.Protocol")]
+[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("4ec14041-7804-4840-ae70-98babdc8b0e2")]
diff --git a/samples/Microsoft.TestPlatform.Protocol/Properties/launchSettings.json b/samples/Microsoft.TestPlatform.Protocol/Properties/launchSettings.json
new file mode 100644
index 0000000000..7521e2ddbe
--- /dev/null
+++ b/samples/Microsoft.TestPlatform.Protocol/Properties/launchSettings.json
@@ -0,0 +1,7 @@
+{
+ "profiles": {
+ "Microsoft.TestPlatform.Protocol": {
+ "commandName": "Project"
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/Microsoft.TestPlatform.Protocol/RunnerProcessManager.cs b/samples/Microsoft.TestPlatform.Protocol/RunnerProcessManager.cs
new file mode 100644
index 0000000000..f52f48f39e
--- /dev/null
+++ b/samples/Microsoft.TestPlatform.Protocol/RunnerProcessManager.cs
@@ -0,0 +1,125 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.TestPlatform.Protocol
+{
+ using System;
+ using System.Diagnostics;
+ using System.IO;
+
+ ///
+ /// dotnet.exe process manager
+ ///
+ internal class RunnerProcessManager
+ {
+ private object syncObject = new object();
+
+ private bool vstestConsoleStarted = false;
+
+ private bool vstestConsoleExited = false;
+
+ private Process process;
+
+ public event EventHandler ProcessExited;
+
+ #region Constructor
+
+ public RunnerProcessManager()
+ {
+ }
+
+ #endregion Constructor
+
+ public bool IsProcessInitialized()
+ {
+ lock (syncObject)
+ {
+ return this.vstestConsoleStarted && !vstestConsoleExited &&
+ this.process != null;
+ }
+ }
+
+ ///
+ /// Call dotnet.exe with the parameters previously specified
+ ///
+ public void StartProcess(string[] args)
+ {
+ this.process = new Process();
+ process.StartInfo.FileName = GetDotnetHostFullPath();
+
+ if (args != null)
+ {
+ process.StartInfo.Arguments = args.Length < 2 ? args[0] : string.Join(" ", args);
+ }
+ process.StartInfo.Arguments = "vstest" + " " + process.StartInfo.Arguments;
+
+ process.StartInfo.UseShellExecute = false;
+ process.StartInfo.CreateNoWindow = true;
+
+ process.Start();
+ process.EnableRaisingEvents = true;
+ process.Exited += Process_Exited;
+
+ lock (syncObject)
+ {
+ vstestConsoleExited = false;
+ vstestConsoleStarted = true;
+ }
+ }
+
+ public void ShutdownProcess()
+ {
+ // Ideally process should die by itself
+ if (IsProcessInitialized())
+ {
+ this.process.Kill();
+ this.process.Dispose();
+ this.process = null;
+ }
+ }
+
+ ///
+ /// Get full path for the .net host
+ ///
+ /// Full path to dotnet executable
+ /// Debuggers require the full path of executable to launch it.
+ private string GetDotnetHostFullPath()
+ {
+ char separator = ';';
+ var dotnetExeName = "dotnet.exe";
+
+#if !NET46
+ // Use semicolon(;) as path separator for windows
+ // colon(:) for Linux and OSX
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ separator = ':';
+ dotnetExeName = "dotnet";
+ }
+#endif
+
+ var pathString = Environment.GetEnvironmentVariable("PATH");
+ foreach (string path in pathString.Split(separator))
+ {
+ string exeFullPath = Path.Combine(path.Trim(), dotnetExeName);
+ if (File.Exists(exeFullPath))
+ {
+ return exeFullPath;
+ }
+ }
+
+ string errorMessage = String.Format("Unable to find dotnet.exe");
+ Console.WriteLine("Error : {0}", errorMessage);
+ throw new FileNotFoundException(errorMessage);
+ }
+
+ private void Process_Exited(object sender, EventArgs e)
+ {
+ lock (syncObject)
+ {
+ vstestConsoleExited = true;
+ this.ProcessExited?.Invoke(sender, e);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/UnitTestProject/UnitTest.cs b/samples/UnitTestProject/UnitTest.cs
index 9d8ee99724..c35757a177 100644
--- a/samples/UnitTestProject/UnitTest.cs
+++ b/samples/UnitTestProject/UnitTest.cs
@@ -8,9 +8,62 @@ namespace UnitTestProject
[TestClass]
public class UnitTest
{
+ ///
+ /// The passing test.
+ ///
[TestMethod]
- public void TestMethod1()
+ public void PassingTest()
{
+ Assert.AreEqual(2, 2);
+ }
+
+ ///
+ /// The failing test.
+ ///
+ [TestMethod]
+ public void FailingTest()
+ {
+ Assert.AreEqual(2, 3);
+ }
+
+ ///
+ /// The skipping test.
+ ///
+ [Ignore]
+ [TestMethod]
+ public void SkippingTest()
+ {
+ }
+
+ [TestCategory("CategoryA")]
+ [TestMethod]
+ public void TestWithTestCategory()
+ {
+ Assert.AreEqual(1, 1);
+ }
+
+ [Priority(0)]
+ [TestMethod]
+ public void TestWithPriority()
+ {
+ Assert.AreEqual(1, 1);
+ }
+
+ [TestProperty("Property1", "Value1")]
+ [TestProperty("Property2", "Value2")]
+ [TestMethod]
+ public void TestWithProperties()
+ {
+ Assert.AreEqual(1, 1);
+ }
+
+ [TestCategory("CategoryA")]
+ [Priority(1)]
+ [TestProperty("Property2", "Value2")]
+ [TestMethod]
+ public void FailingTestWithTraits()
+ {
+ Assert.Fail();
}
}
}
diff --git a/samples/UnitTestProject/UnitTestProject.csproj b/samples/UnitTestProject/UnitTestProject.csproj
index 9503396589..a8527f9017 100644
--- a/samples/UnitTestProject/UnitTestProject.csproj
+++ b/samples/UnitTestProject/UnitTestProject.csproj
@@ -1,8 +1,8 @@
-
netcoreapp1.0;net46
+ Exe
UnitTestProject
$(PackageTargetFallback);dnxcore50;portable-net45+win8
false
@@ -14,12 +14,10 @@
false
false
-
-
+
-
1.0.0-alpha-20161104-2
@@ -29,28 +27,30 @@
1.6.0
- 1.0.4-preview
+ 1.0.8-rc
+
+
+ 1.1.8-rc
-
1.0.0
- 15.0.0-preview-20161123-03
+ 15.0.0-preview-20161216-01
-
-
+
+
+
$(DefineConstants);RELEASE
-
-
+
\ No newline at end of file