Skip to content

Commit 9b539c8

Browse files
author
Bart Koelman
committed
Improved hit tracking assertions for resource definition callbacks.
Optimization: Removed callback invocations for to-one include (see QueryLayerComposer) because their results are never used.
1 parent 31df90d commit 9b539c8

34 files changed

+894
-187
lines changed

src/JsonApiDotNetCore/Queries/Internal/QueryLayerComposer.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,15 @@ private IReadOnlyCollection<IncludeElementExpression> ProcessIncludeSet(IReadOnl
164164
// @formatter:wrap_chained_method_calls restore
165165

166166
ResourceContext resourceContext = _resourceContextProvider.GetResourceContext(includeElement.Relationship.RightType);
167+
bool isToManyRelationship = includeElement.Relationship is HasManyAttribute;
167168

168169
var child = new QueryLayer(resourceContext)
169170
{
170-
Filter = GetFilter(expressionsInCurrentScope, resourceContext),
171-
Sort = GetSort(expressionsInCurrentScope, resourceContext),
172-
Pagination = ((JsonApiOptions)_options).DisableChildrenPagination ? null : GetPagination(expressionsInCurrentScope, resourceContext),
171+
Filter = isToManyRelationship ? GetFilter(expressionsInCurrentScope, resourceContext) : null,
172+
Sort = isToManyRelationship ? GetSort(expressionsInCurrentScope, resourceContext) : null,
173+
Pagination = isToManyRelationship
174+
? ((JsonApiOptions)_options).DisableChildrenPagination ? null : GetPagination(expressionsInCurrentScope, resourceContext)
175+
: null,
173176
Projection = GetProjectionForSparseAttributeSet(resourceContext)
174177
};
175178

test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Meta/AtomicResourceMetaTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using JsonApiDotNetCore.Serialization.Objects;
88
using JsonApiDotNetCoreExample.Controllers;
99
using JsonApiDotNetCoreExampleTests.Startups;
10+
using Microsoft.Extensions.DependencyInjection;
1011
using TestBuildingBlocks;
1112
using Xunit;
1213

@@ -27,13 +28,20 @@ public AtomicResourceMetaTests(ExampleIntegrationTestContext<TestableStartup<Ope
2728
{
2829
services.AddResourceDefinition<MusicTrackMetaDefinition>();
2930
services.AddResourceDefinition<TextLanguageMetaDefinition>();
31+
32+
services.AddSingleton<ResourceDefinitionHitCounter>();
3033
});
34+
35+
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
36+
hitCounter.Reset();
3137
}
3238

3339
[Fact]
3440
public async Task Returns_resource_meta_in_create_resource_with_side_effects()
3541
{
3642
// Arrange
43+
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
44+
3745
string newTitle1 = _fakers.MusicTrack.Generate().Title;
3846
string newTitle2 = _fakers.MusicTrack.Generate().Title;
3947

@@ -86,12 +94,20 @@ public async Task Returns_resource_meta_in_create_resource_with_side_effects()
8694

8795
responseDocument.Results[1].SingleData.Meta.Should().HaveCount(1);
8896
responseDocument.Results[1].SingleData.Meta["Copyright"].Should().Be("(C) 1994. All rights reserved.");
97+
98+
hitCounter.HitExtensibilityPoints.Should().BeEquivalentTo(new[]
99+
{
100+
(typeof(MusicTrack), ResourceDefinitionHitCounter.ExtensibilityPoint.GetMeta),
101+
(typeof(MusicTrack), ResourceDefinitionHitCounter.ExtensibilityPoint.GetMeta)
102+
}, options => options.WithStrictOrdering());
89103
}
90104

