public async Task Preparing_with_large_entities_Sets_The_Number_Of_Batches_Correctly() { // Arrange var endpointName = nameof(Preparing_with_large_entities_Sets_The_Number_Of_Batches_Correctly); var timeoutsSource = new AspTimeoutsSource(connectionString, 1024, containerName, fakeEndpointName, fakeEndpointTimeoutTableName, tablePrefix: tableNamePrefix); var runParameters = new Dictionary <string, string> { { "Test", "TestValue" } }; var cutOffDate = DateTime.UtcNow; var endpointTimeoutTableName = tableClient.GetTableReference($"{tableNamePrefix}{fakeEndpointTimeoutTableName}"); await endpointTimeoutTableName.CreateIfNotExistsAsync(); // the entity will roughly be 98 KB and we will store 50 of those which makes the actual payload be around 5 MB string destination = new string('a', 32 * 1024); string stateAddress = new string('s', 32 * 1024); string headers = new string('h', 32 * 1024); var batch = new TableBatchOperation(); for (var x = 0; x < 50; x++) { var dateTime = cutOffDate.AddDays(2); var entity = new TimeoutDataEntity(dateTime.ToString(AspConstants.PartitionKeyScope), Guid.NewGuid().ToString()) { OwningTimeoutManager = endpointName, Destination = destination, SagaId = Guid.NewGuid(), StateAddress = stateAddress, Time = dateTime, Headers = headers, }; batch.Add(TableOperation.Insert(entity)); if (batch.Count % 25 == 0) { await endpointTimeoutTableName.ExecuteBatchAsync(batch); batch.Clear(); } } if (batch.Count > 0) { await endpointTimeoutTableName.ExecuteBatchAsync(batch); } // Act var currentMigration = await timeoutsSource.Prepare(cutOffDate, endpointName, runParameters); // Assert Assert.IsNotNull(currentMigration); Assert.AreEqual(endpointName, currentMigration.EndpointName); Assert.AreEqual(runParameters, currentMigration.RunParameters); Assert.AreEqual(1, currentMigration.NumberOfBatches); Assert.AreEqual(MigrationStatus.StoragePrepared, currentMigration.Status); }
public async Task Aborting_Unhides_The_TimeoutEntities_even_when_preparing_failed() { // Arrange var endpointName = nameof(Aborting_Unhides_The_TimeoutEntities); var timeoutsSource = new AspTimeoutsSource(connectionString, 1, containerName, fakeEndpointName, fakeEndpointTimeoutTableName, tablePrefix: tableNamePrefix); var cutOffDate = DateTime.UtcNow; var endpointTimeoutTableName = tableClient.GetTableReference($"{tableNamePrefix}{fakeEndpointTimeoutTableName}"); await endpointTimeoutTableName.CreateIfNotExistsAsync(); var toolStateTable = tableClient.GetTableReference($"{tableNamePrefix}{AspConstants.ToolStateTableName}"); await toolStateTable.CreateIfNotExistsAsync(); var uniqueHiddenEndpointName = string.Format(AspConstants.MigrationHiddenEndpointNameFormat, "gurlugurlu", endpointName); var toolStateEntity = new ToolStateEntity() { Status = MigrationStatus.Preparing, EndpointName = endpointName, PartitionKey = ToolStateEntity.FixedPartitionKey, RowKey = "bar", UniqueHiddenEndpointName = uniqueHiddenEndpointName }; await toolStateTable.ExecuteAsync(TableOperation.Insert(toolStateEntity)); for (var x = 0; x < 3; x++) { var dateTime = cutOffDate.AddDays(random.Next(1, 5)); var entity = new TimeoutDataEntity(dateTime.ToString(AspConstants.PartitionKeyScope), Guid.NewGuid().ToString()) { OwningTimeoutManager = uniqueHiddenEndpointName, Destination = endpointName, SagaId = Guid.NewGuid(), StateAddress = x.ToString(), Time = dateTime, Headers = "Headers", }; await endpointTimeoutTableName.ExecuteAsync(TableOperation.Insert(entity)); } // Act await timeoutsSource.Abort(); // Assert var query = new TableQuery <TimeoutDataEntity>() .Where(TableQuery.GenerateFilterCondition("OwningTimeoutManager", QueryComparisons.Equal, endpointName)); var timeouts = await endpointTimeoutTableName.ExecuteQuerySegmentedAsync(query, null); Assert.AreEqual(3, timeouts.Results.Count); var currentAfterAborting = await timeoutsSource.TryLoadOngoingMigration(); Assert.IsNull(currentAfterAborting); Assert.IsFalse(await timeoutsSource.CheckIfAMigrationIsInProgress()); }
public async Task Can_Read_Batch_By_Batch_Number() { // Arrange var endpointName = nameof(Can_Read_Batch_By_Batch_Number); var timeoutsSource = new AspTimeoutsSource(connectionString, 1, containerName, fakeEndpointName, fakeEndpointTimeoutTableName, tablePrefix: tableNamePrefix); var runParameters = new Dictionary <string, string> { { "Test", "TestValue" } }; var cutOffDate = DateTime.UtcNow; var expectedDestinations = new List <string>(); var endpointTimeoutTableName = tableClient.GetTableReference($"{tableNamePrefix}{fakeEndpointTimeoutTableName}"); await endpointTimeoutTableName.CreateIfNotExistsAsync(); for (var x = 0; x < 3; x++) { var dateTime = cutOffDate.AddDays(random.Next(1, 5)); var stateAddress = x.ToString(); var entity = new TimeoutDataEntity(dateTime.ToString(AspConstants.PartitionKeyScope), Guid.NewGuid().ToString()) { OwningTimeoutManager = endpointName, Destination = endpointName + stateAddress, SagaId = Guid.NewGuid(), StateAddress = stateAddress, Time = dateTime, Headers = JsonConvert.SerializeObject(runParameters), }; await endpointTimeoutTableName.ExecuteAsync(TableOperation.Insert(entity)); await blobContainerClient.GetBlobClient(stateAddress) .UploadAsync(new MemoryStream(Encoding.UTF8.GetBytes("Hello World!"))); expectedDestinations.Add(endpointName + stateAddress); } await timeoutsSource.Prepare(cutOffDate, endpointName, runParameters); // Act for (var x = 0; x < 3; x++) { var batch = await timeoutsSource.ReadBatch(x + 1); expectedDestinations.Remove(batch.First().Destination); } // Assert // If all the batches were loaded correctly, the destinations would have been removed from the list. Assert.IsEmpty(expectedDestinations); }
public async Task Aborting_Returns_StagedTimeouts_Back_To_TimeoutEntity_Table() { // Arrange var endpointName = nameof(Aborting_Returns_StagedTimeouts_Back_To_TimeoutEntity_Table); var timeoutsSource = new AspTimeoutsSource(connectionString, 1, containerName, fakeEndpointName, fakeEndpointTimeoutTableName, tablePrefix: tableNamePrefix); var runParameters = new Dictionary <string, string> { { "Test", "TestValue" } }; var cutOffDate = DateTime.UtcNow; var endpointTimeoutTableName = tableClient.GetTableReference($"{tableNamePrefix}{fakeEndpointTimeoutTableName}"); await endpointTimeoutTableName.CreateIfNotExistsAsync(); for (var x = 0; x < 3; x++) { var dateTime = cutOffDate.AddDays(random.Next(1, 5)); var entity = new TimeoutDataEntity(dateTime.ToString(AspConstants.PartitionKeyScope), Guid.NewGuid().ToString()) { OwningTimeoutManager = endpointName, Destination = endpointName, SagaId = Guid.NewGuid(), StateAddress = x.ToString(), Time = dateTime, Headers = "Headers", }; await endpointTimeoutTableName.ExecuteAsync(TableOperation.Insert(entity)); } await timeoutsSource.Prepare(cutOffDate, endpointName, runParameters); // Act await timeoutsSource.Abort(); // Assert var query = new TableQuery <TimeoutDataEntity>() .Where(TableQuery.GenerateFilterCondition("OwningTimeoutManager", QueryComparisons.Equal, endpointName)); var timeouts = await endpointTimeoutTableName.ExecuteQuerySegmentedAsync(query, null); Assert.AreEqual(3, timeouts.Results.Count); var currentAfterAborting = await timeoutsSource.TryLoadOngoingMigration(); Assert.IsNull(currentAfterAborting); }
public async Task Complete_Sets_The_MigrationStatus_Correctly() { // Arrange var endpointName = nameof(Marking_A_Batch_As_Complete_Updates_The_Status_Correctly); var timeoutsSource = new AspTimeoutsSource(connectionString, 1, containerName, fakeEndpointName, fakeEndpointTimeoutTableName, tablePrefix: tableNamePrefix); var runParameters = new Dictionary <string, string> { { "Test", "TestValue" } }; var cutOffDate = DateTime.UtcNow; var endpointTimeoutTableName = tableClient.GetTableReference($"{tableNamePrefix}{fakeEndpointTimeoutTableName}"); await endpointTimeoutTableName.CreateIfNotExistsAsync(); for (var x = 0; x < 3; x++) { var dateTime = cutOffDate.AddDays(random.Next(1, 5)); var entity = new TimeoutDataEntity(dateTime.ToString(AspConstants.PartitionKeyScope), Guid.NewGuid().ToString()) { OwningTimeoutManager = endpointName, Destination = endpointName, SagaId = Guid.NewGuid(), StateAddress = x.ToString(), Time = dateTime, Headers = "Headers", }; await endpointTimeoutTableName.ExecuteAsync(TableOperation.Insert(entity)); } var currentMigration = await timeoutsSource.Prepare(cutOffDate, endpointName, runParameters); for (var x = 0; x < currentMigration.NumberOfBatches; x++) { await timeoutsSource.MarkBatchAsCompleted(x + 1); } // Act await timeoutsSource.Complete(); // Assert var loadedMigrationAfterCompletion = await timeoutsSource.TryLoadOngoingMigration(); Assert.IsNull(loadedMigrationAfterCompletion); }
public async Task Preparing_Sets_The_Number_Of_Batches_Correctly() { // Arrange var endpointName = nameof(Preparing_Sets_The_Number_Of_Batches_Correctly); var timeoutsSource = new AspTimeoutsSource(connectionString, 2, containerName, fakeEndpointName, fakeEndpointTimeoutTableName, tablePrefix: tableNamePrefix); var runParameters = new Dictionary <string, string> { { "Test", "TestValue" } }; var cutOffDate = DateTime.UtcNow; var endpointTimeoutTableName = tableClient.GetTableReference($"{tableNamePrefix}{fakeEndpointTimeoutTableName}"); await endpointTimeoutTableName.CreateIfNotExistsAsync(); for (var x = 0; x < 3; x++) { var dateTime = cutOffDate.AddDays(random.Next(1, 5)); var entity = new TimeoutDataEntity(dateTime.ToString(AspConstants.PartitionKeyScope), Guid.NewGuid().ToString()) { OwningTimeoutManager = endpointName, Destination = "SomeDestination", SagaId = Guid.NewGuid(), StateAddress = x.ToString(), Time = dateTime, Headers = "Headers", }; await endpointTimeoutTableName.ExecuteAsync(TableOperation.Insert(entity)); } // Act var currentMigration = await timeoutsSource.Prepare(cutOffDate, endpointName, runParameters); // Assert Assert.IsNotNull(currentMigration); Assert.AreEqual(endpointName, currentMigration.EndpointName); Assert.AreEqual(runParameters, currentMigration.RunParameters); Assert.AreEqual(2, currentMigration.NumberOfBatches); Assert.AreEqual(MigrationStatus.StoragePrepared, currentMigration.Status); }
public async Task ListEndpoint_should_ignore_endpoints_outside_cutoff_date() { // Arrange var timeoutsSource = new AspTimeoutsSource(connectionString, 10, containerName, fakeEndpointName, fakeEndpointTimeoutTableName, tablePrefix: tableNamePrefix); var cutOffDate = DateTime.UtcNow; var endpointTimeoutTableName = tableClient.GetTableReference($"{tableNamePrefix}{fakeEndpointTimeoutTableName}"); await endpointTimeoutTableName.CreateIfNotExistsAsync(); for (var x = 0; x < 5; x++) { int value = x + 1; var dateTime = cutOffDate.AddDays(value); var entity = new TimeoutDataEntity(dateTime.ToString(AspConstants.PartitionKeyScope), Guid.NewGuid().ToString()) { OwningTimeoutManager = fakeEndpointName, Destination = $"Destination{value}", SagaId = Guid.NewGuid(), StateAddress = value.ToString(), Time = dateTime, Headers = "Headers", }; await endpointTimeoutTableName.ExecuteAsync(TableOperation.Insert(entity)); } for (var x = 0; x < 5; x++) { var dateTime = cutOffDate.AddDays(random.Next(1, 5)); var entity = new TimeoutDataEntity(dateTime.ToString(AspConstants.PartitionKeyScope), Guid.NewGuid().ToString()) { OwningTimeoutManager = "DifferentEndpoint", Destination = $"Destination{x}", SagaId = Guid.NewGuid(), StateAddress = x.ToString(), Time = dateTime, Headers = "Headers", }; await endpointTimeoutTableName.ExecuteAsync(TableOperation.Insert(entity)); } var result = await timeoutsSource.ListEndpoints(cutOffDate); Assert.AreEqual(1, result.Count); var singleElement = result[0]; Assert.AreEqual(5, singleElement.NrOfTimeouts); Assert.AreEqual(DateTime.UtcNow.AddDays(1).Day, singleElement.ShortestTimeout.Day); Assert.AreEqual(DateTime.UtcNow.AddDays(5).Day, singleElement.LongestTimeout.Day); CollectionAssert.AreEquivalent(new List <string> { "Destination1", "Destination2", "Destination3", "Destination4", "Destination5", }, singleElement.Destinations); Assert.AreEqual(fakeEndpointName, singleElement.EndpointName); }
public async Task Marking_A_Batch_As_Complete_Updates_The_Status_Correctly(BatchState batchState) { // Arrange var endpointName = nameof(Marking_A_Batch_As_Complete_Updates_The_Status_Correctly); var timeoutsSource = new AspTimeoutsSource(connectionString, 1, containerName, fakeEndpointName, fakeEndpointTimeoutTableName, tablePrefix: tableNamePrefix); var runParameters = new Dictionary <string, string> { { "Test", "TestValue" } }; var cutOffDate = DateTime.UtcNow; var endpointTimeoutTableName = tableClient.GetTableReference($"{tableNamePrefix}{fakeEndpointTimeoutTableName}"); await endpointTimeoutTableName.CreateIfNotExistsAsync(); for (var x = 0; x < 3; x++) { var dateTime = cutOffDate.AddDays(random.Next(1, 5)); var entity = new TimeoutDataEntity(dateTime.ToString(AspConstants.PartitionKeyScope), Guid.NewGuid().ToString()) { OwningTimeoutManager = endpointName, Destination = endpointName, SagaId = Guid.NewGuid(), StateAddress = x.ToString(), Time = dateTime, Headers = "Headers", }; await endpointTimeoutTableName.ExecuteAsync(TableOperation.Insert(entity)); } await timeoutsSource.Prepare(cutOffDate, endpointName, runParameters); // Act switch (batchState) { case BatchState.Staged: await timeoutsSource.MarkBatchAsStaged(1); break; case BatchState.Completed: await timeoutsSource.MarkBatchAsCompleted(1); break; case BatchState.Pending: break; default: return; } // Assert var query = new TableQuery <MigratedTimeoutDataEntity>() .Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, 1.ToString(CultureInfo.InvariantCulture))) .Take(1); var migrationTableName = tableClient.GetTableReference($"{tableNamePrefix}{AspConstants.MigrationTableName}"); var timeoutDataEntities = await migrationTableName.ExecuteQuerySegmentedAsync(query, null); Assert.True(timeoutDataEntities.All(t => t.BatchState == batchState), $"Expected all TimeoutEntity rows to have the batch state set to {batchState}"); }