Skip to content

Commit b7031fb

Browse files
committed
Revert removal of relaxed media type in tests to maintain code coverage
1 parent bd14bdb commit b7031fb

6 files changed

Lines changed: 196 additions & 9 deletions

File tree

test/JsonApiDotNetCoreTests/IntegrationTests/ContentNegotiation/CustomExtensions/CustomExtensionsAcceptHeaderTests.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ public CustomExtensionsAcceptHeaderTests(IntegrationTestContext<TestableStartup<
3030
});
3131

3232
var options = (JsonApiOptions)_testContext.Factory.Services.GetRequiredService<IJsonApiOptions>();
33-
options.IncludeExtensions(ServerTimeMediaTypeExtension.ServerTime);
33+
#pragma warning disable CS0618 // Type or member is obsolete
34+
options.IncludeExtensions(ServerTimeMediaTypeExtension.ServerTime, ServerTimeMediaTypeExtension.RelaxedServerTime);
35+
#pragma warning restore CS0618 // Type or member is obsolete
3436
}
3537

3638
[Fact]
@@ -68,6 +70,9 @@ public async Task Prefers_first_match_from_GetPossibleMediaTypes_with_largest_nu
6870
{
6971
headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("text/html"));
7072
headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(JsonApiMediaType.Default.ToString()));
73+
#pragma warning disable CS0618 // Type or member is obsolete
74+
headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(ServerTimeMediaTypes.RelaxedServerTime.ToString()));
75+
#pragma warning restore CS0618 // Type or member is obsolete
7176
headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(ServerTimeMediaTypes.ServerTime.ToString()));
7277
};
7378

@@ -142,8 +147,10 @@ public async Task Denies_extensions_mismatch_between_ContentType_and_Accept_head
142147

143148
responseDocument.Errors.Should().HaveCount(1);
144149

145-
string detail =
146-
$"Include '{JsonApiMediaType.AtomicOperations}' or '{ServerTimeMediaTypes.AtomicOperationsWithServerTime}' in the Accept header values.";
150+
#pragma warning disable CS0618 // Type or member is obsolete
151+
string detail = $"Include '{JsonApiMediaType.AtomicOperations}' or '{ServerTimeMediaTypes.AtomicOperationsWithServerTime}' or " +
152+
$"'{JsonApiMediaType.RelaxedAtomicOperations}' or '{ServerTimeMediaTypes.RelaxedAtomicOperationsWithRelaxedServerTime}' in the Accept header values.";
153+
#pragma warning restore CS0618 // Type or member is obsolete
147154

148155
ErrorObject error = responseDocument.Errors[0];
149156
error.StatusCode.Should().Be(HttpStatusCode.NotAcceptable);

test/JsonApiDotNetCoreTests/IntegrationTests/ContentNegotiation/CustomExtensions/CustomExtensionsContentTypeTests.cs

Lines changed: 150 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ public CustomExtensionsContentTypeTests(IntegrationTestContext<TestableStartup<P
4646
ServiceDescriptor.Singleton<TimeProvider>(new FrozenTimeProvider(CurrentTime, TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time")))));
4747

4848
var options = (JsonApiOptions)_testContext.Factory.Services.GetRequiredService<IJsonApiOptions>();
49-
options.IncludeExtensions(ServerTimeMediaTypeExtension.ServerTime);
49+
#pragma warning disable CS0618 // Type or member is obsolete
50+
options.IncludeExtensions(ServerTimeMediaTypeExtension.ServerTime, ServerTimeMediaTypeExtension.RelaxedServerTime);
51+
#pragma warning restore CS0618 // Type or member is obsolete
5052
}
5153

5254
[Fact]
@@ -118,6 +120,44 @@ public async Task Permits_JsonApi_ContentType_header_with_ServerTime_extension()
118120
.Be("2025-01-01T06:53:40.0000000+09:00");
119121
}
120122

123+
#pragma warning disable CS0618 // Type or member is obsolete
124+
[Fact]
125+
public async Task Permits_JsonApi_ContentType_header_with_relaxed_ServerTime_extension()
126+
{
127+
// Arrange
128+
var requestBody = new
129+
{
130+
data = new
131+
{
132+
type = "policies",
133+
attributes = new
134+
{
135+
name = "some"
136+
}
137+
}
138+
};
139+
140+
const string route = "/policies";
141+
string contentType = ServerTimeMediaTypes.RelaxedServerTime.ToString();
142+
143+
Action<HttpRequestHeaders> setRequestHeaders = headers =>
144+
headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(ServerTimeMediaTypes.RelaxedServerTime.ToString()));
145+
146+
// Act
147+
(HttpResponseMessage httpResponse, Document responseDocument) =
148+
await _testContext.ExecutePostAsync<Document>(route, requestBody, contentType, setRequestHeaders);
149+
150+
// Assert
151+
httpResponse.ShouldHaveStatusCode(HttpStatusCode.Created);
152+
153+
httpResponse.Content.Headers.ContentType.Should().NotBeNull();
154+
httpResponse.Content.Headers.ContentType.ToString().Should().Be(ServerTimeMediaTypes.RelaxedServerTime.ToString());
155+
156+
responseDocument.Meta.Should().ContainKey("utcServerTime").WhoseValue.Should().NotBeNull().And.Subject.ToString().Should()
157+
.Be("2024-12-31T21:53:40.0000000Z");
158+
}
159+
#pragma warning restore CS0618 // Type or member is obsolete
160+
121161
[Fact]
122162
public async Task Permits_JsonApi_ContentType_header_with_AtomicOperations_and_ServerTime_extension_at_operations_endpoint()
123163
{
@@ -161,6 +201,55 @@ public async Task Permits_JsonApi_ContentType_header_with_AtomicOperations_and_S
161201
.Be("2024-12-31T21:53:40.0000000Z");
162202
}
163203

