Skip to content

Commit 2554891

Browse files
committed
Add test support for obfuscation in operations
1 parent 0e4432b commit 2554891

File tree

4 files changed

+157
-3
lines changed

4 files changed

+157
-3
lines changed

test/JsonApiDotNetCoreTests/IntegrationTests/IdObfuscation/IdObfuscationTests.cs

Lines changed: 111 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@
99

1010
namespace JsonApiDotNetCoreTests.IntegrationTests.IdObfuscation;
1111

12-
public sealed class IdObfuscationTests : IClassFixture<IntegrationTestContext<TestableStartup<ObfuscationDbContext>, ObfuscationDbContext>>
12+
public sealed class IdObfuscationTests : IClassFixture<IntegrationTestContext<ObfuscationStartup, ObfuscationDbContext>>
1313
{
14-
private readonly IntegrationTestContext<TestableStartup<ObfuscationDbContext>, ObfuscationDbContext> _testContext;
14+
private readonly IntegrationTestContext<ObfuscationStartup, ObfuscationDbContext> _testContext;
1515
private readonly ObfuscationFakers _fakers = new();
1616

17-
public IdObfuscationTests(IntegrationTestContext<TestableStartup<ObfuscationDbContext>, ObfuscationDbContext> testContext)
17+
public IdObfuscationTests(IntegrationTestContext<ObfuscationStartup, ObfuscationDbContext> testContext)
1818
{
1919
_testContext = testContext;
2020

2121
testContext.UseController<BankAccountsController>();
2222
testContext.UseController<DebitCardsController>();
23+
testContext.UseController<OperationsController>();
2324

2425
var options = (JsonApiOptions)testContext.Factory.Services.GetRequiredService<IJsonApiOptions>();
2526
options.UseRelativeLinks = true;
@@ -584,4 +585,111 @@ public async Task Cannot_delete_unknown_resource()
584585
error.Title.Should().Be("The requested resource does not exist.");
585586
error.Detail.Should().Be($"Resource of type 'bankAccounts' with ID '{stringId}' does not exist.");
586587
}
588+
589+
[Fact]
590+
public async Task Can_use_operations()
591+
{
592+
// Arrange
593+
BankAccount newAccount = _fakers.BankAccount.GenerateOne();
594+
DebitCard newCard = _fakers.DebitCard.GenerateOne();
595+
596+
const string accountLocalId = "new-bank-account";
597+
598+
var requestBody = new
599+
{
600+
atomic__operations = new object[]
601+
{
602+
new
603+
{
604+
op = "add",
605+
data = new
606+
{
607+
type = "bankAccounts",
608+
lid = accountLocalId,
609+
attributes = new
610+
{
611+
iban = newAccount.Iban
612+
}
613+
}
614+
},
615+
new
616+
{
617+
op = "add",
618+
data = new
619+
{
620+
type = "debitCards",
621+
attributes = new
622+
{
623+
ownerName = newCard.OwnerName,
624+
pinCode = newCard.PinCode
625+
},
626+
relationships = new
627+
{
628+
account = new
629+
{
630+
data = new
631+
{
632+
type = "bankAccounts",
633+
lid = accountLocalId
634+
}
635+
}
636+
}
637+
}
638+
}
639+
}
640+
};
641+
642+
const string route = "/operations";
643+
644+
// Act
645+
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAtomicAsync<Document>(route, requestBody);
646+
647+
// Assert
648+
httpResponse.ShouldHaveStatusCode(HttpStatusCode.OK);
649+
650+
responseDocument.Results.Should().HaveCount(2);
651+
652+
ResourceObject resultData1 = responseDocument.Results[0].Data.SingleValue.RefShould().NotBeNull().And.Subject;
653+
ResourceObject resultData2 = responseDocument.Results[1].Data.SingleValue.RefShould().NotBeNull().And.Subject;
654+
655+
string newAccountStringId = resultData1.Id.RefShould().NotBeNull().And.Subject;
656+
string newCardStringId = resultData2.Id.RefShould().NotBeNull().And.Subject;
657+
658+
resultData1.Type.Should().Be("bankAccounts");
659+
resultData1.Links.RefShould().NotBeNull().And.Subject.Self.Should().Be($"/bankAccounts/{newAccountStringId}");
660+
661+
resultData1.Relationships.Should().ContainKey("cards").WhoseValue.With(value =>
662+
{
663+
value.Should().NotBeNull();
664+
value.Links.Should().NotBeNull();
665+
value.Links.Self.Should().Be($"/bankAccounts/{newAccountStringId}/relationships/cards");
666+
value.Links.Related.Should().Be($"/bankAccounts/{newAccountStringId}/cards");
667+
});
668+
669+
resultData2.Type.Should().Be("debitCards");
670+
resultData2.Links.RefShould().NotBeNull().And.Subject.Self.Should().Be($"/debitCards/{newCardStringId}");
671+
672+
resultData2.Relationships.Should().ContainKey("account").WhoseValue.With(value =>
673+
{
674+
value.Should().NotBeNull();
675+
value.Links.Should().NotBeNull();
676+
value.Links.Self.Should().Be($"/debitCards/{newCardStringId}/relationships/account");
677+
value.Links.Related.Should().Be($"/debitCards/{newCardStringId}/account");
678+
});
679+
680+
long newAccountId = HexadecimalCodec.Instance.Decode(newAccountStringId);
681+
long newCardId = HexadecimalCodec.Instance.Decode(newCardStringId);
682+
683+
await _testContext.RunOnDatabaseAsync(async dbContext =>
684+
{
685+
DebitCard cardInDatabase = await dbContext.DebitCards.Include(card => card.Account).FirstWithIdAsync(newCardId);
686+
687+
cardInDatabase.OwnerName.Should().Be(newCard.OwnerName);
688+
cardInDatabase.PinCode.Should().Be(newCard.PinCode);
689+
690+
cardInDatabase.Account.Should().NotBeNull();
691+
cardInDatabase.Account.Id.Should().Be(newAccountId);
692+
cardInDatabase.Account.Iban.Should().Be(newAccount.Iban);
693+
});
694+
}
587695
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using JsonApiDotNetCore.AtomicOperations;
2+
using JsonApiDotNetCore.Configuration;
3+
using JsonApiDotNetCore.Controllers;
4+
5+
namespace JsonApiDotNetCoreTests.IntegrationTests.IdObfuscation;
6+
7+
internal sealed class ObfuscationOperationFilter : DefaultOperationFilter
8+
{
9+
protected override JsonApiEndpoints? GetJsonApiEndpoints(ResourceType resourceType)
10+
{
11+
return resourceType.ClrType.Name == nameof(ObfuscatedIdentifiable) ? JsonApiEndpoints.None : JsonApiEndpoints.All;
12+
}
13+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using JsonApiDotNetCore.AtomicOperations;
2+
using JsonApiDotNetCore.Configuration;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using TestBuildingBlocks;
5+
6+
namespace JsonApiDotNetCoreTests.IntegrationTests.IdObfuscation;
7+
8+
public sealed class ObfuscationStartup : TestableStartup<ObfuscationDbContext>
9+
{
10+
public override void ConfigureServices(IServiceCollection services)
11+
{
12+
services.AddSingleton<IAtomicOperationFilter, ObfuscationOperationFilter>();
13+
base.ConfigureServices(services);
14+
}
15+
16+
protected override void AddJsonApi(IServiceCollection services)
17+
{
18+
services.AddJsonApi<ObfuscationDbContext>(ConfigureJsonApiOptions, resources: builder => builder.Remove<ObfuscatedIdentifiable>());
19+
}
20+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using JsonApiDotNetCore.AtomicOperations;
2+
using JsonApiDotNetCore.Configuration;
3+
using JsonApiDotNetCore.Controllers;
4+
using JsonApiDotNetCore.Middleware;
5+
using JsonApiDotNetCore.Resources;
6+
using Microsoft.Extensions.Logging;
7+
8+
namespace JsonApiDotNetCoreTests.IntegrationTests.IdObfuscation;
9+
10+
public sealed class OperationsController(
11+
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IOperationsProcessor processor, IJsonApiRequest request,
12+
ITargetedFields targetedFields, IAtomicOperationFilter operationFilter)
13+
: JsonApiOperationsController(options, resourceGraph, loggerFactory, processor, request, targetedFields, operationFilter);

0 commit comments

Comments
 (0)