Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added custom contract resolvers to handle STJ property name attributes #124

Merged
merged 11 commits into from
Jan 5, 2023
3 changes: 3 additions & 0 deletions build/AssemblyVersion.proj
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ Configures the version based on the build number. Assumes $AssemblyVersion has a
depends on each project.
-->
<Project>
<PropertyGroup>
elenavillamil marked this conversation as resolved.
Show resolved Hide resolved
<DisableUsernameInAssemblyVersion></DisableUsernameInAssemblyVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Version)' == '' ">
<BUILD_BUILDNUMBER Condition=" '$(BUILD_BUILDNUMBER)' == '' ">$(MINDARO_BUILD_NUMBER)</BUILD_BUILDNUMBER>
<BUILD_BUILDNUMBER Condition=" '$(BUILD_BUILDNUMBER)' == '' ">$([System.DateTime]::Now.ToString(`yyyyMMdd`))</BUILD_BUILDNUMBER>
Expand Down
6 changes: 3 additions & 3 deletions src/common.json.tests/JsonHelpersTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,23 @@ public void CreateSerializerSettingsDefault()
{
var settings = (JsonSerializerSettings)JsonHelpers.CreateSerializerSettings();
Assert.Equal(Formatting.None, settings.Formatting);
Assert.IsType<CamelCasePropertyNamesContractResolver>(settings.ContractResolver);
Assert.IsType<STJCamelCaseContractResolver>(settings.ContractResolver);
}

[Fact]
public void CreateSerializerSettingsCustomIndentation()
{
var settings = (JsonSerializerSettings)JsonHelpers.CreateSerializerSettings(indented: true);
Assert.Equal(Formatting.Indented, settings.Formatting);
Assert.IsType<CamelCasePropertyNamesContractResolver>(settings.ContractResolver);
Assert.IsType<STJCamelCaseContractResolver>(settings.ContractResolver);
}

[Fact]
public void CreateSerializerSettingsCustomCasing()
{
var settings = (JsonSerializerSettings)JsonHelpers.CreateSerializerSettings(camelCaseContextResolver: false);
Assert.Equal(Formatting.None, settings.Formatting);
Assert.IsType<DefaultContractResolver>(settings.ContractResolver);
Assert.IsType<STJContractResolver>(settings.ContractResolver);
}

