From 064340a40619652cd454313787c6e274cac103ea Mon Sep 17 00:00:00 2001 From: Sarabjot Singh Date: Thu, 30 Mar 2017 11:24:13 +0530 Subject: [PATCH 1/7] 1. Enable use of new Message type. 2. Protocol version check between runner and host 3. Object model changes for reducing the verbosity. 4. Serializers for supported protocol versions. 5. Unit tests --- .../Interfaces/ICommunicationManager.cs | 9 +- .../Interfaces/IDataSerializer.cs | 9 ++ .../Interfaces/ITestRequestSender.cs | 6 + .../JsonDataSerializer.cs | 106 +++++++++----- .../Messages/Message.cs | 8 ++ .../Messages/MessageType.cs | 5 + ...=> DefaultTestPlatformContractResolver.cs} | 4 +- .../Serialization/TestCaseConverter.cs | 60 ++++++++ .../TestPlatformContractResolver1.cs | 29 ++++ .../Serialization/TestResultConverter.cs | 69 +++++++++ .../SocketCommunicationManager.cs | 12 ++ .../TestRequestHandler.cs | 30 ++-- .../TestRequestSender.cs | 42 +++++- .../Client/ProxyOperationManager.cs | 35 +++-- .../Hosting/DotnetTestHostManager.cs | 10 +- .../TestCase.cs | 69 +++++---- .../TestObject.cs | 11 +- .../TestResult.cs | 72 ++++++---- .../TestCaseSerializationTests.cs | 131 ++++++++++++++---- .../TestResultSerializationTests.cs | 90 ++++++++++-- .../TestRequestSenderTests.cs | 54 ++++++-- .../Client/ProxyDiscoveryManagerTests.cs | 1 + .../Client/ProxyExecutionManagerTests.cs | 1 + .../Client/ProxyOperationManagerTests.cs | 46 +++++- .../TestObjectTests.cs | 28 +++- .../VsTestConsoleRequestSenderTests.cs | 2 +- 26 files changed, 768 insertions(+), 171 deletions(-) rename src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/{TestPlatformContractResolver.cs => DefaultTestPlatformContractResolver.cs} (96%) create mode 100644 src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs create mode 100644 src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver1.cs create mode 100644 src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ICommunicationManager.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ICommunicationManager.cs index 98ea1a1b09..f102fd1560 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ICommunicationManager.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ICommunicationManager.cs @@ -31,7 +31,6 @@ public interface ICommunicationManager /// True, if Server got a connection from client bool WaitForClientConnection(int connectionTimeout); - /// /// Waits for server to be connected /// Whoever creating the client and trying to connect to a server @@ -104,6 +103,14 @@ public interface ICommunicationManager /// payload to be sent void SendMessage(string messageType, object payload); + /// + /// Writes message to the binary writer with payload + /// + /// Type of Message to be sent, for instance TestSessionStart + /// payload to be sent + /// version to be sent + void SendMessage(string messageType, object payload, int version); + /// /// Send serialized raw message /// diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/IDataSerializer.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/IDataSerializer.cs index a5ec20fe11..5704a10e14 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/IDataSerializer.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/IDataSerializer.cs @@ -37,5 +37,14 @@ public interface IDataSerializer /// Payload of the message /// Raw Serialized message string SerializePayload(string messageType, object payload); + + /// + /// Serializes and creates a raw message given a message type and the object payload + /// + /// Message Type + /// Payload of the message + /// version to be sent + /// Raw Serialized message + string SerializePayload(string messageType, object payload, int version); } } diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestSender.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestSender.cs index 5f5cf24099..85c7017949 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestSender.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestSender.cs @@ -21,6 +21,12 @@ public interface ITestRequestSender : IDisposable /// Port Number of the communication channel int InitializeCommunication(); + /// + /// Used for protocol version check with TestHost + /// + /// + bool CheckVersionWithTestHost(); + /// /// Waits for Request Handler to be connected /// diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs index ec6d010d52..22a67f481a 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs @@ -6,7 +6,6 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities using System.IO; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; - using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serialization; using Newtonsoft.Json; @@ -20,26 +19,33 @@ public class JsonDataSerializer : IDataSerializer { private static JsonDataSerializer instance; - private static JsonSerializer serializer; + private static JsonSerializer payloadSerializer; + private static JsonSerializer payloadSerializer2; /// /// Prevents a default instance of the class from being created. /// private JsonDataSerializer() { - serializer = JsonSerializer.Create( - new JsonSerializerSettings - { - ContractResolver = new TestPlatformContractResolver(), - DateFormatHandling = DateFormatHandling.IsoDateFormat, - DateParseHandling = DateParseHandling.DateTimeOffset, - DateTimeZoneHandling = DateTimeZoneHandling.Utc, - TypeNameHandling = TypeNameHandling.None - }); + var jsonSettings = new JsonSerializerSettings + { + DateFormatHandling = DateFormatHandling.IsoDateFormat, + DateParseHandling = DateParseHandling.DateTimeOffset, + DateTimeZoneHandling = DateTimeZoneHandling.Utc, + TypeNameHandling = TypeNameHandling.None + }; + + payloadSerializer = JsonSerializer.Create(jsonSettings); + payloadSerializer2 = JsonSerializer.Create(jsonSettings); + + payloadSerializer.ContractResolver = new TestPlatformContractResolver1(); + payloadSerializer2.ContractResolver = new DefaultTestPlatformContractResolver(); + #if DEBUG // MemoryTraceWriter can help diagnose serialization issues. Enable it for // debug builds only. - serializer.TraceWriter = new MemoryTraceWriter(); + payloadSerializer.TraceWriter = new MemoryTraceWriter(); + payloadSerializer2.TraceWriter = new MemoryTraceWriter(); #endif } @@ -61,7 +67,9 @@ public static JsonDataSerializer Instance /// A instance. public Message DeserializeMessage(string rawMessage) { - return JsonConvert.DeserializeObject(rawMessage); + // Convert to VersionedMessage + // Message can be deserialized to VersionedMessage where version will be 0 + return JsonConvert.DeserializeObject(rawMessage); } /// @@ -73,17 +81,21 @@ public Message DeserializeMessage(string rawMessage) public T DeserializePayload(Message message) { T retValue = default(T); + + var versionedMessage = message as VersionedMessage; + var serializer = versionedMessage?.Version == 2 ? payloadSerializer2 : payloadSerializer; + // 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(message.MessageType)) - { - retValue = message.Payload.ToObject(); - } - else - { - retValue = message.Payload.ToObject(serializer); - } + //if (MessageType.TestMessage.Equals(message.MessageType)) + //{ + // retValue = message.Payload.ToObject(); + //} + //else + //{ + retValue = message.Payload.ToObject(serializer); + //} return retValue; } @@ -94,8 +106,10 @@ public T DeserializePayload(Message message) /// JSON string. /// Target type to deserialize. /// An instance of . - public T Deserialize(string json) + public T Deserialize(string json, int version = 1) { + var serializer = version == 2 ? payloadSerializer2 : payloadSerializer; + using (var stringReader = new StringReader(json)) using (var jsonReader = new JsonTextReader(stringReader)) { @@ -122,29 +136,53 @@ public string SerializeMessage(string messageType) 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); - } + + serializedPayload = JToken.FromObject(payload, payloadSerializer); return JsonConvert.SerializeObject(new Message { MessageType = messageType, Payload = serializedPayload }); } + /// + /// Serialize a message with payload. + /// + /// Type of the message. + /// Payload for the message. + /// Version for the message. + /// Serialized message. + public string SerializePayload(string messageType, object payload, int version) + { + JToken serializedPayload = null; + + var serializer = version == 2 ? payloadSerializer2 : payloadSerializer; + + // 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); + //} + + var message = version == 1 ? + new Message { MessageType = messageType, Payload = serializedPayload } : + new VersionedMessage { MessageType = messageType, Version = version, Payload = serializedPayload }; + + return JsonConvert.SerializeObject(message); + } + /// /// 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) + public string Serialize(T data, int version = 1) { + var serializer = version == 2 ? payloadSerializer2 : payloadSerializer; + using (var stringWriter = new StringWriter()) using (var jsonWriter = new JsonTextWriter(stringWriter)) { diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/Message.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/Message.cs index 544959dc2c..ddbfa4bd31 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/Message.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/Message.cs @@ -27,4 +27,12 @@ public override string ToString() return "(" + MessageType + ") -> " + (Payload == null ? "null" : Payload.ToString(Formatting.Indented)); } } + + public class VersionedMessage : Message + { + /// + /// Gets or sets the version of the message + /// + public int Version { get; set; } + } } \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs index fdd67613db..32e4abb5de 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/MessageType.cs @@ -38,6 +38,11 @@ public static class MessageType /// public const string VersionCheck = "ProtocolVersion"; + /// + /// Protocol Error + /// + public const string ProtocolError = "ProtocolError"; + /// /// The session start. /// diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/DefaultTestPlatformContractResolver.cs similarity index 96% rename from src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver.cs rename to src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/DefaultTestPlatformContractResolver.cs index 30be74678e..3928f6be0d 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/DefaultTestPlatformContractResolver.cs @@ -10,11 +10,11 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serializati using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Newtonsoft.Json.Serialization; - + /// /// JSON contract resolver for mapping test platform types. /// - public class TestPlatformContractResolver : DefaultContractResolver + public class DefaultTestPlatformContractResolver : DefaultContractResolver { /// protected override JsonContract CreateContract(Type objectType) diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs new file mode 100644 index 0000000000..134d4784d6 --- /dev/null +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs @@ -0,0 +1,60 @@ +// 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.CommunicationUtilities.Serialization +{ + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Newtonsoft.Json; + using System; + + public class TestCaseConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return typeof(TestCase) == objectType; + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var testCase = new TestCase(); + serializer.Populate(reader, testCase); + + testCase.Id = testCase.GetPropertyValue(TestCaseProperties.Id, Guid.Empty); + testCase.FullyQualifiedName = testCase.GetPropertyValue(TestCaseProperties.FullyQualifiedName, null); + testCase.DisplayName = testCase.GetPropertyValue(TestCaseProperties.DisplayName, null); + testCase.Source = testCase.GetPropertyValue(TestCaseProperties.Source, null); + testCase.ExecutorUri = testCase.GetPropertyValue(TestCaseProperties.ExecutorUri, null); + testCase.CodeFilePath = testCase.GetPropertyValue(TestCaseProperties.CodeFilePath, null); + testCase.LineNumber = testCase.GetPropertyValue(TestCaseProperties.LineNumber, -1); + return testCase; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + // P2 to P1 + var testCase = (value as TestCase); + + testCase.SetPropertyValue(TestCaseProperties.FullyQualifiedName, testCase.FullyQualifiedName); + testCase.SetPropertyValue(TestCaseProperties.ExecutorUri, testCase.ExecutorUri); + testCase.SetPropertyValue(TestCaseProperties.Source, testCase.Source); + testCase.SetPropertyValue(TestCaseProperties.Id, testCase.Id); + if (!testCase.DisplayName.Equals(testCase.FullyQualifiedName)) testCase.SetPropertyValue(TestCaseProperties.DisplayName, testCase.DisplayName); + + if (!string.IsNullOrEmpty(testCase.CodeFilePath)) testCase.SetPropertyValue(TestCaseProperties.CodeFilePath, testCase.CodeFilePath); + if (testCase.LineNumber >= 0) testCase.SetPropertyValue(TestCaseProperties.LineNumber, testCase.LineNumber); + + var properties = testCase.GetProperties(); + + writer.WriteStartObject(); + writer.WritePropertyName("Properties"); + writer.WriteStartArray(); + foreach (var property in properties) + { + serializer.Serialize(writer, property); + } + + writer.WriteEndArray(); + writer.WriteEndObject(); + } + } +} diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver1.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver1.cs new file mode 100644 index 0000000000..674372fb08 --- /dev/null +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver1.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.CommunicationUtilities.Serialization +{ + using System; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Newtonsoft.Json.Serialization; + + /// + /// JSON contract resolver for mapping test platform types for v1 serialization. + /// + public class TestPlatformContractResolver1 : DefaultTestPlatformContractResolver + { + protected override JsonContract CreateContract(Type objectType) + { + var contract = base.CreateContract(objectType); + if (typeof(TestCase) == objectType) + { + contract.Converter = new TestCaseConverter(); + } + if (typeof(TestResult) == objectType) + { + contract.Converter = new TestResultConverter(); + } + return contract; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs new file mode 100644 index 0000000000..d5920bdba2 --- /dev/null +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs @@ -0,0 +1,69 @@ +// 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.CommunicationUtilities.Serialization +{ + using System; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Newtonsoft.Json; + + public class TestResultConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return typeof(TestResult) == objectType; + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var testResult = new TestResult(); + serializer.Populate(reader, testResult); + + testResult.Outcome = testResult.GetPropertyValue(TestResultProperties.Outcome, TestOutcome.None); + testResult.ErrorMessage = testResult.GetPropertyValue(TestResultProperties.ErrorMessage, null); + testResult.ErrorStackTrace = testResult.GetPropertyValue(TestResultProperties.ErrorStackTrace, null); + testResult.DisplayName = testResult.GetPropertyValue(TestResultProperties.DisplayName, null); + testResult.ComputerName = testResult.GetPropertyValue(TestResultProperties.ComputerName, null); + testResult.Duration = testResult.GetPropertyValue(TestResultProperties.Duration, TimeSpan.Zero); + testResult.StartTime = testResult.GetPropertyValue(TestResultProperties.StartTime, DateTimeOffset.Now); + testResult.EndTime = testResult.GetPropertyValue(TestResultProperties.EndTime, DateTimeOffset.Now); + + return testResult; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + // P2 to P1 + var testResult = (value as TestResult); + if (testResult.Outcome != TestOutcome.None) testResult.SetPropertyValue(TestResultProperties.Outcome, testResult.Outcome); + if (!string.IsNullOrEmpty(testResult.ErrorMessage)) testResult.SetPropertyValue(TestResultProperties.ErrorMessage, testResult.ErrorMessage); + if (!string.IsNullOrEmpty(testResult.ErrorStackTrace)) testResult.SetPropertyValue(TestResultProperties.ErrorStackTrace, testResult.ErrorStackTrace); + if (!string.IsNullOrEmpty(testResult.DisplayName)) testResult.SetPropertyValue(TestResultProperties.DisplayName, testResult.DisplayName); + if (!string.IsNullOrEmpty(testResult.ComputerName)) testResult.SetPropertyValue(TestResultProperties.ComputerName, testResult.ComputerName); + if (testResult.Duration != default(TimeSpan)) testResult.SetPropertyValue(TestResultProperties.Duration, testResult.Duration); + + if (testResult.StartTime != default(DateTimeOffset)) testResult.SetPropertyValue(TestResultProperties.StartTime, testResult.StartTime); + if (testResult.EndTime != default(DateTimeOffset)) testResult.SetPropertyValue(TestResultProperties.EndTime, testResult.EndTime); + + var properties = testResult.GetProperties(); + + writer.WriteStartObject(); + writer.WritePropertyName("TestCase"); + serializer.Serialize(writer, testResult.TestCase); + writer.WritePropertyName("Attachments"); + serializer.Serialize(writer, testResult.Attachments); + writer.WritePropertyName("Messages"); + serializer.Serialize(writer, testResult.Messages); + + writer.WritePropertyName("Properties"); + writer.WriteStartArray(); + foreach (var property in properties) + { + serializer.Serialize(writer, property); + } + + writer.WriteEndArray(); + writer.WriteEndObject(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/SocketCommunicationManager.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/SocketCommunicationManager.cs index c0f897f353..805875cf4c 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/SocketCommunicationManager.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/SocketCommunicationManager.cs @@ -223,6 +223,18 @@ public void SendMessage(string messageType, object payload) this.WriteAndFlushToChannel(rawMessage); } + /// + /// Writes message to the binary writer with payload + /// + /// Type of Message to be sent, for instance TestSessionStart + /// payload to be sent + /// version to be sent + public void SendMessage(string messageType, object payload, int version) + { + var rawMessage = this.dataSerializer.SerializePayload(messageType, payload, version); + this.WriteAndFlushToChannel(rawMessage); + } + /// /// The send hand shake message. /// diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestHandler.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestHandler.cs index a1cf726e3e..dd761ef53b 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestHandler.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestHandler.cs @@ -28,6 +28,12 @@ public class TestRequestHandler : IDisposable, ITestRequestHandler private Action OnAckMessageRecieved; + private int highestSupportedVersion = 2; + + // Set default to 1, if protocol version check does not happen + // that implies runner is using version 1 + private int protocolVersion = 1; + /// /// The timeout for the client to connect to the server. /// @@ -72,13 +78,21 @@ public void ProcessRequests(ITestHostManagerFactory testHostManagerFactory) 500, 25000000, true, - (message) => EqtTrace.Error(message)); - + (errorMessage) => EqtTrace.Error(errorMessage)); + do { var message = this.communicationManager.ReceiveMessage(); + switch (message.MessageType) { + case MessageType.VersionCheck: + var version = this.dataSerializer.DeserializePayload(message); + this.protocolVersion = Math.Min(version, highestSupportedVersion); + this.communicationManager.SendMessage(MessageType.VersionCheck, this.protocolVersion); + + break; + case MessageType.DiscoveryInitialize: { EqtTrace.Info("Discovery Session Initialize."); @@ -216,7 +230,7 @@ public void Close() /// public void SendTestCases(IEnumerable discoveredTestCases) { - this.communicationManager.SendMessage(MessageType.TestCasesFound, discoveredTestCases); + this.communicationManager.SendMessage(MessageType.TestCasesFound, discoveredTestCases, protocolVersion); } /// @@ -225,7 +239,7 @@ public void SendTestCases(IEnumerable discoveredTestCases) /// public void SendTestRunStatistics(TestRunChangedEventArgs testRunChangedArgs) { - this.communicationManager.SendMessage(MessageType.TestRunStatsChange, testRunChangedArgs); + this.communicationManager.SendMessage(MessageType.TestRunStatsChange, testRunChangedArgs, protocolVersion); } /// @@ -236,7 +250,7 @@ public void SendTestRunStatistics(TestRunChangedEventArgs testRunChangedArgs) public void SendLog(TestMessageLevel messageLevel, string message) { var testMessagePayload = new TestMessagePayload {MessageLevel = messageLevel,Message = message}; - this.communicationManager.SendMessage(MessageType.TestMessage, testMessagePayload); + this.communicationManager.SendMessage(MessageType.TestMessage, testMessagePayload, protocolVersion); } /// @@ -260,7 +274,7 @@ public void SendExecutionComplete( ExecutorUris = executorUris }; - this.communicationManager.SendMessage(MessageType.ExecutionComplete, payload); + this.communicationManager.SendMessage(MessageType.ExecutionComplete, payload, protocolVersion); } /// @@ -275,7 +289,7 @@ public void DiscoveryComplete(long totalTests, IEnumerable lastChunk, IsAborted = isAborted }; - this.communicationManager.SendMessage(MessageType.DiscoveryComplete, discoveryCompletePayload); + this.communicationManager.SendMessage(MessageType.DiscoveryComplete, discoveryCompletePayload, protocolVersion); } /// @@ -292,7 +306,7 @@ public int LaunchProcessWithDebuggerAttached(TestProcessStartInfo testProcessSta waitHandle.Set(); }; - this.communicationManager.SendMessage(MessageType.LaunchAdapterProcessWithDebuggerAttached, testProcessStartInfo); + this.communicationManager.SendMessage(MessageType.LaunchAdapterProcessWithDebuggerAttached, testProcessStartInfo, protocolVersion); waitHandle.WaitOne(); this.OnAckMessageRecieved = null; diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs index d0c12fe5da..a76a2b9f14 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs @@ -28,6 +28,9 @@ public sealed class TestRequestSender : ITestRequestSender private IDataSerializer dataSerializer; + // TODO:sasin Change the version to 2 + private int highestNegotiatedVersion = 1; + /// /// Use to cancel blocking tasks associated with testhost process /// @@ -77,6 +80,35 @@ public void Close() EqtTrace.Info("Closing the connection"); } + /// + public bool CheckVersionWithTestHost() + { + var success = false; + this.communicationManager.SendMessage(MessageType.VersionCheck, payload: highestNegotiatedVersion); + + var message = this.communicationManager.ReceiveMessage(); + + if (message.MessageType == MessageType.VersionCheck) + { + var protocolVersion = this.dataSerializer.DeserializePayload(message); + + // TODO: Should we check if this is valid ? + highestNegotiatedVersion = protocolVersion; + success = true; + + } + else if (message.MessageType == MessageType.ProtocolError) + { + EqtTrace.Error("TestRequestSender: VersionCheck Failed"); + } + else + { + EqtTrace.Error("TestRequestSender: VersionCheck Message Expected but different message received: Received MessageType: {0}", message.MessageType); + } + + return success; + } + /// /// Initializes the extensions in the test host. /// @@ -84,7 +116,7 @@ public void Close() /// Flag to indicate if only well known extensions are to be loaded. public void InitializeDiscovery(IEnumerable pathToAdditionalExtensions, bool loadOnlyWellKnownExtensions) { - this.communicationManager.SendMessage(MessageType.DiscoveryInitialize, pathToAdditionalExtensions); + this.communicationManager.SendMessage(MessageType.DiscoveryInitialize, pathToAdditionalExtensions, version: highestNegotiatedVersion); } /// @@ -94,7 +126,7 @@ public void InitializeDiscovery(IEnumerable pathToAdditionalExtensions, /// Flag to indicate if only well known extensions are to be loaded. public void InitializeExecution(IEnumerable pathToAdditionalExtensions, bool loadOnlyWellKnownExtensions) { - this.communicationManager.SendMessage(MessageType.ExecutionInitialize, pathToAdditionalExtensions); + this.communicationManager.SendMessage(MessageType.ExecutionInitialize, pathToAdditionalExtensions, version: highestNegotiatedVersion); } /// @@ -106,7 +138,7 @@ public void DiscoverTests(DiscoveryCriteria discoveryCriteria, ITestDiscoveryEve { try { - this.communicationManager.SendMessage(MessageType.StartDiscovery, discoveryCriteria); + this.communicationManager.SendMessage(MessageType.StartDiscovery, discoveryCriteria, version: highestNegotiatedVersion); var isDiscoveryComplete = false; @@ -192,7 +224,7 @@ private void StartTestRunAndListenAndReportTestResults( { try { - this.communicationManager.SendMessage(messageType, payload); + this.communicationManager.SendMessage(messageType, payload, version: highestNegotiatedVersion); // This needs to happen asynchronously. Task.Run(() => this.ListenAndReportTestResults(eventHandler)); @@ -251,7 +283,7 @@ private void ListenAndReportTestResults(ITestRunEventsHandler testRunEventsHandl this.communicationManager.SendMessage( MessageType.LaunchAdapterProcessWithDebuggerAttachedCallback, - processId); + processId, version: highestNegotiatedVersion); } } catch (IOException exception) diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs index f323a470a9..be16e1ef53 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs @@ -18,6 +18,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client using Microsoft.VisualStudio.TestPlatform.Utilities; using CrossPlatEngineResources = Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Resources.Resources; + using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting; /// /// Base class for any operations that the client needs to drive through the engine. @@ -114,22 +115,34 @@ public virtual void SetupChannel(IEnumerable sources) // Increase connection timeout when debugging is enabled. connTimeout = 5 * this.connectionTimeout; } - - this.initialized = true; - } - // Wait for a timeout for the client to connect. - if (!this.RequestSender.WaitForRequestHandlerConnection(connTimeout)) - { - var errorMsg = CrossPlatEngineResources.InitializationFailed; + // Wait for a timeout for the client to connect. + if (!this.RequestSender.WaitForRequestHandlerConnection(connTimeout)) + { + var errorMsg = CrossPlatEngineResources.InitializationFailed; - if (!string.IsNullOrWhiteSpace(this.testHostProcessStdError)) + if (!string.IsNullOrWhiteSpace(this.testHostProcessStdError.ToString())) + { + // Testhost failed with error + errorMsg = string.Format(CrossPlatEngineResources.TestHostExitedWithError, this.testHostProcessStdError); + } + + throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, errorMsg)); + } + + // Handling special case for dotnet core projects with older test hosts + // Older test hosts are not aware of protocol version check + // Hence we should not be sending VersionCheck message to these test hosts + var dotnetHostManager = this.testHostManager as DotnetTestHostManager; + if (dotnetHostManager == null || dotnetHostManager.IsVersionCheckRequired) { - // Testhost failed with error - errorMsg = string.Format(CrossPlatEngineResources.TestHostExitedWithError, this.testHostProcessStdError); + if (!this.RequestSender.CheckVersionWithTestHost()) + { + throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, "Protocol version check failed")); + } } - throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, errorMsg)); + this.initialized = true; } } diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Hosting/DotnetTestHostManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Hosting/DotnetTestHostManager.cs index e7fb3c01bf..04419eee4f 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Hosting/DotnetTestHostManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Hosting/DotnetTestHostManager.cs @@ -56,6 +56,8 @@ public class DotnetTestHostManager : ITestRuntimeProvider private bool hostExitedEventRaised; + private string hostPackageVersion = "15.0.0"; + /// /// Initializes a new instance of the class. /// @@ -94,6 +96,11 @@ internal DotnetTestHostManager( /// public bool Shared => false; + /// + /// Check if the test host supports protocol version check + /// + internal virtual bool IsVersionCheckRequired => !hostPackageVersion.StartsWith("15.0.0"); + protected int ErrorLength { get; set; } = 1000; protected int TimeOut { get; set; } = 10000; @@ -342,6 +349,7 @@ private string GetTestHostPath(string runtimeConfigDevPath, string depsFilePath, } testHostPath = Path.Combine(testhostPackage.Path, testHostPath); + hostPackageVersion = testhostPackage.Version; EqtTrace.Verbose("DotnetTestHostmanager: Relative path of testhost.dll with respect to package folder is {0}", testHostPath); } } @@ -376,7 +384,7 @@ private string GetTestHostPath(string runtimeConfigDevPath, string depsFilePath, return testHostPath; } - + private CancellationTokenSource GetCancellationTokenSource() { this.hostLaunchCts = new CancellationTokenSource(this.TimeOut); diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs index ba550f482f..936d0ec150 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs @@ -8,6 +8,7 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel using System.Runtime.Serialization; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; + using System.Globalization; /// /// Stores information about a test case. @@ -24,6 +25,14 @@ public sealed class TestCase : TestObject #endif private Guid defaultId = Guid.Empty; + private string fullyQualifiedName; + private string displayName; + private Guid id; + private string source; + private Uri executerUri; + private string codeFilePath; + private int lineNumber = -1; + #region Constructor /// @@ -77,13 +86,12 @@ public Object LocalExtensionData /// /// Gets or sets the id of the test case. /// - [IgnoreDataMember] + [DataMember] public Guid Id { get { - var id = this.GetPropertyValue(TestCaseProperties.Id, Guid.Empty); - if (id == Guid.Empty) + if (this.id == Guid.Empty) { // user has not specified his own Id during ctor! We will cache Id if its empty if (this.defaultId == Guid.Empty) @@ -94,83 +102,86 @@ public Guid Id return this.defaultId; } - return id; + return this.id; } set { - this.SetPropertyValue(TestCaseProperties.Id, value); + var convertedValue = ConvertPropertyFrom(TestCaseProperties.Id, CultureInfo.InvariantCulture, value); + this.id = (Guid)convertedValue; } } /// /// Gets or sets the fully qualified name of the test case. /// - [IgnoreDataMember] + [DataMember] public string FullyQualifiedName { get { - return this.GetPropertyValue(TestCaseProperties.FullyQualifiedName, string.Empty); + return this.fullyQualifiedName; } set { - this.SetPropertyValue(TestCaseProperties.FullyQualifiedName, value); - - // Id is based on Name/Source, will nulll out guid and it gets calc next time we access it. - this.defaultId = Guid.Empty; + this.fullyQualifiedName = value; } } /// /// Gets or sets the display name of the test case. /// - [IgnoreDataMember] + [DataMember] public string DisplayName { get { - return this.GetPropertyValue(TestCaseProperties.DisplayName, this.FullyQualifiedName); + if (string.IsNullOrEmpty(this.displayName)) + { + return this.FullyQualifiedName; + } + return this.displayName; } set { - this.SetPropertyValue(TestCaseProperties.DisplayName, value); + this.displayName = value; } } /// /// Gets or sets the Uri of the Executor to use for running this test. /// - [IgnoreDataMember] + [DataMember] public Uri ExecutorUri { get { - return this.GetPropertyValue(TestCaseProperties.ExecutorUri, null); + return this.executerUri; } set { - this.SetPropertyValue(TestCaseProperties.ExecutorUri, value); + var convertedValue = ConvertPropertyFrom(TestCaseProperties.ExecutorUri, CultureInfo.InvariantCulture, value); + this.executerUri = (Uri)convertedValue; } } /// /// Gets the test container source from which the test is discovered. /// - [IgnoreDataMember] + [DataMember] public string Source { get { - return this.GetPropertyValue(TestCaseProperties.Source, null); + return source; } - - private set + + set { - this.SetPropertyValue(TestCaseProperties.Source, value); + this.source = value; // Id is based on Name/Source, will nulll out guid and it gets calc next time we access it. this.defaultId = Guid.Empty; @@ -180,37 +191,39 @@ private set /// /// Gets or sets the source code file path of the test. /// - [IgnoreDataMember] + [DataMember] public string CodeFilePath { get { - return this.GetPropertyValue(TestCaseProperties.CodeFilePath, null); + return this.codeFilePath; } set { - this.SetPropertyValue(TestCaseProperties.CodeFilePath, value); + this.codeFilePath = value; } } /// /// Gets or sets the line number of the test. /// - [IgnoreDataMember] + [DataMember] public int LineNumber { get { - return this.GetPropertyValue(TestCaseProperties.LineNumber, -1); + return this.lineNumber; } set { - this.SetPropertyValue(TestCaseProperties.LineNumber, value); + var convertedValue = ConvertPropertyFrom(TestCaseProperties.LineNumber, CultureInfo.InvariantCulture, value); + this.lineNumber = (int)convertedValue; } } + /// public override string ToString() { diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestObject.cs b/src/Microsoft.TestPlatform.ObjectModel/TestObject.cs index 2c954da006..aaab0e5128 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestObject.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestObject.cs @@ -64,6 +64,15 @@ private List> StoreKeyValuePairs } } + /// + /// Returns the list of testproperties associated with the test object + /// + /// + public List> GetProperties() + { + return this.store.ToList(); + } + #endregion Fields #region Constructors @@ -269,7 +278,7 @@ private void PrivateSetPropertyValue(TestProperty property, object value) /// Convert passed in value from TestProperty's specified value type. /// /// Converted object - private static object ConvertPropertyFrom(TestProperty property, CultureInfo culture, object value) + internal static object ConvertPropertyFrom(TestProperty property, CultureInfo culture, object value) { ValidateArg.NotNull(property, "property"); ValidateArg.NotNull(culture, "culture"); diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestResult.cs b/src/Microsoft.TestPlatform.ObjectModel/TestResult.cs index 12a7ac6ca8..5a82028e12 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestResult.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestResult.cs @@ -15,6 +15,15 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel [DataContract] public sealed class TestResult : TestObject { + private TestOutcome outcome; + private string errorMessage; + private string errorStackTrace; + private string displayName; + private string computerName; + private TimeSpan duration; + private DateTimeOffset startTime; + private DateTimeOffset endTime; + #region Constructor /// @@ -61,68 +70,69 @@ public TestResult(TestCase testCase) /// /// Gets or sets the outcome of a test case. /// - [IgnoreDataMember] + [DataMember] public TestOutcome Outcome { get { - return this.GetPropertyValue(TestResultProperties.Outcome, TestOutcome.None); + return this.outcome; } set { - this.SetPropertyValue(TestResultProperties.Outcome, value); + var convertedValue = ConvertPropertyFrom(TestResultProperties.Outcome, CultureInfo.InvariantCulture, value); + this.outcome = (TestOutcome)convertedValue; } } /// /// Gets or sets the exception message. /// - [IgnoreDataMember] + [DataMember] public string ErrorMessage { get { - return this.GetPropertyValue(TestResultProperties.ErrorMessage, null); + return this.errorMessage; } set { - this.SetPropertyValue(TestResultProperties.ErrorMessage, value); + this.errorMessage = value; } } /// /// Gets or sets the exception stack trace. /// - [IgnoreDataMember] + [DataMember] public string ErrorStackTrace { get { - return this.GetPropertyValue(TestResultProperties.ErrorStackTrace, null); + return this.errorStackTrace; } set { - this.SetPropertyValue(TestResultProperties.ErrorStackTrace, value); + this.errorStackTrace = value; } } /// /// Gets or sets the TestResult Display name. Used for Data Driven Test (i.e. Data Driven Test. E.g. InlineData in xUnit) /// - [IgnoreDataMember] + [DataMember] public string DisplayName { get { - return this.GetPropertyValue(TestResultProperties.DisplayName, null); + return this.displayName; } set { - this.SetPropertyValue(TestResultProperties.DisplayName, value); + this.displayName = value; } } @@ -139,75 +149,87 @@ public Collection Messages /// /// Gets or sets test result ComputerName. /// - [IgnoreDataMember] + [DataMember] public string ComputerName { get { - return this.GetPropertyValue(TestResultProperties.ComputerName, string.Empty); + return this.computerName; } set { - this.SetPropertyValue(TestResultProperties.ComputerName, value); + var convertedValue = ConvertPropertyFrom(TestResultProperties.ComputerName, CultureInfo.InvariantCulture, value); + this.computerName = (string)convertedValue; } } /// /// Gets or sets the test result Duration. /// - [IgnoreDataMember] + [DataMember] public TimeSpan Duration { get { - return this.GetPropertyValue(TestResultProperties.Duration, TimeSpan.Zero); + return this.duration; } set { - this.SetPropertyValue(TestResultProperties.Duration, value); + var convertedValue = ConvertPropertyFrom(TestResultProperties.Duration, CultureInfo.InvariantCulture, value); + this.duration = (TimeSpan)convertedValue; } } /// /// Gets or sets the test result StartTime. /// - [IgnoreDataMember] + [DataMember] public DateTimeOffset StartTime { get { - return this.GetPropertyValue(TestResultProperties.StartTime, DateTimeOffset.Now); + //if (this.startTime == default(DateTimeOffset)) + //{ + // this.startTime = DateTimeOffset.Now; + //} + return this.startTime; } set { - this.SetPropertyValue(TestResultProperties.StartTime, value); + var convertedValue = ConvertPropertyFrom(TestResultProperties.StartTime, CultureInfo.InvariantCulture, value); + this.startTime = (DateTimeOffset)convertedValue; } } /// /// Gets or sets test result EndTime. /// - [IgnoreDataMember] + [DataMember] public DateTimeOffset EndTime { get { - return this.GetPropertyValue(TestResultProperties.EndTime, DateTimeOffset.Now); + //if (this.endTime == default(DateTimeOffset)) + //{ + // this.endTime = DateTimeOffset.Now; + //} + return this.endTime; } set { - this.SetPropertyValue(TestResultProperties.EndTime, value); + var convertedValue = ConvertPropertyFrom(TestResultProperties.EndTime, CultureInfo.InvariantCulture, value); + this.endTime = (DateTimeOffset)convertedValue; } } #endregion #region Methods - + /// public override string ToString() diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestCaseSerializationTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestCaseSerializationTests.cs index 58654d89aa..7a82ee4243 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestCaseSerializationTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestCaseSerializationTests.cs @@ -28,6 +28,8 @@ public class TestCaseSerializationTests Traits = { new Trait("Priority", "0"), new Trait("Category", "unit") } }; + #region v1 Tests + [TestMethod] public void TestCaseJsonShouldContainAllPropertiesOnSerialization() { @@ -36,24 +38,25 @@ public void TestCaseJsonShouldContainAllPropertiesOnSerialization() // Use raw deserialization to validate basic properties dynamic data = JObject.Parse(json); dynamic properties = data["Properties"]; - Assert.AreEqual("TestCase.FullyQualifiedName", properties[0]["Key"]["Id"].Value); - Assert.AreEqual("sampleTestClass.sampleTestCase", properties[0]["Value"].Value); - Assert.AreEqual("TestCase.ExecutorUri", properties[1]["Key"]["Id"].Value); - Assert.AreEqual("executor://sampleTestExecutor", properties[1]["Value"].Value); - Assert.AreEqual("TestCase.Source", properties[2]["Key"]["Id"].Value); - Assert.AreEqual("sampleTest.dll", properties[2]["Value"].Value); - Assert.AreEqual("TestCase.CodeFilePath", properties[3]["Key"]["Id"].Value); - Assert.AreEqual("/user/src/testFile.cs", properties[3]["Value"].Value); - Assert.AreEqual("TestCase.DisplayName", properties[4]["Key"]["Id"].Value); - Assert.AreEqual("sampleTestCase", properties[4]["Value"].Value); - Assert.AreEqual("TestCase.Id", properties[5]["Key"]["Id"].Value); - Assert.AreEqual("be78d6fc-61b0-4882-9d07-40d796fd96ce", properties[5]["Value"].Value); - Assert.AreEqual("TestCase.LineNumber", properties[6]["Key"]["Id"].Value); - Assert.AreEqual(999, properties[6]["Value"].Value); // Traits require special handling with TestPlatformContract resolver. It should be null without it. - Assert.AreEqual("TestObject.Traits", properties[7]["Key"]["Id"].Value); - Assert.IsNull(properties[7]["Key"]["Value"]); + Assert.AreEqual("TestObject.Traits", properties[0]["Key"]["Id"].Value); + Assert.IsNotNull(properties[0]["Value"]); + + Assert.AreEqual("TestCase.FullyQualifiedName", properties[1]["Key"]["Id"].Value); + Assert.AreEqual("sampleTestClass.sampleTestCase", properties[1]["Value"].Value); + Assert.AreEqual("TestCase.ExecutorUri", properties[2]["Key"]["Id"].Value); + Assert.AreEqual("executor://sampleTestExecutor", properties[2]["Value"].Value); + Assert.AreEqual("TestCase.Source", properties[3]["Key"]["Id"].Value); + Assert.AreEqual("sampleTest.dll", properties[3]["Value"].Value); + Assert.AreEqual("TestCase.Id", properties[4]["Key"]["Id"].Value); + Assert.AreEqual("be78d6fc-61b0-4882-9d07-40d796fd96ce", properties[4]["Value"].Value); + Assert.AreEqual("TestCase.DisplayName", properties[5]["Key"]["Id"].Value); + Assert.AreEqual("sampleTestCase", properties[5]["Value"].Value); + Assert.AreEqual("TestCase.CodeFilePath", properties[6]["Key"]["Id"].Value); + Assert.AreEqual("/user/src/testFile.cs", properties[6]["Value"].Value); + Assert.AreEqual("TestCase.LineNumber", properties[7]["Key"]["Id"].Value); + Assert.AreEqual(999, properties[7]["Value"].Value); } [TestMethod] @@ -105,44 +108,120 @@ public void TestCaseObjectShouldDeserializeEscapedWindowsPath() Assert.AreEqual(@"C:\Test\TestAssembly.dll", test.Source); } + #endregion + + #region v2 Tests + + [TestMethod] + public void TestCaseJsonShouldContainAllPropertiesOnSerializationV2() + { + var json = Serialize(testCase, 2); + + // Use raw deserialization to validate basic properties + dynamic data = JObject.Parse(json); + dynamic properties = data["Properties"]; + + // Traits require special handling with TestPlatformContract resolver. It should be null without it. + Assert.AreEqual("TestObject.Traits", properties[0]["Key"]["Id"].Value); + Assert.IsNotNull(properties[0]["Value"]); + + Assert.AreEqual("be78d6fc-61b0-4882-9d07-40d796fd96ce", data["Id"].Value); + Assert.AreEqual("sampleTestClass.sampleTestCase", data["FullyQualifiedName"].Value); + Assert.AreEqual("sampleTestCase", data["DisplayName"].Value); + Assert.AreEqual("sampleTest.dll", data["Source"].Value); + Assert.AreEqual("executor://sampleTestExecutor", data["ExecutorUri"].Value); + Assert.AreEqual("/user/src/testFile.cs", data["CodeFilePath"].Value); + Assert.AreEqual(999, data["LineNumber"].Value); + } + + [TestMethod] + public void TestCaseObjectShouldContainAllPropertiesOnDeserializationV2() + { + var json = "{\"Id\": \"be78d6fc-61b0-4882-9d07-40d796fd96ce\",\"FullyQualifiedName\": \"sampleTestClass.sampleTestCase\",\"DisplayName\": \"sampleTestCase\",\"ExecutorUri\": \"executor://sampleTestExecutor\",\"Source\": \"sampleTest.dll\",\"CodeFilePath\": \"/user/src/testFile.cs\", \"LineNumber\": 999," + + "\"Properties\": [{ \"Key\": { \"Id\": \"TestObject.Traits\", \"Label\": \"Traits\", \"Category\": \"\", \"Description\": \"\", \"Attributes\": 5, \"ValueType\": \"System.Collections.Generic.KeyValuePair`2[[System.String],[System.String]][]\"}, \"Value\": [{\"Key\": \"Priority\",\"Value\": \"0\"}, {\"Key\": \"Category\",\"Value\": \"unit\"}]}]}"; + + var test = Deserialize(json, 2); + + Assert.AreEqual(testCase.CodeFilePath, test.CodeFilePath); + Assert.AreEqual(testCase.DisplayName, test.DisplayName); + Assert.AreEqual(testCase.ExecutorUri, test.ExecutorUri); + Assert.AreEqual(testCase.FullyQualifiedName, test.FullyQualifiedName); + Assert.AreEqual(testCase.LineNumber, test.LineNumber); + Assert.AreEqual(testCase.Source, test.Source); + Assert.AreEqual(testCase.Traits.First().Name, test.Traits.First().Name); + Assert.AreEqual(testCase.Id, test.Id); + } + + [TestMethod] + public void TestCaseObjectShouldSerializeWindowsPathWithEscapingV2() + { + var test = new TestCase("a.b", new Uri("uri://x"), @"C:\Test\TestAssembly.dll"); + + var json = Serialize(test, 2); + + // Use raw deserialization to validate basic properties + dynamic data = JObject.Parse(json); + Assert.AreEqual(@"C:\Test\TestAssembly.dll", data["Source"].Value); + } + + [TestMethod] + public void TestCaseObjectShouldDeserializeEscapedWindowsPathV2() + { + var json = "{\"Id\":\"4e35ed85-a5e8-946e-fb14-0d3de2304e74\",\"FullyQualifiedName\":\"a.b\",\"DisplayName\":\"a.b\",\"ExecutorUri\":\"uri://x\",\"Source\":\"C:\\\\Test\\\\TestAssembly.dll\",\"CodeFilePath\":null,\"LineNumber\":-1,\"Properties\":[]}"; + + var test = Deserialize(json, 2); + + Assert.AreEqual(@"C:\Test\TestAssembly.dll", test.Source); + } + + #endregion + + #region Common Tests + [TestMethod] - public void TestCaseObjectShouldSerializeTraitsWithSpecialCharacters() + [DataRow(1)] + [DataRow(2)] + public void TestCaseObjectShouldSerializeTraitsWithSpecialCharacters(int version) { var test = new TestCase("a.b", new Uri("uri://x"), @"/tmp/a.b.dll"); test.Traits.Add("t", @"SDJDDHW>,:&^%//\\\\"); - var json = Serialize(test); + var json = Serialize(test, version); // Use raw deserialization to validate basic properties dynamic data = JObject.Parse(json); dynamic properties = data["Properties"]; - Assert.AreEqual(@"TestObject.Traits", properties[3]["Key"]["Id"].Value); - Assert.AreEqual("[{\"Key\":\"t\",\"Value\":\"SDJDDHW>,:&^%//\\\\\\\\\\\\\\\\\"}]", properties[3]["Value"].ToString(Formatting.None)); + Assert.AreEqual(@"TestObject.Traits", properties[0]["Key"]["Id"].Value); + Assert.AreEqual("[{\"Key\":\"t\",\"Value\":\"SDJDDHW>,:&^%//\\\\\\\\\\\\\\\\\"}]", properties[0]["Value"].ToString(Formatting.None)); } [TestMethod] - public void TestCaseObjectShouldDeserializeTraitsWithSpecialCharacters() + [DataRow(1)] + [DataRow(2)] + public void TestCaseObjectShouldDeserializeTraitsWithSpecialCharacters(int version) { var json = "{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"a.b\"}," + "{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"uri://x\"}," + "{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"/tmp/a.b.dll\"}," + "{\"Key\":{\"Id\":\"TestObject.Traits\",\"Label\":\"Traits\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":5,\"ValueType\":\"System.Collections.Generic.KeyValuePair`2[[System.String],[System.String]][]\"},\"Value\":[{\"Key\":\"t\",\"Value\":\"SDJDDHW>,:&^%//\\\\\\\\\\\\\\\\\"}]}]}"; - var test = Deserialize(json); + var test = Deserialize(json, version); var traits = test.Traits.ToArray(); Assert.AreEqual(1, traits.Length); Assert.AreEqual(@"SDJDDHW>,:&^%//\\\\", traits[0].Value); } - private static string Serialize(T data) + #endregion + + private static string Serialize(T data, int version = 1) { - return JsonDataSerializer.Instance.Serialize(data); + return JsonDataSerializer.Instance.Serialize(data, version); } - private static T Deserialize(string json) + private static T Deserialize(string json, int version = 1) { - return JsonDataSerializer.Instance.Deserialize(json); + return JsonDataSerializer.Instance.Deserialize(json, version); } } } \ No newline at end of file diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs index 022d3d905b..cc799b132e 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs @@ -20,6 +20,7 @@ public class TestResultSerializationTests new Uri("executor://sampleTestExecutor"), "sampleTest.dll"); + private static DateTimeOffset startTime = new DateTimeOffset(new DateTime(2007, 3, 10, 0, 0, 0)); private static TestResult testResult = new TestResult(testCase) { // Attachments = ? @@ -30,10 +31,12 @@ public class TestResultSerializationTests DisplayName = "sampleTestResult", ComputerName = "sampleComputerName", Duration = TimeSpan.MaxValue, - StartTime = DateTimeOffset.MinValue, + StartTime = startTime, EndTime = DateTimeOffset.MaxValue }; + #region v1 tests + [TestMethod] public void TestResultJsonShouldContainAllPropertiesOnSerialization() { @@ -57,7 +60,7 @@ public void TestResultJsonShouldContainAllPropertiesOnSerialization() // By default json.net converts DateTimes to current time zone Assert.AreEqual("TestResult.StartTime", properties[6]["Key"]["Id"].Value); - Assert.AreEqual(DateTimeOffset.MinValue.Year, ((DateTimeOffset)properties[6]["Value"].Value).Year); + Assert.AreEqual(startTime.Year, ((DateTimeOffset)properties[6]["Value"].Value).Year); Assert.AreEqual("TestResult.EndTime", properties[7]["Key"]["Id"].Value); Assert.AreEqual(DateTimeOffset.MaxValue.Year, ((DateTimeOffset)properties[7]["Value"].Value).Year); } @@ -65,7 +68,7 @@ public void TestResultJsonShouldContainAllPropertiesOnSerialization() [TestMethod] public void TestResultObjectShouldContainAllPropertiesOnDeserialization() { - var json = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"}]},\"Attachments\":[],\"Messages\":[],\"Properties\":[{\"Key\":{\"Id\":\"TestResult.Outcome\",\"Label\":\"Outcome\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"Microsoft.VisualStudio.TestPlatform.ObjectModel.TestOutcome\"},\"Value\":1},{\"Key\":{\"Id\":\"TestResult.ErrorMessage\",\"Label\":\"Error Message\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleError\"},{\"Key\":{\"Id\":\"TestResult.ErrorStackTrace\",\"Label\":\"Error Stack Trace\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleStackTrace\"},{\"Key\":{\"Id\":\"TestResult.DisplayName\",\"Label\":\"TestResult Display Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestResult\"},{\"Key\":{\"Id\":\"TestResult.ComputerName\",\"Label\":\"Computer Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleComputerName\"},{\"Key\":{\"Id\":\"TestResult.Duration\",\"Label\":\"Duration\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.TimeSpan\"},\"Value\":\"10675199.02:48:05.4775807\"},{\"Key\":{\"Id\":\"TestResult.StartTime\",\"Label\":\"Start Time\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.DateTimeOffset\"},\"Value\":\"0001-01-01T00:00:00+00:00\"},{\"Key\":{\"Id\":\"TestResult.EndTime\",\"Label\":\"End Time\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.DateTimeOffset\"},\"Value\":\"9999-12-31T23:59:59.9999999+00:00\"}]}"; + var json = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"}]},\"Attachments\":[],\"Messages\":[],\"Properties\":[{\"Key\":{\"Id\":\"TestResult.Outcome\",\"Label\":\"Outcome\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"Microsoft.VisualStudio.TestPlatform.ObjectModel.TestOutcome\"},\"Value\":1},{\"Key\":{\"Id\":\"TestResult.ErrorMessage\",\"Label\":\"Error Message\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleError\"},{\"Key\":{\"Id\":\"TestResult.ErrorStackTrace\",\"Label\":\"Error Stack Trace\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleStackTrace\"},{\"Key\":{\"Id\":\"TestResult.DisplayName\",\"Label\":\"TestResult Display Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestResult\"},{\"Key\":{\"Id\":\"TestResult.ComputerName\",\"Label\":\"Computer Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleComputerName\"},{\"Key\":{\"Id\":\"TestResult.Duration\",\"Label\":\"Duration\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.TimeSpan\"},\"Value\":\"10675199.02:48:05.4775807\"},{\"Key\":{\"Id\":\"TestResult.StartTime\",\"Label\":\"Start Time\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.DateTimeOffset\"},\"Value\":\"2007-03-10T00:00:00+05:30\"},{\"Key\":{\"Id\":\"TestResult.EndTime\",\"Label\":\"End Time\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.DateTimeOffset\"},\"Value\":\"9999-12-31T23:59:59.9999999+00:00\"}]}"; var test = Deserialize(json); @@ -88,8 +91,7 @@ public void TestResultObjectShouldSerializeAttachments() { var result = new TestResult(testCase); result.Attachments.Add(new AttachmentSet(new Uri("http://dummyUri"), "sampleAttachment")); - var expectedJson = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"}]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Messages\":[],\"Properties\":[]}"; - + var expectedJson = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"},{\"Key\":{\"Id\":\"TestCase.Id\",\"Label\":\"Id\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Guid\"},\"Value\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\"}]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Messages\":[],\"Properties\":[]}"; var json = Serialize(result); Assert.AreEqual(expectedJson, json); @@ -107,14 +109,84 @@ public void TestResultObjectShouldDeserializeAttachments() Assert.AreEqual("sampleAttachment", result.Attachments[0].DisplayName); } - private static string Serialize(T data) + #endregion + + #region v2 Tests + + [TestMethod] + public void TestResultJsonShouldContainAllPropertiesOnSerializationV2() + { + var json = Serialize(testResult, 2); + + // Use raw deserialization to validate basic properties + dynamic data = JObject.Parse(json); + + Assert.AreEqual(1, data["Outcome"].Value); + Assert.AreEqual("sampleError", data["ErrorMessage"].Value); + Assert.AreEqual("sampleStackTrace", data["ErrorStackTrace"].Value); + Assert.AreEqual("sampleTestResult", data["DisplayName"].Value); + Assert.AreEqual("sampleComputerName", data["ComputerName"].Value); + Assert.AreEqual("10675199.02:48:05.4775807", data["Duration"].Value); + + // By default json.net converts DateTimes to current time zone + Assert.AreEqual(startTime.Year, ((DateTimeOffset)data["StartTime"].Value).Year); + Assert.AreEqual(DateTimeOffset.MaxValue.Year, ((DateTimeOffset)data["EndTime"].Value).Year); + } + + [TestMethod] + public void TestResultObjectShouldContainAllPropertiesOnDeserializationV2() + { + var json = "{\"TestCase\":{\"Id\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\",\"FullyQualifiedName\":\"sampleTestClass.sampleTestCase\",\"DisplayName\":\"sampleTestClass.sampleTestCase\",\"ExecutorUri\":\"executor://sampleTestExecutor\",\"Source\":\"sampleTest.dll\",\"CodeFilePath\":null,\"LineNumber\":-1,\"Properties\":[]},\"Attachments\":[],\"Outcome\":1,\"ErrorMessage\":\"sampleError\",\"ErrorStackTrace\":\"sampleStackTrace\",\"DisplayName\":\"sampleTestResult\",\"Messages\":[],\"ComputerName\":\"sampleComputerName\",\"Duration\":\"10675199.02:48:05.4775807\",\"StartTime\":\"2007-03-10T00:00:00+05:30\",\"EndTime\":\"9999-12-31T23:59:59.9999999+00:00\",\"Properties\":[]}"; + + var test = Deserialize(json, 2); + + Assert.AreEqual(testResult.TestCase.Id, test.TestCase.Id); + Assert.AreEqual(testResult.Attachments.Count, test.Attachments.Count); + Assert.AreEqual(testResult.Messages.Count, test.Messages.Count); + + Assert.AreEqual(testResult.ComputerName, test.ComputerName); + Assert.AreEqual(testResult.DisplayName, test.DisplayName); + Assert.AreEqual(testResult.Duration, test.Duration); + Assert.AreEqual(testResult.EndTime, test.EndTime); + Assert.AreEqual(testResult.ErrorMessage, test.ErrorMessage); + Assert.AreEqual(testResult.ErrorStackTrace, test.ErrorStackTrace); + Assert.AreEqual(testResult.Outcome, test.Outcome); + Assert.AreEqual(testResult.StartTime, test.StartTime); + } + + [TestMethod] + public void TestResultObjectShouldSerializeAttachmentsV2() + { + var result = new TestResult(testCase); + result.Attachments.Add(new AttachmentSet(new Uri("http://dummyUri"), "sampleAttachment")); + var expectedJson = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"},{\"Key\":{\"Id\":\"TestCase.Id\",\"Label\":\"Id\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Guid\"},\"Value\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\"}]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Messages\":[],\"Properties\":[]}"; + var json = Serialize(result); + + Assert.AreEqual(expectedJson, json); + } + + [TestMethod] + public void TestResultObjectShouldDeserializeAttachmentsV2() + { + var json = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"},{\"Key\":{\"Id\":\"TestCase.Id\",\"Label\":\"Id\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Guid\"},\"Value\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\"}]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Messages\":[],\"Properties\":[]}"; + + var result = Deserialize(json); + + Assert.AreEqual(1, result.Attachments.Count); + Assert.AreEqual(new Uri("http://dummyUri"), result.Attachments[0].Uri); + Assert.AreEqual("sampleAttachment", result.Attachments[0].DisplayName); + } + + #endregion + + private static string Serialize(T data, int version = 1) { - return JsonDataSerializer.Instance.Serialize(data); + return JsonDataSerializer.Instance.Serialize(data, version); } - private static T Deserialize(string json) + private static T Deserialize(string json, int version = 1) { - return JsonDataSerializer.Instance.Deserialize(json); + return JsonDataSerializer.Instance.Deserialize(json, version); } } } \ No newline at end of file diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs index 39d47a6bb6..7651578452 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs @@ -26,6 +26,7 @@ public class TestRequestSenderTests private ITestRequestSender testRequestSender; private Mock mockCommunicationManager; private Mock mockDataSerializer; + private int version = 1; [TestInitialize] public void TestInit() @@ -72,6 +73,35 @@ public void DisposeShouldCallStopServerOnCommunicationManager() this.mockCommunicationManager.Verify(mc => mc.StopServer(), Times.Once); } + [TestMethod] + public void VersionCheckWithTestHostShouldCheckVersionIfVersionCheckPassesReturnTrue() + { + var message = new Message() { MessageType = MessageType.VersionCheck, Payload = version }; + this.mockCommunicationManager.Setup(mc => mc.ReceiveMessage()).Returns(message); + var success = this.testRequestSender.CheckVersionWithTestHost(); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.VersionCheck, this.version), Times.Once); + Assert.IsTrue(success); + } + + [TestMethod] + public void VersionCheckWithTestHostShouldBeAbleToReceiveProtocolErrorAndReturnFalse() + { + var message = new Message() { MessageType = MessageType.ProtocolError, Payload = version }; + this.mockCommunicationManager.Setup(mc => mc.ReceiveMessage()).Returns(message); + var success = this.testRequestSender.CheckVersionWithTestHost(); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.VersionCheck, this.version), Times.Once); + Assert.IsFalse(success); + } + + [TestMethod] + public void VersionCheckWithTestHostForInvalidMessageShouldReturnFalse() + { + var message = new Message() { MessageType = MessageType.TestCasesFound, Payload = null }; + this.mockCommunicationManager.Setup(mc => mc.ReceiveMessage()).Returns(message); + var success = this.testRequestSender.CheckVersionWithTestHost(); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.VersionCheck, this.version), Times.Once); + Assert.IsFalse(success); + } [TestMethod] public void InitializeDiscoveryShouldSendCommunicationMessageWithCorrectParameters() @@ -79,7 +109,7 @@ public void InitializeDiscoveryShouldSendCommunicationMessageWithCorrectParamete var paths = new List() { "Hello", "World" }; this.testRequestSender.InitializeDiscovery(paths, false); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.DiscoveryInitialize, paths), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.DiscoveryInitialize, paths, version), Times.Once); } [TestMethod] @@ -88,7 +118,7 @@ public void InitializeExecutionShouldSendCommunicationMessageWithCorrectParamete var paths = new List() { "Hello", "World" }; this.testRequestSender.InitializeExecution(paths, true); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.ExecutionInitialize, paths), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.ExecutionInitialize, paths, version), Times.Once); } private void SetupReceiveRawMessageAsyncAndDeserializeMessageAndInitialize(string rawMessage, Message message) @@ -129,7 +159,7 @@ public void DiscoverTestsShouldCallHandleDiscoveredTestsOnTestCaseEvent() this.testRequestSender.DiscoverTests(discoveryCriteria, mockHandler.Object); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartDiscovery, discoveryCriteria), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartDiscovery, discoveryCriteria, version), Times.Once); this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(rawMessage), Times.Exactly(2)); mockHandler.Verify(mh => mh.HandleDiscoveredTests(testCases), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.Exactly(2)); @@ -167,7 +197,7 @@ public void DiscoverTestsShouldCallHandleLogMessageOnTestMessage() this.testRequestSender.DiscoverTests(discoveryCriteria, mockHandler.Object); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartDiscovery, discoveryCriteria), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartDiscovery, discoveryCriteria, version), Times.Once); this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(rawMessage), Times.Exactly(2)); mockHandler.Verify(mh => mh.HandleLogMessage(TestMessageLevel.Error, rawMessage), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.Exactly(2)); @@ -195,7 +225,7 @@ public void DiscoverTestsShouldCallHandleDiscoveryCompleteOnDiscoveryCompletion( this.testRequestSender.DiscoverTests(discoveryCriteria, mockHandler.Object); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartDiscovery, discoveryCriteria), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartDiscovery, discoveryCriteria, version), Times.Once); this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(rawMessage), Times.Once); mockHandler.Verify(mh => mh.HandleDiscoveryComplete(1, null, false), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.Once); @@ -209,7 +239,7 @@ public void DiscoverTestsShouldHandleExceptionOnSendMessage() var mockHandler = new Mock(); var discoveryCriteria = new DiscoveryCriteria(sources, 100, settingsXml); var exception = new Exception(); - this.mockCommunicationManager.Setup(cm => cm.SendMessage(MessageType.StartDiscovery, discoveryCriteria)) + this.mockCommunicationManager.Setup(cm => cm.SendMessage(MessageType.StartDiscovery, discoveryCriteria, version)) .Throws(exception); this.testRequestSender.DiscoverTests(discoveryCriteria, mockHandler.Object); @@ -286,7 +316,7 @@ public void StartTestRunWithSourcesShouldCallHandleTestRunStatsChange() waitHandle.WaitOne(); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithSources, runCriteria), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithSources, runCriteria, version), Times.Once); // One for run stats and another for runcomplete this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(rawMessage), Times.Exactly(2)); @@ -329,7 +359,7 @@ public void StartTestRunWithTestsShouldCallHandleTestRunStatsChange() this.testRequestSender.StartTestRun(runCriteria, mockHandler.Object); waitHandle.WaitOne(); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithTests, runCriteria), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithTests, runCriteria, version), Times.Once); mockHandler.Verify(mh => mh.HandleTestRunStatsChange(testRunChangedArgs), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.AtLeastOnce); } @@ -364,7 +394,7 @@ public void StartTestRunShouldCallHandleLogMessageOnTestMessage() this.testRequestSender.StartTestRun(runCriteria, mockHandler.Object); waitHandle.WaitOne(); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithSources, runCriteria), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithSources, runCriteria, version), Times.Once); this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(It.IsAny()), Times.Exactly(2)); mockHandler.Verify(mh => mh.HandleLogMessage(payload.MessageLevel, payload.Message), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.AtLeastOnce); @@ -408,12 +438,12 @@ public void StartTestRunShouldCallLaunchProcessWithDebuggerAndWaitForCallback() waitHandle.WaitOne(); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithSources, runCriteria), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithSources, runCriteria, version), Times.Once); this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(It.IsAny()), Times.Exactly(2)); mockHandler.Verify(mh => mh.LaunchProcessWithDebuggerAttached(payload), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.Exactly(2)); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.LaunchAdapterProcessWithDebuggerAttachedCallback, It.IsAny()), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.LaunchAdapterProcessWithDebuggerAttachedCallback, It.IsAny(), version), Times.Once); } [TestMethod] @@ -438,7 +468,7 @@ public void StartTestRunShouldCallHandleTestRunCompleteOnRunCompletion() waitHandle.WaitOne(); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithTests, runCriteria), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithTests, runCriteria, version), Times.Once); this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(rawMessage), Times.Once); mockHandler.Verify(mh => mh.HandleTestRunComplete(null, null, null, null), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.Once); diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs index 98c74a3605..d29dcfe35e 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs @@ -38,6 +38,7 @@ public ProxyDiscoveryManagerTests() { this.mockTestHostManager = new Mock(); this.mockRequestSender = new Mock(); + this.mockRequestSender.Setup(rs => rs.CheckVersionWithTestHost()).Returns(true); this.testDiscoveryManager = new ProxyDiscoveryManager( this.mockRequestSender.Object, this.mockTestHostManager.Object, diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs index 06e1630ba5..49f2d66578 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs @@ -42,6 +42,7 @@ public ProxyExecutionManagerTests() { this.mockTestHostManager = new Mock(); this.mockRequestSender = new Mock(); + this.mockRequestSender.Setup(rs => rs.CheckVersionWithTestHost()).Returns(true); this.mockTestRunCriteria = new Mock(new List { "source.dll" }, 10); this.testExecutionManager = new ProxyExecutionManager(this.mockRequestSender.Object, this.mockTestHostManager.Object, this.clientConnectionTimeout); diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs index f7cb4096fa..97483ee03b 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs @@ -14,7 +14,7 @@ namespace TestPlatform.CrossPlatEngine.UnitTests.Client using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Host; using Microsoft.VisualStudio.TestTools.UnitTesting; - + using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting; using Moq; [TestClass] @@ -36,6 +36,7 @@ public ProxyOperationManagerTests() this.mockTestHostManager = new Mock(); this.mockRequestSender = new Mock(); this.mockRequestSender.Setup(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout)).Returns(true); + this.mockRequestSender.Setup(rs => rs.CheckVersionWithTestHost()).Returns(true); this.testOperationManager = new TestableProxyOperationManager(this.mockRequestSender.Object, this.mockTestHostManager.Object, this.connectionTimeout); } @@ -127,12 +128,12 @@ public void SetupChannelShouldWaitForTestHostConnection() } [TestMethod] - public void SetupChannelShouldWaitForTestHostConnectionEvenIfConnectionIsInitialized() + public void SetupChannelShouldNotWaitForTestHostConnectionIfConnectionIsInitialized() { this.testOperationManager.SetupChannel(Enumerable.Empty()); this.testOperationManager.SetupChannel(Enumerable.Empty()); - this.mockRequestSender.Verify(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout), Times.Exactly(2)); + this.mockRequestSender.Verify(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout), Times.Exactly(1)); } [TestMethod] @@ -143,6 +144,45 @@ public void SetupChannelShouldThrowIfWaitForTestHostConnectionTimesOut() Assert.ThrowsException(() => this.testOperationManager.SetupChannel(Enumerable.Empty())); } + [TestMethod] + public void SetupChannelShouldCheckVersionWithTestHost() + { + this.testOperationManager.SetupChannel(Enumerable.Empty()); + this.mockRequestSender.Verify(rs => rs.CheckVersionWithTestHost(), Times.Once); + } + + [TestMethod] + public void SetupChannelShouldThrowExceptionIfVersionCheckFails() + { + // Make the version check fail + this.mockRequestSender.Setup(rs => rs.CheckVersionWithTestHost()).Returns(false); + Assert.ThrowsException(() => this.testOperationManager.SetupChannel(Enumerable.Empty())); + } + + [TestMethod] + public void SetupChannelForDotnetHostManagerWithIsVersionCheckRequiredFalseShouldNotCheckVersionWithTestHost() + { + var testHostManager = new Mock(); + testHostManager.Setup(thm => thm.IsVersionCheckRequired).Returns(false); + var operationManager = new TestableProxyOperationManager(this.mockRequestSender.Object, testHostManager.Object, this.connectionTimeout); + + operationManager.SetupChannel(Enumerable.Empty()); + + this.mockRequestSender.Verify(rs => rs.CheckVersionWithTestHost(), Times.Never); + } + + [TestMethod] + public void SetupChannelForDotnetHostManagerWithIsVersionCheckRequiredTrueShouldCheckVersionWithTestHost() + { + var testHostManager = new Mock(); + testHostManager.Setup(thm => thm.IsVersionCheckRequired).Returns(true); + var operationManager = new TestableProxyOperationManager(this.mockRequestSender.Object, testHostManager.Object, this.connectionTimeout); + + operationManager.SetupChannel(Enumerable.Empty()); + + this.mockRequestSender.Verify(rs => rs.CheckVersionWithTestHost(), Times.Once); + } + [TestMethod] [Ignore] //Not valid test anymore, since host providers now monitor test host themselves diff --git a/test/Microsoft.TestPlatform.ObjectModel.UnitTests/TestObjectTests.cs b/test/Microsoft.TestPlatform.ObjectModel.UnitTests/TestObjectTests.cs index 65e3b601ee..6f04c4f19f 100644 --- a/test/Microsoft.TestPlatform.ObjectModel.UnitTests/TestObjectTests.cs +++ b/test/Microsoft.TestPlatform.ObjectModel.UnitTests/TestObjectTests.cs @@ -7,20 +7,40 @@ namespace Microsoft.TestPlatform.ObjectModel.UnitTests using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Collections.Generic; [TestClass] public class TestObjectTests { + private static TestCase testCase = new TestCase( + "sampleTestClass.sampleTestCase", + new Uri("executor://sampleTestExecutor"), + "sampleTest.dll") + { + CodeFilePath = "/user/src/testFile.cs", + DisplayName = "sampleTestCase", + Id = new Guid("be78d6fc-61b0-4882-9d07-40d796fd96ce"), + Traits = { new Trait("Priority", "0"), new Trait("Category", "unit") } + }; + [TestMethod] public void TestCaseIdShouldReturnGuidWhenTestPropertiesIdIsSet() { - TestCase testCase = new TestCase("DummyNS.DummyClass.DummyTest", new Uri("executor://mstestadapter/v1"), "C:\tests.dll"); Guid expected = new Guid("{8167845C-9CDB-476F-9F2B-1B1C1FE01B7D}"); - testCase.SetPropertyValue(TestCaseProperties.Id, expected); - + testCase.Id = expected; var actual = testCase.Id; - Assert.AreEqual(expected, actual); } + + [TestMethod] + public void GetPropertiesShouldReturnListOfPropertiesInStore() + { + TestProperty tp = TestProperty.Register("dummyId", "dummyLabel", typeof(int), typeof(TestObjectTests)); + var kvp = new KeyValuePair(tp, 123); + testCase.SetPropertyValue(kvp.Key, kvp.Value); + + var properties = testCase.GetProperties(); + properties.Contains(kvp); + } } } diff --git a/test/Microsoft.TestPlatform.VsTestConsole.TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs b/test/Microsoft.TestPlatform.VsTestConsole.TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs index c07b0d3737..ee829d65c7 100644 --- a/test/Microsoft.TestPlatform.VsTestConsole.TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs +++ b/test/Microsoft.TestPlatform.VsTestConsole.TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs @@ -960,7 +960,7 @@ private static Message CreateMessage(string messageType, T payload) JsonSerializer.Create( new JsonSerializerSettings { - ContractResolver = new TestPlatformContractResolver(), + ContractResolver = new DefaultTestPlatformContractResolver(), TypeNameHandling = TypeNameHandling.None })) }; From 45b237ae35e7ec62e9645616dcfd02042481a640 Mon Sep 17 00:00:00 2001 From: Sarabjot Singh Date: Thu, 30 Mar 2017 15:44:14 +0530 Subject: [PATCH 2/7] Code analysis related fixes. --- .../Interfaces/ITestRequestSender.cs | 4 +- .../Messages/Message.cs | 11 +--- .../Messages/VersionedMessage.cs | 16 +++++ .../DefaultTestPlatformContractResolver.cs | 2 +- .../Serialization/TestCaseConverter.cs | 24 ++++++-- .../TestPlatformContractResolver1.cs | 3 + .../Serialization/TestResultConverter.cs | 58 +++++++++++++++---- .../TestRequestSenderTests.cs | 28 ++++----- 8 files changed, 104 insertions(+), 42 deletions(-) create mode 100644 src/Microsoft.TestPlatform.CommunicationUtilities/Messages/VersionedMessage.cs diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestSender.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestSender.cs index 8ae1c4acab..f22e18c164 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestSender.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestSender.cs @@ -23,11 +23,11 @@ public interface ITestRequestSender : IDisposable /// /// Used for protocol version check with TestHost /// - /// + /// true if the version check is successful bool CheckVersionWithTestHost(); /// - /// Waits for Request Handler to be connected + /// Waits for Request Handler to be connected /// /// Time to wait for connection /// True, if Handler is connected diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/Message.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/Message.cs index 1ecaa58482..2ea60f3454 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/Message.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/Message.cs @@ -6,6 +6,9 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities using Newtonsoft.Json; using Newtonsoft.Json.Linq; + /// + /// Construct used for communication + /// public class Message { /// @@ -27,12 +30,4 @@ public override string ToString() return "(" + this.MessageType + ") -> " + (this.Payload == null ? "null" : this.Payload.ToString(Formatting.Indented)); } } - - public class VersionedMessage : Message - { - /// - /// Gets or sets the version of the message - /// - public int Version { get; set; } - } } \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/VersionedMessage.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/VersionedMessage.cs new file mode 100644 index 0000000000..ca7f1f1887 --- /dev/null +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/VersionedMessage.cs @@ -0,0 +1,16 @@ +// 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.CommunicationUtilities +{ + /// + /// New construct with version used for communication + /// + public class VersionedMessage : Message + { + /// + /// Gets or sets the version of the message + /// + public int Version { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/DefaultTestPlatformContractResolver.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/DefaultTestPlatformContractResolver.cs index 3928f6be0d..3b8e3c526f 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/DefaultTestPlatformContractResolver.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/DefaultTestPlatformContractResolver.cs @@ -10,7 +10,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serializati using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Newtonsoft.Json.Serialization; - + /// /// JSON contract resolver for mapping test platform types. /// diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs index 134d4784d6..99d0822b40 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs @@ -3,17 +3,20 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serialization { + using System; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Newtonsoft.Json; - using System; + /// public class TestCaseConverter : JsonConverter { + /// public override bool CanConvert(Type objectType) { return typeof(TestCase) == objectType; } + /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var testCase = new TestCase(); @@ -29,19 +32,30 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist return testCase; } + /// public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { // P2 to P1 - var testCase = (value as TestCase); + var testCase = value as TestCase; testCase.SetPropertyValue(TestCaseProperties.FullyQualifiedName, testCase.FullyQualifiedName); testCase.SetPropertyValue(TestCaseProperties.ExecutorUri, testCase.ExecutorUri); testCase.SetPropertyValue(TestCaseProperties.Source, testCase.Source); testCase.SetPropertyValue(TestCaseProperties.Id, testCase.Id); - if (!testCase.DisplayName.Equals(testCase.FullyQualifiedName)) testCase.SetPropertyValue(TestCaseProperties.DisplayName, testCase.DisplayName); + if (!testCase.DisplayName.Equals(testCase.FullyQualifiedName)) + { + testCase.SetPropertyValue(TestCaseProperties.DisplayName, testCase.DisplayName); + } - if (!string.IsNullOrEmpty(testCase.CodeFilePath)) testCase.SetPropertyValue(TestCaseProperties.CodeFilePath, testCase.CodeFilePath); - if (testCase.LineNumber >= 0) testCase.SetPropertyValue(TestCaseProperties.LineNumber, testCase.LineNumber); + if (!string.IsNullOrEmpty(testCase.CodeFilePath)) + { + testCase.SetPropertyValue(TestCaseProperties.CodeFilePath, testCase.CodeFilePath); + } + + if (testCase.LineNumber >= 0) + { + testCase.SetPropertyValue(TestCaseProperties.LineNumber, testCase.LineNumber); + } var properties = testCase.GetProperties(); diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver1.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver1.cs index 674372fb08..a1a130a011 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver1.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver1.cs @@ -12,6 +12,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serializati /// public class TestPlatformContractResolver1 : DefaultTestPlatformContractResolver { + /// protected override JsonContract CreateContract(Type objectType) { var contract = base.CreateContract(objectType); @@ -19,10 +20,12 @@ protected override JsonContract CreateContract(Type objectType) { contract.Converter = new TestCaseConverter(); } + if (typeof(TestResult) == objectType) { contract.Converter = new TestResultConverter(); } + return contract; } } diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs index d5920bdba2..e75abf3796 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs @@ -6,19 +6,22 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serializati using System; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Newtonsoft.Json; - + + /// public class TestResultConverter : JsonConverter { + /// public override bool CanConvert(Type objectType) { return typeof(TestResult) == objectType; } + /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var testResult = new TestResult(); serializer.Populate(reader, testResult); - + testResult.Outcome = testResult.GetPropertyValue(TestResultProperties.Outcome, TestOutcome.None); testResult.ErrorMessage = testResult.GetPropertyValue(TestResultProperties.ErrorMessage, null); testResult.ErrorStackTrace = testResult.GetPropertyValue(TestResultProperties.ErrorStackTrace, null); @@ -31,19 +34,50 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist return testResult; } + /// public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { // P2 to P1 - var testResult = (value as TestResult); - if (testResult.Outcome != TestOutcome.None) testResult.SetPropertyValue(TestResultProperties.Outcome, testResult.Outcome); - if (!string.IsNullOrEmpty(testResult.ErrorMessage)) testResult.SetPropertyValue(TestResultProperties.ErrorMessage, testResult.ErrorMessage); - if (!string.IsNullOrEmpty(testResult.ErrorStackTrace)) testResult.SetPropertyValue(TestResultProperties.ErrorStackTrace, testResult.ErrorStackTrace); - if (!string.IsNullOrEmpty(testResult.DisplayName)) testResult.SetPropertyValue(TestResultProperties.DisplayName, testResult.DisplayName); - if (!string.IsNullOrEmpty(testResult.ComputerName)) testResult.SetPropertyValue(TestResultProperties.ComputerName, testResult.ComputerName); - if (testResult.Duration != default(TimeSpan)) testResult.SetPropertyValue(TestResultProperties.Duration, testResult.Duration); - - if (testResult.StartTime != default(DateTimeOffset)) testResult.SetPropertyValue(TestResultProperties.StartTime, testResult.StartTime); - if (testResult.EndTime != default(DateTimeOffset)) testResult.SetPropertyValue(TestResultProperties.EndTime, testResult.EndTime); + var testResult = value as TestResult; + if (testResult.Outcome != TestOutcome.None) + { + testResult.SetPropertyValue(TestResultProperties.Outcome, testResult.Outcome); + } + + if (!string.IsNullOrEmpty(testResult.ErrorMessage)) + { + testResult.SetPropertyValue(TestResultProperties.ErrorMessage, testResult.ErrorMessage); + } + + if (!string.IsNullOrEmpty(testResult.ErrorStackTrace)) + { + testResult.SetPropertyValue(TestResultProperties.ErrorStackTrace, testResult.ErrorStackTrace); + } + + if (!string.IsNullOrEmpty(testResult.DisplayName)) + { + testResult.SetPropertyValue(TestResultProperties.DisplayName, testResult.DisplayName); + } + + if (!string.IsNullOrEmpty(testResult.ComputerName)) + { + testResult.SetPropertyValue(TestResultProperties.ComputerName, testResult.ComputerName); + } + + if (testResult.Duration != default(TimeSpan)) + { + testResult.SetPropertyValue(TestResultProperties.Duration, testResult.Duration); + } + + if (testResult.StartTime != default(DateTimeOffset)) + { + testResult.SetPropertyValue(TestResultProperties.StartTime, testResult.StartTime); + } + + if (testResult.EndTime != default(DateTimeOffset)) + { + testResult.SetPropertyValue(TestResultProperties.EndTime, testResult.EndTime); + } var properties = testResult.GetProperties(); diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs index 4d415e6478..36190a1860 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs @@ -75,7 +75,7 @@ public void DisposeShouldCallStopServerOnCommunicationManager() [TestMethod] public void VersionCheckWithTestHostShouldCheckVersionIfVersionCheckPassesReturnTrue() { - var message = new Message() { MessageType = MessageType.VersionCheck, Payload = version }; + var message = new Message() { MessageType = MessageType.VersionCheck, Payload = this.version }; this.mockCommunicationManager.Setup(mc => mc.ReceiveMessage()).Returns(message); var success = this.testRequestSender.CheckVersionWithTestHost(); this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.VersionCheck, this.version), Times.Once); @@ -85,7 +85,7 @@ public void VersionCheckWithTestHostShouldCheckVersionIfVersionCheckPassesReturn [TestMethod] public void VersionCheckWithTestHostShouldBeAbleToReceiveProtocolErrorAndReturnFalse() { - var message = new Message() { MessageType = MessageType.ProtocolError, Payload = version }; + var message = new Message() { MessageType = MessageType.ProtocolError, Payload = this.version }; this.mockCommunicationManager.Setup(mc => mc.ReceiveMessage()).Returns(message); var success = this.testRequestSender.CheckVersionWithTestHost(); this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.VersionCheck, this.version), Times.Once); @@ -108,7 +108,7 @@ public void InitializeDiscoveryShouldSendCommunicationMessageWithCorrectParamete var paths = new List() { "Hello", "World" }; this.testRequestSender.InitializeDiscovery(paths, false); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.DiscoveryInitialize, paths, version), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.DiscoveryInitialize, paths, this.version), Times.Once); } [TestMethod] @@ -117,7 +117,7 @@ public void InitializeExecutionShouldSendCommunicationMessageWithCorrectParamete var paths = new List() { "Hello", "World" }; this.testRequestSender.InitializeExecution(paths, true); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.ExecutionInitialize, paths, version), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.ExecutionInitialize, paths, this.version), Times.Once); } [TestMethod] @@ -151,7 +151,7 @@ public void DiscoverTestsShouldCallHandleDiscoveredTestsOnTestCaseEvent() this.testRequestSender.DiscoverTests(discoveryCriteria, mockHandler.Object); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartDiscovery, discoveryCriteria, version), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartDiscovery, discoveryCriteria, this.version), Times.Once); this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(rawMessage), Times.Exactly(2)); mockHandler.Verify(mh => mh.HandleDiscoveredTests(testCases), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.Exactly(2)); @@ -188,7 +188,7 @@ public void DiscoverTestsShouldCallHandleLogMessageOnTestMessage() this.testRequestSender.DiscoverTests(discoveryCriteria, mockHandler.Object); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartDiscovery, discoveryCriteria, version), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartDiscovery, discoveryCriteria, this.version), Times.Once); this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(rawMessage), Times.Exactly(2)); mockHandler.Verify(mh => mh.HandleLogMessage(TestMessageLevel.Error, rawMessage), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.Exactly(2)); @@ -216,7 +216,7 @@ public void DiscoverTestsShouldCallHandleDiscoveryCompleteOnDiscoveryCompletion( this.testRequestSender.DiscoverTests(discoveryCriteria, mockHandler.Object); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartDiscovery, discoveryCriteria, version), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartDiscovery, discoveryCriteria, this.version), Times.Once); this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(rawMessage), Times.Once); mockHandler.Verify(mh => mh.HandleDiscoveryComplete(1, null, false), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.Once); @@ -230,7 +230,7 @@ public void DiscoverTestsShouldHandleExceptionOnSendMessage() var mockHandler = new Mock(); var discoveryCriteria = new DiscoveryCriteria(sources, 100, settingsXml); var exception = new Exception(); - this.mockCommunicationManager.Setup(cm => cm.SendMessage(MessageType.StartDiscovery, discoveryCriteria, version)) + this.mockCommunicationManager.Setup(cm => cm.SendMessage(MessageType.StartDiscovery, discoveryCriteria, this.version)) .Throws(exception); this.testRequestSender.DiscoverTests(discoveryCriteria, mockHandler.Object); @@ -308,7 +308,7 @@ public void StartTestRunWithSourcesShouldCallHandleTestRunStatsChange() waitHandle.WaitOne(); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithSources, runCriteria, version), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithSources, runCriteria, this.version), Times.Once); // One for run stats and another for runcomplete this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(rawMessage), Times.Exactly(2)); @@ -349,7 +349,7 @@ public void StartTestRunWithTestsShouldCallHandleTestRunStatsChange() this.testRequestSender.StartTestRun(runCriteria, mockHandler.Object); waitHandle.WaitOne(); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithTests, runCriteria, version), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithTests, runCriteria, this.version), Times.Once); mockHandler.Verify(mh => mh.HandleTestRunStatsChange(testRunChangedArgs), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.AtLeastOnce); } @@ -384,7 +384,7 @@ public void StartTestRunShouldCallHandleLogMessageOnTestMessage() this.testRequestSender.StartTestRun(runCriteria, mockHandler.Object); waitHandle.WaitOne(); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithSources, runCriteria, version), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithSources, runCriteria, this.version), Times.Once); this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(It.IsAny()), Times.Exactly(2)); mockHandler.Verify(mh => mh.HandleLogMessage(payload.MessageLevel, payload.Message), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.AtLeastOnce); @@ -429,12 +429,12 @@ public void StartTestRunShouldCallLaunchProcessWithDebuggerAndWaitForCallback() waitHandle.WaitOne(); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithSources, runCriteria, version), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithSources, runCriteria, this.version), Times.Once); this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(It.IsAny()), Times.Exactly(2)); mockHandler.Verify(mh => mh.LaunchProcessWithDebuggerAttached(payload), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.Exactly(2)); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.LaunchAdapterProcessWithDebuggerAttachedCallback, It.IsAny(), version), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.LaunchAdapterProcessWithDebuggerAttachedCallback, It.IsAny(), this.version), Times.Once); } [TestMethod] @@ -461,7 +461,7 @@ public void StartTestRunShouldCallHandleTestRunCompleteOnRunCompletion() waitHandle.WaitOne(); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithTests, runCriteria, version), Times.Once); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.StartTestExecutionWithTests, runCriteria, this.version), Times.Once); this.mockDataSerializer.Verify(ds => ds.DeserializeMessage(rawMessage), Times.Once); mockHandler.Verify(mh => mh.HandleTestRunComplete(null, null, null, null), Times.Once); mockHandler.Verify(mh => mh.HandleRawMessage(rawMessage), Times.Once); From b6e8238b124d09788a2e1f9c16483f953e7e78ab Mon Sep 17 00:00:00 2001 From: Sarabjot Singh Date: Thu, 30 Mar 2017 18:11:26 +0530 Subject: [PATCH 3/7] Fixed the failing tests. --- .../Serialization/TestResultSerializationTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs index f37c4f1401..0960a22d3b 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs @@ -21,7 +21,7 @@ public class TestResultSerializationTests new Uri("executor://sampleTestExecutor"), "sampleTest.dll"); - private static DateTimeOffset startTime = new DateTimeOffset(new DateTime(2007, 3, 10, 0, 0, 0)); + private static DateTimeOffset startTime = new DateTimeOffset(new DateTime(2007, 3, 10, 0, 0, 0, DateTimeKind.Utc)); private static TestResult testResult = new TestResult(testCase) { // Attachments = ? @@ -69,7 +69,7 @@ public void TestResultJsonShouldContainAllPropertiesOnSerialization() [TestMethod] public void TestResultObjectShouldContainAllPropertiesOnDeserialization() { - var json = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"}]},\"Attachments\":[],\"Messages\":[],\"Properties\":[{\"Key\":{\"Id\":\"TestResult.Outcome\",\"Label\":\"Outcome\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"Microsoft.VisualStudio.TestPlatform.ObjectModel.TestOutcome\"},\"Value\":1},{\"Key\":{\"Id\":\"TestResult.ErrorMessage\",\"Label\":\"Error Message\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleError\"},{\"Key\":{\"Id\":\"TestResult.ErrorStackTrace\",\"Label\":\"Error Stack Trace\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleStackTrace\"},{\"Key\":{\"Id\":\"TestResult.DisplayName\",\"Label\":\"TestResult Display Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestResult\"},{\"Key\":{\"Id\":\"TestResult.ComputerName\",\"Label\":\"Computer Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleComputerName\"},{\"Key\":{\"Id\":\"TestResult.Duration\",\"Label\":\"Duration\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.TimeSpan\"},\"Value\":\"10675199.02:48:05.4775807\"},{\"Key\":{\"Id\":\"TestResult.StartTime\",\"Label\":\"Start Time\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.DateTimeOffset\"},\"Value\":\"2007-03-10T00:00:00+05:30\"},{\"Key\":{\"Id\":\"TestResult.EndTime\",\"Label\":\"End Time\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.DateTimeOffset\"},\"Value\":\"9999-12-31T23:59:59.9999999+00:00\"}]}"; + var json = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"}]},\"Attachments\":[],\"Messages\":[],\"Properties\":[{\"Key\":{\"Id\":\"TestResult.Outcome\",\"Label\":\"Outcome\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"Microsoft.VisualStudio.TestPlatform.ObjectModel.TestOutcome\"},\"Value\":1},{\"Key\":{\"Id\":\"TestResult.ErrorMessage\",\"Label\":\"Error Message\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleError\"},{\"Key\":{\"Id\":\"TestResult.ErrorStackTrace\",\"Label\":\"Error Stack Trace\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleStackTrace\"},{\"Key\":{\"Id\":\"TestResult.DisplayName\",\"Label\":\"TestResult Display Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestResult\"},{\"Key\":{\"Id\":\"TestResult.ComputerName\",\"Label\":\"Computer Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleComputerName\"},{\"Key\":{\"Id\":\"TestResult.Duration\",\"Label\":\"Duration\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.TimeSpan\"},\"Value\":\"10675199.02:48:05.4775807\"},{\"Key\":{\"Id\":\"TestResult.StartTime\",\"Label\":\"Start Time\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.DateTimeOffset\"},\"Value\":\"2007-03-10T00:00:00+00:00\"},{\"Key\":{\"Id\":\"TestResult.EndTime\",\"Label\":\"End Time\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.DateTimeOffset\"},\"Value\":\"9999-12-31T23:59:59.9999999+00:00\"}]}"; var test = Deserialize(json); @@ -137,7 +137,7 @@ public void TestResultJsonShouldContainAllPropertiesOnSerializationV2() [TestMethod] public void TestResultObjectShouldContainAllPropertiesOnDeserializationV2() { - var json = "{\"TestCase\":{\"Id\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\",\"FullyQualifiedName\":\"sampleTestClass.sampleTestCase\",\"DisplayName\":\"sampleTestClass.sampleTestCase\",\"ExecutorUri\":\"executor://sampleTestExecutor\",\"Source\":\"sampleTest.dll\",\"CodeFilePath\":null,\"LineNumber\":-1,\"Properties\":[]},\"Attachments\":[],\"Outcome\":1,\"ErrorMessage\":\"sampleError\",\"ErrorStackTrace\":\"sampleStackTrace\",\"DisplayName\":\"sampleTestResult\",\"Messages\":[],\"ComputerName\":\"sampleComputerName\",\"Duration\":\"10675199.02:48:05.4775807\",\"StartTime\":\"2007-03-10T00:00:00+05:30\",\"EndTime\":\"9999-12-31T23:59:59.9999999+00:00\",\"Properties\":[]}"; + var json = "{\"TestCase\":{\"Id\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\",\"FullyQualifiedName\":\"sampleTestClass.sampleTestCase\",\"DisplayName\":\"sampleTestClass.sampleTestCase\",\"ExecutorUri\":\"executor://sampleTestExecutor\",\"Source\":\"sampleTest.dll\",\"CodeFilePath\":null,\"LineNumber\":-1,\"Properties\":[]},\"Attachments\":[],\"Outcome\":1,\"ErrorMessage\":\"sampleError\",\"ErrorStackTrace\":\"sampleStackTrace\",\"DisplayName\":\"sampleTestResult\",\"Messages\":[],\"ComputerName\":\"sampleComputerName\",\"Duration\":\"10675199.02:48:05.4775807\",\"StartTime\":\"2007-03-10T00:00:00+00:00\",\"EndTime\":\"9999-12-31T23:59:59.9999999+00:00\",\"Properties\":[]}"; var test = Deserialize(json, 2); From e2da06db2b0e517c7bf19c6c06829e966a1a0a71 Mon Sep 17 00:00:00 2001 From: Sarabjot Singh Date: Fri, 31 Mar 2017 21:29:51 +0530 Subject: [PATCH 4/7] Fix : SendLog message to be sent post version check. --- .../EventHandlers/TestRequestHandler.cs | 5 +++++ src/testhost.x86/DefaultEngineInvoker.cs | 6 ------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs index 63755e94f3..fa31b3bb36 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs @@ -94,6 +94,11 @@ public void ProcessRequests(ITestHostManagerFactory testHostManagerFactory) this.protocolVersion = Math.Min(version, highestSupportedVersion); this.communicationManager.SendMessage(MessageType.VersionCheck, this.protocolVersion); + // Can only do this after InitializeCommunication because TestHost cannot "Send Log" unless communications are initialized + if (!string.IsNullOrEmpty(EqtTrace.LogFile)) + { + this.SendLog(TestMessageLevel.Informational, string.Format("Logging TestHost Diagnostics in file: {0}", EqtTrace.LogFile)); + } break; case MessageType.DiscoveryInitialize: diff --git a/src/testhost.x86/DefaultEngineInvoker.cs b/src/testhost.x86/DefaultEngineInvoker.cs index 6c80d538aa..562c998372 100644 --- a/src/testhost.x86/DefaultEngineInvoker.cs +++ b/src/testhost.x86/DefaultEngineInvoker.cs @@ -73,12 +73,6 @@ public void Invoke(IDictionary argsDictionary) EqtTrace.Info("DefaultEngineInvoker: Initialize communication on port number: '{0}'", portNumber); requestHandler.InitializeCommunication(portNumber); - // Can only do this after InitializeCommunication because TestHost cannot "Send Log" unless communications are initialized - if (!string.IsNullOrEmpty(EqtTrace.LogFile)) - { - requestHandler.SendLog(TestMessageLevel.Informational, string.Format("Logging TestHost Diagnostics in file: {0}", EqtTrace.LogFile)); - } - // Initialize DataCollection Communication if data collection port is provided. var dcPort = CommandLineArgumentsHelper.GetIntArgFromDict(argsDictionary, DataCollectionPortArgument); if (dcPort > 0) From dda2b84c7818b51c54ccda83285e7c7727208862 Mon Sep 17 00:00:00 2001 From: Sarabjot Singh Date: Sat, 1 Apr 2017 01:15:06 +0530 Subject: [PATCH 5/7] Fixing the test case filter issue. Changing the TestCase and TestResult objects, and cleaned up the converters. --- .../Serialization/TestCaseConverter.cs | 35 ++-------- .../Serialization/TestResultConverter.cs | 57 ++-------------- .../TestCase.cs | 55 ++++++---------- .../TestObject.cs | 35 +++++++--- .../TestResult.cs | 65 ++++++------------- ...DataCollectionTestCaseEventHandlerTests.cs | 3 +- .../DataCollectionTestCaseEventSenderTests.cs | 8 +-- .../TestCaseSerializationTests.cs | 8 +-- .../TestResultSerializationTests.cs | 4 +- 9 files changed, 85 insertions(+), 185 deletions(-) diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs index 99d0822b40..6617f9e79c 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs @@ -10,6 +10,9 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serializati /// public class TestCaseConverter : JsonConverter { + /// + public override bool CanRead => false; + /// public override bool CanConvert(Type objectType) { @@ -19,17 +22,7 @@ public override bool CanConvert(Type objectType) /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - var testCase = new TestCase(); - serializer.Populate(reader, testCase); - - testCase.Id = testCase.GetPropertyValue(TestCaseProperties.Id, Guid.Empty); - testCase.FullyQualifiedName = testCase.GetPropertyValue(TestCaseProperties.FullyQualifiedName, null); - testCase.DisplayName = testCase.GetPropertyValue(TestCaseProperties.DisplayName, null); - testCase.Source = testCase.GetPropertyValue(TestCaseProperties.Source, null); - testCase.ExecutorUri = testCase.GetPropertyValue(TestCaseProperties.ExecutorUri, null); - testCase.CodeFilePath = testCase.GetPropertyValue(TestCaseProperties.CodeFilePath, null); - testCase.LineNumber = testCase.GetPropertyValue(TestCaseProperties.LineNumber, -1); - return testCase; + throw new NotImplementedException(); } /// @@ -37,26 +30,6 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s { // P2 to P1 var testCase = value as TestCase; - - testCase.SetPropertyValue(TestCaseProperties.FullyQualifiedName, testCase.FullyQualifiedName); - testCase.SetPropertyValue(TestCaseProperties.ExecutorUri, testCase.ExecutorUri); - testCase.SetPropertyValue(TestCaseProperties.Source, testCase.Source); - testCase.SetPropertyValue(TestCaseProperties.Id, testCase.Id); - if (!testCase.DisplayName.Equals(testCase.FullyQualifiedName)) - { - testCase.SetPropertyValue(TestCaseProperties.DisplayName, testCase.DisplayName); - } - - if (!string.IsNullOrEmpty(testCase.CodeFilePath)) - { - testCase.SetPropertyValue(TestCaseProperties.CodeFilePath, testCase.CodeFilePath); - } - - if (testCase.LineNumber >= 0) - { - testCase.SetPropertyValue(TestCaseProperties.LineNumber, testCase.LineNumber); - } - var properties = testCase.GetProperties(); writer.WriteStartObject(); diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs index e75abf3796..207d4964a6 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs @@ -10,6 +10,9 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serializati /// public class TestResultConverter : JsonConverter { + /// + public override bool CanRead => false; + /// public override bool CanConvert(Type objectType) { @@ -19,19 +22,7 @@ public override bool CanConvert(Type objectType) /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - var testResult = new TestResult(); - serializer.Populate(reader, testResult); - - testResult.Outcome = testResult.GetPropertyValue(TestResultProperties.Outcome, TestOutcome.None); - testResult.ErrorMessage = testResult.GetPropertyValue(TestResultProperties.ErrorMessage, null); - testResult.ErrorStackTrace = testResult.GetPropertyValue(TestResultProperties.ErrorStackTrace, null); - testResult.DisplayName = testResult.GetPropertyValue(TestResultProperties.DisplayName, null); - testResult.ComputerName = testResult.GetPropertyValue(TestResultProperties.ComputerName, null); - testResult.Duration = testResult.GetPropertyValue(TestResultProperties.Duration, TimeSpan.Zero); - testResult.StartTime = testResult.GetPropertyValue(TestResultProperties.StartTime, DateTimeOffset.Now); - testResult.EndTime = testResult.GetPropertyValue(TestResultProperties.EndTime, DateTimeOffset.Now); - - return testResult; + throw new NotImplementedException(); } /// @@ -39,46 +30,6 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s { // P2 to P1 var testResult = value as TestResult; - if (testResult.Outcome != TestOutcome.None) - { - testResult.SetPropertyValue(TestResultProperties.Outcome, testResult.Outcome); - } - - if (!string.IsNullOrEmpty(testResult.ErrorMessage)) - { - testResult.SetPropertyValue(TestResultProperties.ErrorMessage, testResult.ErrorMessage); - } - - if (!string.IsNullOrEmpty(testResult.ErrorStackTrace)) - { - testResult.SetPropertyValue(TestResultProperties.ErrorStackTrace, testResult.ErrorStackTrace); - } - - if (!string.IsNullOrEmpty(testResult.DisplayName)) - { - testResult.SetPropertyValue(TestResultProperties.DisplayName, testResult.DisplayName); - } - - if (!string.IsNullOrEmpty(testResult.ComputerName)) - { - testResult.SetPropertyValue(TestResultProperties.ComputerName, testResult.ComputerName); - } - - if (testResult.Duration != default(TimeSpan)) - { - testResult.SetPropertyValue(TestResultProperties.Duration, testResult.Duration); - } - - if (testResult.StartTime != default(DateTimeOffset)) - { - testResult.SetPropertyValue(TestResultProperties.StartTime, testResult.StartTime); - } - - if (testResult.EndTime != default(DateTimeOffset)) - { - testResult.SetPropertyValue(TestResultProperties.EndTime, testResult.EndTime); - } - var properties = testResult.GetProperties(); writer.WriteStartObject(); diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs index 936d0ec150..f13036a3f4 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs @@ -8,7 +8,6 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel using System.Runtime.Serialization; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; - using System.Globalization; /// /// Stores information about a test case. @@ -25,14 +24,6 @@ public sealed class TestCase : TestObject #endif private Guid defaultId = Guid.Empty; - private string fullyQualifiedName; - private string displayName; - private Guid id; - private string source; - private Uri executerUri; - private string codeFilePath; - private int lineNumber = -1; - #region Constructor /// @@ -91,7 +82,8 @@ public Guid Id { get { - if (this.id == Guid.Empty) + var id = this.GetPropertyValue(TestCaseProperties.Id, Guid.Empty); + if (id == Guid.Empty) { // user has not specified his own Id during ctor! We will cache Id if its empty if (this.defaultId == Guid.Empty) @@ -102,13 +94,12 @@ public Guid Id return this.defaultId; } - return this.id; + return id; } set { - var convertedValue = ConvertPropertyFrom(TestCaseProperties.Id, CultureInfo.InvariantCulture, value); - this.id = (Guid)convertedValue; + this.SetLocalPropertyValue(TestCaseProperties.Id, value); } } @@ -120,12 +111,15 @@ public string FullyQualifiedName { get { - return this.fullyQualifiedName; + return this.GetPropertyValue(TestCaseProperties.FullyQualifiedName, string.Empty); } set { - this.fullyQualifiedName = value; + this.SetLocalPropertyValue(TestCaseProperties.FullyQualifiedName, value); + + // Id is based on Name/Source, will nulll out guid and it gets calc next time we access it. + this.defaultId = Guid.Empty; } } @@ -137,16 +131,12 @@ public string DisplayName { get { - if (string.IsNullOrEmpty(this.displayName)) - { - return this.FullyQualifiedName; - } - return this.displayName; + return this.GetPropertyValue(TestCaseProperties.DisplayName, this.FullyQualifiedName); } set { - this.displayName = value; + this.SetLocalPropertyValue(TestCaseProperties.DisplayName, value); } } @@ -158,13 +148,12 @@ public Uri ExecutorUri { get { - return this.executerUri; + return this.GetPropertyValue(TestCaseProperties.ExecutorUri, null); } set { - var convertedValue = ConvertPropertyFrom(TestCaseProperties.ExecutorUri, CultureInfo.InvariantCulture, value); - this.executerUri = (Uri)convertedValue; + this.SetLocalPropertyValue(TestCaseProperties.ExecutorUri, value); } } @@ -176,12 +165,12 @@ public string Source { get { - return source; + return this.GetPropertyValue(TestCaseProperties.Source, null); } - - set + + private set { - this.source = value; + this.SetLocalPropertyValue(TestCaseProperties.Source, value); // Id is based on Name/Source, will nulll out guid and it gets calc next time we access it. this.defaultId = Guid.Empty; @@ -196,12 +185,12 @@ public string CodeFilePath { get { - return this.codeFilePath; + return this.GetPropertyValue(TestCaseProperties.CodeFilePath, null); } set { - this.codeFilePath = value; + this.SetLocalPropertyValue(TestCaseProperties.CodeFilePath, value); } } @@ -213,17 +202,15 @@ public int LineNumber { get { - return this.lineNumber; + return this.GetPropertyValue(TestCaseProperties.LineNumber, -1); } set { - var convertedValue = ConvertPropertyFrom(TestCaseProperties.LineNumber, CultureInfo.InvariantCulture, value); - this.lineNumber = (int)convertedValue; + this.SetLocalPropertyValue(TestCaseProperties.LineNumber, value); } } - /// public override string ToString() { diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestObject.cs b/src/Microsoft.TestPlatform.ObjectModel/TestObject.cs index aaab0e5128..796467a69b 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestObject.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestObject.cs @@ -28,6 +28,11 @@ public abstract class TestObject /// private readonly Dictionary store; + /// + /// The store for all the local properties registered. + /// + private readonly Dictionary localStore; + /// /// Property used for Json (de)serialization of store dictionary. Serialization of dictionaries /// by default doesn't provide the required object representation. List of KeyValuePair on the @@ -70,7 +75,7 @@ private List> StoreKeyValuePairs /// public List> GetProperties() { - return this.store.ToList(); + return this.store.Concat(this.localStore).ToList(); } #endregion Fields @@ -79,7 +84,8 @@ public List> GetProperties() protected TestObject() { - this.store = new Dictionary(); + this.store = new Dictionary(); + this.localStore = new Dictionary(); } [OnSerializing] @@ -113,7 +119,7 @@ public void CacheLazyValuesOnSerializing(StreamingContext context) /// public IEnumerable Properties { - get { return this.store.Keys; } + get { return this.store.Keys.Concat(this.localStore.Keys); } } /// @@ -177,7 +183,7 @@ public void SetPropertyValue(TestProperty property, LazyPropertyValue valu /// value to be set public void SetPropertyValue(TestProperty property, object value) { - this.PrivateSetPropertyValue(property, value); + this.PrivateSetPropertyValue(property, value, store); } /// @@ -220,7 +226,7 @@ public void SetPropertyValue(TestProperty property, T value, CultureInfo cult object objValue = ConvertPropertyFrom(property, culture, value); - this.PrivateSetPropertyValue(property, objValue); + this.PrivateSetPropertyValue(property, objValue, store); } /// @@ -233,7 +239,18 @@ public void SetPropertyValue(TestProperty property, LazyPropertyValue valu object objValue = ConvertPropertyFrom(property, culture, value); - this.PrivateSetPropertyValue(property, objValue); + this.PrivateSetPropertyValue(property, objValue, store); + } + + /// + /// Set TestProperty's value to the specified value T. + /// + protected void SetLocalPropertyValue(TestProperty property, T value) + { + ValidateArg.NotNull(property, "property"); + + object objValue = ConvertPropertyFrom(property, CultureInfo.InvariantCulture, value); + this.PrivateSetPropertyValue(property, objValue, localStore); } #endregion Property Values @@ -249,7 +266,7 @@ private object PrivateGetPropertyValue(TestProperty property, object defaultValu ValidateArg.NotNull(property, "property"); object value; - if (!this.store.TryGetValue(property, out value)) + if (!this.store.TryGetValue(property, out value) && !this.localStore.TryGetValue(property, out value)) { value = defaultValue; } @@ -260,13 +277,13 @@ private object PrivateGetPropertyValue(TestProperty property, object defaultValu /// /// Set TestProperty's value /// - private void PrivateSetPropertyValue(TestProperty property, object value) + private void PrivateSetPropertyValue(TestProperty property, object value, Dictionary dictionary) { ValidateArg.NotNull(property, "property"); if (property.ValidateValueCallback == null || property.ValidateValueCallback(value)) { - this.store[property] = value; + dictionary[property] = value; } else { diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestResult.cs b/src/Microsoft.TestPlatform.ObjectModel/TestResult.cs index 5a82028e12..7b176f8989 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestResult.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestResult.cs @@ -15,15 +15,6 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel [DataContract] public sealed class TestResult : TestObject { - private TestOutcome outcome; - private string errorMessage; - private string errorStackTrace; - private string displayName; - private string computerName; - private TimeSpan duration; - private DateTimeOffset startTime; - private DateTimeOffset endTime; - #region Constructor /// @@ -75,13 +66,12 @@ public TestOutcome Outcome { get { - return this.outcome; + return this.GetPropertyValue(TestResultProperties.Outcome, TestOutcome.None); } set { - var convertedValue = ConvertPropertyFrom(TestResultProperties.Outcome, CultureInfo.InvariantCulture, value); - this.outcome = (TestOutcome)convertedValue; + this.SetLocalPropertyValue(TestResultProperties.Outcome, value); } } @@ -93,12 +83,12 @@ public string ErrorMessage { get { - return this.errorMessage; + return this.GetPropertyValue(TestResultProperties.ErrorMessage, null); } set { - this.errorMessage = value; + this.SetLocalPropertyValue(TestResultProperties.ErrorMessage, value); } } @@ -110,12 +100,12 @@ public string ErrorStackTrace { get { - return this.errorStackTrace; + return this.GetPropertyValue(TestResultProperties.ErrorStackTrace, null); } set { - this.errorStackTrace = value; + this.SetLocalPropertyValue(TestResultProperties.ErrorStackTrace, value); } } @@ -127,12 +117,12 @@ public string DisplayName { get { - return this.displayName; + return this.GetPropertyValue(TestResultProperties.DisplayName, null); } set { - this.displayName = value; + this.SetLocalPropertyValue(TestResultProperties.DisplayName, value); } } @@ -154,13 +144,12 @@ public string ComputerName { get { - return this.computerName; + return this.GetPropertyValue(TestResultProperties.ComputerName, string.Empty); } set { - var convertedValue = ConvertPropertyFrom(TestResultProperties.ComputerName, CultureInfo.InvariantCulture, value); - this.computerName = (string)convertedValue; + this.SetLocalPropertyValue(TestResultProperties.ComputerName, value); } } @@ -172,13 +161,12 @@ public TimeSpan Duration { get { - return this.duration; + return this.GetPropertyValue(TestResultProperties.Duration, TimeSpan.Zero); } set { - var convertedValue = ConvertPropertyFrom(TestResultProperties.Duration, CultureInfo.InvariantCulture, value); - this.duration = (TimeSpan)convertedValue; + this.SetLocalPropertyValue(TestResultProperties.Duration, value); } } @@ -190,17 +178,12 @@ public DateTimeOffset StartTime { get { - //if (this.startTime == default(DateTimeOffset)) - //{ - // this.startTime = DateTimeOffset.Now; - //} - return this.startTime; + return this.GetPropertyValue(TestResultProperties.StartTime, DateTimeOffset.Now); } set { - var convertedValue = ConvertPropertyFrom(TestResultProperties.StartTime, CultureInfo.InvariantCulture, value); - this.startTime = (DateTimeOffset)convertedValue; + this.SetLocalPropertyValue(TestResultProperties.StartTime, value); } } @@ -212,17 +195,12 @@ public DateTimeOffset EndTime { get { - //if (this.endTime == default(DateTimeOffset)) - //{ - // this.endTime = DateTimeOffset.Now; - //} - return this.endTime; + return this.GetPropertyValue(TestResultProperties.EndTime, DateTimeOffset.Now); } set { - var convertedValue = ConvertPropertyFrom(TestResultProperties.EndTime, CultureInfo.InvariantCulture, value); - this.endTime = (DateTimeOffset)convertedValue; + this.SetLocalPropertyValue(TestResultProperties.EndTime, value); } } @@ -361,7 +339,7 @@ public static class TestResultProperties public static readonly TestProperty DisplayName = TestProperty.Register("TestResult.DisplayName", "TestResult Display Name", typeof(string), TestPropertyAttributes.Hidden, typeof(TestResult)); [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly TestProperty ComputerName = TestProperty.Register("TestResult.ComputerName", "Computer Name", string.Empty, string.Empty, typeof(string), ValidateComputerName, TestPropertyAttributes.None, typeof(TestResult)); + public static readonly TestProperty ComputerName = TestProperty.Register("TestResult.ComputerName", "Computer Name", typeof(string), TestPropertyAttributes.None, typeof(TestResult)); [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly TestProperty Outcome = TestProperty.Register("TestResult.Outcome", "Outcome", string.Empty, string.Empty, typeof(TestOutcome), ValidateOutcome, TestPropertyAttributes.None, typeof(TestResult)); @@ -385,7 +363,7 @@ public static class TestResultProperties public static readonly TestProperty DisplayName = TestProperty.Register("TestResult.DisplayName", Resources.Resources.TestResultPropertyDisplayNameLabel, typeof(string), TestPropertyAttributes.Hidden, typeof(TestResult)); [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] - public static readonly TestProperty ComputerName = TestProperty.Register("TestResult.ComputerName", Resources.Resources.TestResultPropertyComputerNameLabel, string.Empty, string.Empty, typeof(string), ValidateComputerName, TestPropertyAttributes.None, typeof(TestResult)); + public static readonly TestProperty ComputerName = TestProperty.Register("TestResult.ComputerName", Resources.Resources.TestResultPropertyComputerNameLabel, typeof(string), TestPropertyAttributes.None, typeof(TestResult)); [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly TestProperty Outcome = TestProperty.Register("TestResult.Outcome", Resources.Resources.TestResultPropertyOutcomeLabel, string.Empty, string.Empty, typeof(TestOutcome), ValidateOutcome, TestPropertyAttributes.None, typeof(TestResult)); @@ -405,12 +383,7 @@ public static class TestResultProperties [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly TestProperty ErrorStackTrace = TestProperty.Register("TestResult.ErrorStackTrace", Resources.Resources.TestResultPropertyErrorStackTraceLabel, typeof(string), typeof(TestResult)); #endif - - private static bool ValidateComputerName(object value) - { - return !string.IsNullOrWhiteSpace((string)value); - } - + private static bool ValidateOutcome(object value) { return (TestOutcome)value <= TestOutcome.NotFound && (TestOutcome)value >= TestOutcome.None; diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionTestCaseEventHandlerTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionTestCaseEventHandlerTests.cs index b4903358a7..4095a6fe8e 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionTestCaseEventHandlerTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionTestCaseEventHandlerTests.cs @@ -124,7 +124,8 @@ public void ProcessRequestsShouldProcessAfterTestCaseCompleteEvent() { var message = new Message(); message.MessageType = MessageType.DataCollectionTestEnd; - message.Payload = JToken.FromObject(new TestResultEventArgs(new VisualStudio.TestPlatform.ObjectModel.TestResult(new TestCase()))); + var testCase = new TestCase("hello", new Uri("world://how"), "1.dll"); + message.Payload = JToken.FromObject(new TestResultEventArgs(new VisualStudio.TestPlatform.ObjectModel.TestResult(testCase))); this.mockCommunicationManager.SetupSequence(x => x.ReceiveMessage()).Returns(message).Returns(new Message() { MessageType = MessageType.SessionEnd, Payload = "false" }); diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionTestCaseEventSenderTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionTestCaseEventSenderTests.cs index 719e30e9f8..1f219fb612 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionTestCaseEventSenderTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/DataCollectionTestCaseEventSenderTests.cs @@ -23,6 +23,7 @@ public class DataCollectionTestCaseEventSenderTests { private DataCollectionTestCaseEventSender dataCollectionTestCaseEventSender; private Mock mockCommunicationManager; + private TestCase testCase = new TestCase("hello", new Uri("world://how"), "1.dll"); public DataCollectionTestCaseEventSenderTests() { @@ -90,8 +91,7 @@ public void CloseShouldThrowExceptionIfThrownByCommunicationManager() [TestMethod] public void SendTestCaseStartShouldSendMessageThroughCommunicationManager() { - var testCase = new TestCase(); - var testcaseStartEventArgs = new TestCaseStartEventArgs(testCase); + var testcaseStartEventArgs = new TestCaseStartEventArgs(this.testCase); this.dataCollectionTestCaseEventSender.SendTestCaseStart(testcaseStartEventArgs); this.mockCommunicationManager.Verify(x => x.SendMessage(MessageType.DataCollectionTestStart, testcaseStartEventArgs), Times.Once); @@ -100,8 +100,7 @@ public void SendTestCaseStartShouldSendMessageThroughCommunicationManager() [TestMethod] public void SendTestCaseStartShouldThrowExceptionIfThrownByCommunicationManager() { - var testCase = new TestCase(); - var testcaseStartEventArgs = new TestCaseStartEventArgs(testCase); + var testcaseStartEventArgs = new TestCaseStartEventArgs(this.testCase); this.mockCommunicationManager.Setup(x => x.SendMessage(MessageType.DataCollectionTestStart, testcaseStartEventArgs)).Throws(); Assert.ThrowsException(() => @@ -126,7 +125,6 @@ public void SendTestCaseEndShouldReturnAttachments() [TestMethod] public void SendTestCaseCompletedShouldThrowExceptionIfThrownByCommunicationManager() { - var testCase = new TestCase(); var testCaseEndEventArgs = new TestCaseEndEventArgs(); this.mockCommunicationManager.Setup(x => x.SendMessage(MessageType.DataCollectionTestEnd, It.IsAny())).Throws(); diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestCaseSerializationTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestCaseSerializationTests.cs index 232baca5e3..274e7a7b48 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestCaseSerializationTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestCaseSerializationTests.cs @@ -49,12 +49,12 @@ public void TestCaseJsonShouldContainAllPropertiesOnSerialization() Assert.AreEqual("executor://sampleTestExecutor", properties[2]["Value"].Value); Assert.AreEqual("TestCase.Source", properties[3]["Key"]["Id"].Value); Assert.AreEqual("sampleTest.dll", properties[3]["Value"].Value); - Assert.AreEqual("TestCase.Id", properties[4]["Key"]["Id"].Value); - Assert.AreEqual("be78d6fc-61b0-4882-9d07-40d796fd96ce", properties[4]["Value"].Value); + Assert.AreEqual("TestCase.CodeFilePath", properties[4]["Key"]["Id"].Value); + Assert.AreEqual("/user/src/testFile.cs", properties[4]["Value"].Value); Assert.AreEqual("TestCase.DisplayName", properties[5]["Key"]["Id"].Value); Assert.AreEqual("sampleTestCase", properties[5]["Value"].Value); - Assert.AreEqual("TestCase.CodeFilePath", properties[6]["Key"]["Id"].Value); - Assert.AreEqual("/user/src/testFile.cs", properties[6]["Value"].Value); + Assert.AreEqual("TestCase.Id", properties[6]["Key"]["Id"].Value); + Assert.AreEqual("be78d6fc-61b0-4882-9d07-40d796fd96ce", properties[6]["Value"].Value); Assert.AreEqual("TestCase.LineNumber", properties[7]["Key"]["Id"].Value); Assert.AreEqual(999, properties[7]["Value"].Value); } diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs index 0960a22d3b..f05c4108c9 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs @@ -92,7 +92,7 @@ public void TestResultObjectShouldSerializeAttachments() { var result = new TestResult(testCase); result.Attachments.Add(new AttachmentSet(new Uri("http://dummyUri"), "sampleAttachment")); - var expectedJson = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"},{\"Key\":{\"Id\":\"TestCase.Id\",\"Label\":\"Id\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Guid\"},\"Value\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\"}]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Messages\":[],\"Properties\":[]}"; + var expectedJson = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"}]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Messages\":[],\"Properties\":[]}"; var json = Serialize(result); Assert.AreEqual(expectedJson, json); @@ -160,7 +160,7 @@ public void TestResultObjectShouldSerializeAttachmentsV2() { var result = new TestResult(testCase); result.Attachments.Add(new AttachmentSet(new Uri("http://dummyUri"), "sampleAttachment")); - var expectedJson = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"},{\"Key\":{\"Id\":\"TestCase.Id\",\"Label\":\"Id\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Guid\"},\"Value\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\"}]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Messages\":[],\"Properties\":[]}"; + var expectedJson = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"}]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Messages\":[],\"Properties\":[]}"; var json = Serialize(result); Assert.AreEqual(expectedJson, json); From 9a0002c23d7e225093ba7ccaada3461203ba81f9 Mon Sep 17 00:00:00 2001 From: Sarabjot Singh Date: Thu, 6 Apr 2017 17:42:45 +0530 Subject: [PATCH 6/7] Changes as per comments. Adding the perf tests. --- .../Interfaces/ITestRequestSender.cs | 3 +- .../JsonDataSerializer.cs | 13 +- .../Messages/VersionedMessage.cs | 3 +- .../Resources/Resources.Designer.cs | 22 ++++ .../Resources/Resources.resx | 6 + .../Serialization/TestCaseConverter.cs | 6 +- .../TestPlatformContractResolver1.cs | 3 +- .../Serialization/TestResultConverter.cs | 6 +- .../TestRequestSender.cs | 18 +-- .../Client/ProxyOperationManager.cs | 5 +- .../EventHandlers/TestRequestHandler.cs | 12 +- .../TestCase.cs | 63 ++++++++- .../TestObject.cs | 40 ++---- .../TestResult.cs | 66 ++++++++-- .../SocketCommunicationManagerTests.cs | 21 ++- .../TestCaseSerializationTests.cs | 81 +++++++----- .../TestResultSerializationTests.cs | 2 + .../TestRequestSenderTests.cs | 21 +-- .../TestObjectTests.cs | 5 +- .../ProtocolV1Tests.cs | 124 ++++++++++++++++++ .../ProtocolV2Tests.cs | 122 +++++++++++++++++ 21 files changed, 519 insertions(+), 123 deletions(-) create mode 100644 test/Microsoft.TestPlatform.PerformanceTests/ProtocolV1Tests.cs create mode 100644 test/Microsoft.TestPlatform.PerformanceTests/ProtocolV2Tests.cs diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestSender.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestSender.cs index f22e18c164..553d9c297a 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestSender.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Interfaces/ITestRequestSender.cs @@ -23,8 +23,7 @@ public interface ITestRequestSender : IDisposable /// /// Used for protocol version check with TestHost /// - /// true if the version check is successful - bool CheckVersionWithTestHost(); + void CheckVersionWithTestHost(); /// /// Waits for Request Handler to be connected diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs index 7125c08a0f..e749781816 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs @@ -83,7 +83,7 @@ public T DeserializePayload(Message message) T retValue = default(T); var versionedMessage = message as VersionedMessage; - var serializer = versionedMessage?.Version == 2 ? payloadSerializer2 : payloadSerializer; + var serializer = this.GetPayloadSerializer(versionedMessage?.Version); retValue = message.Payload.ToObject(serializer); return retValue; @@ -98,7 +98,7 @@ public T DeserializePayload(Message message) /// An instance of . public T Deserialize(string json, int version = 1) { - var serializer = version == 2 ? payloadSerializer2 : payloadSerializer; + var serializer = this.GetPayloadSerializer(version); using (var stringReader = new StringReader(json)) using (var jsonReader = new JsonTextReader(stringReader)) @@ -139,7 +139,7 @@ public string SerializePayload(string messageType, object payload) /// Serialized message. public string SerializePayload(string messageType, object payload, int version) { - var serializer = version == 2 ? payloadSerializer2 : payloadSerializer; + var serializer = this.GetPayloadSerializer(version); var serializedPayload = JToken.FromObject(payload, serializer); var message = version == 1 ? @@ -158,7 +158,7 @@ public string SerializePayload(string messageType, object payload, int version) /// JSON string. public string Serialize(T data, int version = 1) { - var serializer = version == 2 ? payloadSerializer2 : payloadSerializer; + var serializer = this.GetPayloadSerializer(version); using (var stringWriter = new StringWriter()) using (var jsonWriter = new JsonTextWriter(stringWriter)) @@ -168,5 +168,10 @@ public string Serialize(T data, int version = 1) return stringWriter.ToString(); } } + + private JsonSerializer GetPayloadSerializer(int? version) + { + return version == 2 ? payloadSerializer2 : payloadSerializer; + } } } diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/VersionedMessage.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/VersionedMessage.cs index ca7f1f1887..a48e59cdae 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/VersionedMessage.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Messages/VersionedMessage.cs @@ -4,7 +4,8 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities { /// - /// New construct with version used for communication + /// Construct with version used for communication + /// Introduced in 15.1.0 version and default message protocol v2 onwards. /// public class VersionedMessage : Message { diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.Designer.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.Designer.cs index e5584b81e8..e2d5c5a448 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.Designer.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.Designer.cs @@ -107,5 +107,27 @@ internal static string DataCollectorUriForLogMessage return ResourceManager.GetString("DataCollectorUriForLogMessage", resourceCulture); } } + + /// + /// Looks up a localized string similar to Unexpected message received. Expected MessageType : {0} Actual MessageType: {1}. + /// + internal static string UnexpectedMessage + { + get + { + return ResourceManager.GetString("UnexpectedMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Protocol version check failed. Make sure test runner and host are compatible.. + /// + internal static string VersionCheckFailed + { + get + { + return ResourceManager.GetString("VersionCheckFailed", resourceCulture); + } + } } } diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.resx b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.resx index 13411e6979..92ba88351c 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.resx +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Resources/Resources.resx @@ -132,4 +132,10 @@ Unable to communicate with test host process. + + Unexpected message received. Expected MessageType : {0} Actual MessageType: {1} + + + Protocol version check failed. Make sure test runner and host are compatible. + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs index 6617f9e79c..03027c3393 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestCaseConverter.cs @@ -7,7 +7,9 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serializati using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Newtonsoft.Json; - /// + /// + /// Converter used by v1 protocol serializer to serialize TestCase object to and from v1 json + /// public class TestCaseConverter : JsonConverter { /// @@ -22,6 +24,8 @@ public override bool CanConvert(Type objectType) /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { + // We do not need this as SetPropetyValue inside StoreKvpList will + // set the properties as expected. throw new NotImplementedException(); } diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver1.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver1.cs index a1a130a011..0f50bd53f0 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver1.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestPlatformContractResolver1.cs @@ -20,8 +20,7 @@ protected override JsonContract CreateContract(Type objectType) { contract.Converter = new TestCaseConverter(); } - - if (typeof(TestResult) == objectType) + else if (typeof(TestResult) == objectType) { contract.Converter = new TestResultConverter(); } diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs index 207d4964a6..9824880490 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/Serialization/TestResultConverter.cs @@ -7,7 +7,9 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serializati using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Newtonsoft.Json; - /// + /// + /// Converter used by v1 protocol serializer to serialize TestResult object to and from v1 json + /// public class TestResultConverter : JsonConverter { /// @@ -22,6 +24,8 @@ public override bool CanConvert(Type objectType) /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { + // We do not need this as SetPropetyValue inside StoreKvpList will + // set the properties as expected. throw new NotImplementedException(); } diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs index 2e80a0211a..c0001b38e6 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs @@ -5,16 +5,15 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities { using System; using System.Collections.Generic; + using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; - using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; - using CommonResources = Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Resources.Resources; /// @@ -87,9 +86,8 @@ public void Close() } /// - public bool CheckVersionWithTestHost() + public void CheckVersionWithTestHost() { - var success = false; this.communicationManager.SendMessage(MessageType.VersionCheck, payload: this.highestNegotiatedVersion); var message = this.communicationManager.ReceiveMessage(); @@ -97,21 +95,19 @@ public bool CheckVersionWithTestHost() if (message.MessageType == MessageType.VersionCheck) { var protocolVersion = this.dataSerializer.DeserializePayload(message); - - // TODO: Should we check if this is valid ? this.highestNegotiatedVersion = protocolVersion; - success = true; + + EqtTrace.Info("TestRequestSender: VersionCheck Succeeded, NegotiatedVersion = {0}", this.highestNegotiatedVersion); } else if (message.MessageType == MessageType.ProtocolError) { - EqtTrace.Error("TestRequestSender: VersionCheck Failed"); + // TODO : Payload for ProtocolError needs to finalized. + throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, CommonResources.VersionCheckFailed)); } else { - EqtTrace.Error("TestRequestSender: VersionCheck Message Expected but different message received: Received MessageType: {0}", message.MessageType); + throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, CommonResources.UnexpectedMessage, MessageType.VersionCheck, message.MessageType)); } - - return success; } /// diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs index 5bb611289a..c10e88f367 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs @@ -143,10 +143,7 @@ public virtual void SetupChannel(IEnumerable sources) if (checkRequired) { - if (!this.RequestSender.CheckVersionWithTestHost()) - { - throw new TestPlatformException(string.Format(CultureInfo.CurrentUICulture, "Protocol version check failed")); - } + this.RequestSender.CheckVersionWithTestHost(); } this.initialized = true; diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs index fa31b3bb36..77a13a5f46 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs @@ -231,20 +231,20 @@ public void Close() /// public void SendTestCases(IEnumerable discoveredTestCases) { - this.communicationManager.SendMessage(MessageType.TestCasesFound, discoveredTestCases, protocolVersion); + this.communicationManager.SendMessage(MessageType.TestCasesFound, discoveredTestCases, this.protocolVersion); } /// public void SendTestRunStatistics(TestRunChangedEventArgs testRunChangedArgs) { - this.communicationManager.SendMessage(MessageType.TestRunStatsChange, testRunChangedArgs, protocolVersion); + this.communicationManager.SendMessage(MessageType.TestRunStatsChange, testRunChangedArgs, this.protocolVersion); } /// public void SendLog(TestMessageLevel messageLevel, string message) { var testMessagePayload = new TestMessagePayload {MessageLevel = messageLevel,Message = message}; - this.communicationManager.SendMessage(MessageType.TestMessage, testMessagePayload, protocolVersion); + this.communicationManager.SendMessage(MessageType.TestMessage, testMessagePayload, this.protocolVersion); } /// @@ -262,7 +262,7 @@ public void SendExecutionComplete( ExecutorUris = executorUris }; - this.communicationManager.SendMessage(MessageType.ExecutionComplete, payload, protocolVersion); + this.communicationManager.SendMessage(MessageType.ExecutionComplete, payload, this.protocolVersion); } /// @@ -275,7 +275,7 @@ public void DiscoveryComplete(long totalTests, IEnumerable lastChunk, IsAborted = isAborted }; - this.communicationManager.SendMessage(MessageType.DiscoveryComplete, discoveryCompletePayload, protocolVersion); + this.communicationManager.SendMessage(MessageType.DiscoveryComplete, discoveryCompletePayload, this.protocolVersion); } /// @@ -289,7 +289,7 @@ public int LaunchProcessWithDebuggerAttached(TestProcessStartInfo testProcessSta waitHandle.Set(); }; - this.communicationManager.SendMessage(MessageType.LaunchAdapterProcessWithDebuggerAttached, testProcessStartInfo, protocolVersion); + this.communicationManager.SendMessage(MessageType.LaunchAdapterProcessWithDebuggerAttached, testProcessStartInfo, this.protocolVersion); waitHandle.WaitOne(); this.onAckMessageRecieved = null; diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs index f13036a3f4..ce70de97b8 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs @@ -99,7 +99,7 @@ public Guid Id set { - this.SetLocalPropertyValue(TestCaseProperties.Id, value); + this.SetPropertyValue(TestCaseProperties.Id, value); } } @@ -116,7 +116,7 @@ public string FullyQualifiedName set { - this.SetLocalPropertyValue(TestCaseProperties.FullyQualifiedName, value); + this.SetPropertyValue(TestCaseProperties.FullyQualifiedName, value); // Id is based on Name/Source, will nulll out guid and it gets calc next time we access it. this.defaultId = Guid.Empty; @@ -136,7 +136,7 @@ public string DisplayName set { - this.SetLocalPropertyValue(TestCaseProperties.DisplayName, value); + this.SetPropertyValue(TestCaseProperties.DisplayName, value); } } @@ -153,7 +153,7 @@ public Uri ExecutorUri set { - this.SetLocalPropertyValue(TestCaseProperties.ExecutorUri, value); + this.SetPropertyValue(TestCaseProperties.ExecutorUri, value); } } @@ -170,7 +170,7 @@ public string Source private set { - this.SetLocalPropertyValue(TestCaseProperties.Source, value); + this.SetPropertyValue(TestCaseProperties.Source, value); // Id is based on Name/Source, will nulll out guid and it gets calc next time we access it. this.defaultId = Guid.Empty; @@ -190,7 +190,7 @@ public string CodeFilePath set { - this.SetLocalPropertyValue(TestCaseProperties.CodeFilePath, value); + this.SetPropertyValue(TestCaseProperties.CodeFilePath, value); } } @@ -207,7 +207,7 @@ public int LineNumber set { - this.SetLocalPropertyValue(TestCaseProperties.LineNumber, value); + this.SetPropertyValue(TestCaseProperties.LineNumber, value); } } @@ -244,6 +244,55 @@ private Guid GetTestId() } #endregion + + #region Protected Methods + + /// + /// Return TestProperty's value + /// + /// + protected override object ProtectedGetPropertyValue(TestProperty property, object defaultValue) + { + ValidateArg.NotNull(property, "property"); + + if (this.localStore.TryGetValue(property, out var value)) + { + return value; + } + + return base.ProtectedGetPropertyValue(property, defaultValue); + } + + /// + /// Set TestProperty's value + /// + protected override void ProtectedSetPropertyValue(TestProperty property, object value) + { + ValidateArg.NotNull(property, "property"); + + switch (property.Id) + { + case "TestCase.Id": + case "TestCase.ExecutorUri": + case "TestCase.FullyQualifiedName": + case "TestCase.DisplayName": + case "TestCase.Source": + case "TestCase.CodeFilePath": + case "TestCase.LineNumber": + if (property.ValidateValueCallback == null || property.ValidateValueCallback(value)) + { + this.localStore[property] = value; + } + else + { + throw new ArgumentException(property.Label); + } + return; + } + base.ProtectedSetPropertyValue(property, value); + } + + #endregion } /// diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestObject.cs b/src/Microsoft.TestPlatform.ObjectModel/TestObject.cs index f589265e7f..423eb9e523 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestObject.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestObject.cs @@ -31,7 +31,7 @@ public abstract class TestObject /// /// The store for all the local properties registered. /// - private readonly Dictionary localStore; + protected readonly Dictionary localStore; /// /// Property used for Json (de)serialization of store dictionary. Serialization of dictionaries @@ -73,9 +73,9 @@ private List> StoreKeyValuePairs /// Returns the list of testproperties associated with the test object /// /// - public List> GetProperties() + public IEnumerable> GetProperties() { - return this.store.Concat(this.localStore).ToList(); + return this.localStore.Concat(this.store); } #endregion Fields @@ -119,7 +119,7 @@ public void CacheLazyValuesOnSerializing(StreamingContext context) /// public IEnumerable Properties { - get { return this.store.Keys.Concat(this.localStore.Keys); } + get { return this.localStore.Keys.Concat(this.store.Keys); } } /// @@ -139,7 +139,7 @@ public object GetPropertyValue(TestProperty property) defaultValue = Activator.CreateInstance(valueType); } - return this.PrivateGetPropertyValue(property, defaultValue); + return this.ProtectedGetPropertyValue(property, defaultValue); } /// @@ -183,7 +183,7 @@ public void SetPropertyValue(TestProperty property, LazyPropertyValue valu /// value to be set public void SetPropertyValue(TestProperty property, object value) { - this.PrivateSetPropertyValue(property, value, this.store); + this.ProtectedSetPropertyValue(property, value); } /// @@ -201,7 +201,6 @@ public void RemovePropertyValue(TestProperty property) } } - /// /// Returns TestProperty's value /// @@ -211,7 +210,7 @@ public T GetPropertyValue(TestProperty property, T defaultValue, CultureInfo ValidateArg.NotNull(property, "property"); ValidateArg.NotNull(culture, "culture"); - object objValue = this.PrivateGetPropertyValue(property, defaultValue); + object objValue = this.ProtectedGetPropertyValue(property, defaultValue); return ConvertPropertyTo(property, culture, objValue); } @@ -226,7 +225,7 @@ public void SetPropertyValue(TestProperty property, T value, CultureInfo cult object objValue = ConvertPropertyFrom(property, culture, value); - this.PrivateSetPropertyValue(property, objValue, this.store); + this.ProtectedSetPropertyValue(property, objValue); } /// @@ -239,18 +238,7 @@ public void SetPropertyValue(TestProperty property, LazyPropertyValue valu object objValue = ConvertPropertyFrom(property, culture, value); - this.PrivateSetPropertyValue(property, objValue, this.store); - } - - /// - /// Set TestProperty's value to the specified value T. - /// - protected void SetLocalPropertyValue(TestProperty property, T value) - { - ValidateArg.NotNull(property, "property"); - - object objValue = ConvertPropertyFrom(property, CultureInfo.InvariantCulture, value); - this.PrivateSetPropertyValue(property, objValue, this.localStore); + this.ProtectedSetPropertyValue(property, objValue); } #endregion Property Values @@ -261,12 +249,12 @@ protected void SetLocalPropertyValue(TestProperty property, T value) /// Return TestProperty's value /// /// - private object PrivateGetPropertyValue(TestProperty property, object defaultValue) + protected virtual object ProtectedGetPropertyValue(TestProperty property, object defaultValue) { ValidateArg.NotNull(property, "property"); object value; - if (!this.store.TryGetValue(property, out value) && !this.localStore.TryGetValue(property, out value)) + if (!this.store.TryGetValue(property, out value) ) { value = defaultValue; } @@ -277,13 +265,13 @@ private object PrivateGetPropertyValue(TestProperty property, object defaultValu /// /// Set TestProperty's value /// - private void PrivateSetPropertyValue(TestProperty property, object value, Dictionary dictionary) + protected virtual void ProtectedSetPropertyValue(TestProperty property, object value) { ValidateArg.NotNull(property, "property"); if (property.ValidateValueCallback == null || property.ValidateValueCallback(value)) { - dictionary[property] = value; + this.store[property] = value; } else { @@ -295,7 +283,7 @@ private void PrivateSetPropertyValue(TestProperty property, object value, Dictio /// Convert passed in value from TestProperty's specified value type. /// /// Converted object - internal static object ConvertPropertyFrom(TestProperty property, CultureInfo culture, object value) + private static object ConvertPropertyFrom(TestProperty property, CultureInfo culture, object value) { ValidateArg.NotNull(property, "property"); ValidateArg.NotNull(culture, "culture"); diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestResult.cs b/src/Microsoft.TestPlatform.ObjectModel/TestResult.cs index 7b176f8989..2c0271c7d3 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestResult.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestResult.cs @@ -71,7 +71,7 @@ public TestOutcome Outcome set { - this.SetLocalPropertyValue(TestResultProperties.Outcome, value); + this.SetPropertyValue(TestResultProperties.Outcome, value); } } @@ -88,7 +88,7 @@ public string ErrorMessage set { - this.SetLocalPropertyValue(TestResultProperties.ErrorMessage, value); + this.SetPropertyValue(TestResultProperties.ErrorMessage, value); } } @@ -105,7 +105,7 @@ public string ErrorStackTrace set { - this.SetLocalPropertyValue(TestResultProperties.ErrorStackTrace, value); + this.SetPropertyValue(TestResultProperties.ErrorStackTrace, value); } } @@ -122,7 +122,7 @@ public string DisplayName set { - this.SetLocalPropertyValue(TestResultProperties.DisplayName, value); + this.SetPropertyValue(TestResultProperties.DisplayName, value); } } @@ -149,7 +149,7 @@ public string ComputerName set { - this.SetLocalPropertyValue(TestResultProperties.ComputerName, value); + this.SetPropertyValue(TestResultProperties.ComputerName, value); } } @@ -166,7 +166,7 @@ public TimeSpan Duration set { - this.SetLocalPropertyValue(TestResultProperties.Duration, value); + this.SetPropertyValue(TestResultProperties.Duration, value); } } @@ -183,7 +183,7 @@ public DateTimeOffset StartTime set { - this.SetLocalPropertyValue(TestResultProperties.StartTime, value); + this.SetPropertyValue(TestResultProperties.StartTime, value); } } @@ -200,7 +200,7 @@ public DateTimeOffset EndTime set { - this.SetLocalPropertyValue(TestResultProperties.EndTime, value); + this.SetPropertyValue(TestResultProperties.EndTime, value); } } @@ -266,6 +266,56 @@ public override string ToString() } #endregion + + #region Protected Methods + + /// + /// Return TestProperty's value + /// + /// + protected override object ProtectedGetPropertyValue(TestProperty property, object defaultValue) + { + ValidateArg.NotNull(property, "property"); + + if (this.localStore.TryGetValue(property, out var value)) + { + return value; + } + + return base.ProtectedGetPropertyValue(property, defaultValue); + } + + /// + /// Set TestProperty's value + /// + protected override void ProtectedSetPropertyValue(TestProperty property, object value) + { + ValidateArg.NotNull(property, "property"); + + switch (property.Id) + { + case "TestResult.DisplayName": + case "TestResult.ComputerName": + case "TestResult.Outcome": + case "TestResult.Duration": + case "TestResult.StartTime": + case "TestResult.EndTime": + case "TestResult.ErrorMessage": + case "TestResult.ErrorStackTrace": + if (property.ValidateValueCallback == null || property.ValidateValueCallback(value)) + { + this.localStore[property] = value; + } + else + { + throw new ArgumentException(property.Label); + } + return; + } + base.ProtectedSetPropertyValue(property, value); + } + + #endregion } /// diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.PlatformTests/SocketCommunicationManagerTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.PlatformTests/SocketCommunicationManagerTests.cs index 8e6088e93e..a922d6aeb4 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.PlatformTests/SocketCommunicationManagerTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.PlatformTests/SocketCommunicationManagerTests.cs @@ -22,6 +22,8 @@ public class SocketCommunicationManagerTests : IDisposable private const string TestDiscoveryStartMessageWithDummyPayload = "{\"MessageType\":\"TestDiscovery.Start\",\"Payload\":\"Dummy Payload\"}"; + private const string TestDiscoveryStartMessageWithVersionAndPayload = "{\"Version\":2,\"MessageType\":\"TestDiscovery.Start\",\"Payload\":\"Dummy Payload\"}"; + private const string DummyPayload = "Dummy Payload"; private readonly SocketCommunicationManager communicationManager; @@ -187,6 +189,16 @@ public async Task SendMessageWithPayloadShouldSerializeAndSendThePayload() Assert.AreEqual(TestDiscoveryStartMessageWithDummyPayload, this.ReadFromStream(client.GetStream())); } + [TestMethod] + public async Task SendMessageWithPayloadShouldSerializeAndSendThePayloadWithVersionStamped() + { + var client = await this.StartServerAndWaitForConnection(); + + this.communicationManager.SendMessage(MessageType.StartDiscovery, DummyPayload, 2); + + Assert.AreEqual(TestDiscoveryStartMessageWithVersionAndPayload, this.ReadFromStream(client.GetStream())); + } + [TestMethod] public async Task SendMessageWithRawMessageShouldNotSerializeThePayload() { @@ -217,12 +229,13 @@ public async Task ReceiveMessageShouldReceiveDeserializedMessage() public async Task ReceiveMessageAsyncShouldReceiveDeserializedMessage() { var client = await this.StartServerAndWaitForConnection(); - this.WriteToStream(client.GetStream(), TestDiscoveryStartMessageWithDummyPayload); + this.WriteToStream(client.GetStream(), TestDiscoveryStartMessageWithVersionAndPayload); var message = await this.communicationManager.ReceiveMessageAsync(CancellationToken.None); - - Assert.AreEqual(MessageType.StartDiscovery, message.MessageType); - Assert.AreEqual(DummyPayload, message.Payload); + var versionedMessage = message as VersionedMessage; + Assert.AreEqual(MessageType.StartDiscovery, versionedMessage.MessageType); + Assert.AreEqual(DummyPayload, versionedMessage.Payload); + Assert.AreEqual(2, versionedMessage.Version); } [TestMethod] diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestCaseSerializationTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestCaseSerializationTests.cs index 274e7a7b48..f28f1f0dda 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestCaseSerializationTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestCaseSerializationTests.cs @@ -39,24 +39,24 @@ public void TestCaseJsonShouldContainAllPropertiesOnSerialization() dynamic data = JObject.Parse(json); dynamic properties = data["Properties"]; - // Traits require special handling with TestPlatformContract resolver. It should be null without it. - Assert.AreEqual("TestObject.Traits", properties[0]["Key"]["Id"].Value); - Assert.IsNotNull(properties[0]["Value"]); + Assert.AreEqual("TestCase.FullyQualifiedName", properties[0]["Key"]["Id"].Value); + Assert.AreEqual("sampleTestClass.sampleTestCase", properties[0]["Value"].Value); + Assert.AreEqual("TestCase.ExecutorUri", properties[1]["Key"]["Id"].Value); + Assert.AreEqual("executor://sampleTestExecutor", properties[1]["Value"].Value); + Assert.AreEqual("TestCase.Source", properties[2]["Key"]["Id"].Value); + Assert.AreEqual("sampleTest.dll", properties[2]["Value"].Value); + Assert.AreEqual("TestCase.CodeFilePath", properties[3]["Key"]["Id"].Value); + Assert.AreEqual("/user/src/testFile.cs", properties[3]["Value"].Value); + Assert.AreEqual("TestCase.DisplayName", properties[4]["Key"]["Id"].Value); + Assert.AreEqual("sampleTestCase", properties[4]["Value"].Value); + Assert.AreEqual("TestCase.Id", properties[5]["Key"]["Id"].Value); + Assert.AreEqual("be78d6fc-61b0-4882-9d07-40d796fd96ce", properties[5]["Value"].Value); + Assert.AreEqual("TestCase.LineNumber", properties[6]["Key"]["Id"].Value); + Assert.AreEqual(999, properties[6]["Value"].Value); - Assert.AreEqual("TestCase.FullyQualifiedName", properties[1]["Key"]["Id"].Value); - Assert.AreEqual("sampleTestClass.sampleTestCase", properties[1]["Value"].Value); - Assert.AreEqual("TestCase.ExecutorUri", properties[2]["Key"]["Id"].Value); - Assert.AreEqual("executor://sampleTestExecutor", properties[2]["Value"].Value); - Assert.AreEqual("TestCase.Source", properties[3]["Key"]["Id"].Value); - Assert.AreEqual("sampleTest.dll", properties[3]["Value"].Value); - Assert.AreEqual("TestCase.CodeFilePath", properties[4]["Key"]["Id"].Value); - Assert.AreEqual("/user/src/testFile.cs", properties[4]["Value"].Value); - Assert.AreEqual("TestCase.DisplayName", properties[5]["Key"]["Id"].Value); - Assert.AreEqual("sampleTestCase", properties[5]["Value"].Value); - Assert.AreEqual("TestCase.Id", properties[6]["Key"]["Id"].Value); - Assert.AreEqual("be78d6fc-61b0-4882-9d07-40d796fd96ce", properties[6]["Value"].Value); - Assert.AreEqual("TestCase.LineNumber", properties[7]["Key"]["Id"].Value); - Assert.AreEqual(999, properties[7]["Value"].Value); + // Traits require special handling with TestPlatformContract resolver. It should be null without it. + Assert.AreEqual("TestObject.Traits", properties[7]["Key"]["Id"].Value); + Assert.IsNotNull(properties[7]["Value"]); } [TestMethod] @@ -108,6 +108,21 @@ public void TestCaseObjectShouldDeserializeEscapedWindowsPath() Assert.AreEqual(@"C:\Test\TestAssembly.dll", test.Source); } + [TestMethod] + public void TestCaseObjectShouldSerializeTraitsWithSpecialCharacters() + { + var test = new TestCase("a.b", new Uri("uri://x"), @"/tmp/a.b.dll"); + test.Traits.Add("t", @"SDJDDHW>,:&^%//\\\\"); + + var json = Serialize(test); + + // Use raw deserialization to validate basic properties + dynamic data = JObject.Parse(json); + dynamic properties = data["Properties"]; + Assert.AreEqual(@"TestObject.Traits", properties[3]["Key"]["Id"].Value); + Assert.AreEqual("[{\"Key\":\"t\",\"Value\":\"SDJDDHW>,:&^%//\\\\\\\\\\\\\\\\\"}]", properties[3]["Value"].ToString(Formatting.None)); + } + #endregion #region v2 Tests @@ -152,6 +167,21 @@ public void TestCaseObjectShouldContainAllPropertiesOnDeserializationV2() Assert.AreEqual(testCase.Id, test.Id); } + [TestMethod] + public void TestCaseObjectShouldSerializeTraitsWithSpecialCharactersV2() + { + var test = new TestCase("a.b", new Uri("uri://x"), @"/tmp/a.b.dll"); + test.Traits.Add("t", @"SDJDDHW>,:&^%//\\\\"); + + var json = Serialize(test, 2); + + // Use raw deserialization to validate basic properties + dynamic data = JObject.Parse(json); + dynamic properties = data["Properties"]; + Assert.AreEqual(@"TestObject.Traits", properties[0]["Key"]["Id"].Value); + Assert.AreEqual("[{\"Key\":\"t\",\"Value\":\"SDJDDHW>,:&^%//\\\\\\\\\\\\\\\\\"}]", properties[0]["Value"].ToString(Formatting.None)); + } + [TestMethod] public void TestCaseObjectShouldSerializeWindowsPathWithEscapingV2() { @@ -178,23 +208,6 @@ public void TestCaseObjectShouldDeserializeEscapedWindowsPathV2() #region Common Tests - [TestMethod] - [DataRow(1)] - [DataRow(2)] - public void TestCaseObjectShouldSerializeTraitsWithSpecialCharacters(int version) - { - var test = new TestCase("a.b", new Uri("uri://x"), @"/tmp/a.b.dll"); - test.Traits.Add("t", @"SDJDDHW>,:&^%//\\\\"); - - var json = Serialize(test, version); - - // Use raw deserialization to validate basic properties - dynamic data = JObject.Parse(json); - dynamic properties = data["Properties"]; - Assert.AreEqual(@"TestObject.Traits", properties[0]["Key"]["Id"].Value); - Assert.AreEqual("[{\"Key\":\"t\",\"Value\":\"SDJDDHW>,:&^%//\\\\\\\\\\\\\\\\\"}]", properties[0]["Value"].ToString(Formatting.None)); - } - [TestMethod] [DataRow(1)] [DataRow(2)] diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs index f05c4108c9..bcc185ed90 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs @@ -93,6 +93,7 @@ public void TestResultObjectShouldSerializeAttachments() var result = new TestResult(testCase); result.Attachments.Add(new AttachmentSet(new Uri("http://dummyUri"), "sampleAttachment")); var expectedJson = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"}]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Messages\":[],\"Properties\":[]}"; + var json = Serialize(result); Assert.AreEqual(expectedJson, json); @@ -161,6 +162,7 @@ public void TestResultObjectShouldSerializeAttachmentsV2() var result = new TestResult(testCase); result.Attachments.Add(new AttachmentSet(new Uri("http://dummyUri"), "sampleAttachment")); var expectedJson = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.ExecutorUri\",\"Label\":\"Executor Uri\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Uri\"},\"Value\":\"executor://sampleTestExecutor\"},{\"Key\":{\"Id\":\"TestCase.Source\",\"Label\":\"Source\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTest.dll\"}]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Messages\":[],\"Properties\":[]}"; + var json = Serialize(result); Assert.AreEqual(expectedJson, json); diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs index 36190a1860..45ea11e6c6 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/TestRequestSenderTests.cs @@ -77,29 +77,30 @@ public void VersionCheckWithTestHostShouldCheckVersionIfVersionCheckPassesReturn { var message = new Message() { MessageType = MessageType.VersionCheck, Payload = this.version }; this.mockCommunicationManager.Setup(mc => mc.ReceiveMessage()).Returns(message); - var success = this.testRequestSender.CheckVersionWithTestHost(); + + this.testRequestSender.CheckVersionWithTestHost(); + this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.VersionCheck, this.version), Times.Once); - Assert.IsTrue(success); } [TestMethod] - public void VersionCheckWithTestHostShouldBeAbleToReceiveProtocolErrorAndReturnFalse() + public void VersionCheckWithTestHostShouldBeAbleToReceiveProtocolErrorAndThrowException() { var message = new Message() { MessageType = MessageType.ProtocolError, Payload = this.version }; this.mockCommunicationManager.Setup(mc => mc.ReceiveMessage()).Returns(message); - var success = this.testRequestSender.CheckVersionWithTestHost(); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.VersionCheck, this.version), Times.Once); - Assert.IsFalse(success); + + var ex = Assert.ThrowsException(() => this.testRequestSender.CheckVersionWithTestHost()); + Assert.AreEqual("Protocol version check failed. Make sure test runner and host are compatible.", ex.Message); } [TestMethod] - public void VersionCheckWithTestHostForInvalidMessageShouldReturnFalse() + public void VersionCheckWithTestHostForInvalidMessageShouldThrowException() { var message = new Message() { MessageType = MessageType.TestCasesFound, Payload = null }; this.mockCommunicationManager.Setup(mc => mc.ReceiveMessage()).Returns(message); - var success = this.testRequestSender.CheckVersionWithTestHost(); - this.mockCommunicationManager.Verify(mc => mc.SendMessage(MessageType.VersionCheck, this.version), Times.Once); - Assert.IsFalse(success); + + var ex = Assert.ThrowsException(() => this.testRequestSender.CheckVersionWithTestHost()); + Assert.AreEqual("Unexpected message received. Expected MessageType : ProtocolVersion Actual MessageType: TestDiscovery.TestFound", ex.Message); } [TestMethod] diff --git a/test/Microsoft.TestPlatform.ObjectModel.UnitTests/TestObjectTests.cs b/test/Microsoft.TestPlatform.ObjectModel.UnitTests/TestObjectTests.cs index 6f04c4f19f..e910b4ad26 100644 --- a/test/Microsoft.TestPlatform.ObjectModel.UnitTests/TestObjectTests.cs +++ b/test/Microsoft.TestPlatform.ObjectModel.UnitTests/TestObjectTests.cs @@ -8,6 +8,7 @@ namespace Microsoft.TestPlatform.ObjectModel.UnitTests using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Generic; + using System.Linq; [TestClass] public class TestObjectTests @@ -39,8 +40,8 @@ public void GetPropertiesShouldReturnListOfPropertiesInStore() var kvp = new KeyValuePair(tp, 123); testCase.SetPropertyValue(kvp.Key, kvp.Value); - var properties = testCase.GetProperties(); - properties.Contains(kvp); + var properties = testCase.GetProperties().ToList(); + Assert.IsTrue(properties.Contains(kvp)); } } } diff --git a/test/Microsoft.TestPlatform.PerformanceTests/ProtocolV1Tests.cs b/test/Microsoft.TestPlatform.PerformanceTests/ProtocolV1Tests.cs new file mode 100644 index 0000000000..7f78e23b16 --- /dev/null +++ b/test/Microsoft.TestPlatform.PerformanceTests/ProtocolV1Tests.cs @@ -0,0 +1,124 @@ +// 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.PerformanceTests +{ + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System; + using System.Diagnostics; + using System.IO; + + using TestResult = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestResult; + + [TestClass] + public class ProtocolV1Tests + { + private static TestCase testCase = new TestCase( + "sampleTestClass.sampleTestCase", + new Uri("executor://sampleTestExecutor"), + "sampleTest.dll") + { + CodeFilePath = "/user/src/testFile.cs", + DisplayName = "sampleTestCase", + Id = new Guid("be78d6fc-61b0-4882-9d07-40d796fd96ce"), + LineNumber = 999, + Traits = { new Trait("Priority", "0"), new Trait("Category", "unit") } + }; + + private static DateTimeOffset startTime = new DateTimeOffset(new DateTime(2007, 3, 10, 0, 0, 0, DateTimeKind.Utc)); + + private static TestResult testResult = new TestResult(testCase) + { + // Attachments = ? + // Messages = ? + Outcome = TestOutcome.Passed, + ErrorMessage = "sampleError", + ErrorStackTrace = "sampleStackTrace", + DisplayName = "sampleTestResult", + ComputerName = "sampleComputerName", + Duration = TimeSpan.MaxValue, + StartTime = startTime, + EndTime = DateTimeOffset.MaxValue + }; + + [TestMethod] + public void TestCaseSerialize() + { + Serialize(testCase); + Stopwatch sw = Stopwatch.StartNew(); + + for (int i = 0; i < 10000; i++) + { + Serialize(testCase); + } + sw.Stop(); + + VerifyPerformanceResult("TestCaseSerialize1", 2000, sw.ElapsedMilliseconds); + } + + [TestMethod] + public void TestCaseDeserialize() + { + var json = Serialize(testCase); + Deserialize(json); + + Stopwatch sw = Stopwatch.StartNew(); + for (int i = 0; i < 10000; i++) + { + Deserialize(json); + } + sw.Stop(); + + VerifyPerformanceResult("TestCaseDeserialize1", 2000, sw.ElapsedMilliseconds); + } + + [TestMethod] + public void TestResultSerialize() + { + Serialize(testResult); + Stopwatch sw = Stopwatch.StartNew(); + + for (int i = 0; i < 10000; i++) + { + Serialize(testResult); + } + sw.Stop(); + + VerifyPerformanceResult("TestResultSerialize1", 2000, sw.ElapsedMilliseconds); + } + + [TestMethod] + public void TestResultDeserialize() + { + var json = Serialize(testResult); + Deserialize(json); + + Stopwatch sw = Stopwatch.StartNew(); + for (int i = 0; i < 10000; i++) + { + Deserialize(json); + } + sw.Stop(); + + VerifyPerformanceResult("TestResultDeserialize1", 3500, sw.ElapsedMilliseconds); + } + + private static string Serialize(T data, int version = 1) + { + return JsonDataSerializer.Instance.Serialize(data, version); + } + + private static T Deserialize(string json, int version = 1) + { + return JsonDataSerializer.Instance.Deserialize(json, version); + } + + private static void VerifyPerformanceResult(string scenario, long expectedElapsedTime, long elapsedTime) + { + Assert.IsTrue(elapsedTime < expectedElapsedTime, $"Scenario '{scenario}' doesn't match with expected elapsed time."); + File.AppendAllText(@"E:\ProtocolPerf.txt", $" {scenario} : " + elapsedTime); + } + } +} diff --git a/test/Microsoft.TestPlatform.PerformanceTests/ProtocolV2Tests.cs b/test/Microsoft.TestPlatform.PerformanceTests/ProtocolV2Tests.cs new file mode 100644 index 0000000000..6f677eb873 --- /dev/null +++ b/test/Microsoft.TestPlatform.PerformanceTests/ProtocolV2Tests.cs @@ -0,0 +1,122 @@ +// 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.PerformanceTests +{ + using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; + using Microsoft.VisualStudio.TestPlatform.ObjectModel; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System; + using System.Diagnostics; + using System.IO; + + using TestResult = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestResult; + + [TestClass] + public class ProtocolV2Tests + { + private static TestCase testCase = new TestCase( + "sampleTestClass.sampleTestCase", + new Uri("executor://sampleTestExecutor"), + "sampleTest.dll") + { + CodeFilePath = "/user/src/testFile.cs", + DisplayName = "sampleTestCase", + Id = new Guid("be78d6fc-61b0-4882-9d07-40d796fd96ce"), + LineNumber = 999, + Traits = { new Trait("Priority", "0"), new Trait("Category", "unit") } + }; + + private static DateTimeOffset startTime = new DateTimeOffset(new DateTime(2007, 3, 10, 0, 0, 0, DateTimeKind.Utc)); + + private static TestResult testResult = new TestResult(testCase) + { + // Attachments = ? + // Messages = ? + Outcome = TestOutcome.Passed, + ErrorMessage = "sampleError", + ErrorStackTrace = "sampleStackTrace", + DisplayName = "sampleTestResult", + ComputerName = "sampleComputerName", + Duration = TimeSpan.MaxValue, + StartTime = startTime, + EndTime = DateTimeOffset.MaxValue + }; + + [TestMethod] + public void TestCaseSerialize2() + { + Serialize(testCase, 2); + Stopwatch sw = Stopwatch.StartNew(); + for (int i = 0; i < 10000; i++) + { + Serialize(testCase, 2); + } + sw.Stop(); + + VerifyPerformanceResult("TestCaseSerialize2", 2000, sw.ElapsedMilliseconds); + } + + [TestMethod] + public void TestCaseDeserialize2() + { + var json = Serialize(testCase, 2); + Deserialize(json, 2); + + Stopwatch sw = Stopwatch.StartNew(); + for (int i = 0; i < 10000; i++) + { + Deserialize(json, 2); + } + sw.Stop(); + + VerifyPerformanceResult("TestCaseDeserialize2", 2000, sw.ElapsedMilliseconds); + } + + [TestMethod] + public void TestResultSerialize2() + { + Serialize(testResult, 2); + Stopwatch sw = Stopwatch.StartNew(); + for (int i = 0; i < 10000; i++) + { + Serialize(testResult, 2); + } + sw.Stop(); + + VerifyPerformanceResult("TestResultSerialize2", 2000, sw.ElapsedMilliseconds); + } + + [TestMethod] + public void TestResultDeserialize2() + { + var json = Serialize(testResult, 2); + Deserialize(json, 2); + + Stopwatch sw = Stopwatch.StartNew(); + for (int i = 0; i < 10000; i++) + { + Deserialize(json, 2); + } + sw.Stop(); + + VerifyPerformanceResult("TestResultDeserialize2", 2000, sw.ElapsedMilliseconds); + } + + private static string Serialize(T data, int version = 1) + { + return JsonDataSerializer.Instance.Serialize(data, version); + } + + private static T Deserialize(string json, int version = 1) + { + return JsonDataSerializer.Instance.Deserialize(json, version); + } + + private static void VerifyPerformanceResult(string scenario, long expectedElapsedTime, long elapsedTime) + { + Assert.IsTrue(elapsedTime < expectedElapsedTime, $"Scenario '{scenario}' doesn't match with expected elapsed time."); + File.AppendAllText(@"E:\ProtocolPerf.txt", $" {scenario} : " + elapsedTime); + } + } +} From ec2d3321e6f77ee4cf2c05c3f71280a1821b309c Mon Sep 17 00:00:00 2001 From: Sarabjot Singh Date: Thu, 6 Apr 2017 17:58:05 +0530 Subject: [PATCH 7/7] Fixed the tests using ITestRequestSender.CheckVersionWithTestHost. --- .../Client/ProxyDiscoveryManagerTests.cs | 1 - .../Client/ProxyExecutionManagerTests.cs | 1 - .../Client/ProxyOperationManagerTests.cs | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs index d29dcfe35e..98c74a3605 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyDiscoveryManagerTests.cs @@ -38,7 +38,6 @@ public ProxyDiscoveryManagerTests() { this.mockTestHostManager = new Mock(); this.mockRequestSender = new Mock(); - this.mockRequestSender.Setup(rs => rs.CheckVersionWithTestHost()).Returns(true); this.testDiscoveryManager = new ProxyDiscoveryManager( this.mockRequestSender.Object, this.mockTestHostManager.Object, diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs index 49f2d66578..06e1630ba5 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyExecutionManagerTests.cs @@ -42,7 +42,6 @@ public ProxyExecutionManagerTests() { this.mockTestHostManager = new Mock(); this.mockRequestSender = new Mock(); - this.mockRequestSender.Setup(rs => rs.CheckVersionWithTestHost()).Returns(true); this.mockTestRunCriteria = new Mock(new List { "source.dll" }, 10); this.testExecutionManager = new ProxyExecutionManager(this.mockRequestSender.Object, this.mockTestHostManager.Object, this.clientConnectionTimeout); diff --git a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs index 4928fe3d71..738c577022 100644 --- a/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs +++ b/test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs @@ -37,7 +37,6 @@ public ProxyOperationManagerTests() this.mockTestHostManager = new Mock(); this.mockRequestSender = new Mock(); this.mockRequestSender.Setup(rs => rs.WaitForRequestHandlerConnection(this.connectionTimeout)).Returns(true); - this.mockRequestSender.Setup(rs => rs.CheckVersionWithTestHost()).Returns(true); this.testOperationManager = new TestableProxyOperationManager(this.mockRequestSender.Object, this.mockTestHostManager.Object, this.connectionTimeout); } @@ -156,7 +155,7 @@ public void SetupChannelShouldCheckVersionWithTestHost() public void SetupChannelShouldThrowExceptionIfVersionCheckFails() { // Make the version check fail - this.mockRequestSender.Setup(rs => rs.CheckVersionWithTestHost()).Returns(false); + this.mockRequestSender.Setup(rs => rs.CheckVersionWithTestHost()).Throws(new TestPlatformException("Version check failed")); Assert.ThrowsException(() => this.testOperationManager.SetupChannel(Enumerable.Empty())); }