Skip to content

Commit

Permalink
Protocol v2 changes (#672)
Browse files Browse the repository at this point in the history
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 and Performance tests
6. Fixed the issue : SendLog message to be sent post version check.
  • Loading branch information
singhsarab authored Apr 6, 2017
1 parent 080f045 commit 208db29
Show file tree
Hide file tree
Showing 33 changed files with 1,125 additions and 150 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ public interface ICommunicationManager
/// <param name="payload">payload to be sent</param>
void SendMessage(string messageType, object payload);

/// <summary>
/// Writes message to the binary writer with payload
/// </summary>
/// <param name="messageType">Type of Message to be sent, for instance TestSessionStart</param>
/// <param name="payload">payload to be sent</param>
/// <param name="version">version to be sent</param>
void SendMessage(string messageType, object payload, int version);

/// <summary>
/// Send serialized raw message
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,14 @@ public interface IDataSerializer
/// <param name="payload">Payload of the message</param>
/// <returns>Raw Serialized message</returns>
string SerializePayload(string messageType, object payload);

/// <summary>
/// Serializes and creates a raw message given a message type and the object payload
/// </summary>
/// <param name="messageType">Message Type</param>
/// <param name="payload">Payload of the message</param>
/// <param name="version">version to be sent</param>
/// <returns>Raw Serialized message</returns>
string SerializePayload(string messageType, object payload, int version);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ public interface ITestRequestSender : IDisposable
/// <returns>Port Number of the communication channel</returns>
int InitializeCommunication();

/// <summary>
/// Used for protocol version check with TestHost
/// </summary>
void CheckVersionWithTestHost();

/// <summary>
/// Waits for Request Handler to be connected
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -20,26 +19,33 @@ public class JsonDataSerializer : IDataSerializer
{
private static JsonDataSerializer instance;

private static JsonSerializer serializer;
private static JsonSerializer payloadSerializer;
private static JsonSerializer payloadSerializer2;

/// <summary>
/// Prevents a default instance of the <see cref="JsonDataSerializer"/> class from being created.
/// </summary>
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
}

Expand All @@ -61,7 +67,9 @@ public static JsonDataSerializer Instance
/// <returns>A <see cref="Message"/> instance.</returns>
public Message DeserializeMessage(string rawMessage)
{
return JsonConvert.DeserializeObject<Message>(rawMessage);
// Convert to VersionedMessage
// Message can be deserialized to VersionedMessage where version will be 0
return JsonConvert.DeserializeObject<VersionedMessage>(rawMessage);
}

/// <summary>
Expand All @@ -74,28 +82,24 @@ public T DeserializePayload<T>(Message message)
{
T retValue = default(T);

// TODO: Currently we use json serializer auto only for non-testmessage types
// CHECK: Can't we just use auto for everything
if (MessageType.TestMessage.Equals(message.MessageType))
{
retValue = message.Payload.ToObject<T>();
}
else
{
retValue = message.Payload.ToObject<T>(serializer);
}
var versionedMessage = message as VersionedMessage;
var serializer = this.GetPayloadSerializer(versionedMessage?.Version);

retValue = message.Payload.ToObject<T>(serializer);
return retValue;
}

/// <summary>
/// Deserialize raw JSON to an object using the default serializer.
/// </summary>
/// <param name="json">JSON string.</param>
/// <param name="version">Version of serializer to be used.</param>
/// <typeparam name="T">Target type to deserialize.</typeparam>
/// <returns>An instance of <see cref="T"/>.</returns>
public T Deserialize<T>(string json)
public T Deserialize<T>(string json, int version = 1)
{
var serializer = this.GetPayloadSerializer(version);

using (var stringReader = new StringReader(json))
using (var jsonReader = new JsonTextReader(stringReader))
{
Expand All @@ -121,30 +125,41 @@ public string SerializeMessage(string messageType)
/// <returns>Serialized message.</returns>
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);
}
var serializedPayload = JToken.FromObject(payload, payloadSerializer);

return JsonConvert.SerializeObject(new Message { MessageType = messageType, Payload = serializedPayload });
}