[Fact]
Expand Down
6 changes: 4 additions & 2 deletions src/common.json/JsonHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ internal static class JsonHelpers
{
public static Encoding DefaultEncoding { get; } = Encoding.UTF8;

private static IContractResolver CamelCaseContractResolver { get; } = new CamelCasePropertyNamesContractResolver();
private static IContractResolver ContractResolver { get; } = new STJCamelCaseContractResolver();

private static IList<JsonConverter> DefaultConverters { get; } = new List<JsonConverter>
{
Expand Down Expand Up @@ -75,12 +75,13 @@ public static T ParseAndGetProperty<T>(string json, string property)
/// <returns>Returns 'object' to prevent binding issues when clients reference specific versions of Newtonsoft.Json</returns>
public static object CreateSerializerSettings(bool indented = false, bool camelCaseContextResolver = true)
{
IContractResolver contractResolver = camelCaseContextResolver ? (IContractResolver)new STJCamelCaseContractResolver() : new STJContractResolver();
return new JsonSerializerSettings
{
Formatting = indented ? Formatting.Indented : Formatting.None,
TypeNameHandling = TypeNameHandling.None, // SDL Requirements dictate that we use this value
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
ContractResolver = camelCaseContextResolver ? CamelCaseContractResolver : new DefaultContractResolver(),
ContractResolver = contractResolver,
Converters = DefaultConverters,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
Error = (object sender, ErrorEventArgs errorArgs) =>
Expand Down Expand Up @@ -121,6 +122,7 @@ internal static object ConvertSerializerSettings(BridgeJsonSerializerSettings se

/// <summary>
/// This contract resolver is used to ignore particular fields when serializing.
/// TODO: Should this derive from a camelcase resolver? Not sure of use cases for this.
elenavillamil marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
private class PropertyIgnoreSerializerContractResolver : DefaultContractResolver
{
Expand Down
3 changes: 2 additions & 1 deletion src/common.json/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@
[assembly: InternalsVisibleTo("EndpointManager, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("EndpointManager.tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("restorationjob, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("Microsoft.BridgeToKubernetes.LocalAgent, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("Microsoft.BridgeToKubernetes.LocalAgent, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("restorationjob.tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
40 changes: 40 additions & 0 deletions src/common.json/STJContractResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Reflection;
using System.Text.Json.Serialization;

namespace Microsoft.BridgeToKubernetes.Common.Json
{
public class STJContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);

if (member.GetCustomAttribute<JsonPropertyNameAttribute>() is { } stj)
{
property.PropertyName = stj.Name;
return property;
}

return property;
}
}

public class STJCamelCaseContractResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);

if (member.GetCustomAttribute<JsonPropertyNameAttribute>() is { } stj)
{
property.PropertyName = stj.Name;
return property;
}

return property;
}
}

}
1 change: 1 addition & 0 deletions src/common.json/common.json.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.Text.Json" Version="6.0.2" />
</ItemGroup>

<Import Project="$(MSBuildThisFileDirectory)\..\..\build\ClientAssemblyVersion.proj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.AspNetCore.JsonPatch;
using Xunit;
using Newtonsoft.Json.Serialization;
using Microsoft.BridgeToKubernetes.Common.Json;

namespace Microsoft.BridgeToKubernetes.Common.Tests.Extensions
{
Expand All @@ -17,10 +18,7 @@ public void TestGetImageReplacement_Deployment()
{
const string image = "foobar";
var patch = new JsonPatchDocument<V1Deployment>();
patch.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
patch.ContractResolver = new STJCamelCaseContractResolver();
patch.Replace(d => d.Spec.Template.Spec.Containers[0].Image, image);
Assert.Equal(image, patch.TryGetContainerImageReplacementValue());

Expand All @@ -33,10 +31,7 @@ public void TestGetImageReplacement_Pod()
{
const string image = "foobar";
var patch = new JsonPatchDocument<V1Pod>();
patch.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
patch.ContractResolver = new STJCamelCaseContractResolver();
patch.Replace(p => p.Spec.Containers[10].Image, image);
Assert.Equal(image, patch.TryGetContainerImageReplacementValue());

Expand Down
16 changes: 4 additions & 12 deletions src/common/Restore/WorkloadRestorationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using k8s.Models;
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.BridgeToKubernetes.Common.Exceptions;
using Microsoft.BridgeToKubernetes.Common.Json;
using Microsoft.BridgeToKubernetes.Common.Kubernetes;
using Microsoft.BridgeToKubernetes.Common.Logging;
using Microsoft.BridgeToKubernetes.Common.Models;
Expand Down Expand Up @@ -40,10 +41,7 @@ public WorkloadRestorationService(IKubernetesClient kubernetesClient, ILog log)
/// </summary>
public Task RestorePodPatchAsync(PodPatch podPatch, CancellationToken cancellationToken, Action<ProgressMessage> progressCallback = null, bool noThrow = false)
{
podPatch.ReversePatch.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
podPatch.ReversePatch.ContractResolver = new STJCamelCaseContractResolver();
var patchString = JsonConvert.SerializeObject(podPatch.ReversePatch);
string originalImage = podPatch.ReversePatch.TryGetContainerImageReplacementValue();

Expand Down Expand Up @@ -122,10 +120,7 @@ public Task RestoreDeploymentPatchAsync(DeploymentPatch deploymentPatch, Cancell
{
var deployment = deploymentPatch.Deployment;
var reversePatch = deploymentPatch.ReversePatch;
reversePatch.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
reversePatch.ContractResolver = new STJCamelCaseContractResolver();
string originalImage = reversePatch.TryGetContainerImageReplacementValue();
var patchString = JsonConvert.SerializeObject(reversePatch);

Expand Down Expand Up @@ -156,10 +151,7 @@ public Task RestoreStatefulSetPatchAsync(StatefulSetPatch statefulSetPatch, Canc
{
var statefulSet = statefulSetPatch.StatefulSet;
var reversePatch = statefulSetPatch.ReversePatch;
reversePatch.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
reversePatch.ContractResolver = new STJCamelCaseContractResolver();
string originalImage = reversePatch.TryGetContainerImageReplacementValue();
var patchString = JsonConvert.SerializeObject(reversePatch);

Expand Down
26 changes: 26 additions & 0 deletions src/devhostAgent.restorationjob.tests/RestorationJobAppTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using Microsoft.BridgeToKubernetes.Common;
using Microsoft.BridgeToKubernetes.Common.DevHostAgent;
using Microsoft.BridgeToKubernetes.Common.IO;
using Microsoft.BridgeToKubernetes.Common.Json;
using Microsoft.BridgeToKubernetes.Common.Kubernetes;
using Microsoft.BridgeToKubernetes.Common.Logging;
using Microsoft.BridgeToKubernetes.Common.Models;
Expand Down Expand Up @@ -74,6 +75,31 @@ public void PatchTypeTest()
Assert.Equal(knownPatchTypes, allPatchTypes);
}

[Fact]
public void EnsureCanDeserializePatch1()
{
string patchStateJson = File.ReadAllText(Path.Combine("TestData", "DeploymentPatch.json"));
var deploymentPatch = JsonHelpers.DeserializeObject<DeploymentPatch>(patchStateJson);

string name = deploymentPatch.Deployment.Name();
string ns = deploymentPatch.Deployment.Namespace();

Assert.Equal("bikes", name);
Assert.Equal("dev", ns);
}

[Fact]
public void EnsureCanDeserializePatchType()
{
string patchStateJson = File.ReadAllText(Path.Combine("TestData", "DeploymentPatch.json"));

var propertyName = typeof(PatchEntityBase).GetJsonPropertyName(nameof(PatchEntityBase.Type));
string type = JsonHelpers.ParseAndGetProperty<string>(patchStateJson, propertyName);

Assert.Equal(nameof(DeploymentPatch), type);
}


[Fact]
public void EnsureFailedPingsExit()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\devhostagent.restorationjob\devhostAgent.restorationjob.csproj" />
<ProjectReference Include="..\common.json\common.json.csproj" />
<ProjectReference Include="..\devhostagent.restorationjob\devhostAgent.restorationjob.csproj" />
<ProjectReference Include="..\testhelpers\testhelpers.csproj" />
</ItemGroup>
</Project>
15 changes: 3 additions & 12 deletions src/devhostagent.restorationjob/RestorationJobApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,7 @@ private async Task<Uri> _GetAgentEndpointAsync(DeploymentPatch deploymentPatch,
return null;
}

deploymentPatch.ReversePatch.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
deploymentPatch.ReversePatch.ContractResolver = new STJCamelCaseContractResolver();

var devhostAgentPod = pods.Items.Single();
if (devhostAgentPod.Spec.Containers.Select(c => c.Image).Contains(deploymentPatch.ReversePatch.TryGetContainerImageReplacementValue()))
Expand Down Expand Up @@ -294,10 +291,7 @@ private async Task<Uri> _GetAgentEndpointAsync(StatefulSetPatch statefulSetPatch
return null;
}

statefulSetPatch.ReversePatch.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
statefulSetPatch.ReversePatch.ContractResolver = new STJCamelCaseContractResolver();

var devhostAgentPod = pods.Items.Single();
if (devhostAgentPod.Spec.Containers.Select(c => c.Image).Contains(statefulSetPatch.ReversePatch.TryGetContainerImageReplacementValue()))
Expand Down Expand Up @@ -326,10 +320,7 @@ private async Task<Uri> _GetAgentEndpointAsync(StatefulSetPatch statefulSetPatch
/// </summary>
private async Task<Uri> _GetAgentEndpointAsync(PodPatch podPatch, CancellationToken cancellationToken)
{
podPatch.ReversePatch.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
podPatch.ReversePatch.ContractResolver = new STJCamelCaseContractResolver();

string ns = podPatch.Pod.Namespace();
string name = podPatch.Pod.Name();
Expand Down
21 changes: 5 additions & 16 deletions src/library/Connect/KubernetesRemoteEnvironmentManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Microsoft.BridgeToKubernetes.Common;
using Microsoft.BridgeToKubernetes.Common.DevHostAgent;
using Microsoft.BridgeToKubernetes.Common.Exceptions;
using Microsoft.BridgeToKubernetes.Common.Json;
using Microsoft.BridgeToKubernetes.Common.Kubernetes;
using Microsoft.BridgeToKubernetes.Common.Logging;
using Microsoft.BridgeToKubernetes.Common.Models;
Expand Down Expand Up @@ -1033,14 +1034,8 @@ private async Task<bool> _WaitForDeploymentChangedAsync(string namespaceName, st
bool dirty = false;
var patch = new JsonPatchDocument<V1Deployment>();
var reversePatch = new JsonPatchDocument<V1Deployment>();
patch.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
reversePatch.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
patch.ContractResolver = new STJCamelCaseContractResolver();
reversePatch.ContractResolver = new STJCamelCaseContractResolver();
int containerIndex = deployment.Spec.Template.Spec.Containers.ToList().FindIndex(c => c.Name == container.Name);

if (deployment.Spec.Replicas != null && deployment.Spec.Replicas.Value != 1)
Expand Down Expand Up @@ -1124,14 +1119,8 @@ private async Task<bool> _WaitForDeploymentChangedAsync(string namespaceName, st
bool dirty = false;
var patch = new JsonPatchDocument<V1StatefulSet>();
var reversePatch = new JsonPatchDocument<V1StatefulSet>();
patch.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
reversePatch.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
patch.ContractResolver = new STJCamelCaseContractResolver();
reversePatch.ContractResolver = new STJCamelCaseContractResolver();
int containerIndex = statefulSet.Spec.Template.Spec.Containers.ToList().FindIndex(c => c.Name == container.Name);

if (statefulSet.Spec.Replicas != null && statefulSet.Spec.Replicas.Value != 1)
Expand Down