/// <summary> /// Used for setting up query model before verification it. /// </summary> /// <typeparam name="TIntegrationEvent">Type of integration event.</typeparam> /// <param name="event">Event.</param> /// <param name="getSnapshotIdFunc">Func that should return snapshot Id.</param> /// <returns>Set up query model.</returns> protected async Task <TQueryModel> SetupQueryModelAsync <TIntegrationEvent>( TIntegrationEvent @event, Func <TIntegrationEvent, SnapshotId> getSnapshotIdFunc) where TIntegrationEvent : Event { var snapshotId = getSnapshotIdFunc(@event); // Setup query model in store. var model = Fixture.Build <TQueryModel>() .With(s => s.Id, snapshotId.EntryId) .With(s => s.Version, snapshotId.EntryVersion - 1) .With(s => s.AppliedEvent, new AppliedEvent { Id = Unified.NewCode(), Created = @event.Created.AddMinutes(-1) }) .Create(); await Storage.CreateAsync(model); model.AppliedEvent = new AppliedEvent { Id = @event.Id, Created = @event.Created }; model.Version = snapshotId.EntryVersion; return(model); }
/// <inheritdoc /> public async Task <ProcessResponse> Execute(ProcessRequest <TState> request, ProcessMiddlewareDelegate next, CancellationToken token) { var response = await next(); var correlationId = request.State is IIntegrationEvent @event ? @event.CorrelationId : Unified.NewCode(); var processMessages = response.ProcessMessages .Select(m => { m.Message.CorrelationId = correlationId; EnrichWithUserId(m.Message, options.ActorId); EnrichWithRoles(m.Message, "[]"); var principal = new Principal { IdentityId = options.ActorId, UserId = options.ActorId, IsProcessManager = true, }; m.Message.Actor = principal.AsActor(); if (m.Message is Command cmd) { cmd.Principal = principal; } return(new ProcessMessage(m.Message, m.IsPublished)); }) .ToArray(); return(new ProcessResponse(response.Id, processMessages, response.IsPersisted)); }
protected override TCommand Create(ISpecimenContext context) { var userId = (Seed.UserId ?? Guid.NewGuid()).ToString(); var command = new TCommand { Id = Unified.NewCode(), AggregateRootId = Seed.AggregateRootId ?? Unified.NewCode(), CorrelationId = Unified.NewCode(), ExpectedVersion = 0, Metadata = { [MetadataKey.UserId] = userId, [MetadataKey.Roles] = "[]" }, Actor = { IdentityId = userId, UserId = userId }, Principal = { IdentityId = userId, UserId = userId } }; Setup(command); Seed.Setup?.Invoke(command); return(command); }
/// <summary> /// Wraps command with some defaults properies like Id, CorrelationId /// and metadata fields UserId, Roles to pass validation. /// </summary> /// <param name="cmd">Comamnd.</param> public static void Wrap(this Command cmd) { cmd.Id = Unified.NewCode(); cmd.CorrelationId = Unified.NewCode(); cmd.Metadata[MetadataKey.UserId] = Guid.NewGuid().ToString(); cmd.Metadata[MetadataKey.Roles] = "Admin"; }
/// <summary> /// Used for setting up query model before verification it. /// </summary> /// <typeparam name="TIntegrationEvent">Type of integration event.</typeparam> /// <param name="event">Event.</param> /// <param name="getId">Func that should return Id.</param> /// <param name="setup">Setup func for query model.</param> /// <returns>Set up query model.</returns> protected async Task <TQueryModel> SetupQueryModelAsync <TIntegrationEvent>( TIntegrationEvent @event, Func <TIntegrationEvent, string> getId, Action <TQueryModel> setup = null) where TIntegrationEvent : Event { var id = getId(@event); // Setup query model in store. var queryModel = Fixture.Build <TQueryModel>() .With(s => s.Id, id) .With(s => s.AppliedEvent, new AppliedEvent { Id = Unified.NewCode(), Created = @event.Created.AddMinutes(-1) }) .Create(); setup?.Invoke(queryModel); await Storage.CreateAsync(queryModel); queryModel.AppliedEvent = new AppliedEvent { Id = @event.Id, Created = @event.Created }; return(queryModel); }
public async Task GetCommands_NoCommnds_EmptyCollcetionReturned() { var id = Unified.NewCode(); var processCommands = await storage.GetMessagesAsync(id); processCommands.Should().BeEmpty(); }
public async Task ReserveDisallowedCharsName() { var dissalowedCharsName = $"{Unified.NewCode()}_#\t\n?"; var result = await uniqueConstraintService.ReserveConstraintAsync("TestIndex", dissalowedCharsName); result.Success.Should().BeTrue(); }
public async Task SaveAsync_NoEvents_Throws() { var id = Unified.NewCode(); var executionContext = new AggregateExecutionContext(Fixtures.Pipelines.FakeCreateCommand()); var aggregateRoot = new FakeAggregateRoot(id, executionContext); await store.Awaiting(s => s.SaveAsync(aggregateRoot)).Should().ThrowAsync <InvalidOperationException>(); }
public async Task MarkCommnadAsPublished_NoPersistedCommnds_ExpectedException() { var id = Unified.NewCode(); var command = fixture.Create <TestCreateCommand>(); Func <Task> act = async() => await storage.MarkMessageAsPublishedAsync(id, command); await act.Should().ThrowAsync <StorageException>(); }
public async Task PersistCommands_MaxBatSize_NotSupportedException() { var id = Unified.NewCode(); var commands = fixture.CreateMany <TestCreateCommand>(100) .ToArray(); Func <Task> act = async() => await storage.PersistMessagesAsync(id, commands); await act.Should().ThrowAsync <NotSupportedException>(); }
public void IsInRole_UserHasAnotherRole_ReturnsFalse() { var principal = new Principal { Claims = new[] { new IdentityClaim { Type = ClaimTypes.Role, Value = Unified.NewCode() } } }; principal.IsInRole(Unified.NewCode()).Should().BeFalse(); }
private TransactionRecord CreateTransactionRecord(params FakeAggregateRoot[] aggregateRoots) { return(new TransactionRecord { TransactionId = Unified.NewCode(), IntegrationEvent = Fixtures.Pipelines.FakeCreatedIntegrationEvent(), StateEvents = aggregateRoots.SelectMany(ar => ar.Events).ToList(), IsCommitted = false }); }
public Task <ProcessResponse> Handle(ProcessRequest <CustomState> request, CancellationToken cancellationToken) { var state = request.State; return(ResponseAsync(request, new TestCreateCommand { AggregateRootId = Unified.NewCode(), TestData = state.Data })); }
private FakeAggregateRoot SetupAggregateRootWithEvents() { var id = Unified.NewCode(); var executionContext = new AggregateExecutionContext(Fixtures.Pipelines.FakeCreateCommand()); var aggregateRoot = new FakeAggregateRoot(id, executionContext); aggregateRoot.Create(FixtureUtils.String()); aggregateRoot.Update(FixtureUtils.String()); return(aggregateRoot); }
public async Task ReserveTestName() { var testId = Unified.NewCode(); await uniqueConstraintService.ReserveConstraintAsync("TestIndex", testId); var hash = Unified.NewCode(Unified.NewHash(Encoding.UTF8.GetBytes(testId))); var testResult = await table.ExecuteAsync(TableOperation.Retrieve("TestIndex", hash)); Assert.NotNull(testResult.Result); }
public async Task RemoveTestName() { var testId = Unified.NewCode(); await uniqueConstraintService.ReserveConstraintAsync("TestIndex", testId); await uniqueConstraintService.RemoveConstraintAsync("TestIndex", testId); var result = await table.ExecuteAsync(TableOperation.Retrieve("TestIndex", testId)); Assert.Null(result.Result); }
public void Validate_AggregateRootIdIsMissing_Fails() { var cmd = new FakeCommand { Id = Unified.NewCode() }; var result = (FailedResult)cmd.Validate(); Assert.Equal($"{nameof(FakeCommand)}.{nameof(cmd.AggregateRootId)}", result.Details.First().Source); }
/// <summary> /// Initializes a new instance of the <see cref="OperationCompletedSignal"/> class. /// </summary> /// <param name="source">Message.</param> public OperationCompletedSignal(IMessage source) { Source = source ?? throw new ArgumentNullException($"Source in the OperationCompletedSignal should be set"); Id = Unified.NewCode(); AggregateRootId = source.AggregateRootId; CorrelationId = source.CorrelationId; Actor = source.Actor; source.CopyMetadata(this); }
public async Task GetLatestAsync_HasQueryModels_ReturnsLatest() { var id = Unified.NewCode(); await storage.CreateAsync(new FakeImmutableQueryModel { Id = id, Version = 1 }); var qm2 = await storage.CreateAsync(new FakeImmutableQueryModel { Id = id, Version = 2 }); var latest = await storage.FindLatestAsync(id); latest.Should().BeEquivalentTo(qm2); }
public async Task RemoveTestNameNoSource() { var testId = Unified.NewCode(); var result = await uniqueConstraintService.RemoveConstraintAsync("TestIndex", testId); Assert.False(result.Success); var failedResult = (FailedResult)result; failedResult.CodeInfo.Should().BeEquivalentTo(CoreErrorCodes.UnhandledError); failedResult.Details.Single().CodeInfo.Should().BeEquivalentTo(CoreErrorCodes.NameIsNotFound); }
public void Serialization_PropertyIsImmutable_UpdatesValue() { var data = new DummyData { SnapshotId = new SnapshotId { EntryId = Unified.NewCode(), EntryVersion = 1 } }; var entity = new DummyJsonTableEntity(data); entity.DeserializeData().Should().BeEquivalentTo(data); }
public async Task GetEqualOrOlderAsync_ExactlyVersion_ReturnsExactlyVersion() { var id = Unified.NewCode(); await storage.CreateAsync(new FakeImmutableQueryModel { Id = id, Version = 1 }); var queryModel = await storage.CreateAsync(new FakeImmutableQueryModel { Id = id, Version = 3 }); var result = await storage.GetEqualOrLessAsync(id, 3); result.Should().BeEquivalentTo(queryModel); }
public void CreateFromSource2_Always_CopiesMessageCorrelationData() { var integrationEvent = Fixtures.Pipelines.FakeCreatedIntegrationEvent(); var signal = QueryModelChangedSignal.CreateFromSource( integrationEvent, Unified.NewCode(), typeof(int), FixtureUtils.FromEnum <QueryModelChangeOperation>()); signal.Should().BeEquivalentTo(integrationEvent, options => options.ForMessage()); }
public async Task Replace_WhenETagIsInvalid_Throws() { var qm1 = await storage.CreateAsync(new FakeMutableQueryModel()); // Update query model. qm1.Data = Unified.NewCode(); await storage.ReplaceAsync(qm1); // Trying to update again should fail as ETag is changed after first update. (await storage.Awaiting(s => s.ReplaceAsync(qm1)).Should().ThrowAsync <StorageException>()) .Which.RequestInformation.ExtendedErrorInformation.ErrorCode.Should().Be(TableErrorCodeStrings.UpdateConditionNotSatisfied); }
public async Task PersistCommands_All_CommandsSaved() { var id = Unified.NewCode(); var commands = fixture.CreateMany <TestCreateCommand>() .ToArray(); var expectedProcessCommands = commands.Select(cmd => new ProcessMessage(cmd)); await storage.PersistMessagesAsync(id, commands); var processCommands = await storage.GetMessagesAsync(id); processCommands.Should().BeEquivalentTo(expectedProcessCommands); }
public void Validate_RolesAreMissing_Fails() { var cmd = new FakeCommand { Id = Unified.NewCode(), AggregateRootId = Unified.NewCode(), CorrelationId = Unified.NewCode() }; var result = (FailedResult)cmd.Validate(); Assert.Equal($"{nameof(FakeCommand)}.{nameof(Command.Metadata)}.{nameof(MetadataKey.Roles)}", result.Details.First().Source); }
public async Task FindEqualOrOlderAsync_OlderVersion_ReturnsClosestOlderVersionVersion() { var id = Unified.NewCode(); await storage.CreateAsync(new FakeImmutableQueryModel { Id = id, Version = 1 }); var queryModel = await storage.CreateAsync(new FakeImmutableQueryModel { Id = id, Version = 4 }); await storage.CreateAsync(new FakeImmutableQueryModel { Id = id, Version = 10 }); var result = await storage.FindEqualOrLessAsync(id, 7); result.Should().BeEquivalentTo(queryModel); }
public void Constructor_Always_UpdatesProperties() { var queryModelId = Unified.NewCode(); var queryModelVersion = FixtureUtils.Int(); var queryModelType = typeof(int); var operation = FixtureUtils.FromEnum <QueryModelChangeOperation>(); var signal = new QueryModelChangedSignal(queryModelId, queryModelVersion, queryModelType, operation); signal.QueryModelId.Should().Be(queryModelId); signal.QueryModelVersion.Should().Be(queryModelVersion); signal.QueryModelType.Should().Be(queryModelType); signal.Operation.Should().Be(operation); }
/// <summary> /// Converts abstract message to another type. /// </summary> /// <param name="source">source message.</param> /// <typeparam name="TMessage">Mesaage Type.</typeparam> /// <returns>Message.</returns> public static TMessage ToType <TMessage>(this IMessage source) where TMessage : AbstractMessage, new() { var result = new TMessage { Id = Unified.NewCode(), AggregateRootId = source.AggregateRootId, CorrelationId = source.CorrelationId }; source.CopyMetadata(result); return(result); }
public async Task Replace_WhenETagIsValid_Replaces() { var qm1 = await storage.CreateAsync(new FakeMutableQueryModel()); // Update for the first time. qm1.Data = Unified.NewCode(); var updated1 = await storage.ReplaceAsync(qm1); // Update again with the valid changed ETag. updated1.Data = Unified.NewCode(); var updated2 = await storage.ReplaceAsync(updated1); updated2.Should().BeEquivalentTo(updated1, options => options.ForMutableQueryModel()); }