/// <summary>
/// Serialize a message with payload.
/// </summary>
/// <param name="messageType">Type of the message.</param>
/// <param name="payload">Payload for the message.</param>
/// <param name="version">Version for the message.</param>
/// <returns>Serialized message.</returns>
public string SerializePayload(string messageType, object payload, int version)
{
var serializer = this.GetPayloadSerializer(version);
var 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);
}

/// <summary>
/// Serialize an object to JSON using default serialization settings.
/// </summary>
/// <typeparam name="T">Type of object to serialize.</typeparam>
/// <param name="data">Instance of the object to serialize.</param>
/// <param name="version">Version to be stamped.</param>
/// <returns>JSON string.</returns>
public string Serialize<T>(T data)
public string Serialize<T>(T data, int version = 1)
{
var serializer = this.GetPayloadSerializer(version);

using (var stringWriter = new StringWriter())
using (var jsonWriter = new JsonTextWriter(stringWriter))
{
Expand All @@ -153,5 +168,10 @@ public string Serialize<T>(T data)
return stringWriter.ToString();
}
}

private JsonSerializer GetPayloadSerializer(int? version)
{
return version == 2 ? payloadSerializer2 : payloadSerializer;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

/// <summary>
/// Construct used for communication
/// </summary>
public class Message
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public static class MessageType
/// </summary>
public const string VersionCheck = "ProtocolVersion";

/// <summary>
/// Protocol Error
/// </summary>
public const string ProtocolError = "ProtocolError";

/// <summary>
/// The session start.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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
{
/// <summary>
/// Construct with version used for communication
/// Introduced in 15.1.0 version and default message protocol v2 onwards.
/// </summary>
public class VersionedMessage : Message
{
/// <summary>
/// Gets or sets the version of the message
/// </summary>
public int Version { get; set; }
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,10 @@
<data name="UnableToCommunicateToTestHost" xml:space="preserve">
<value>Unable to communicate with test host process.</value>
</data>
<data name="UnexpectedMessage" xml:space="preserve">
<value>Unexpected message received. Expected MessageType : {0} Actual MessageType: {1}</value>
</data>
<data name="VersionCheckFailed" xml:space="preserve">
<value>Protocol version check failed. Make sure test runner and host are compatible.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serializati
/// <summary>
/// JSON contract resolver for mapping test platform types.
/// </summary>
public class TestPlatformContractResolver : DefaultContractResolver
public class DefaultTestPlatformContractResolver : DefaultContractResolver
{
/// <inheritdoc/>
protected override JsonContract CreateContract(Type objectType)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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;

/// <summary>
/// Converter used by v1 protocol serializer to serialize TestCase object to and from v1 json
/// </summary>
public class TestCaseConverter : JsonConverter
{
/// <inheritdoc/>
public override bool CanRead => false;

/// <inheritdoc/>
public override bool CanConvert(Type objectType)
{
return typeof(TestCase) == objectType;
}

/// <inheritdoc/>
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();
}

/// <inheritdoc/>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// P2 to P1
var testCase = value as TestCase;
var properties = testCase.GetProperties();

writer.WriteStartObject();
writer.WritePropertyName("Properties");
writer.WriteStartArray();
foreach (var property in properties)
{
serializer.Serialize(writer, property);
}

writer.WriteEndArray();
writer.WriteEndObject();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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;

/// <summary>
/// JSON contract resolver for mapping test platform types for v1 serialization.
/// </summary>
public class TestPlatformContractResolver1 : DefaultTestPlatformContractResolver
{
/// <inheritdoc/>
protected override JsonContract CreateContract(Type objectType)
{
var contract = base.CreateContract(objectType);
if (typeof(TestCase) == objectType)
{
contract.Converter = new TestCaseConverter();
}
else if (typeof(TestResult) == objectType)
{
contract.Converter = new TestResultConverter();
}

return contract;
}
}
}
Loading

0 comments on commit 208db29

Please sign in to comment.