204+
#pragma warning disable CS0618 // Type or member is obsolete
205+
[Fact]
206+
public async Task Permits_JsonApi_ContentType_header_with_relaxed_AtomicOperations_and_relaxed_ServerTime_extension_at_operations_endpoint()
207+
{
208+
// Arrange
209+
var requestBody = new
210+
{
211+
meta = new
212+
{
213+
useLocalTime = true
214+
},
215+
216+
atomic__operations = new[]
217+
{
218+
new
219+
{
220+
op = "add",
221+
data = new
222+
{
223+
type = "policies",
224+
attributes = new
225+
{
226+
name = "some"
227+
}
228+
}
229+
}
230+
}
231+
};
232+
233+
const string route = "/operations";
234+
string contentType = ServerTimeMediaTypes.RelaxedAtomicOperationsWithRelaxedServerTime.ToString();
235+
236+
Action<HttpRequestHeaders> setRequestHeaders = headers =>
237+
headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(ServerTimeMediaTypes.RelaxedAtomicOperationsWithRelaxedServerTime.ToString()));
238+
239+
// Act
240+
(HttpResponseMessage httpResponse, Document responseDocument) =
241+
await _testContext.ExecutePostAsync<Document>(route, requestBody, contentType, setRequestHeaders);
242+
243+
// Assert
244+
httpResponse.ShouldHaveStatusCode(HttpStatusCode.OK);
245+
246+
httpResponse.Content.Headers.ContentType.Should().NotBeNull();
247+
httpResponse.Content.Headers.ContentType.ToString().Should().Be(ServerTimeMediaTypes.RelaxedAtomicOperationsWithRelaxedServerTime.ToString());
248+
249+
responseDocument.Meta.Should().ContainKey("localServerTime");
250+
}
251+
#pragma warning restore CS0618 // Type or member is obsolete
252+
164253
[Fact]
165254
public async Task Denies_JsonApi_ContentType_header_with_AtomicOperations_extension_and_ServerTime_at_resource_endpoint()
166255
{
@@ -191,8 +280,10 @@ public async Task Denies_JsonApi_ContentType_header_with_AtomicOperations_extens
191280

192281
responseDocument.Errors.Should().HaveCount(1);
193282

194-
string detail =
195-
$"Use '{JsonApiMediaType.Default}' or '{ServerTimeMediaTypes.ServerTime}' instead of '{contentType}' for the Content-Type header value.";
283+
#pragma warning disable CS0618 // Type or member is obsolete
284+
string detail = $"Use '{JsonApiMediaType.Default}' or '{ServerTimeMediaTypes.ServerTime}' or " +
285+
$"'{ServerTimeMediaTypes.RelaxedServerTime}' instead of '{contentType}' for the Content-Type header value.";
286+
#pragma warning restore CS0618 // Type or member is obsolete
196287

197288
ErrorObject error = responseDocument.Errors[0];
198289
error.StatusCode.Should().Be(HttpStatusCode.UnsupportedMediaType);
@@ -239,8 +330,61 @@ public async Task Denies_JsonApi_ContentType_header_with_ServerTime_at_operation
239330

240331
responseDocument.Errors.Should().HaveCount(1);
241332

242-
string detail =
243-
$"Use '{JsonApiMediaType.AtomicOperations}' or '{ServerTimeMediaTypes.AtomicOperationsWithServerTime}' instead of '{contentType}' for the Content-Type header value.";
333+
#pragma warning disable CS0618 // Type or member is obsolete
334+
string detail = $"Use '{JsonApiMediaType.AtomicOperations}' or '{ServerTimeMediaTypes.AtomicOperationsWithServerTime}' or " +
335+
$"'{JsonApiMediaType.RelaxedAtomicOperations}' or '{ServerTimeMediaTypes.RelaxedAtomicOperationsWithRelaxedServerTime}' " +
336+
$"instead of '{contentType}' for the Content-Type header value.";
337+
#pragma warning restore CS0618 // Type or member is obsolete
338+
339+
ErrorObject error = responseDocument.Errors[0];
340+
error.StatusCode.Should().Be(HttpStatusCode.UnsupportedMediaType);
341+
error.Title.Should().Be("The specified Content-Type header value is not supported.");
342+
error.Detail.Should().Be(detail);
343+
error.Source.Should().NotBeNull();
344+
error.Source.Header.Should().Be("Content-Type");
345+
}
346+
347+
#pragma warning disable CS0618 // Type or member is obsolete
348+
[Fact]
349+
public async Task Denies_JsonApi_ContentType_header_with_relaxed_ServerTime_at_operations_endpoint()
350+
{
351+
// Arrange
352+
var requestBody = new
353+
{
354+
atomic__operations = new[]
355+
{
356+
new
357+
{
358+
op = "add",
359+
data = new
360+
{
361+
type = "policies",
362+
attributes = new
363+
{
364+
name = "some"
365+
}
366+
}
367+
}
368+
}
369+
};
370+
371+
const string route = "/operations";
372+
string contentType = ServerTimeMediaTypes.RelaxedServerTime.ToString();
373+
374+
// Act
375+
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAsync<Document>(route, requestBody, contentType);
376+
377+
// Assert
378+
httpResponse.ShouldHaveStatusCode(HttpStatusCode.UnsupportedMediaType);
379+
380+
httpResponse.Content.Headers.ContentType.Should().NotBeNull();
381+
httpResponse.Content.Headers.ContentType.ToString().Should().Be(JsonApiMediaType.Default.ToString());
382+
383+
responseDocument.Errors.Should().HaveCount(1);
384+
385+
string detail = $"Use '{JsonApiMediaType.AtomicOperations}' or '{ServerTimeMediaTypes.AtomicOperationsWithServerTime}' or " +
386+
$"'{JsonApiMediaType.RelaxedAtomicOperations}' or '{ServerTimeMediaTypes.RelaxedAtomicOperationsWithRelaxedServerTime}' " +
387+
$"instead of '{contentType}' for the Content-Type header value.";
244388

245389
ErrorObject error = responseDocument.Errors[0];
246390
error.StatusCode.Should().Be(HttpStatusCode.UnsupportedMediaType);
@@ -249,4 +393,5 @@ public async Task Denies_JsonApi_ContentType_header_with_ServerTime_at_operation
249393
error.Source.Should().NotBeNull();
250394
error.Source.Header.Should().Be("Content-Type");
251395
}
396+
#pragma warning restore CS0618 // Type or member is obsolete
252397
}

