|
|
|
@ -29,10 +29,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
{ |
|
|
|
private readonly IGrainFactory grainFactory = A.Fake<IGrainFactory>(); |
|
|
|
private readonly IAppsByNameIndexGrain indexByName = A.Fake<IAppsByNameIndexGrain>(); |
|
|
|
private readonly IAppsByUserIndexGrain indexByUser = A.Fake<IAppsByUserIndexGrain>(); |
|
|
|
private readonly IAppsByUserIndexGrain indexForUser = A.Fake<IAppsByUserIndexGrain>(); |
|
|
|
private readonly IAppsByUserIndexGrain indexForClient = A.Fake<IAppsByUserIndexGrain>(); |
|
|
|
private readonly ICommandBus commandBus = A.Fake<ICommandBus>(); |
|
|
|
private readonly NamedId<DomainId> appId = NamedId.Of(DomainId.NewGuid(), "my-app"); |
|
|
|
private readonly string userId = "user-1"; |
|
|
|
private readonly string userId = "user1"; |
|
|
|
private readonly string clientId = "client1"; |
|
|
|
private readonly AppsIndex sut; |
|
|
|
|
|
|
|
public AppsIndexTests() |
|
|
|
@ -41,7 +43,10 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
.Returns(indexByName); |
|
|
|
|
|
|
|
A.CallTo(() => grainFactory.GetGrain<IAppsByUserIndexGrain>(userId, null)) |
|
|
|
.Returns(indexByUser); |
|
|
|
.Returns(indexForUser); |
|
|
|
|
|
|
|
A.CallTo(() => grainFactory.GetGrain<IAppsByUserIndexGrain>(clientId, null)) |
|
|
|
.Returns(indexForClient); |
|
|
|
|
|
|
|
var cache = |
|
|
|
new ReplicatedCache(new MemoryCache(Options.Create(new MemoryCacheOptions())), new SimplePubSub(A.Fake<ILogger<SimplePubSub>>()), |
|
|
|
@ -68,7 +73,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
{ |
|
|
|
var (expected, _) = SetupApp(); |
|
|
|
|
|
|
|
A.CallTo(() => indexByUser.GetIdsAsync()) |
|
|
|
A.CallTo(() => indexForUser.GetIdsAsync()) |
|
|
|
.Returns(new List<DomainId> { appId.Id }); |
|
|
|
|
|
|
|
var actual = await sut.GetAppsForUserAsync(userId, PermissionSet.Empty); |
|
|
|
@ -84,7 +89,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
A.CallTo(() => indexByName.GetIdsAsync(A<string[]>.That.IsSameSequenceAs(new[] { appId.Name }))) |
|
|
|
.Returns(new List<DomainId> { appId.Id }); |
|
|
|
|
|
|
|
A.CallTo(() => indexByUser.GetIdsAsync()) |
|
|
|
A.CallTo(() => indexForUser.GetIdsAsync()) |
|
|
|
.Returns(new List<DomainId> { appId.Id }); |
|
|
|
|
|
|
|
var actual = await sut.GetAppsForUserAsync(userId, new PermissionSet($"squidex.apps.{appId.Name}")); |
|
|
|
@ -188,26 +193,42 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
.MustNotHaveHappened(); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public async Task Should_return_null_if_app_archived() |
|
|
|
{ |
|
|
|
SetupApp(isArchived: true); |
|
|
|
|
|
|
|
var actual1 = await sut.GetAppAsync(appId.Id, true); |
|
|
|
var actual2 = await sut.GetAppAsync(appId.Id, true); |
|
|
|
|
|
|
|
Assert.Null(actual1); |
|
|
|
Assert.Null(actual2); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public async Task Should_return_null_if_app_not_created() |
|
|
|
{ |
|
|
|
SetupApp(EtagVersion.NotFound); |
|
|
|
|
|
|
|
var actual = await sut.GetAppAsync(appId.Id, false); |
|
|
|
var actual1 = await sut.GetAppAsync(appId.Id, true); |
|
|
|
var actual2 = await sut.GetAppAsync(appId.Id, true); |
|
|
|
|
|
|
|
Assert.Null(actual); |
|
|
|
Assert.Null(actual1); |
|
|
|
Assert.Null(actual2); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public async Task Should_add_app_to_indexes_on_create() |
|
|
|
public async Task Should_add_app_to_indexes_when_creating() |
|
|
|
{ |
|
|
|
var token = RandomHash.Simple(); |
|
|
|
|
|
|
|
A.CallTo(() => indexByName.ReserveAsync(appId.Id, appId.Name)) |
|
|
|
.Returns(token); |
|
|
|
|
|
|
|
var command = Create(appId.Name); |
|
|
|
|
|
|
|
var context = |
|
|
|
new CommandContext(Create(appId.Name), commandBus) |
|
|
|
new CommandContext(command, commandBus) |
|
|
|
.Complete(); |
|
|
|
|
|
|
|
await sut.HandleAsync(context); |
|
|
|
@ -218,20 +239,22 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
A.CallTo(() => indexByName.RemoveReservationAsync(A<string>._)) |
|
|
|
.MustNotHaveHappened(); |
|
|
|
|
|
|
|
A.CallTo(() => indexByUser.AddAsync(appId.Id)) |
|
|
|
A.CallTo(() => indexForUser.AddAsync(appId.Id)) |
|
|
|
.MustHaveHappened(); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public async Task Should_also_app_to_user_index_if_app_created_by_client() |
|
|
|
public async Task Should_also_add_to_user_index_if_app_is_created_by_client() |
|
|
|
{ |
|
|
|
var token = RandomHash.Simple(); |
|
|
|
|
|
|
|
A.CallTo(() => indexByName.ReserveAsync(appId.Id, appId.Name)) |
|
|
|
.Returns(token); |
|
|
|
|
|
|
|
var command = CreateFromClient(appId.Name); |
|
|
|
|
|
|
|
var context = |
|
|
|
new CommandContext(CreateFromClient(appId.Name), commandBus) |
|
|
|
new CommandContext(command, commandBus) |
|
|
|
.Complete(); |
|
|
|
|
|
|
|
await sut.HandleAsync(context); |
|
|
|
@ -242,8 +265,11 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
A.CallTo(() => indexByName.RemoveReservationAsync(A<string>._)) |
|
|
|
.MustNotHaveHappened(); |
|
|
|
|
|
|
|
A.CallTo(() => indexByUser.AddAsync(appId.Id)) |
|
|
|
A.CallTo(() => indexForClient.AddAsync(appId.Id)) |
|
|
|
.MustHaveHappened(); |
|
|
|
|
|
|
|
A.CallTo(() => indexForUser.AddAsync(appId.Id)) |
|
|
|
.MustNotHaveHappened(); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
@ -254,8 +280,10 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
A.CallTo(() => indexByName.ReserveAsync(appId.Id, appId.Name)) |
|
|
|
.Returns(token); |
|
|
|
|
|
|
|
var command = CreateFromClient(appId.Name); |
|
|
|
|
|
|
|
var context = |
|
|
|
new CommandContext(CreateFromClient(appId.Name), commandBus); |
|
|
|
new CommandContext(command, commandBus); |
|
|
|
|
|
|
|
await sut.HandleAsync(context); |
|
|
|
|
|
|
|
@ -265,18 +293,20 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
A.CallTo(() => indexByName.RemoveReservationAsync(token)) |
|
|
|
.MustHaveHappened(); |
|
|
|
|
|
|
|
A.CallTo(() => indexByUser.AddAsync(appId.Id)) |
|
|
|
A.CallTo(() => indexForUser.AddAsync(appId.Id)) |
|
|
|
.MustNotHaveHappened(); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public async Task Should_not_add_to_indexes_on_create_if_name_taken() |
|
|
|
public async Task Should_not_add_to_indexes_when_name_is_taken() |
|
|
|
{ |
|
|
|
A.CallTo(() => indexByName.ReserveAsync(appId.Id, appId.Name)) |
|
|
|
.Returns(Task.FromResult<string?>(null)); |
|
|
|
|
|
|
|
var command = Create(appId.Name); |
|
|
|
|
|
|
|
var context = |
|
|
|
new CommandContext(Create(appId.Name), commandBus) |
|
|
|
new CommandContext(command, commandBus) |
|
|
|
.Complete(); |
|
|
|
|
|
|
|
await Assert.ThrowsAsync<ValidationException>(() => sut.HandleAsync(context)); |
|
|
|
@ -287,15 +317,17 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
A.CallTo(() => indexByName.RemoveReservationAsync(A<string>._)) |
|
|
|
.MustNotHaveHappened(); |
|
|
|
|
|
|
|
A.CallTo(() => indexByUser.AddAsync(appId.Id)) |
|
|
|
A.CallTo(() => indexForUser.AddAsync(appId.Id)) |
|
|
|
.MustNotHaveHappened(); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public async Task Should_not_add_to_indexes_on_create_if_name_invalid() |
|
|
|
public async Task Should_not_add_to_indexes_when_name_is_invalid() |
|
|
|
{ |
|
|
|
var command = Create("INVALID"); |
|
|
|
|
|
|
|
var context = |
|
|
|
new CommandContext(Create("INVALID"), commandBus) |
|
|
|
new CommandContext(command, commandBus) |
|
|
|
.Complete(); |
|
|
|
|
|
|
|
await sut.HandleAsync(context); |
|
|
|
@ -306,12 +338,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
A.CallTo(() => indexByName.RemoveReservationAsync(A<string>._)) |
|
|
|
.MustNotHaveHappened(); |
|
|
|
|
|
|
|
A.CallTo(() => indexByUser.AddAsync(appId.Id)) |
|
|
|
A.CallTo(() => indexForUser.AddAsync(appId.Id)) |
|
|
|
.MustNotHaveHappened(); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public async Task Should_add_app_to_index_on_contributor_assignment() |
|
|
|
public async Task Should_add_app_to_index_when_contributor_assigned() |
|
|
|
{ |
|
|
|
SetupApp(); |
|
|
|
|
|
|
|
@ -323,7 +355,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
|
|
|
|
await sut.HandleAsync(context); |
|
|
|
|
|
|
|
A.CallTo(() => indexByUser.AddAsync(appId.Id)) |
|
|
|
A.CallTo(() => indexForUser.AddAsync(appId.Id)) |
|
|
|
.MustHaveHappened(); |
|
|
|
} |
|
|
|
|
|
|
|
@ -362,7 +394,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public async Task Should_remove_from_user_index_on_remove_of_contributor() |
|
|
|
public async Task Should_remove_from_user_index_when_contributor_removed() |
|
|
|
{ |
|
|
|
SetupApp(); |
|
|
|
|
|
|
|
@ -374,12 +406,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
|
|
|
|
await sut.HandleAsync(context); |
|
|
|
|
|
|
|
A.CallTo(() => indexByUser.RemoveAsync(appId.Id)) |
|
|
|
A.CallTo(() => indexForUser.RemoveAsync(appId.Id)) |
|
|
|
.MustHaveHappened(); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public async Task Should_remove_app_from_indexes_on_archive() |
|
|
|
public async Task Should_remove_app_from_indexes_when_app_gets_archived() |
|
|
|
{ |
|
|
|
SetupApp(); |
|
|
|
|
|
|
|
@ -394,7 +426,30 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
A.CallTo(() => indexByName.RemoveAsync(appId.Id)) |
|
|
|
.MustHaveHappened(); |
|
|
|
|
|
|
|
A.CallTo(() => indexByUser.RemoveAsync(appId.Id)) |
|
|
|
A.CallTo(() => indexForUser.RemoveAsync(appId.Id)) |
|
|
|
.MustHaveHappenedOnceExactly(); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public async Task Should_also_remove_app_from_client_index_when_created_by_client() |
|
|
|
{ |
|
|
|
SetupApp(fromClient: true); |
|
|
|
|
|
|
|
var command = new ArchiveApp { AppId = appId }; |
|
|
|
|
|
|
|
var context = |
|
|
|
new CommandContext(command, commandBus) |
|
|
|
.Complete(); |
|
|
|
|
|
|
|
await sut.HandleAsync(context); |
|
|
|
|
|
|
|
A.CallTo(() => indexByName.RemoveAsync(appId.Id)) |
|
|
|
.MustHaveHappened(); |
|
|
|
|
|
|
|
A.CallTo(() => indexForUser.RemoveAsync(appId.Id)) |
|
|
|
.MustHaveHappened(); |
|
|
|
|
|
|
|
A.CallTo(() => indexForClient.RemoveAsync(appId.Id)) |
|
|
|
.MustHaveHappened(); |
|
|
|
} |
|
|
|
|
|
|
|
@ -405,7 +460,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
|
|
|
|
await sut.RebuildByContributorsAsync(userId, apps); |
|
|
|
|
|
|
|
A.CallTo(() => indexByUser.RebuildAsync(apps)) |
|
|
|
A.CallTo(() => indexForUser.RebuildAsync(apps)) |
|
|
|
.MustHaveHappened(); |
|
|
|
} |
|
|
|
|
|
|
|
@ -416,7 +471,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
|
|
|
|
await sut.RebuildByContributorsAsync(appId.Id, users); |
|
|
|
|
|
|
|
A.CallTo(() => indexByUser.AddAsync(appId.Id)) |
|
|
|
A.CallTo(() => indexForUser.AddAsync(appId.Id)) |
|
|
|
.MustHaveHappened(); |
|
|
|
} |
|
|
|
|
|
|
|
@ -458,7 +513,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
.MustHaveHappened(); |
|
|
|
} |
|
|
|
|
|
|
|
private (IAppEntity, IAppGrain) SetupApp(long version = 0) |
|
|
|
private (IAppEntity, IAppGrain) SetupApp(long version = 0, bool fromClient = false, bool isArchived = false) |
|
|
|
{ |
|
|
|
var appEntity = A.Fake<IAppEntity>(); |
|
|
|
|
|
|
|
@ -468,9 +523,22 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
.Returns(appId.Name); |
|
|
|
A.CallTo(() => appEntity.Version) |
|
|
|
.Returns(version); |
|
|
|
A.CallTo(() => appEntity.IsArchived) |
|
|
|
.Returns(isArchived); |
|
|
|
A.CallTo(() => appEntity.Contributors) |
|
|
|
.Returns(AppContributors.Empty.Assign(userId, Role.Owner)); |
|
|
|
|
|
|
|
if (fromClient) |
|
|
|
{ |
|
|
|
A.CallTo(() => appEntity.CreatedBy) |
|
|
|
.Returns(ClientActor()); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
A.CallTo(() => appEntity.CreatedBy) |
|
|
|
.Returns(UserActor()); |
|
|
|
} |
|
|
|
|
|
|
|
var appGrain = A.Fake<IAppGrain>(); |
|
|
|
|
|
|
|
A.CallTo(() => appGrain.GetStateAsync()) |
|
|
|
@ -484,22 +552,22 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes |
|
|
|
|
|
|
|
private CreateApp Create(string name) |
|
|
|
{ |
|
|
|
return new CreateApp { AppId = appId.Id, Name = name, Actor = ActorSubject() }; |
|
|
|
return new CreateApp { AppId = appId.Id, Name = name, Actor = UserActor() }; |
|
|
|
} |
|
|
|
|
|
|
|
private CreateApp CreateFromClient(string name) |
|
|
|
{ |
|
|
|
return new CreateApp { AppId = appId.Id, Name = name, Actor = ActorClient() }; |
|
|
|
return new CreateApp { AppId = appId.Id, Name = name, Actor = ClientActor() }; |
|
|
|
} |
|
|
|
|
|
|
|
private RefToken ActorSubject() |
|
|
|
private RefToken UserActor() |
|
|
|
{ |
|
|
|
return new RefToken(RefTokenType.Subject, userId); |
|
|
|
} |
|
|
|
|
|
|
|
private RefToken ActorClient() |
|
|
|
private RefToken ClientActor() |
|
|
|
{ |
|
|
|
return new RefToken(RefTokenType.Client, userId); |
|
|
|
return new RefToken(RefTokenType.Client, clientId); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|