Skip to content

Commit 4e8e619

Browse files
committed
Improved bulk API testing
1 parent 62b2a8c commit 4e8e619

File tree

12 files changed

+257
-59
lines changed

12 files changed

+257
-59
lines changed

Elasticsearch.sln

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,6 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "scripts", "build\scripts\sc
5656
EndProject
5757
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.ClusterLauncher", "tests\Tests.ClusterLauncher\Tests.ClusterLauncher.csproj", "{F6162603-D134-4121-8106-2BA4DAD7350B}"
5858
EndProject
59-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elasticsearch.Net.VirtualizedCluster", "src\Elasticsearch.Net.VirtualizedCluster\Elasticsearch.Net.VirtualizedCluster.csproj", "{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}"
60-
EndProject
6159
Global
6260
GlobalSection(SolutionConfigurationPlatforms) = preSolution
6361
Debug|Any CPU = Debug|Any CPU
@@ -224,18 +222,6 @@ Global
224222
{F6162603-D134-4121-8106-2BA4DAD7350B}.Release|x64.Build.0 = Release|Any CPU
225223
{F6162603-D134-4121-8106-2BA4DAD7350B}.Release|x86.ActiveCfg = Release|Any CPU
226224
{F6162603-D134-4121-8106-2BA4DAD7350B}.Release|x86.Build.0 = Release|Any CPU
227-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
228-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
229-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}.Debug|x64.ActiveCfg = Debug|Any CPU
230-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}.Debug|x64.Build.0 = Debug|Any CPU
231-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}.Debug|x86.ActiveCfg = Debug|Any CPU
232-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}.Debug|x86.Build.0 = Debug|Any CPU
233-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
234-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}.Release|Any CPU.Build.0 = Release|Any CPU
235-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}.Release|x64.ActiveCfg = Release|Any CPU
236-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}.Release|x64.Build.0 = Release|Any CPU
237-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}.Release|x86.ActiveCfg = Release|Any CPU
238-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F}.Release|x86.Build.0 = Release|Any CPU
239225
EndGlobalSection
240226
GlobalSection(SolutionProperties) = preSolution
241227
HideSolutionNode = FALSE
@@ -254,7 +240,6 @@ Global
254240
{11362CEE-B4B3-4EFE-A9A1-A6CDEEFCEA10} = {D455EC79-E1E0-4509-B297-0DA3AED8DFF7}
255241
{68D1BFDC-F447-4D2C-AF81-537807636610} = {1FE49D14-216A-41EE-A177-E42BFF53E0DC}
256242
{F6162603-D134-4121-8106-2BA4DAD7350B} = {362B2776-4B29-46AB-B237-56776B5372B6}
257-
{DFF12151-BB2A-479D-97C6-F4FF6815AA7F} = {D455EC79-E1E0-4509-B297-0DA3AED8DFF7}
258243
EndGlobalSection
259244
GlobalSection(ExtensibilityGlobals) = postSolution
260245
SolutionGuid = {CE74F821-B001-4C69-A58D-CF81F8B0B632}

src/Elastic.Clients.Elasticsearch/Common/Infer/Inferrer.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
using System.Text;
1212
using System.Runtime.Serialization;
1313
using System.Collections;
14+
using System.Text.Json.Serialization;
15+
using System.Text.Json;
1416

1517
namespace Elastic.Clients.Elasticsearch
1618
{
@@ -228,6 +230,7 @@ private static PropertyInfo GetJoinFieldProperty(Type type)
228230
}
229231
}
230232

233+
[JsonConverter(typeof(JoinFieldConverter))]
231234
public class JoinField
232235
{
233236
internal Child ChildOption { get; }
@@ -313,6 +316,23 @@ public Child(RelationName name, Id parent)
313316
}
314317
}
315318

319+
internal sealed class JoinFieldConverter : JsonConverter<JoinField>
320+
{
321+
public override JoinField? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException();
322+
public override void Write(Utf8JsonWriter writer, JoinField value, JsonSerializerOptions options)
323+
{
324+
switch (value.Tag)
325+
{
326+
case 0:
327+
JsonSerializer.Serialize(writer, value.ParentOption.Name, options);
328+
break;
329+
}
330+
331+
// TODO - Finish this
332+
}
333+
}
334+
335+
[JsonConverter(typeof(RelationNameConverter))]
316336
public class RelationName : IEquatable<RelationName>, IUrlParameter
317337
{
318338
private RelationName(string type) => Name = type;
@@ -382,6 +402,26 @@ public bool EqualsMarker(RelationName other)
382402

383403
}
384404

