diff --git a/sdk/loadtestservice/Azure.Developer.LoadTesting/src/GlobalSuppressions.cs b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/GlobalSuppressions.cs index e4d23f35b57a..c27823d8cbc4 100644 --- a/sdk/loadtestservice/Azure.Developer.LoadTesting/src/GlobalSuppressions.cs +++ b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/GlobalSuppressions.cs @@ -4,3 +4,6 @@ using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Usage", "AZC0001:Use one of the following pre-approved namespace groups (https://azure.github.io/azure-sdk/registered_namespaces.html): Azure.AI, Azure.Analytics, Azure.Communication, Azure.Data, Azure.DigitalTwins, Azure.IoT, Azure.Learn, Azure.Media, Azure.Management, Azure.Messaging, Azure.ResourceManager, Azure.Search, Azure.Security, Azure.Storage, Azure.Template, Azure.Identity, Microsoft.Extensions.Azure", Justification = "", Scope = "namespace", Target = "~N:Azure.Developer.LoadTesting")] +[assembly: SuppressMessage("Usage", "AZC0004:DO provide both asynchronous and synchronous variants for all service methods.", Justification = "")] +[assembly: SuppressMessage("Usage", "AZC0007:DO provide a minimal constructor that takes only the parameters required to connect to the service.", Justification = "", Scope = "member", Target = "~M:Azure.Developer.LoadTesting.TestV2Client.#ctor")] +[assembly: SuppressMessage("Usage", "AZC0002:DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken.", Justification = "", Scope = "member", Target = "~M:Azure.Developer.LoadTesting.TestV2Client.GetTestV2Async(System.String,Azure.RequestContext)~System.Threading.Tasks.Task{Azure.Response}")] diff --git a/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/RoundTripModel.Serialization.cs b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/RoundTripModel.Serialization.cs new file mode 100644 index 000000000000..a91b10ecec24 --- /dev/null +++ b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/RoundTripModel.Serialization.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Text.Json; +using System.Xml.Linq; +using Azure.Core; +using Azure.Core.Json; + +namespace Azure.Developer.LoadTesting.Models +{ + public partial class RoundTripModel : IUtf8JsonSerializable + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) + { + _element.WriteTo(writer, 'P'); // TO-DO: we need another option not calling 'P' but its logic is the same as 'P' + } + + /// Deserializes the model from a raw response. + /// The response to deserialize the model from. + internal static RoundTripModel FromResponse(Response response) + { + MutableJsonDocument jsonDocument = MutableJsonDocument.Parse(response.Content); + return new RoundTripModel(jsonDocument.RootElement); + } + + /// Convert into a Utf8JsonRequestContent. + internal RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this); + return content; + } + } +} diff --git a/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/RoundTripModel.cs b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/RoundTripModel.cs new file mode 100644 index 000000000000..e8f1458bc339 --- /dev/null +++ b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/RoundTripModel.cs @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using System.Xml.Linq; +using Azure.Core; +using Azure.Core.Json; + +namespace Azure.Developer.LoadTesting.Models +{ + /// + /// model RoundTripModel { + /// requiredString: string; + /// requiredNullableInt: int32 | null; + /// requiredNullableString: string | null; + /// nonRequiredNullableInt?: int32 | null; + /// nonRequiredNullableString?: string | null; + /// } + /// + public partial class RoundTripModel + { + private MutableJsonElement _element; + + /// + /// Initializes a new instance of the class. + /// + public RoundTripModel(string requiredString, int? requiredNullableInt, string requiredNullableString) + { + Argument.AssertNotNull(requiredString, nameof(requiredString)); + + BinaryData utf8Json; + using (MemoryStream stream = new()) + { + using Utf8JsonWriter writer = new Utf8JsonWriter(stream); + writer.WriteStartObject(); + writer.WritePropertyName("requiredString"); + writer.WriteStringValue(requiredString); + if (requiredNullableInt != null) + { + writer.WritePropertyName("requiredNullableInt"); + writer.WriteNumberValue(requiredNullableInt.Value); + } + else + { + writer.WriteNull("requiredNullableInt"); + } + if (requiredNullableString != null) + { + writer.WritePropertyName("requiredNullableString"); + writer.WriteStringValue(requiredNullableString); + } + else + { + writer.WriteNull("requiredNullableString"); + } + writer.WriteEndObject(); + writer.Flush(); + stream.Position = 0; + utf8Json = BinaryData.FromStream(stream); + } + _element = MutableJsonDocument.Parse(utf8Json).RootElement; + } + + internal RoundTripModel(MutableJsonElement element) + { + _element = element; + } + + /// Required string, illustrating a reference type property. + public string RequiredString + { + get + { + if (_element.TryGetProperty("requiredString", out MutableJsonElement value)) + { + return value.GetString(); + } + return default; + } + set => _element.SetProperty("requiredString", value); + } + + /// Required nullable int. + public int? RequiredNullableInt + { + get + { + if (_element.TryGetProperty("requiredNullableInt", out MutableJsonElement value)) + { + return value.GetInt32(); + } + return default; + } + set => _element.SetProperty("requiredNullableInt", value); + } + + /// Required nullable string. + public string RequiredNullableString + { + get + { + if (_element.TryGetProperty("requiredNullableString", out MutableJsonElement value)) + { + return value.GetString(); + } + return default; + } + set => _element.SetProperty("requiredNullableString", value); + } + + /// Optional nullable int. + public int? NonRequiredNullableInt + { + get + { + if (_element.TryGetProperty("nonRequiredNullableInt", out MutableJsonElement value)) + { + return value.GetInt32(); + } + return null; + } + set => _element.SetProperty("nonRequiredNullableInt", value); + } + + /// Optional nullable string. + public string NonRequiredNullableString + { + get + { + if (_element.TryGetProperty("nonRequiredNullableString", out MutableJsonElement value)) + { + return value.GetString(); + } + return null; + } + set => _element.SetProperty("nonRequiredNullableString", value); + } + } +} diff --git a/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/TestV2.Serialization.cs b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/TestV2.Serialization.cs new file mode 100644 index 000000000000..f71214d98748 --- /dev/null +++ b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/TestV2.Serialization.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable disable + +using Azure.Core.Serialization; +using Azure.Core; +using Azure.Core.Json; +using System.Text.Json; +using System; + +namespace Azure.Developer.LoadTesting.Models +{ + public partial class TestV2 : IUtf8JsonSerializable, IJsonModelSerializable + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) + { + writer.WriteStartObject(); + writer.WritePropertyName("key"u8); + writer.WriteStringValue(Key); + writer.WritePropertyName("requiredProperty"u8); + writer.WriteNumberValue(RequiredProperty); + if (Optional.IsDefined(OptionalProperty)) + { + writer.WritePropertyName("optionalProperty"u8); + writer.WriteStringValue(OptionalProperty); + } + writer.WriteEndObject(); + } + + void IJsonModelSerializable.Serialize(Utf8JsonWriter writer, ModelSerializerOptions options) + { + ((IUtf8JsonSerializable)this).Write(writer); + } + + object IJsonModelSerializable.Deserialize(ref Utf8JsonReader reader, ModelSerializerOptions options) + { + JsonDocument doc = JsonDocument.ParseValue(ref reader); + MutableJsonDocument mdoc = new MutableJsonDocument(doc, new JsonSerializerOptions()); + return new TestV2(mdoc.RootElement); + } + + object IModelSerializable.Deserialize(BinaryData data, ModelSerializerOptions options) + { + MutableJsonDocument jsonDocument = MutableJsonDocument.Parse(data); + return new TestV2(jsonDocument.RootElement); + } + + BinaryData IModelSerializable.Serialize(ModelSerializerOptions options) => ModelSerializerHelper.SerializeToBinaryData(writer => ((IJsonModelSerializable)this).Serialize(writer, options)); + + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this); + return content; + } + + internal static TestV2 FromResponse(Response response) + { + MutableJsonDocument jsonDocument = MutableJsonDocument.Parse(response.Content); + return new TestV2(jsonDocument.RootElement); + } + } +} diff --git a/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/TestV2.cs b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/TestV2.cs new file mode 100644 index 000000000000..0fc3ddaef5c8 --- /dev/null +++ b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/TestV2.cs @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable disable +using System.IO; +using System.Text.Json; +using System; +using Azure.Core.Json; +using Azure.Core; +using System.Collections.Generic; + +namespace Azure.Developer.LoadTesting.Models +{ + /// + /// model TestV2 { + /// @key + /// key: string; // Because it has @key so there will be a @path implictly added to it. + /// + /// @visibility("read") + /// readOnlyProperty: string; // Add this propery to differentiate request from response. + /// optionalProperty?: string; + /// requiredProperty: int32; + /// } + /// + public partial class TestV2 + { + private MutableJsonElement _element; + + /// + public TestV2(string key, int required) + { + BinaryData utf8Json; + using (MemoryStream stream = new()) + { + using Utf8JsonWriter writer = new Utf8JsonWriter(stream); + writer.WriteStartObject(); + writer.WritePropertyName("key"); + writer.WriteStringValue(key.AsSpan()); + writer.WritePropertyName("requiredProperty"); + writer.WriteNumberValue(required); + writer.WriteEndObject(); + writer.Flush(); + stream.Position = 0; + utf8Json = BinaryData.FromStream(stream); + } + _element = MutableJsonDocument.Parse(utf8Json).RootElement; + } + + internal TestV2(MutableJsonElement element) + { + _element = element; + } + + /// + public string Key + { + get + { + if (_element.TryGetProperty("key", out MutableJsonElement value)) + { + return value.GetString(); + } + return default; + } + set => _element.SetProperty("key", value); + } + + /// + public int RequiredProperty + { + get + { + if (_element.TryGetProperty("requiredProperty", out MutableJsonElement value)) + { + return value.GetInt32(); + } + return default; + } + set => _element.SetProperty("requiredProperty", value); + } + + /// + public string OptionalProperty + { + get + { + if (_element.TryGetProperty("optionalProperty", out MutableJsonElement value)) + { + return value.GetString(); + } + return default; + } + set => _element.SetProperty("optionalProperty", value); + } + + /// + public string ReadOnlyProperty + { + get + { + if (_element.TryGetProperty("readOnlyProperty", out MutableJsonElement value)) + { + return value.GetString(); + } + return default; + } + } + } +} diff --git a/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/TestV2Update.Serialization.cs b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/TestV2Update.Serialization.cs new file mode 100644 index 000000000000..8fc6b9e8b1cb --- /dev/null +++ b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/TestV2Update.Serialization.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Text.Json; +using Azure.Core; +using Azure.Core.Json; +using Azure.Core.Serialization; + +namespace Azure.Developer.LoadTesting.Models +{ + public partial class TestV2Update : IUtf8JsonSerializable, IJsonModelSerializable + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) + { + _element.WriteTo(writer, 'P'); + } + + void IJsonModelSerializable.Serialize(Utf8JsonWriter writer, ModelSerializerOptions options) + { + _element.WriteTo(writer, 'P'); + } + + BinaryData IModelSerializable.Serialize(ModelSerializerOptions options) => ModelSerializerHelper.SerializeToBinaryData(writer => ((IJsonModelSerializable)this).Serialize(writer, options)); + + // Do ew need deserialization + object IJsonModelSerializable.Deserialize(ref Utf8JsonReader reader, ModelSerializerOptions options) + { + JsonDocument doc = JsonDocument.ParseValue(ref reader); + MutableJsonDocument mdoc = new MutableJsonDocument(doc, new JsonSerializerOptions()); + return new TestV2Update(mdoc.RootElement); // We don't know what it means when a property is null + } + + object IModelSerializable.Deserialize(BinaryData data, ModelSerializerOptions options) + { + MutableJsonDocument jsonDocument = MutableJsonDocument.Parse(data); + return new TestV2Update(jsonDocument.RootElement); + } + + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this); + return content; + } + } +} diff --git a/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/TestV2Update.cs b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/TestV2Update.cs new file mode 100644 index 000000000000..556c800965f0 --- /dev/null +++ b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/Models/TestV2Update.cs @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using Azure.Core; +using Azure.Core.Json; + +namespace Azure.Developer.LoadTesting.Models +{ + /// + /// It is the patch model of TestV2, so it would be like + /// model TestV2 { + /// @key + /// key?: string; // Because it has @key so there will be a @path implictly added to it. + /// + /// @visibility("read") + /// readOnlyProperty?: string; // Add this propery to differentiate request from response. + /// optionalProperty?: string; + /// requiredProperty?: int32; + /// } + /// + public partial class TestV2Update + { + private MutableJsonElement _element; + + /// + public TestV2Update() + { + _element = MutableJsonDocument.Parse(MutableJsonDocument.EmptyJson).RootElement; + } + + internal TestV2Update(MutableJsonElement element) + { + _element = element; + } + + /// + public string Key + { + get + { + if (_element.TryGetProperty("key", out MutableJsonElement value)) + { + return value.GetString(); + } + return null; + } + set + { + _element.SetProperty("key", value); + } + } + + /// + public int? RequiredProperty + { + get + { + if (_element.TryGetProperty("requiredProperty", out MutableJsonElement value)) + { + return value.GetInt32(); + } + return null; + } + set + { + _element.SetProperty("requiredProperty", value); + } + } + + /// + public string OptionalProperty + { + get + { + if (_element.TryGetProperty("optionalProperty", out MutableJsonElement value)) + { + return value.GetString(); + } + return null; + } + set => _element.SetProperty("optionalProperty", value); + } + + // We don't generate ReadOnlyProperty as it will not in the request + } +} diff --git a/sdk/loadtestservice/Azure.Developer.LoadTesting/src/TestV2Client.cs b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/TestV2Client.cs new file mode 100644 index 000000000000..ed85730ec5df --- /dev/null +++ b/sdk/loadtestservice/Azure.Developer.LoadTesting/src/TestV2Client.cs @@ -0,0 +1,174 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core.Serialization; +using Azure.Developer.LoadTesting.Models; +using System.IO; +using System.Text.Json; +using System.Threading.Tasks; +using System.Threading; +using System; +using Azure.Core.Pipeline; +using Azure.Core; + +namespace Azure.Developer.LoadTesting +{ + /// + /// + public partial class TestV2Client + { + private readonly HttpPipeline _pipeline = null; + internal ClientDiagnostics ClientDiagnostics { get; } + + /// + /// Initializes a new instance of the class. + /// + public TestV2Client() { } + + /// + /// + /// + /// + /// + /// A representing the result of the asynchronous operation. + public virtual async Task> PatchAsync(string key, TestV2Update resource, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(key, nameof(key)); + Argument.AssertNotNull(resource, nameof(resource)); + + RequestContext context = FromCancellationToken(cancellationToken); + Response response = await PatchAsync(key, resource.ToRequestContent(), context).ConfigureAwait(false); + + return Response.FromValue(TestV2.FromResponse(response), response); + } + + /// + /// + /// + /// + /// + /// A representing the result of the asynchronous operation. + public virtual async Task PatchAsync(string key, RequestContent content, RequestContext context = null) + { + Argument.AssertNotNullOrEmpty(key, nameof(key)); + Argument.AssertNotNull(content, nameof(content)); + + using var scope = ClientDiagnostics.CreateScope("TestV2Client.Patch"); + scope.Start(); + try + { + using HttpMessage message = CreatePatchRequest(key, content, context); + return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal HttpMessage CreatePatchRequest(string key, RequestContent content, RequestContext context) + { + return new HttpMessage(null, null); + } + + /// + /// + /// + /// + /// + /// A representing the result of the asynchronous operation. + public virtual async Task> PutAsync(string key, TestV2 resource, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(key, nameof(key)); + Argument.AssertNotNull(resource, nameof(resource)); + + RequestContext context = FromCancellationToken(cancellationToken); + Response response = await PutAsync(key, resource.ToRequestContent(), context).ConfigureAwait(false); + return Response.FromValue(TestV2.FromResponse(response), response); + } + + /// + /// + /// + /// + /// + /// A representing the result of the asynchronous operation. + public virtual async Task PutAsync(string key, RequestContent content, RequestContext context = null) + { + Argument.AssertNotNullOrEmpty(key, nameof(key)); + Argument.AssertNotNull(content, nameof(content)); + + using var scope = ClientDiagnostics.CreateScope("TestV2Client.Put"); + scope.Start(); + try + { + using HttpMessage message = CreatePutRequest(key, content, context); + return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal HttpMessage CreatePutRequest(string key, RequestContent content, RequestContext context) + { + return new HttpMessage(null, null); + } + + /// + /// + /// + /// + /// A representing the result of the asynchronous operation. + public virtual async Task> GetTestV2Async(string key, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(key, nameof(key)); + + RequestContext context = FromCancellationToken(cancellationToken); + Response response = await GetTestV2Async(key, context).ConfigureAwait(false); + return Response.FromValue(TestV2.FromResponse(response), response); + } + + /// + /// + /// + /// + /// A representing the result of the asynchronous operation. + public virtual async Task GetTestV2Async(string key, RequestContext context) + { + Argument.AssertNotNullOrEmpty(key, nameof(key)); + + using var scope = ClientDiagnostics.CreateScope("WidgetManagerClient.GetTestV2"); + scope.Start(); + try + { + using HttpMessage message = CreateGetRequest(key, context); + return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal HttpMessage CreateGetRequest(string key, RequestContext context) + { + return new HttpMessage(null, null); + } + + private static RequestContext DefaultRequestContext = new RequestContext(); + internal static RequestContext FromCancellationToken(CancellationToken cancellationToken = default) + { + if (!cancellationToken.CanBeCanceled) + { + return DefaultRequestContext; + } + + return new RequestContext() { CancellationToken = cancellationToken }; + } + } +} diff --git a/sdk/loadtestservice/Azure.Developer.LoadTesting/tests/RoundTripModelTests.cs b/sdk/loadtestservice/Azure.Developer.LoadTesting/tests/RoundTripModelTests.cs new file mode 100644 index 000000000000..a8640439e9a7 --- /dev/null +++ b/sdk/loadtestservice/Azure.Developer.LoadTesting/tests/RoundTripModelTests.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.IO; +using System.Text.Json; +using Azure.Core; +using Azure.Developer.LoadTesting.Models; +using NUnit.Framework; +using NUnit.Framework.Internal; + +namespace Azure.Developer.LoadTesting.Tests +{ + public class RoundTripModelTests + { + [Test] + public void TestSolution1() + { + RoundTripModel model = new RoundTripModel("requiredString", null, null); + model.RequiredNullableString = null; + + var payload = Serialize(model.ToRequestContent()); + } + + private static string Serialize(RequestContent content) + { + var memStream = new MemoryStream(); + content.WriteTo(memStream, default); + memStream.Position = 0; + var dsr = new StreamReader(memStream); + return dsr.ReadToEnd(); + } + + private static bool GetProperty(string json, string name, out object value) + { + var document = JsonDocument.Parse(json); + if (document.RootElement.TryGetProperty(name, out var element)) + { + value = element.GetObject(); + return true; + } + value = null; + return false; + } + } +} diff --git a/sdk/loadtestservice/Azure.Developer.LoadTesting/tests/TestV2ClientTest.cs b/sdk/loadtestservice/Azure.Developer.LoadTesting/tests/TestV2ClientTest.cs new file mode 100644 index 000000000000..11a46d0ec20b --- /dev/null +++ b/sdk/loadtestservice/Azure.Developer.LoadTesting/tests/TestV2ClientTest.cs @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Json; +using Azure.Developer.LoadTesting.Models; +using NUnit.Framework; + +namespace Azure.Developer.LoadTesting.Tests +{ + public class TestV2ClientTest + { + [Test] + public void TestV2UpdateSerializeTest() + { + // RequiredProperty could not set + TestV2Update testV2 = new TestV2Update(); + testV2.Key = "key"; + + var payload = Deserialize(testV2.ToRequestContent()); + Assert.AreEqual(true, GetProperty(payload, "key", out var key)); + Assert.AreEqual("key", key); + Assert.AreEqual(false, GetProperty(payload, "requiredProperty", out var requiredProperty)); + + // RequiredProperty could be set null + testV2 = new TestV2Update(); + testV2.RequiredProperty = null; + payload = Deserialize(testV2.ToRequestContent()); + Assert.AreEqual(true, GetProperty(payload, "requiredProperty", out requiredProperty)); + Assert.AreEqual(null, requiredProperty); + } + + [Test] + // This test is make sure the behavior is the same as befpre + public void TestV2SerializeTest() + { + // Should only provide public constructor with required properties + TestV2 testV2 = new TestV2("key", 15); + testV2.OptionalProperty = null; // Only optional property could set + var payload = Deserialize(testV2.ToRequestContent()); + // When optional prperty is null, then it should be not in the payload + Assert.AreEqual(false, GetProperty(payload, "optionalProperty", out var optionalProperty)); + } + + [Test] + // This test is make sure the behavior is the same as befpre + public void TestV2DeserializeTest() + { + // Required properties should be set + var json1 = new + { + key = "key", + requiredProperty = 15 + }; + + MutableJsonDocument jsonDocument = MutableJsonDocument.Parse(new BinaryData(json1)); + TestV2 testV2 = new TestV2(jsonDocument.RootElement); + Assert.AreEqual("key", testV2.Key); + Assert.AreEqual(15, testV2.RequiredProperty); + + // If required property is not set, set to default value + var json2 = new + { + key = "key" + }; + jsonDocument = MutableJsonDocument.Parse(new BinaryData(json2)); + testV2 = new TestV2(jsonDocument.RootElement); + Assert.AreEqual(0, testV2.RequiredProperty); + + // If required property is null. then throw error + var json3 = "{\"key\": \"key\", \"requiredProperty\": null}"; + jsonDocument = MutableJsonDocument.Parse(json3); + testV2 = new TestV2(jsonDocument.RootElement); + // TO-DO: previously the error happens at deserialization after returning from service. Now it happens when we use that property. + Assert.Throws(() => _ = testV2.RequiredProperty); + } + + private static string Deserialize(RequestContent content) + { + var memStream = new MemoryStream(); + content.WriteTo(memStream, default); + memStream.Position = 0; + var dsr = new StreamReader(memStream); + return dsr.ReadToEnd(); + } + + private static bool GetProperty(string json, string name, out object value) + { + var document = JsonDocument.Parse(json); + if (document.RootElement.TryGetProperty(name, out var element)) + { + value = element.GetObject(); + return true; + } + value = null; + return false; + } + } +}