Skip to content

Commit fc00620

Browse files
author
Bart Koelman
committed
Converted atomic:operations Add tests
1 parent ee52719 commit fc00620

File tree

13 files changed

+688
-313
lines changed

13 files changed

+688
-313
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using JsonApiDotNetCore.AtomicOperations;
2+
using JsonApiDotNetCore.Configuration;
3+
using JsonApiDotNetCore.Controllers;
4+
using JsonApiDotNetCore.Controllers.Annotations;
5+
using Microsoft.AspNetCore.Mvc;
6+
using Microsoft.Extensions.Logging;
7+
8+
namespace JsonApiDotNetCoreExample.Controllers
9+
{
10+
[DisableRoutingConvention, Route("/operations")]
11+
public class AtomicOperationsController : JsonApiAtomicOperationsController
12+
{
13+
public AtomicOperationsController(IJsonApiOptions options, ILoggerFactory loggerFactory,
14+
IAtomicOperationsProcessor processor)
15+
: base(options, loggerFactory, processor)
16+
{
17+
}
18+
}
19+
}

test/JsonApiDotNetCoreExampleTests/IntegrationTestContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ public async Task RunOnDatabaseAsync(Func<TDbContext, Task> asyncAction)
145145

146146
if (!string.IsNullOrEmpty(requestText))
147147
{
148+
requestText = requestText.Replace("atomic__", "atomic:");
149+
148150
request.Content = new StringContent(requestText);
149151

150152
if (contentType != null)
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Net;
5+
using System.Threading.Tasks;
6+
using FluentAssertions;
7+
using JsonApiDotNetCore.Serialization.Objects;
8+
using JsonApiDotNetCoreExample;
9+
using Microsoft.AspNetCore.Mvc.ApplicationParts;
10+
using Microsoft.EntityFrameworkCore;
11+
using Microsoft.Extensions.DependencyInjection;
12+
using Xunit;
13+
14+
namespace JsonApiDotNetCoreExampleTests.IntegrationTests.AtomicOperations.Add
15+
{
16+
public sealed class AtomicAddResourceTests
17+
: IClassFixture<IntegrationTestContext<TestableStartup<OperationsDbContext>, OperationsDbContext>>
18+
{
19+
private readonly IntegrationTestContext<TestableStartup<OperationsDbContext>, OperationsDbContext> _testContext;
20+
private readonly OperationsFakers _fakers = new OperationsFakers();
21+
22+
public AtomicAddResourceTests(IntegrationTestContext<TestableStartup<OperationsDbContext>, OperationsDbContext> testContext)
23+
{
24+
_testContext = testContext;
25+
26+
testContext.ConfigureServicesAfterStartup(services =>
27+
{
28+
var part = new AssemblyPart(typeof(EmptyStartup).Assembly);
29+
services.AddMvcCore().ConfigureApplicationPartManager(apm => apm.ApplicationParts.Add(part));
30+
});
31+
}
32+
33+
[Fact]
34+
public async Task Can_add_resource()
35+
{
36+
// Arrange
37+
var newArtistName = _fakers.Performer.Generate().ArtistName;
38+
var newBornAt = _fakers.Performer.Generate().BornAt;
39+
40+
var requestBody = new
41+
{
42+
atomic__operations = new[]
43+
{
44+
new
45+
{
46+
op = "add",
47+
data = new
48+
{
49+
type = "performers",
50+
attributes = new
51+
{
52+
artistName = newArtistName,
53+
bornAt = newBornAt
54+
}
55+
}
56+
}
57+
}
58+
};
59+
60+
var route = "/operations";
61+
62+
// Act
63+
var (httpResponse, responseDocument) = await _testContext.ExecutePostAsync<AtomicOperationsDocument>(route, requestBody);
64+
65+
// Assert
66+
httpResponse.Should().HaveStatusCode(HttpStatusCode.OK);
67+
68+
responseDocument.Results.Should().HaveCount(1);
69+
responseDocument.Results[0].SingleData.Should().NotBeNull();
70+
responseDocument.Results[0].SingleData.Type.Should().Be("performers");
71+
responseDocument.Results[0].SingleData.Attributes["artistName"].Should().Be(newArtistName);
72+
responseDocument.Results[0].SingleData.Attributes["bornAt"].Should().BeCloseTo(newBornAt);
73+
74+
var newPerformerId = int.Parse(responseDocument.Results[0].SingleData.Id);
75+
76+
await _testContext.RunOnDatabaseAsync(async dbContext =>
77+
{
78+
var performerInDatabase = await dbContext.Performers
79+
.FirstAsync(performer => performer.Id == newPerformerId);
80+
81+
performerInDatabase.ArtistName.Should().Be(newArtistName);
82+
performerInDatabase.BornAt.Should().BeCloseTo(newBornAt);
83+
});
84+
}
85+
86+
[Fact]
87+
public async Task Can_add_resource_without_attributes_or_relationships()
88+
{
89+
// Arrange
90+
var requestBody = new
91+
{
92+
atomic__operations = new[]
93+
{
94+
new
95+
{
96+
op = "add",
97+
data = new
98+
{
99+
type = "performers",
100+
attributes = new
101+
{
102+
},
103+
relationship = new
104+
{
105+
}
106+
}
107+
}
108+
}
109+
};
110+
111+
var route = "/operations";
112+
113+
// Act
114+
var (httpResponse, responseDocument) = await _testContext.ExecutePostAsync<AtomicOperationsDocument>(route, requestBody);
115+
116+
// Assert
117+
httpResponse.Should().HaveStatusCode(HttpStatusCode.OK);
118+
119+
responseDocument.Results.Should().HaveCount(1);
120+
responseDocument.Results[0].SingleData.Should().NotBeNull();
121+
responseDocument.Results[0].SingleData.Type.Should().Be("performers");
122+
responseDocument.Results[0].SingleData.Attributes["artistName"].Should().BeNull();
123+
responseDocument.Results[0].SingleData.Attributes["bornAt"].Should().BeCloseTo(default(DateTimeOffset));
124+
125+
var newPerformerId = int.Parse(responseDocument.Results[0].SingleData.Id);
126+
127+
await _testContext.RunOnDatabaseAsync(async dbContext =>
128+
{
129+
var performerInDatabase = await dbContext.Performers
130+
.FirstAsync(performer => performer.Id == newPerformerId);
131+
132+
performerInDatabase.ArtistName.Should().BeNull();
133+
performerInDatabase.BornAt.Should().Be(default);
134+
});
135+
}
136+
137+
[Fact]
138+
public async Task Can_add_resources()
139+
{
140+
// Arrange
141+
const int elementCount = 5;
142+
143+
var newTracks = _fakers.MusicTrack.Generate(elementCount);
144+
145+
var operationElements = new List<object>(elementCount);
146+
for (int index = 0; index < elementCount; index++)
147+
{
148+
operationElements.Add(new
149+
{
150+
op = "add",
151+
data = new
152+
{
153+
type = "musicTracks",
154+
attributes = new
155+
{
156+
title = newTracks[index].Title,
157+
lengthInSeconds = newTracks[index].LengthInSeconds,
158+
genre = newTracks[index].Genre,
159+
releasedAt = newTracks[index].ReleasedAt
160+
}
161+
}
162+
});
163+
}
164+
165+
var requestBody = new
166+
{
167+
atomic__operations = operationElements
168+
};
169+
170+
var route = "/operations";
171+
172+
// Act
173+
var (httpResponse, responseDocument) = await _testContext.ExecutePostAsync<AtomicOperationsDocument>(route, requestBody);
174+
175+
// Assert
176+
httpResponse.Should().HaveStatusCode(HttpStatusCode.OK);
177+
178+
responseDocument.Results.Should().HaveCount(elementCount);
179+
180+
for (int index = 0; index < elementCount; index++)
181+
{
182+
responseDocument.Results[index].SingleData.Should().NotBeNull();
183+
responseDocument.Results[index].SingleData.Type.Should().Be("musicTracks");
184+
responseDocument.Results[index].SingleData.Attributes["title"].Should().Be(newTracks[index].Title);
185+
responseDocument.Results[index].SingleData.Attributes["lengthInSeconds"].Should().BeApproximately(newTracks[index].LengthInSeconds, 0.00000000001M);
186+
responseDocument.Results[index].SingleData.Attributes["genre"].Should().Be(newTracks[index].Genre);
187+
responseDocument.Results[index].SingleData.Attributes["releasedAt"].Should().BeCloseTo(newTracks[index].ReleasedAt);
188+
}
189+
190+
var newTrackIds = responseDocument.Results.Select(result => Guid.Parse(result.SingleData.Id));
191+
192+
await _testContext.RunOnDatabaseAsync(async dbContext =>
193+
{
194+
var tracksInDatabase = await dbContext.MusicTracks
195+
.Where(musicTrack => newTrackIds.Contains(musicTrack.Id))
196+
.ToListAsync();
197+
198+
tracksInDatabase.Should().HaveCount(elementCount);
199+
200+
for (int index = 0; index < elementCount; index++)
201+
{
202+
var trackInDatabase = tracksInDatabase.Single(musicTrack => musicTrack.Id == Guid.Parse(responseDocument.Results[index].SingleData.Id));
203+
204+
trackInDatabase.Title.Should().Be(newTracks[index].Title);
205+
trackInDatabase.LengthInSeconds.Should().BeApproximately(newTracks[index].LengthInSeconds, 0.00000000001M);
206+
trackInDatabase.Genre.Should().Be(newTracks[index].Genre);
207+
trackInDatabase.ReleasedAt.Should().BeCloseTo(newTracks[index].ReleasedAt);
208+
}
209+
});
210+
}
211+
}
212+
}

0 commit comments

Comments
 (0)