Skip to content

Commit 8e065ce

Browse files
committed
fix(OperationProcessorResolver): #340.2 wrong type throws null ref
1 parent 66492a2 commit 8e065ce

File tree

3 files changed

+188
-54
lines changed

3 files changed

+188
-54
lines changed

Diff for: src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs

+16-6
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ public IOpProcessor LocateCreateService(Operation operation)
5151
{
5252
var resource = operation.GetResourceTypeName();
5353

54-
var contextEntity = _context.ContextGraph.GetContextEntity(resource);
54+
var contextEntity = GetResourceMetadata(resource);
55+
5556
var processor = _processorFactory.GetProcessor<IOpProcessor>(
5657
typeof(ICreateOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType
5758
);
@@ -64,7 +65,8 @@ public IOpProcessor LocateGetService(Operation operation)
6465
{
6566
var resource = operation.GetResourceTypeName();
6667

67-
var contextEntity = _context.ContextGraph.GetContextEntity(resource);
68+
var contextEntity = GetResourceMetadata(resource);
69+
6870
var processor = _processorFactory.GetProcessor<IOpProcessor>(
6971
typeof(IGetOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType
7072
);
@@ -77,7 +79,8 @@ public IOpProcessor LocateRemoveService(Operation operation)
7779
{
7880
var resource = operation.GetResourceTypeName();
7981

80-
var contextEntity = _context.ContextGraph.GetContextEntity(resource);
82+
var contextEntity = GetResourceMetadata(resource);
83+
8184
var processor = _processorFactory.GetProcessor<IOpProcessor>(
8285
typeof(IRemoveOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType
8386
);
@@ -90,15 +93,22 @@ public IOpProcessor LocateUpdateService(Operation operation)
9093
{
9194
var resource = operation.GetResourceTypeName();
9295

93-
var contextEntity = _context.ContextGraph.GetContextEntity(resource);
94-
if (contextEntity == null)
95-
throw new JsonApiException(400, $"This API does not expose a resource of type '{resource}'.");
96+
var contextEntity = GetResourceMetadata(resource);
9697

9798
var processor = _processorFactory.GetProcessor<IOpProcessor>(
9899
typeof(IUpdateOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType
99100
);
100101

101102
return processor;
102103
}
104+
105+
private ContextEntity GetResourceMetadata(string resourceName)
106+
{
107+
var contextEntity = _context.ContextGraph.GetContextEntity(resourceName);
108+
if(contextEntity == null)
109+
throw new JsonApiException(400, $"This API does not expose a resource of type '{resourceName}'.");
110+
111+
return contextEntity;
112+
}
103113
}
104114
}

Diff for: test/OperationsExampleTests/Get/GetTests.cs

+70-48
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,73 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Net;
5-
using System.Threading.Tasks;
6-
using Bogus;
7-
using JsonApiDotNetCore.Models.Operations;
1+
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Net;
6+
using System.Threading.Tasks;
7+
using Bogus;
8+
using JsonApiDotNetCore.Models.Operations;
89
using JsonApiDotNetCoreExample.Data;
9-
using OperationsExampleTests.Factories;
10-
using Xunit;
11-
12-
namespace OperationsExampleTests
13-
{
14-
public class GetByIdTests : Fixture, IDisposable
15-
{
10+
using OperationsExampleTests.Factories;
11+
using Xunit;
12+
13+
namespace OperationsExampleTests
14+
{
15+
public class GetByIdTests : Fixture, IDisposable
16+
{
1617
private readonly Faker _faker = new Faker();
17-
18-
[Fact]
19-
public async Task Can_Get_Authors()
20-
{
21-
// arrange
22-
var expectedCount = _faker.Random.Int(1, 10);
23-
var context = GetService<AppDbContext>();
24-
context.Articles.RemoveRange(context.Articles);
25-
context.Authors.RemoveRange(context.Authors);
26-
var authors = AuthorFactory.Get(expectedCount);
27-
context.AddRange(authors);
28-
context.SaveChanges();
29-
30-
var content = new
31-
{
32-
operations = new[] {
33-
new Dictionary<string, object> {
34-
{ "op", "get"},
35-
{ "ref", new { type = "authors" } }
36-
}
37-
}
38-
};
39-
40-
// act
41-
var result = await PatchAsync<OperationsDocument>("api/bulk", content);
42-
43-
// assert
44-
Assert.NotNull(result.response);
45-
Assert.NotNull(result.data);
46-
Assert.Equal(HttpStatusCode.OK, result.response.StatusCode);
47-
Assert.Single(result.data.Operations);
48-
Assert.Equal(expectedCount, result.data.Operations.Single().DataList.Count);
18+
19+
[Fact]
20+
public async Task Can_Get_Authors()
21+
{
22+
// arrange
23+
var expectedCount = _faker.Random.Int(1, 10);
24+
var context = GetService<AppDbContext>();
25+
context.Articles.RemoveRange(context.Articles);
26+
context.Authors.RemoveRange(context.Authors);
27+
var authors = AuthorFactory.Get(expectedCount);
28+
context.AddRange(authors);
29+
context.SaveChanges();
30+
31+
var content = new
32+
{
33+
operations = new[] {
34+
new Dictionary<string, object> {
35+
{ "op", "get"},
36+
{ "ref", new { type = "authors" } }
37+
}
38+
}
39+
};
40+
41+
// act
42+
var result = await PatchAsync<OperationsDocument>("api/bulk", content);
43+
44+
// assert
45+
Assert.NotNull(result.response);
46+
Assert.NotNull(result.data);
47+
Assert.Equal(HttpStatusCode.OK, result.response.StatusCode);
48+
Assert.Single(result.data.Operations);
49+
Assert.Equal(expectedCount, result.data.Operations.Single().DataList.Count);
4950
}
50-
}
51-
}
51+
52+
[Fact]
53+
public async Task Get_Non_Existent_Type_Returns_400()
54+
{
55+
// arrange
56+
var content = new
57+
{
58+
operations = new[] {
59+
new Dictionary<string, object> {
60+
{ "op", "get"},
61+
{ "ref", new { type = "non-existent-type" } }
62+
}
63+
}
64+
};
65+
66+
// act
67+
var result = await PatchAsync<OperationsDocument>("api/bulk", content);
68+
69+
// assert
70+
Assert.Equal(HttpStatusCode.BadRequest, result.response.StatusCode);
71+
}
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using JsonApiDotNetCore.Builders;
2+
using JsonApiDotNetCore.Internal;
3+
using JsonApiDotNetCore.Internal.Generics;
4+
using JsonApiDotNetCore.Models.Operations;
5+
using JsonApiDotNetCore.Services;
6+
using JsonApiDotNetCore.Services.Operations;
7+
using Moq;
8+
using Xunit;
9+
10+
namespace UnitTests.Services
11+
{
12+
public class OperationProcessorResolverTests
13+
{
14+
private readonly Mock<IGenericProcessorFactory> _processorFactoryMock;
15+
public readonly Mock<IJsonApiContext> _jsonApiContextMock;
16+
17+
public OperationProcessorResolverTests()
18+
{
19+
_processorFactoryMock = new Mock<IGenericProcessorFactory>();
20+
_jsonApiContextMock = new Mock<IJsonApiContext>();
21+
}
22+
23+
[Fact]
24+
public void LocateCreateService_Throws_400_For_Entity_Not_Registered()
25+
{
26+
// arrange
27+
_jsonApiContextMock.Setup(m => m.ContextGraph).Returns(new ContextGraphBuilder().Build());
28+
var service = GetService();
29+
var op = new Operation
30+
{
31+
Ref = new ResourceReference
32+
{
33+
Type = "non-existent-type"
34+
}
35+
};
36+
37+
// act, assert
38+
var e = Assert.Throws<JsonApiException>(() => service.LocateCreateService(op));
39+
Assert.Equal(400, e.GetStatusCode());
40+
}
41+
42+
[Fact]
43+
public void LocateGetService_Throws_400_For_Entity_Not_Registered()
44+
{
45+
// arrange
46+
_jsonApiContextMock.Setup(m => m.ContextGraph).Returns(new ContextGraphBuilder().Build());
47+
var service = GetService();
48+
var op = new Operation
49+
{
50+
Ref = new ResourceReference
51+
{
52+
Type = "non-existent-type"
53+
}
54+
};
55+
56+
// act, assert
57+
var e = Assert.Throws<JsonApiException>(() => service.LocateGetService(op));
58+
Assert.Equal(400, e.GetStatusCode());
59+
}
60+
61+
[Fact]
62+
public void LocateRemoveService_Throws_400_For_Entity_Not_Registered()
63+
{
64+
// arrange
65+
_jsonApiContextMock.Setup(m => m.ContextGraph).Returns(new ContextGraphBuilder().Build());
66+
var service = GetService();
67+
var op = new Operation
68+
{
69+
Ref = new ResourceReference
70+
{
71+
Type = "non-existent-type"
72+
}
73+
};
74+
75+
// act, assert
76+
var e = Assert.Throws<JsonApiException>(() => service.LocateRemoveService(op));
77+
Assert.Equal(400, e.GetStatusCode());
78+
}
79+
80+
[Fact]
81+
public void LocateUpdateService_Throws_400_For_Entity_Not_Registered()
82+
{
83+
// arrange
84+
_jsonApiContextMock.Setup(m => m.ContextGraph).Returns(new ContextGraphBuilder().Build());
85+
var service = GetService();
86+
var op = new Operation
87+
{
88+
Ref = new ResourceReference
89+
{
90+
Type = "non-existent-type"
91+
}
92+
};
93+
94+
// act, assert
95+
var e = Assert.Throws<JsonApiException>(() => service.LocateUpdateService(op));
96+
Assert.Equal(400, e.GetStatusCode());
97+
}
98+
99+
private OperationProcessorResolver GetService()
100+
=> new OperationProcessorResolver(_processorFactoryMock.Object, _jsonApiContextMock.Object);
101+
}
102+
}

0 commit comments

Comments
 (0)