diff --git a/src/Nest/CommonAbstractions/SerializationBehavior/JsonFormatters/IntStringFormatter.cs b/src/Nest/CommonAbstractions/SerializationBehavior/JsonFormatters/IntStringFormatter.cs new file mode 100644 index 00000000000..0f0de7c34df --- /dev/null +++ b/src/Nest/CommonAbstractions/SerializationBehavior/JsonFormatters/IntStringFormatter.cs @@ -0,0 +1,34 @@ +using System; +using System.Globalization; +using Elasticsearch.Net.Utf8Json; + +namespace Nest +{ + /// + /// A formatter to deserialize an int into a string, + /// and serialize a string into an int. + /// + internal class IntStringFormatter: IJsonFormatter + { + public void Serialize(ref JsonWriter writer, string value, IJsonFormatterResolver formatterResolver) + { + if (int.TryParse(value, out var i)) + writer.WriteInt32(i); + else + throw new InvalidOperationException($"expected a int string value, but found {value}"); + } + + public string Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + switch (reader.GetCurrentJsonToken()) + { + case JsonToken.Number: + return reader.ReadInt32().ToString(CultureInfo.InvariantCulture); + case JsonToken.String: + return reader.ReadString(); + default: + throw new JsonParsingException($"expected string or int but found {reader.GetCurrentJsonToken()}"); + } + } + } +} diff --git a/src/Nest/Modules/SnapshotAndRestore/Snapshot/SnapshotShardFailure.cs b/src/Nest/Modules/SnapshotAndRestore/Snapshot/SnapshotShardFailure.cs index 2cd780bcd3f..cdec5440e59 100644 --- a/src/Nest/Modules/SnapshotAndRestore/Snapshot/SnapshotShardFailure.cs +++ b/src/Nest/Modules/SnapshotAndRestore/Snapshot/SnapshotShardFailure.cs @@ -1,4 +1,5 @@ using System.Runtime.Serialization; +using Elasticsearch.Net.Utf8Json; namespace Nest { @@ -15,6 +16,7 @@ public class SnapshotShardFailure public string Reason { get; set; } [DataMember(Name ="shard_id")] + [JsonFormatter(typeof(IntStringFormatter))] public string ShardId { get; set; } [DataMember(Name ="status")] diff --git a/tests/Tests.Reproduce/GitHubIssue4537.cs b/tests/Tests.Reproduce/GitHubIssue4537.cs new file mode 100644 index 00000000000..f7fae1917c3 --- /dev/null +++ b/tests/Tests.Reproduce/GitHubIssue4537.cs @@ -0,0 +1,77 @@ +using System; +using System.Linq; +using System.Text; +using Elastic.Xunit.XunitPlumbing; +using FluentAssertions; +using Nest; +using Tests.Core.Client; + +namespace Tests.Reproduce +{ + public class GitHubIssue4537 + { + [U] + public void CanDeserializeSnapshotShardFailure() + { + var json = @"{ + ""snapshots"": [ + { + ""snapshot"": ""snapshot_2020-03-31t00:02:18z"", + ""uuid"": ""P9oZzuEfS8qbT-FVZLFSgw"", + ""version_id"": 7040299, + ""version"": ""7.4.2"", + ""indices"": [ ""someIndices"" ], + ""include_global_state"": true, + ""state"": ""FAILED"", + ""reason"": ""Indices don't have primary shards [someIndex]"", + ""start_time"": ""2020-03-31T00:02:21.478Z"", + ""start_time_in_millis"": 1585612941478, + ""end_time"": ""2020-03-31T00:02:25.353Z"", + ""end_time_in_millis"": 1585612945353, + ""duration_in_millis"": 3875, + ""failures"": [ + { + ""index"": ""someIndex"", + ""index_uuid"": ""someIndex"", + ""shard_id"": 1, + ""reason"": ""primary shard is not allocated"", + ""status"": ""INTERNAL_SERVER_ERROR"" + }, + { + ""index"": ""someIndex"", + ""index_uuid"": ""someIndex"", + ""shard_id"": 0, + ""reason"": ""primary shard is not allocated"", + ""status"": ""INTERNAL_SERVER_ERROR"" + }, + { + ""index"": ""someIndex"", + ""index_uuid"": ""someIndex"", + ""shard_id"": 2, + ""reason"": ""primary shard is not allocated"", + ""status"": ""INTERNAL_SERVER_ERROR"" + } + ], + ""shards"": { + ""total"": 78, + ""failed"": 3, + ""successful"": 75 + } + } + ] + }"; + + var client = TestClient.FixedInMemoryClient(Encoding.UTF8.GetBytes(json)); + + Func action = () => client.Snapshot.Get("repo", "snapshot_2020-03-31t00:02:18z"); + + action.Should().NotThrow(); + + var response = action(); + + var failures = response.Snapshots.First().Failures; + failures.Should().HaveCount(3); + failures.First().ShardId.Should().Be("1"); + } + } +}