test/JsonApiDotNetCoreTests/IntegrationTests/ContentNegotiation/CustomExtensions/ServerTimeContentNegotiator.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ protected override IReadOnlyList<JsonApiMediaType> GetPossibleMediaTypes()
1313
{
1414
List<JsonApiMediaType> mediaTypes = [];
1515

16+
// Relaxed entries come after JSON:API compliant entries, which makes them less likely to be selected.
17+
18+
#pragma warning disable CS0618 // Type or member is obsolete
1619
if (IsOperationsEndpoint())
1720
{
1821
if (_options.Extensions.Contains(JsonApiMediaTypeExtension.AtomicOperations))
@@ -25,6 +28,17 @@ protected override IReadOnlyList<JsonApiMediaType> GetPossibleMediaTypes()
2528
{
2629
mediaTypes.Add(ServerTimeMediaTypes.AtomicOperationsWithServerTime);
2730
}
31+
32+
if (_options.Extensions.Contains(JsonApiMediaTypeExtension.RelaxedAtomicOperations))
33+
{
34+
mediaTypes.Add(JsonApiMediaType.RelaxedAtomicOperations);
35+
}
36+
37+
if (_options.Extensions.Contains(JsonApiMediaTypeExtension.RelaxedAtomicOperations) &&
38+
_options.Extensions.Contains(ServerTimeMediaTypeExtension.RelaxedServerTime))
39+
{
40+
mediaTypes.Add(ServerTimeMediaTypes.RelaxedAtomicOperationsWithRelaxedServerTime);
41+
}
2842
}
2943
else
3044
{
@@ -34,7 +48,13 @@ protected override IReadOnlyList<JsonApiMediaType> GetPossibleMediaTypes()
3448
{
3549
mediaTypes.Add(ServerTimeMediaTypes.ServerTime);
3650
}
51+
52+
if (_options.Extensions.Contains(ServerTimeMediaTypeExtension.RelaxedServerTime))
53+
{
54+
mediaTypes.Add(ServerTimeMediaTypes.RelaxedServerTime);
55+
}
3756
}
57+
#pragma warning restore CS0618 // Type or member is obsolete
3858

3959
return mediaTypes.AsReadOnly();
4060
}