405+
internal sealed class RelationNameConverter : JsonConverter<RelationName>
406+
{
407+
private readonly IElasticsearchClientSettings _settings;
408+
409+
public RelationNameConverter(IElasticsearchClientSettings settings) => _settings = settings;
410+
411+
public override RelationName? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException();
412+
public override void Write(Utf8JsonWriter writer, RelationName value, JsonSerializerOptions options)
413+
{
414+
if (value is null)
415+
{
416+
writer.WriteNullValue();
417+
return;
418+
}
419+
420+
var relationName = _settings.Inferrer.RelationName(value);
421+
writer.WriteStringValue(relationName);
422+
}
423+
}
424+
385425
internal class FieldResolver
386426
{
387427
protected readonly ConcurrentDictionary<Field, string> Fields = new ConcurrentDictionary<Field, string>();

src/Elastic.Clients.Elasticsearch/Common/Infer/JoinFieldRouting/Routing.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public static implicit operator Routing(string[] routing) =>
9595
/// <summary> Use the inferred routing from <paramref name="document" /> </summary>
9696
public static Routing From<T>(T document) where T : class => new(document);
9797

98-
private string GetString(IElasticsearchClientSettings settings)
98+
internal string GetString(IElasticsearchClientSettings settings)
9999
{
100100
string value = null;
101101
if (DocumentGetter != null)
@@ -193,6 +193,13 @@ public override void Write(Utf8JsonWriter writer, Routing value, JsonSerializerO
193193
if (value.Document is not null)
194194
{
195195
var documentId = _settings.Inferrer.Routing(value.Document.GetType(), value.Document);
196+
197+
if (documentId is null)
198+
{
199+
writer.WriteNullValue();
200+
return;
201+
}
202+
196203
writer.WriteStringValue(documentId);
197204
}
198205
else if (value.DocumentGetter is not null)

src/Elastic.Clients.Elasticsearch/Serialization/DefaultHighLevelSerializer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public DefaultHighLevelSerializer(IElasticsearchClientSettings settings)
4949
new IdConverter(settings),
5050
new FieldConverter(settings),
5151
new SortCollectionConverter(settings),
52+
new RelationNameConverter(settings),
5253
//new FieldNameQueryConverterFactory(settings),
5354
new CustomJsonWriterConverterFactory(settings),
5455
new RoutingConverter(settings),

src/Elastic.Clients.Elasticsearch/Types/Bulk/BulkOperationDescriptorBase.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,15 @@ protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions o
7474

7575
if (RoutingValue is not null)
7676
{
77-
writer.WritePropertyName("routing");
78-
JsonSerializer.Serialize(writer, RoutingValue, options);
77+
// TODO - This flow is a bit inefficient and annoying just to get "clean" JSON
78+
79+
var value = RoutingValue.GetString(settings);
80+
81+
if (!string.IsNullOrEmpty(value))
82+
{
83+
writer.WritePropertyName("routing");
84+
JsonSerializer.Serialize(writer, value, options);
85+
}
7986
}
8087

8188
if (_version.HasValue)

tests/Tests.Core/Extensions/SerializationTesterAssertionExtensions.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
//// See the LICENSE file in the project root for more information
44

55
using System;
6+
using System.Collections.Generic;
7+
using System.Text.Json;
68
using Tests.Core.Serialization;
79

810
namespace Tests.Core.Extensions
@@ -49,5 +51,22 @@ public static void AssertSerialize<T>(this SerializationTester tester, T @object
4951
var roundTripResult = tester.Serializes(@object, expectedJson, preserveNullInExpected);
5052
roundTripResult.ShouldBeValid(message);
5153
}
54+
55+
public static void AssertSerializeNdjson<T>(this SerializationTester tester, T @object, IReadOnlyList<object> expectedJson, string message = null,
56+
bool preserveNullInExpected = false
57+
)
58+
{
59+
var roundTripResult = tester.SerializesNdJson(@object, expectedJson, preserveNullInExpected);
60+
roundTripResult.ShouldBeValid(message);
61+
}
62+
63+
public static void AssertSerialize<T>(this SerializationTester tester, string actualJsonString, object expectedJson, string message = null,
64+
bool preserveNullInExpected = false
65+
)
66+
{
67+
var roundTripResult = tester.Serializes(actualJsonString, expectedJson, preserveNullInExpected);
68+
69+
roundTripResult.ShouldBeValid(message);
70+
}
5271
}
5372
}

tests/Tests.Core/Serialization/ExpectJsonTestBase.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5+
using System.Collections.Generic;
56
using Elastic.Clients.Elasticsearch;
67
using Tests.Core.Extensions;
78
using Xunit;
@@ -13,10 +14,20 @@ public abstract class ExpectJsonTestBase
1314
protected ExpectJsonTestBase(IElasticClient client) => Tester = new SerializationTester(client);
1415

1516
protected abstract object ExpectJson { get; }
17+
protected abstract IReadOnlyList<object> ExpectNdjson { get; }
18+
1619
protected virtual bool IncludeNullInExpected => true;
1720
protected virtual bool SupportsDeserialization => true; //TODO Validate all overrides for false whether they truly do not support deserialization
1821
protected SerializationTester Tester { get; }
1922

23+
protected void SerializesNdjson<T>(T @object)
24+
{
25+
if (@object is null || ExpectNdjson is null)
26+
return;
27+
28+
Tester.AssertSerializeNdjson(@object, ExpectNdjson, preserveNullInExpected: IncludeNullInExpected);
29+
}
30+
2031
protected void RoundTripsOrSerializes<T>(T @object)
2132
{
2233
if (@object is null || ExpectJson is null)

tests/Tests.Core/Serialization/SerializationTester.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,39 @@ public SerializationResult Serializes<T>(T @object, object expectedJson, bool pr
132132
return result;
133133
}
134134

135+
public SerializationResult SerializesNdJson<T>(T @object, IReadOnlyList<object> expectedJson, bool preserveNullInExpected = false)
136+
{
137+
var stream = new MemoryStream();
138+
139+
Serializer.Serialize(@object, stream);
140+
141+
stream.Position = 0;
142+
var reader = new StreamReader(stream);
143+
144+
var counter = 0;
145+
string line;
146+
147+
var finalResult = new RoundTripResult<T> { Success = true };
148+
149+
while ((line = reader.ReadLine()) is not null)
150+
{
151+
var result = new RoundTripResult<T> { Success = false };
152+
result.Serialized = line;
153+
154+
var expected = expectedJson[counter];
155+
var expectedJsonToken = ExpectedJsonToJsonDocument(expected, preserveNullInExpected);
156+
157+
if (!TokenMatches(expectedJsonToken, result))
158+
{
159+
finalResult.Success = false;
160+
}
161+
162+
counter++;
163+
}
164+
165+
return finalResult;
166+
}
167+
135168
public DeserializationResult<T> Deserializes<T>(object expectedJson, bool preserveNullInExpected = false)
136169
{
137170
var expectedJsonString = ExpectedJsonString(expectedJson, preserveNullInExpected);
@@ -187,6 +220,8 @@ private bool SerializesAndMatches<T>(T @object, JsonDocument expectedJsonDocumen
187220
// : TokenMatches(expectedJsonDocument, result);
188221
}
189222

223+
224+
190225
private string SerializeUsingClientDefault<T>(T @object) =>
191226
@object switch
192227
{

tests/Tests.Domain/Project.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
using Tests.Domain.Helpers;
1010
using System.Linq;
1111
using Elastic.Clients.Elasticsearch;
12+
using Elastic.Transport;
13+
using Tests.Domain.Extensions;
1214

1315
namespace Tests.Domain;
1416

@@ -27,7 +29,7 @@ public class Project
2729
? InstanceAnonymousSourceSerializer
2830
: InstanceAnonymousDefault;
2931

30-
//public JoinField Join => JoinField.Root<Project>();
32+
public JoinField Join => JoinField.Root<Project>();
3133

3234
public Labels Labels { get; set; }
3335
public DateTime LastActivity { get; set; }
@@ -126,7 +128,7 @@ public class Project
126128
{
127129
name = First.Name,
128130
type = TypeName,
129-
//join = Instance.Join.ToAnonymousObject(),
131+
join = Instance.Join.ToAnonymousObject(),
130132
state = "BellyUp",
131133
visibility = "Public",
132134
startedOn = "2015-01-01T00:00:00",
@@ -141,7 +143,7 @@ public class Project
141143
{
142144
name = First.Name,
143145
type = TypeName,
144-
//join = Instance.Join.ToAnonymousObject(),
146+
join = Instance.Join.ToAnonymousObject(),
145147
state = "BellyUp",
146148
visibility = "Public",
147149
startedOn = "2015-01-01T00:00:00",
@@ -156,3 +158,15 @@ public class Project
156158

157159
// @formatter:on — enable formatter after this line
158160
}
161+
162+
public static class AnonymizerExtensions
163+
{
164+
private static readonly Inferrer Infer = new Inferrer(new ElasticsearchClientSettings(new InMemoryConnection()).ApplyDomainSettings());
165+
166+
public static object ToAnonymousObject(this JoinField field) =>
167+
field.Match<object>(p => Infer.RelationName(p.Name), c => new
168+
{
169+
parent = Infer.Id(c.ParentId),
170+
name = Infer.RelationName(c.Name)
171+
});
172+
}

0 commit comments

Comments
 (0)