diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs index d0aa538ebe..5eea4ca571 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/JsonDataSerializer.cs @@ -3,6 +3,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities { + using System; using System.IO; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Interfaces; @@ -210,7 +211,29 @@ private T Deserialize(JsonSerializer serializer, JToken jToken) private JsonSerializer GetPayloadSerializer(int? version) { - return version == 2 ? payloadSerializer2 : payloadSerializer; + if (version == null) + { + version = 1; + } + + switch (version) + { + // 0 is used during negotiation + case 0: + case 1: + // Protocol version 3 was accidentally used with serializer v1 and not + // serializer v2, we downgrade to protocol 2 when 3 would be negotiated + // unless this is disabled by VSTEST_DISABLE_PROTOCOL_3_VERSION_DOWNGRADE + // env variable. + case 3: + return payloadSerializer; + case 2: + case 4: + return payloadSerializer2; + default: + throw new NotSupportedException($"Protocol version {version} is not supported. " + + "Ensure it is compatible with the latest serializer or add a new one."); + } } } } diff --git a/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs b/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs index 2edc603016..e0896ab338 100644 --- a/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs +++ b/src/Microsoft.TestPlatform.CommunicationUtilities/TestRequestSender.cs @@ -52,7 +52,8 @@ public class TestRequestSender : ITestRequestSender // that implies host is using version 1. private int protocolVersion = 1; - private int highestSupportedVersion = 3; + // Also check TestRequestHandler. + private int highestSupportedVersion = 4; private TestHostConnectionInfo connectionInfo; diff --git a/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs b/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs index 5319d0bb78..89809c139e 100644 --- a/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs +++ b/src/Microsoft.TestPlatform.CrossPlatEngine/EventHandlers/TestRequestHandler.cs @@ -24,7 +24,9 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities public class TestRequestHandler : ITestRequestHandler { private int protocolVersion = 1; - private int highestSupportedVersion = 3; + + // Also check TestRequestSender. + private int highestSupportedVersion = 4; private readonly IDataSerializer dataSerializer; private ITestHostManagerFactory testHostManagerFactory; @@ -261,7 +263,36 @@ public void OnMessageReceived(object sender, MessageReceivedEventArgs messageRec { case MessageType.VersionCheck: var version = this.dataSerializer.DeserializePayload(message); - this.protocolVersion = Math.Min(version, highestSupportedVersion); + // choose the highest version that we both support + var negotiatedVersion = Math.Min(version, highestSupportedVersion); + // BUT don't choose 3, because protocol version 3 has performance problems in 16.7.1-16.8. Those problems are caused + // by choosing payloadSerializer instead of payloadSerializer2 for protocol version 3. + // + // We cannot just update the code to choose the new serializer, because then that change would apply only to testhost. + // Testhost is is delivered by Microsoft.NET.Test.SDK nuget package, and can be used with an older vstest.console. + // An older vstest.console, that supports protocol version 3, would serialize its messages using payloadSerializer, + // but the fixed testhost would serialize it using payloadSerializer2, resulting in incompatible messages. + // + // Instead we must downgrade to protocol version 2 when 3 would be negotiated. Or higher when higher version + // would be negotiated. + if (negotiatedVersion != 3) + { + this.protocolVersion = negotiatedVersion; + } + else + { + var flag = Environment.GetEnvironmentVariable("VSTEST_DISABLE_PROTOCOL_3_VERSION_DOWNGRADE"); + var flagIsEnabled = flag != null && flag != "0"; + var dowgradeIsDisabled = flagIsEnabled; + if (dowgradeIsDisabled) + { + this.protocolVersion = negotiatedVersion; + } + else + { + this.protocolVersion = 2; + } + } // Send the negotiated protocol to request sender this.channel.Send(this.dataSerializer.SerializePayload(MessageType.VersionCheck, this.protocolVersion)); diff --git a/src/Microsoft.TestPlatform.ObjectModel/Constants.cs b/src/Microsoft.TestPlatform.ObjectModel/Constants.cs index 668f380b6c..9252657190 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Constants.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/Constants.cs @@ -168,7 +168,7 @@ public static class Constants /// /// The default protocol version /// - public static readonly ProtocolConfig DefaultProtocolConfig = new ProtocolConfig { Version = 3 }; + public static readonly ProtocolConfig DefaultProtocolConfig = new ProtocolConfig { Version = 4 }; /// /// The minimum protocol version that has debug support diff --git a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleRequestSender.cs b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleRequestSender.cs index f61b47fdce..2529e8c6bf 100644 --- a/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleRequestSender.cs +++ b/src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/VsTestConsoleRequestSender.cs @@ -37,7 +37,7 @@ internal class VsTestConsoleRequestSender : ITranslationLayerRequestSender private bool handShakeSuccessful = false; - private int protocolVersion = 3; + private int protocolVersion = 4; /// /// Use to cancel blocking tasks associated with vstest.console process diff --git a/test/Microsoft.TestPlatform.Client.UnitTests/DesignMode/DesignModeClientTests.cs b/test/Microsoft.TestPlatform.Client.UnitTests/DesignMode/DesignModeClientTests.cs index 1066cc4f3d..583f3106b9 100644 --- a/test/Microsoft.TestPlatform.Client.UnitTests/DesignMode/DesignModeClientTests.cs +++ b/test/Microsoft.TestPlatform.Client.UnitTests/DesignMode/DesignModeClientTests.cs @@ -39,7 +39,7 @@ public class DesignModeClientTests private readonly DesignModeClient designModeClient; - private readonly int protocolVersion = 3; + private readonly int protocolVersion = 4; private readonly AutoResetEvent complateEvent; @@ -131,8 +131,9 @@ public void DesignModeClientConnectShouldNotSendConnectedIfServerConnectionTimes [TestMethod] public void DesignModeClientDuringConnectShouldHighestCommonVersionWhenReceivedVersionIsGreaterThanSupportedVersion() - { - var verCheck = new Message { MessageType = MessageType.VersionCheck, Payload = 3 }; + { + + var verCheck = new Message { MessageType = MessageType.VersionCheck, Payload = 4 }; var sessionEnd = new Message { MessageType = MessageType.SessionEnd }; this.mockCommunicationManager.Setup(cm => cm.WaitForServerConnection(It.IsAny())).Returns(true); this.mockCommunicationManager.SetupSequence(cm => cm.ReceiveMessage()).Returns(verCheck).Returns(sessionEnd); diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs index 6ddd654e19..f84c978312 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs @@ -23,25 +23,27 @@ public class TestResultSerializationTests 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 - }; - - #region v1 tests + { + // Attachments = ? + // Messages = ? + Outcome = TestOutcome.Passed, + ErrorMessage = "sampleError", + ErrorStackTrace = "sampleStackTrace", + DisplayName = "sampleTestResult", + ComputerName = "sampleComputerName", + Duration = TimeSpan.MaxValue, + StartTime = startTime, + EndTime = DateTimeOffset.MaxValue + }; + + #region v1 serializer Tests (used with protocol 1 and accidentally with 3) [TestMethod] - public void TestResultJsonShouldContainAllPropertiesOnSerialization() + [DataRow(1)] + [DataRow(3)] + public void TestResultJsonShouldContainAllPropertiesOnSerialization(int version) { - var json = Serialize(testResult); + var json = Serialize(testResult, version); // Use raw deserialization to validate basic properties dynamic data = JObject.Parse(json); @@ -67,11 +69,13 @@ public void TestResultJsonShouldContainAllPropertiesOnSerialization() } [TestMethod] - public void TestResultObjectShouldContainAllPropertiesOnDeserialization() + [DataRow(1)] + [DataRow(3)] + public void TestResultObjectShouldContainAllPropertiesOnDeserialization(int version) { 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); + var test = Deserialize(json, version); Assert.AreEqual(testResult.TestCase.Id, test.TestCase.Id); Assert.AreEqual(testResult.Attachments.Count, test.Attachments.Count); @@ -88,7 +92,9 @@ public void TestResultObjectShouldContainAllPropertiesOnDeserialization() } [TestMethod] - public void TestResultObjectShouldSerializeAttachments() + [DataRow(1)] + [DataRow(3)] + public void TestResultObjectShouldSerializeAttachments(int version) { var result = new TestResult(testCase); result.StartTime = default(DateTimeOffset); @@ -96,17 +102,19 @@ public void TestResultObjectShouldSerializeAttachments() 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.CodeFilePath\",\"Label\":\"File Path\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":null},{\"Key\":{\"Id\":\"TestCase.DisplayName\",\"Label\":\"Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.Id\",\"Label\":\"Id\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Guid\"},\"Value\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\"},{\"Key\":{\"Id\":\"TestCase.LineNumber\",\"Label\":\"Line Number\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Int32\"},\"Value\":-1}]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Messages\":[],\"Properties\":[{\"Key\":{\"Id\":\"TestResult.Outcome\",\"Label\":\"Outcome\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"Microsoft.VisualStudio.TestPlatform.ObjectModel.TestOutcome, Microsoft.VisualStudio.TestPlatform.ObjectModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\"},\"Value\":0},{\"Key\":{\"Id\":\"TestResult.ErrorMessage\",\"Label\":\"Error Message\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":null},{\"Key\":{\"Id\":\"TestResult.ErrorStackTrace\",\"Label\":\"Error Stack Trace\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":null},{\"Key\":{\"Id\":\"TestResult.DisplayName\",\"Label\":\"TestResult Display Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":null},{\"Key\":{\"Id\":\"TestResult.ComputerName\",\"Label\":\"Computer Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"\"},{\"Key\":{\"Id\":\"TestResult.Duration\",\"Label\":\"Duration\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.TimeSpan\"},\"Value\":\"00:00:00\"},{\"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\":\"0001-01-01T00:00:00+00:00\"}]}"; - var json = Serialize(result); + var json = Serialize(result, version); Assert.AreEqual(expectedJson, json); } [TestMethod] - public void TestResultObjectShouldDeserializeAttachments() + [DataRow(1)] + [DataRow(3)] + public void TestResultObjectShouldDeserializeAttachments(int version) { 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\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Messages\":[],\"Properties\":[]}"; - var result = Deserialize(json); + var result = Deserialize(json, version); Assert.AreEqual(1, result.Attachments.Count); Assert.AreEqual(new Uri("http://dummyUri"), result.Attachments[0].Uri); @@ -114,14 +122,16 @@ public void TestResultObjectShouldDeserializeAttachments() } [TestMethod] - public void TestResultObjectShouldSerializeDefaultValues() + [DataRow(1)] + [DataRow(3)] + public void TestResultObjectShouldSerializeDefaultValues(int version) { var result = new TestResult(testCase); result.StartTime = default(DateTimeOffset); result.EndTime = default(DateTimeOffset); 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.CodeFilePath\",\"Label\":\"File Path\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":null},{\"Key\":{\"Id\":\"TestCase.DisplayName\",\"Label\":\"Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.Id\",\"Label\":\"Id\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Guid\"},\"Value\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\"},{\"Key\":{\"Id\":\"TestCase.LineNumber\",\"Label\":\"Line Number\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Int32\"},\"Value\":-1}]},\"Attachments\":[],\"Messages\":[],\"Properties\":[{\"Key\":{\"Id\":\"TestResult.Outcome\",\"Label\":\"Outcome\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"Microsoft.VisualStudio.TestPlatform.ObjectModel.TestOutcome, Microsoft.VisualStudio.TestPlatform.ObjectModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\"},\"Value\":0},{\"Key\":{\"Id\":\"TestResult.ErrorMessage\",\"Label\":\"Error Message\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":null},{\"Key\":{\"Id\":\"TestResult.ErrorStackTrace\",\"Label\":\"Error Stack Trace\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":null},{\"Key\":{\"Id\":\"TestResult.DisplayName\",\"Label\":\"TestResult Display Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":null},{\"Key\":{\"Id\":\"TestResult.ComputerName\",\"Label\":\"Computer Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"\"},{\"Key\":{\"Id\":\"TestResult.Duration\",\"Label\":\"Duration\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.TimeSpan\"},\"Value\":\"00:00:00\"},{\"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\":\"0001-01-01T00:00:00+00:00\"}]}"; - var json = Serialize(result); + var json = Serialize(result, version); // Values that should be null: DisplayName, ErrorMessage, ErrorStackTrace // Values that should be empty: ComputerName @@ -129,11 +139,13 @@ public void TestResultObjectShouldSerializeDefaultValues() } [TestMethod] - public void TestResultObjectShouldDeserializeDefaultValues() + [DataRow(1)] + [DataRow(3)] + public void TestResultObjectShouldDeserializeDefaultValues(int version) { 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.CodeFilePath\",\"Label\":\"File Path\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":null},{\"Key\":{\"Id\":\"TestCase.DisplayName\",\"Label\":\"Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"},{\"Key\":{\"Id\":\"TestCase.Id\",\"Label\":\"Id\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Guid\"},\"Value\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\"},{\"Key\":{\"Id\":\"TestCase.LineNumber\",\"Label\":\"Line Number\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.Int32\"},\"Value\":-1}]},\"Attachments\":[],\"Messages\":[],\"Properties\":[{\"Key\":{\"Id\":\"TestResult.Outcome\",\"Label\":\"Outcome\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"Microsoft.VisualStudio.TestPlatform.ObjectModel.TestOutcome, Microsoft.VisualStudio.TestPlatform.ObjectModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\"},\"Value\":0},{\"Key\":{\"Id\":\"TestResult.ErrorMessage\",\"Label\":\"Error Message\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":null},{\"Key\":{\"Id\":\"TestResult.ErrorStackTrace\",\"Label\":\"Error Stack Trace\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":null},{\"Key\":{\"Id\":\"TestResult.DisplayName\",\"Label\":\"TestResult Display Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":null},{\"Key\":{\"Id\":\"TestResult.ComputerName\",\"Label\":\"Computer Name\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.String\"},\"Value\":\"\"},{\"Key\":{\"Id\":\"TestResult.Duration\",\"Label\":\"Duration\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.TimeSpan\"},\"Value\":\"00:00:00\"},{\"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\":\"0001-01-01T00:00:00+00:00\"}]}"; - var result = Deserialize(json); + var result = Deserialize(json, version); Assert.AreEqual(0, result.Attachments.Count); Assert.AreEqual(0, result.Messages.Count); @@ -144,7 +156,9 @@ public void TestResultObjectShouldDeserializeDefaultValues() } [TestMethod] - public void TestResultPropertiesShouldGetRegisteredAsPartOfDeserialization() + [DataRow(1)] + [DataRow(3)] + public void TestResultPropertiesShouldGetRegisteredAsPartOfDeserialization(int version) { TestProperty.TryUnregister("DummyProperty", out var property); var json = "{\"TestCase\":{\"Properties\":[{\"Key\":{\"Id\":\"TestCase.FullyQualifiedName\",\"Label\":\"FullyQualifiedName\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":1,\"ValueType\":\"System.String\"},\"Value\":\"sampleTestClass.sampleTestCase\"}," + @@ -161,19 +175,21 @@ public void TestResultPropertiesShouldGetRegisteredAsPartOfDeserialization() "{\"Key\":{\"Id\":\"TestResult.Duration\",\"Label\":\"Duration\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.TimeSpan\"},\"Value\":\"00:00:00\"},{\"Key\":{\"Id\":\"TestResult.StartTime\",\"Label\":\"Start Time\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.DateTimeOffset\"},\"Value\":\"0001-01-01T00:00:00+00:00\"}," + "{\"Key\":{\"Id\":\"DummyProperty\",\"Label\":\"DummyPropertyLabel\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":5,\"ValueType\":\"System.String\"},\"Value\":\"dummyString\"}," + "{\"Key\":{\"Id\":\"TestResult.EndTime\",\"Label\":\"End Time\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":0,\"ValueType\":\"System.DateTimeOffset\"},\"Value\":\"0001-01-01T00:00:00+00:00\"}]}"; - var test = Deserialize(json); + var test = Deserialize(json, version); this.VerifyDummyPropertyIsRegistered(); } #endregion - #region v2 Tests + #region v2 serializer Tests (used with protocol 2 and 4) [TestMethod] - public void TestResultJsonShouldContainAllPropertiesOnSerializationV2() + [DataRow(2)] + [DataRow(4)] + public void TestResultJsonShouldContainAllPropertiesOnSerializationV2(int version) { - var json = Serialize(testResult, 2); + var json = Serialize(testResult, version); // Use raw deserialization to validate basic properties dynamic data = JObject.Parse(json); @@ -191,11 +207,13 @@ public void TestResultJsonShouldContainAllPropertiesOnSerializationV2() } [TestMethod] - public void TestResultObjectShouldContainAllPropertiesOnDeserializationV2() + [DataRow(2)] + [DataRow(4)] + public void TestResultObjectShouldContainAllPropertiesOnDeserializationV2(int version) { 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); + var test = Deserialize(json, version); Assert.AreEqual(testResult.TestCase.Id, test.TestCase.Id); Assert.AreEqual(testResult.Attachments.Count, test.Attachments.Count); @@ -212,7 +230,9 @@ public void TestResultObjectShouldContainAllPropertiesOnDeserializationV2() } [TestMethod] - public void TestResultObjectShouldSerializeAttachmentsV2() + [DataRow(2)] + [DataRow(4)] + public void TestResultObjectShouldSerializeAttachmentsV2(int version) { var result = new TestResult(testCase); result.StartTime = default(DateTimeOffset); @@ -220,17 +240,19 @@ public void TestResultObjectShouldSerializeAttachmentsV2() result.Attachments.Add(new AttachmentSet(new Uri("http://dummyUri"), "sampleAttachment")); var expectedJson = "{\"TestCase\":{\"Id\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\",\"FullyQualifiedName\":\"sampleTestClass.sampleTestCase\",\"DisplayName\":\"sampleTestClass.sampleTestCase\",\"ExecutorUri\":\"executor://sampleTestExecutor\",\"Source\":\"sampleTest.dll\",\"CodeFilePath\":null,\"LineNumber\":-1,\"Properties\":[]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Outcome\":0,\"ErrorMessage\":null,\"ErrorStackTrace\":null,\"DisplayName\":null,\"Messages\":[],\"ComputerName\":null,\"Duration\":\"00:00:00\",\"StartTime\":\"0001-01-01T00:00:00+00:00\",\"EndTime\":\"0001-01-01T00:00:00+00:00\",\"Properties\":[]}"; - var json = Serialize(result, 2); + var json = Serialize(result, version); Assert.AreEqual(expectedJson, json); } [TestMethod] - public void TestResultObjectShouldDeserializeAttachmentsV2() + [DataRow(2)] + [DataRow(4)] + public void TestResultObjectShouldDeserializeAttachmentsV2(int version) { 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, 2); + var result = Deserialize(json, version); Assert.AreEqual(1, result.Attachments.Count); Assert.AreEqual(new Uri("http://dummyUri"), result.Attachments[0].Uri); @@ -238,25 +260,42 @@ public void TestResultObjectShouldDeserializeAttachmentsV2() } [TestMethod] - public void TestResultPropertiesShouldGetRegisteredAsPartOfDeserializationV2() + [DataRow(2)] + [DataRow(4)] + public void TestResultPropertiesShouldGetRegisteredAsPartOfDeserializationV2(int version) { TestProperty.TryUnregister("DummyProperty", out var property); 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\":[{\"Key\":{\"Id\":\"DummyProperty\",\"Label\":\"DummyPropertyLabel\",\"Category\":\"\",\"Description\":\"\",\"Attributes\":5,\"ValueType\":\"System.String\"},\"Value\":\"dummyString\"},]}"; - var test = Deserialize(json, 2); + var test = Deserialize(json, version); this.VerifyDummyPropertyIsRegistered(); } #endregion - private static string Serialize(T data, int version = 1) + #region future + + [TestMethod] + public void TestResultSerializationShouldThrowWhenProvidedProtocolVersionDoesNotExist() + { + // this is to ensure that introducing a new version is a conscious choice and + // and that we don't fallback to version 1 as it happened with version 3, because the serializer + // only checked for version 2 + var version = int.MaxValue; + + Assert.ThrowsException(() => Serialize(testResult, version)); + } + + #endregion + + private static string Serialize(T data, int version) { return JsonDataSerializer.Instance.Serialize(data, version); } - private static T Deserialize(string json, int version = 1) + private static T Deserialize(string json, int version) { return JsonDataSerializer.Instance.Deserialize(json, version); } diff --git a/test/TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs b/test/TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs index add71d422e..3b2a134a68 100644 --- a/test/TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs +++ b/test/TranslationLayer.UnitTests/VsTestConsoleRequestSenderTests.cs @@ -37,7 +37,7 @@ public class VsTestConsoleRequestSenderTests private readonly int WaitTimeout = 2000; - private int protocolVersion = 3; + private int protocolVersion = 4; private IDataSerializer serializer = JsonDataSerializer.Instance; public VsTestConsoleRequestSenderTests()