91105
[Fact]
92106
public async Task Returns_resource_meta_in_update_resource_with_side_effects()
93107
{
94108
// Arrange
109+
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
110+
95111
TextLanguage existingLanguage = _fakers.TextLanguage.Generate();
96112

97113
await _testContext.RunOnDatabaseAsync(async dbContext =>
@@ -131,6 +147,11 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
131147
responseDocument.Results.Should().HaveCount(1);
132148
responseDocument.Results[0].SingleData.Meta.Should().HaveCount(1);
133149
responseDocument.Results[0].SingleData.Meta["Notice"].Should().Be(TextLanguageMetaDefinition.NoticeText);
150+
151+
hitCounter.HitExtensibilityPoints.Should().BeEquivalentTo(new[]
152+
{
153+
(typeof(TextLanguage), ResourceDefinitionHitCounter.ExtensibilityPoint.GetMeta)
154+
}, options => options.WithStrictOrdering());
134155
}
135156
}
136157
}

test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Meta/MusicTrackMetaDefinition.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,18 @@ namespace JsonApiDotNetCoreExampleTests.IntegrationTests.AtomicOperations.Meta
99
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
1010
public sealed class MusicTrackMetaDefinition : JsonApiResourceDefinition<MusicTrack, Guid>
1111
{
12-
public MusicTrackMetaDefinition(IResourceGraph resourceGraph)
12+
private readonly ResourceDefinitionHitCounter _hitCounter;
13+
14+
public MusicTrackMetaDefinition(IResourceGraph resourceGraph, ResourceDefinitionHitCounter hitCounter)
1315
: base(resourceGraph)
1416
{
17+
_hitCounter = hitCounter;
1518
}
1619

1720
public override IDictionary<string, object> GetMeta(MusicTrack resource)
1821
{
22+
_hitCounter.TrackInvocation<MusicTrack>(ResourceDefinitionHitCounter.ExtensibilityPoint.GetMeta);
23+
1924
return new Dictionary<string, object>
2025
{
2126
["Copyright"] = $"(C) {resource.ReleasedAt.Year}. All rights reserved."

test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/Meta/TextLanguageMetaDefinition.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,18 @@ public sealed class TextLanguageMetaDefinition : JsonApiResourceDefinition<TextL
1111
{
1212
internal const string NoticeText = "See https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes for ISO 639-1 language codes.";
1313

14-
public TextLanguageMetaDefinition(IResourceGraph resourceGraph)
14+
private readonly ResourceDefinitionHitCounter _hitCounter;
15+
16+
public TextLanguageMetaDefinition(IResourceGraph resourceGraph, ResourceDefinitionHitCounter hitCounter)
1517
: base(resourceGraph)
1618
{
19+
_hitCounter = hitCounter;
1720
}
1821

1922
public override IDictionary<string, object> GetMeta(TextLanguage resource)
2023
{
24+
_hitCounter.TrackInvocation<TextLanguage>(ResourceDefinitionHitCounter.ExtensibilityPoint.GetMeta);
25+
2126
return new Dictionary<string, object>
2227
{
2328
["Notice"] = NoticeText

test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/ResourceDefinitions/Serialization/AtomicSerializationHitCounter.cs

Lines changed: 0 additions & 24 deletions
This file was deleted.

test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/ResourceDefinitions/Serialization/AtomicSerializationResourceDefinitionTests.cs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,20 @@ public AtomicSerializationResourceDefinitionTests(ExampleIntegrationTestContext<
3131
{
3232
services.AddResourceDefinition<RecordCompanyDefinition>();
3333

34-
services.AddSingleton<AtomicSerializationHitCounter>();
34+
services.AddSingleton<ResourceDefinitionHitCounter>();
3535
services.AddScoped(typeof(IResourceChangeTracker<>), typeof(NeverSameResourceChangeTracker<>));
3636
});
3737

38-
var hitCounter = _testContext.Factory.Services.GetRequiredService<AtomicSerializationHitCounter>();
38+
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
3939
hitCounter.Reset();
4040
}
4141

4242
[Fact]
4343
public async Task Transforms_on_create_resource_with_side_effects()
4444
{
4545
// Arrange
46+
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
47+
4648
List<RecordCompany> newCompanies = _fakers.RecordCompany.Generate(2);
4749

4850
await _testContext.RunOnDatabaseAsync(async dbContext =>
@@ -112,15 +114,21 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
112114
companiesInDatabase[1].CountryOfResidence.Should().Be(newCompanies[1].CountryOfResidence);
113115
});
114116

115-
var hitCounter = _testContext.Factory.Services.GetRequiredService<AtomicSerializationHitCounter>();
116-
hitCounter.DeserializeCount.Should().Be(2);
117-
hitCounter.SerializeCount.Should().Be(2);
117+
hitCounter.HitExtensibilityPoints.Should().BeEquivalentTo(new[]
118+
{
119+
(typeof(RecordCompany), ResourceDefinitionHitCounter.ExtensibilityPoint.OnDeserialize),
120+
(typeof(RecordCompany), ResourceDefinitionHitCounter.ExtensibilityPoint.OnDeserialize),
121+
(typeof(RecordCompany), ResourceDefinitionHitCounter.ExtensibilityPoint.OnSerialize),
122+
(typeof(RecordCompany), ResourceDefinitionHitCounter.ExtensibilityPoint.OnSerialize)
123+
}, options => options.WithStrictOrdering());
118124
}
119125

120126
[Fact]
121127
public async Task Skips_on_create_resource_with_ToOne_relationship()
122128
{
123129
// Arrange
130+
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
131+
124132
RecordCompany existingCompany = _fakers.RecordCompany.Generate();
125133

126134
string newTrackTitle = _fakers.MusicTrack.Generate().Title;
@@ -172,15 +180,15 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
172180

173181
responseDocument.Results.Should().HaveCount(1);
174182

175-
var hitCounter = _testContext.Factory.Services.GetRequiredService<AtomicSerializationHitCounter>();
176-
hitCounter.DeserializeCount.Should().Be(0);
177-
hitCounter.SerializeCount.Should().Be(0);
183+
hitCounter.HitExtensibilityPoints.Should().BeEmpty();
178184
}
179185

180186
[Fact]
181187
public async Task Transforms_on_update_resource_with_side_effects()
182188
{
183189
// Arrange
190+
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
191+
184192
List<RecordCompany> existingCompanies = _fakers.RecordCompany.Generate(2);
185193

186194
await _testContext.RunOnDatabaseAsync(async dbContext =>
@@ -250,15 +258,21 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
250258
companiesInDatabase[1].CountryOfResidence.Should().Be(existingCompanies[1].CountryOfResidence);
251259
});
252260

253-
var hitCounter = _testContext.Factory.Services.GetRequiredService<AtomicSerializationHitCounter>();
254-
hitCounter.DeserializeCount.Should().Be(2);
255-
hitCounter.SerializeCount.Should().Be(2);
261+
hitCounter.HitExtensibilityPoints.Should().BeEquivalentTo(new[]
262+
{
263+
(typeof(RecordCompany), ResourceDefinitionHitCounter.ExtensibilityPoint.OnDeserialize),
264+
(typeof(RecordCompany), ResourceDefinitionHitCounter.ExtensibilityPoint.OnDeserialize),
265+
(typeof(RecordCompany), ResourceDefinitionHitCounter.ExtensibilityPoint.OnSerialize),
266+
(typeof(RecordCompany), ResourceDefinitionHitCounter.ExtensibilityPoint.OnSerialize)
267+
}, options => options.WithStrictOrdering());
256268
}
257269

258270
[Fact]
259271
public async Task Skips_on_update_resource_with_ToOne_relationship()
260272
{
261273
// Arrange
274+
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
275+
262276
MusicTrack existingTrack = _fakers.MusicTrack.Generate();
263277
RecordCompany existingCompany = _fakers.RecordCompany.Generate();
264278

@@ -309,15 +323,15 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
309323

310324
responseDocument.Results.Should().HaveCount(1);
311325

312-
var hitCounter = _testContext.Factory.Services.GetRequiredService<AtomicSerializationHitCounter>();
313-
hitCounter.DeserializeCount.Should().Be(0);
314-
hitCounter.SerializeCount.Should().Be(0);
326+
hitCounter.HitExtensibilityPoints.Should().BeEmpty();
315327
}
316328

317329
[Fact]
318330
public async Task Skips_on_update_ToOne_relationship()
319331
{
320332
// Arrange
333+
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
334+
321335
MusicTrack existingTrack = _fakers.MusicTrack.Generate();
322336
RecordCompany existingCompany = _fakers.RecordCompany.Generate();
323337

@@ -359,9 +373,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
359373

360374
responseDocument.Should().BeEmpty();
361375

362-
var hitCounter = _testContext.Factory.Services.GetRequiredService<AtomicSerializationHitCounter>();
363-
hitCounter.DeserializeCount.Should().Be(0);
364-
hitCounter.SerializeCount.Should().Be(0);
376+
hitCounter.HitExtensibilityPoints.Should().BeEmpty();
365377
}
366378
}
367379
}

test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/ResourceDefinitions/Serialization/RecordCompanyDefinition.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ namespace JsonApiDotNetCoreExampleTests.IntegrationTests.AtomicOperations.Resour
77
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
88
public sealed class RecordCompanyDefinition : JsonApiResourceDefinition<RecordCompany, short>
99
{
10-
private readonly AtomicSerializationHitCounter _hitCounter;
10+
private readonly ResourceDefinitionHitCounter _hitCounter;
1111

12-
public RecordCompanyDefinition(IResourceGraph resourceGraph, AtomicSerializationHitCounter hitCounter)
12+
public RecordCompanyDefinition(IResourceGraph resourceGraph, ResourceDefinitionHitCounter hitCounter)
1313
: base(resourceGraph)
1414
{
1515
_hitCounter = hitCounter;
1616
}
1717

1818
public override void OnDeserialize(RecordCompany resource)
1919
{
20-
_hitCounter.IncrementDeserializeCount();
20+
_hitCounter.TrackInvocation<RecordCompany>(ResourceDefinitionHitCounter.ExtensibilityPoint.OnDeserialize);
2121

2222
if (!string.IsNullOrEmpty(resource.Name))
2323
{
@@ -27,7 +27,7 @@ public override void OnDeserialize(RecordCompany resource)
2727

2828
public override void OnSerialize(RecordCompany resource)
2929
{
30-
_hitCounter.IncrementSerializeCount();
30+
_hitCounter.TrackInvocation<RecordCompany>(ResourceDefinitionHitCounter.ExtensibilityPoint.OnSerialize);
3131

3232
if (!string.IsNullOrEmpty(resource.CountryOfResidence))
3333
{

test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/ResourceDefinitions/SparseFieldSets/AtomicSparseFieldSetResourceDefinitionTests.cs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,25 @@ public AtomicSparseFieldSetResourceDefinitionTests(ExampleIntegrationTestContext
2828

2929
testContext.ConfigureServicesAfterStartup(services =>
3030
{
31-
services.AddSingleton<LyricPermissionProvider>();
3231
services.AddResourceDefinition<LyricTextDefinition>();
32+
33+
services.AddSingleton<LyricPermissionProvider>();
34+
services.AddSingleton<ResourceDefinitionHitCounter>();
3335
services.AddScoped(typeof(IResourceChangeTracker<>), typeof(NeverSameResourceChangeTracker<>));
3436
});
37+
38+
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
39+
hitCounter.Reset();
3540
}
3641

3742
[Fact]
3843
public async Task Hides_text_in_create_resource_with_side_effects()
3944
{
4045
// Arrange
46+
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
47+
4148
var provider = _testContext.Factory.Services.GetRequiredService<LyricPermissionProvider>();
4249
provider.CanViewText = false;
43-
provider.HitCount = 0;
4450

4551
List<Lyric> newLyrics = _fakers.Lyric.Generate(2);
4652

@@ -94,16 +100,23 @@ public async Task Hides_text_in_create_resource_with_side_effects()
94100
responseDocument.Results[1].SingleData.Attributes["format"].Should().Be(newLyrics[1].Format);
95101
responseDocument.Results[1].SingleData.Attributes.Should().NotContainKey("text");
96102

97-
provider.HitCount.Should().Be(4);
103+
hitCounter.HitExtensibilityPoints.Should().BeEquivalentTo(new[]
104+
{
105+
(typeof(Lyric), ResourceDefinitionHitCounter.ExtensibilityPoint.OnApplySparseFieldSet),
106+
(typeof(Lyric), ResourceDefinitionHitCounter.ExtensibilityPoint.OnApplySparseFieldSet),
107+
(typeof(Lyric), ResourceDefinitionHitCounter.ExtensibilityPoint.OnApplySparseFieldSet),
108+
(typeof(Lyric), ResourceDefinitionHitCounter.ExtensibilityPoint.OnApplySparseFieldSet)
109+
}, options => options.WithStrictOrdering());
98110
}
99111

100112
[Fact]
101113
public async Task Hides_text_in_update_resource_with_side_effects()
102114
{
103115
// Arrange
116+
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
117+
104118
var provider = _testContext.Factory.Services.GetRequiredService<LyricPermissionProvider>();
105119
provider.CanViewText = false;
106-
provider.HitCount = 0;
107120

108121
List<Lyric> existingLyrics = _fakers.Lyric.Generate(2);
109122

@@ -161,7 +174,13 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
161174
responseDocument.Results[1].SingleData.Attributes["format"].Should().Be(existingLyrics[1].Format);
162175
responseDocument.Results[1].SingleData.Attributes.Should().NotContainKey("text");
163176

164-
provider.HitCount.Should().Be(4);
177+
hitCounter.HitExtensibilityPoints.Should().BeEquivalentTo(new[]
178+
{
179+
(typeof(Lyric), ResourceDefinitionHitCounter.ExtensibilityPoint.OnApplySparseFieldSet),
180+
(typeof(Lyric), ResourceDefinitionHitCounter.ExtensibilityPoint.OnApplySparseFieldSet),
181+
(typeof(Lyric), ResourceDefinitionHitCounter.ExtensibilityPoint.OnApplySparseFieldSet),
182+
(typeof(Lyric), ResourceDefinitionHitCounter.ExtensibilityPoint.OnApplySparseFieldSet)
183+
}, options => options.WithStrictOrdering());
165184
}
166185
}
167186
}

test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/ResourceDefinitions/SparseFieldSets/LyricPermissionProvider.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,5 @@ namespace JsonApiDotNetCoreExampleTests.IntegrationTests.AtomicOperations.Resour
33
public sealed class LyricPermissionProvider
44
{
55
internal bool CanViewText { get; set; }
6-
internal int HitCount { get; set; }
76
}
87
}

test/JsonApiDotNetCoreExampleTests/IntegrationTests/AtomicOperations/ResourceDefinitions/SparseFieldSets/LyricTextDefinition.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,18 @@ namespace JsonApiDotNetCoreExampleTests.IntegrationTests.AtomicOperations.Resour
99
public sealed class LyricTextDefinition : JsonApiResourceDefinition<Lyric, long>
1010
{
1111
private readonly LyricPermissionProvider _lyricPermissionProvider;
12+
private readonly ResourceDefinitionHitCounter _hitCounter;
1213

13-
public LyricTextDefinition(IResourceGraph resourceGraph, LyricPermissionProvider lyricPermissionProvider)
14+
public LyricTextDefinition(IResourceGraph resourceGraph, LyricPermissionProvider lyricPermissionProvider, ResourceDefinitionHitCounter hitCounter)
1415
: base(resourceGraph)
1516
{
1617
_lyricPermissionProvider = lyricPermissionProvider;
18+
_hitCounter = hitCounter;
1719
}
1820

1921
public override SparseFieldSetExpression OnApplySparseFieldSet(SparseFieldSetExpression existingSparseFieldSet)
2022
{
21-
_lyricPermissionProvider.HitCount++;
23+
_hitCounter.TrackInvocation<Lyric>(ResourceDefinitionHitCounter.ExtensibilityPoint.OnApplySparseFieldSet);
2224

2325
return _lyricPermissionProvider.CanViewText
2426
? base.OnApplySparseFieldSet(existingSparseFieldSet)

0 commit comments

Comments
 (0)