Skip to content

Commit f8d9a4d

Browse files
author
Bart Koelman
committed
Updated tests
1 parent 8afff1a commit f8d9a4d

File tree

146 files changed

+3676
-3002
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

146 files changed

+3676
-3002
lines changed

test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/AtomicOperationsFixture.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
using JetBrains.Annotations;
2-
using JsonApiDotNetCoreMongoDbExampleTests.TestBuildingBlocks;
2+
using JsonApiDotNetCoreMongoDbTests.TestBuildingBlocks;
3+
using Microsoft.Extensions.DependencyInjection;
34

4-
namespace JsonApiDotNetCoreMongoDbExampleTests.IntegrationTests.AtomicOperations;
5+
namespace JsonApiDotNetCoreMongoDbTests.IntegrationTests.AtomicOperations;
56

67
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
78
public sealed class AtomicOperationsFixture : IDisposable
89
{
9-
internal IntegrationTestContext<TestableStartup> TestContext { get; }
10+
internal IntegrationTestContext<TestableStartup, OperationsDbContext> TestContext { get; }
1011

1112
public AtomicOperationsFixture()
1213
{
13-
TestContext = new IntegrationTestContext<TestableStartup>
14+
TestContext = new IntegrationTestContext<TestableStartup, OperationsDbContext>
1415
{
1516
StartMongoDbInSingleNodeReplicaSetMode = true
1617
};
18+
19+
TestContext.UseController<OperationsController>();
20+
21+
TestContext.ConfigureServicesAfterStartup(services => services.AddSingleton<ResourceDefinitionHitCounter>());
1722
}
1823

1924
public void Dispose()

test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/AtomicOperationsTestCollection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Xunit;
22

3-
namespace JsonApiDotNetCoreMongoDbExampleTests.IntegrationTests.AtomicOperations;
3+
namespace JsonApiDotNetCoreMongoDbTests.IntegrationTests.AtomicOperations;
44

55
[CollectionDefinition("AtomicOperationsFixture")]
66
public sealed class AtomicOperationsTestCollection : ICollectionFixture<AtomicOperationsFixture>
Lines changed: 103 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,35 @@
11
using System.Net;
22
using FluentAssertions;
3+
using JsonApiDotNetCore.Configuration;
34
using JsonApiDotNetCore.Serialization.Objects;
4-
using JsonApiDotNetCoreMongoDbExampleTests.TestBuildingBlocks;
5-
using MongoDB.Driver;
6-
using MongoDB.Driver.Linq;
5+
using JsonApiDotNetCoreMongoDbTests.TestBuildingBlocks;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using MongoDB.Bson;
78
using Xunit;
89

9-
namespace JsonApiDotNetCoreMongoDbExampleTests.IntegrationTests.AtomicOperations.Creating;
10+
namespace JsonApiDotNetCoreMongoDbTests.IntegrationTests.AtomicOperations.Creating;
1011

1112
[Collection("AtomicOperationsFixture")]
1213
public sealed class AtomicCreateResourceTests
1314
{
14-
private readonly IntegrationTestContext<TestableStartup> _testContext;
15+
private readonly IntegrationTestContext<TestableStartup, OperationsDbContext> _testContext;
1516
private readonly OperationsFakers _fakers = new();
1617

1718
public AtomicCreateResourceTests(AtomicOperationsFixture fixture)
1819
{
1920
_testContext = fixture.TestContext;
2021

21-
fixture.TestContext.ConfigureServicesAfterStartup(services => services.AddControllersFromExampleProject());
22+
var options = (JsonApiOptions)fixture.TestContext.Factory.Services.GetRequiredService<IJsonApiOptions>();
23+
options.AllowClientGeneratedIds = false;
2224
}
2325

2426
[Fact]
2527
public async Task Can_create_resource()
2628
{
2729
// Arrange
28-
string newArtistName = _fakers.Performer.Generate().ArtistName;
30+
string newArtistName = _fakers.Performer.Generate().ArtistName!;
2931
DateTimeOffset newBornAt = _fakers.Performer.Generate().BornAt;
3032

31-
await _testContext.RunOnDatabaseAsync(async db =>
32-
{
33-
await db.EnsureEmptyCollectionAsync<Performer>();
34-
});
35-
3633
var requestBody = new
3734
{
3835
atomic__operations = new[]
@@ -56,27 +53,29 @@ await _testContext.RunOnDatabaseAsync(async db =>
5653
const string route = "/operations";
5754

5855
// Act
59-
(HttpResponseMessage httpResponse, AtomicOperationsDocument responseDocument) =
60-
await _testContext.ExecutePostAtomicAsync<AtomicOperationsDocument>(route, requestBody);
56+
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAtomicAsync<Document>(route, requestBody);
6157

6258
// Assert
6359
httpResponse.Should().HaveStatusCode(HttpStatusCode.OK);
6460

65-
responseDocument.Results.Should().HaveCount(1);
66-
responseDocument.Results[0].SingleData.Should().NotBeNull();
67-
responseDocument.Results[0].SingleData.Type.Should().Be("performers");
68-
responseDocument.Results[0].SingleData.Attributes["artistName"].Should().Be(newArtistName);
69-
responseDocument.Results[0].SingleData.Attributes["bornAt"].Should().BeCloseTo(newBornAt);
70-
responseDocument.Results[0].SingleData.Relationships.Should().BeNull();
61+
responseDocument.Results.ShouldHaveCount(1);
7162

72-
string newPerformerId = responseDocument.Results[0].SingleData.Id;
63+
responseDocument.Results[0].Data.SingleValue.ShouldNotBeNull().With(resource =>
64+
{
65+
resource.Type.Should().Be("performers");
66+
resource.Attributes.ShouldContainKey("artistName").With(value => value.Should().Be(newArtistName));
67+
resource.Attributes.ShouldContainKey("bornAt").With(value => value.Should().Be(newBornAt));
68+
resource.Relationships.Should().BeNull();
69+
});
70+
71+
string newPerformerId = responseDocument.Results[0].Data.SingleValue!.Id.ShouldNotBeNull();
7372

74-
await _testContext.RunOnDatabaseAsync(async db =>
73+
await _testContext.RunOnDatabaseAsync(async dbContext =>
7574
{
76-
Performer performerInDatabase = await db.GetCollection<Performer>().AsQueryable().FirstWithIdAsync(newPerformerId);
75+
Performer performerInDatabase = await dbContext.Performers.FirstWithIdAsync(newPerformerId);
7776

7877
performerInDatabase.ArtistName.Should().Be(newArtistName);
79-
performerInDatabase.BornAt.Should().BeCloseTo(newBornAt, TimeSpan.FromMilliseconds(20));
78+
performerInDatabase.BornAt.Should().Be(newBornAt);
8079
});
8180
}
8281

@@ -88,11 +87,6 @@ public async Task Can_create_resources()
8887

8988
List<MusicTrack> newTracks = _fakers.MusicTrack.Generate(elementCount);
9089

91-
await _testContext.RunOnDatabaseAsync(async db =>
92-
{
93-
await db.EnsureEmptyCollectionAsync<MusicTrack>();
94-
});
95-
9690
var operationElements = new List<object>(elementCount);
9791

9892
for (int index = 0; index < elementCount; index++)
@@ -122,35 +116,38 @@ await _testContext.RunOnDatabaseAsync(async db =>
122116
const string route = "/operations";
123117

124118
// Act
125-
(HttpResponseMessage httpResponse, AtomicOperationsDocument responseDocument) =
126-
await _testContext.ExecutePostAtomicAsync<AtomicOperationsDocument>(route, requestBody);
119+
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAtomicAsync<Document>(route, requestBody);
127120

128121
// Assert
129122
httpResponse.Should().HaveStatusCode(HttpStatusCode.OK);
130123

131-
responseDocument.Results.Should().HaveCount(elementCount);
124+
responseDocument.Results.ShouldHaveCount(elementCount);
132125

133126
for (int index = 0; index < elementCount; index++)
134127
{
135-
ResourceObject singleData = responseDocument.Results[index].SingleData;
136-
137-
singleData.Should().NotBeNull();
138-
singleData.Type.Should().Be("musicTracks");
139-
singleData.Attributes["title"].Should().Be(newTracks[index].Title);
140-
singleData.Attributes["lengthInSeconds"].As<decimal?>().Should().BeApproximately(newTracks[index].LengthInSeconds);
141-
singleData.Attributes["genre"].Should().Be(newTracks[index].Genre);
142-
singleData.Attributes["releasedAt"].Should().BeCloseTo(newTracks[index].ReleasedAt);
143-
singleData.Relationships.Should().BeNull();
128+
responseDocument.Results[index].Data.SingleValue.ShouldNotBeNull().With(resource =>
129+
{
130+
resource.ShouldNotBeNull();
131+
resource.Type.Should().Be("musicTracks");
132+
resource.Attributes.ShouldContainKey("title").With(value => value.Should().Be(newTracks[index].Title));
133+
134+
resource.Attributes.ShouldContainKey("lengthInSeconds")
135+
.With(value => value.As<decimal?>().Should().BeApproximately(newTracks[index].LengthInSeconds));
136+
137+
resource.Attributes.ShouldContainKey("genre").With(value => value.Should().Be(newTracks[index].Genre));
138+
resource.Attributes.ShouldContainKey("releasedAt").With(value => value.Should().Be(newTracks[index].ReleasedAt));
139+
140+
resource.Relationships.Should().BeNull();
141+
});
144142
}
145143

146-
string[] newTrackIds = responseDocument.Results.Select(result => result.SingleData.Id).ToArray();
144+
string[] newTrackIds = responseDocument.Results.Select(result => result.Data.SingleValue!.Id.ShouldNotBeNull()).ToArray();
147145

148-
await _testContext.RunOnDatabaseAsync(async db =>
146+
await _testContext.RunOnDatabaseAsync(async dbContext =>
149147
{
150-
List<MusicTrack> tracksInDatabase = await db.GetCollection<MusicTrack>().AsQueryable().Where(musicTrack => newTrackIds.Contains(musicTrack.Id))
151-
.ToListAsync();
148+
List<MusicTrack> tracksInDatabase = await dbContext.MusicTracks.ToListWhereAsync(musicTrack => newTrackIds.Contains(musicTrack.Id));
152149

153-
tracksInDatabase.Should().HaveCount(elementCount);
150+
tracksInDatabase.ShouldHaveCount(elementCount);
154151

155152
for (int index = 0; index < elementCount; index++)
156153
{
@@ -159,7 +156,7 @@ await _testContext.RunOnDatabaseAsync(async db =>
159156
trackInDatabase.Title.Should().Be(newTracks[index].Title);
160157
trackInDatabase.LengthInSeconds.Should().BeApproximately(newTracks[index].LengthInSeconds);
161158
trackInDatabase.Genre.Should().Be(newTracks[index].Genre);
162-
trackInDatabase.ReleasedAt.Should().BeCloseTo(newTracks[index].ReleasedAt, TimeSpan.FromMilliseconds(20));
159+
trackInDatabase.ReleasedAt.Should().Be(newTracks[index].ReleasedAt);
163160
}
164161
});
165162
}
@@ -168,11 +165,6 @@ await _testContext.RunOnDatabaseAsync(async db =>
168165
public async Task Can_create_resource_without_attributes_or_relationships()
169166
{
170167
// Arrange
171-
await _testContext.RunOnDatabaseAsync(async db =>
172-
{
173-
await db.EnsureEmptyCollectionAsync<Performer>();
174-
});
175-
176168
var requestBody = new
177169
{
178170
atomic__operations = new[]
@@ -197,27 +189,75 @@ await _testContext.RunOnDatabaseAsync(async db =>
197189
const string route = "/operations";
198190

199191
// Act
200-
(HttpResponseMessage httpResponse, AtomicOperationsDocument responseDocument) =
201-
await _testContext.ExecutePostAtomicAsync<AtomicOperationsDocument>(route, requestBody);
192+
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAtomicAsync<Document>(route, requestBody);
202193

203194
// Assert
204195
httpResponse.Should().HaveStatusCode(HttpStatusCode.OK);
205196

206-
responseDocument.Results.Should().HaveCount(1);
207-
responseDocument.Results[0].SingleData.Should().NotBeNull();
208-
responseDocument.Results[0].SingleData.Type.Should().Be("performers");
209-
responseDocument.Results[0].SingleData.Attributes["artistName"].Should().BeNull();
210-
responseDocument.Results[0].SingleData.Attributes["bornAt"].Should().BeCloseTo(default(DateTimeOffset));
211-
responseDocument.Results[0].SingleData.Relationships.Should().BeNull();
197+
responseDocument.Results.ShouldHaveCount(1);
198+
199+
responseDocument.Results[0].Data.SingleValue.ShouldNotBeNull().With(resource =>
200+
{
201+
resource.Type.Should().Be("performers");
202+
resource.Attributes.ShouldContainKey("artistName").With(value => value.Should().BeNull());
203+
resource.Attributes.ShouldContainKey("bornAt").With(value => value.Should().Be(default(DateTimeOffset)));
204+
resource.Relationships.Should().BeNull();
205+
});
212206

213-
string newPerformerId = responseDocument.Results[0].SingleData.Id;
207+
string newPerformerId = responseDocument.Results[0].Data.SingleValue!.Id.ShouldNotBeNull();
214208

215-
await _testContext.RunOnDatabaseAsync(async db =>
209+
await _testContext.RunOnDatabaseAsync(async dbContext =>
216210
{
217-
Performer performerInDatabase = await db.GetCollection<Performer>().AsQueryable().FirstWithIdAsync(newPerformerId);
211+
Performer performerInDatabase = await dbContext.Performers.FirstWithIdAsync(newPerformerId);
218212

219213
performerInDatabase.ArtistName.Should().BeNull();
220214
performerInDatabase.BornAt.Should().Be(default);
221215
});
222216
}
217+
218+
[Fact]
219+
public async Task Cannot_create_resource_with_client_generated_ID()
220+
{
221+
// Arrange
222+
MusicTrack newTrack = _fakers.MusicTrack.Generate();
223+
newTrack.Id = ObjectId.GenerateNewId().ToString();
224+
225+
var requestBody = new
226+
{
227+
atomic__operations = new[]
228+
{
229+
new
230+
{
231+
op = "add",
232+
data = new
233+
{
234+
type = "musicTracks",
235+
id = newTrack.StringId,
236+
attributes = new
237+
{
238+
title = newTrack.Title
239+
}
240+
}
241+
}
242+
}
243+
};
244+
245+
const string route = "/operations";
246+
247+
// Act
248+
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAtomicAsync<Document>(route, requestBody);
249+
250+
// Assert
251+
httpResponse.Should().HaveStatusCode(HttpStatusCode.Forbidden);
252+
253+
responseDocument.Errors.ShouldHaveCount(1);
254+
255+
ErrorObject error = responseDocument.Errors[0];
256+
error.StatusCode.Should().Be(HttpStatusCode.Forbidden);
257+
error.Title.Should().Be("Failed to deserialize request body: The use of client-generated IDs is disabled.");
258+
error.Detail.Should().BeNull();
259+
error.Source.ShouldNotBeNull();
260+
error.Source.Pointer.Should().Be("/atomic:operations[0]/data/id");
261+
error.Meta.ShouldContainKey("requestBody").With(value => value.ShouldNotBeNull().ToString().ShouldNotBeEmpty());
262+
}
223263
}

0 commit comments

Comments
 (0)