test/JsonApiDotNetCoreTests/IntegrationTests/ContentNegotiation/CustomExtensions/ServerTimeMediaTypeExtension.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@ namespace JsonApiDotNetCoreTests.IntegrationTests.ContentNegotiation.CustomExten
77
internal static class ServerTimeMediaTypeExtension
88
{
99
public static readonly JsonApiMediaTypeExtension ServerTime = new("https://www.jsonapi.net/ext/server-time");
10+
11+
[Obsolete("This media type is no longer needed and will be removed in a future version. Use ServerTime instead.")]
12+
public static readonly JsonApiMediaTypeExtension RelaxedServerTime = new("server-time");
1013
}

test/JsonApiDotNetCoreTests/IntegrationTests/ContentNegotiation/CustomExtensions/ServerTimeMediaTypes.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,17 @@ internal static class ServerTimeMediaTypes
88
{
99
public static readonly JsonApiMediaType ServerTime = new([ServerTimeMediaTypeExtension.ServerTime]);
1010

11+
[Obsolete("This media type is no longer needed and will be removed in a future version. Use ServerTime instead.")]
12+
public static readonly JsonApiMediaType RelaxedServerTime = new([ServerTimeMediaTypeExtension.RelaxedServerTime]);
13+
1114
public static readonly JsonApiMediaType AtomicOperationsWithServerTime = new([
1215
JsonApiMediaTypeExtension.AtomicOperations,
1316
ServerTimeMediaTypeExtension.ServerTime
1417
]);
18+
19+
[Obsolete("This media type is no longer needed and will be removed in a future version. Use AtomicOperationsWithServerTime instead.")]
20+
public static readonly JsonApiMediaType RelaxedAtomicOperationsWithRelaxedServerTime = new([
21+
JsonApiMediaTypeExtension.RelaxedAtomicOperations,
22+
ServerTimeMediaTypeExtension.RelaxedServerTime
23+
]);
1524
}

test/JsonApiDotNetCoreTests/IntegrationTests/ContentNegotiation/CustomExtensions/ServerTimeResponseMeta.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ internal sealed class ServerTimeResponseMeta(IJsonApiRequest request, RequestDoc
1212

1313
public IDictionary<string, object?>? GetMeta()
1414
{
15-
if (_request.Extensions.Contains(ServerTimeMediaTypeExtension.ServerTime))
15+
#pragma warning disable CS0618 // Type or member is obsolete
16+
if (_request.Extensions.Contains(ServerTimeMediaTypeExtension.ServerTime) ||
17+
_request.Extensions.Contains(ServerTimeMediaTypeExtension.RelaxedServerTime))
18+
#pragma warning restore CS0618 // Type or member is obsolete
1619
{
1720
if (_documentStore.Document is not { Meta: not null } || !_documentStore.Document.Meta.TryGetValue("useLocalTime", out object? useLocalTimeValue) ||
1821
useLocalTimeValue == null || !bool.TryParse(useLocalTimeValue.ToString(), out bool useLocalTime))

0 commit comments

Comments
 (0)