diff --git a/pipeline/azure-pipelines-emulator.yml b/pipeline/azure-pipelines-emulator.yml new file mode 100644 index 0000000..f7e608d --- /dev/null +++ b/pipeline/azure-pipelines-emulator.yml @@ -0,0 +1,45 @@ +trigger: none +pr: + branches: + include: + - master + - releases/* + +pool: + vmImage: 'windows-latest' + +steps: +- pwsh: | + Write-Host "Downloading Cosmos Emulator - $env:EMULATORMSIURL" -ForegroundColor green + Invoke-WebRequest "$env:EMULATORMSIURL" -OutFile "$env:temp\azure-cosmosdb-emulator.msi" + Write-Host "Finished Downloading Cosmos Emulator - $env:temp\azure-cosmosdb-emulator.msi" -ForegroundColor green + dir "$env:temp" + choco install lessmsi + choco upgrade lessmsi + mkdir "$env:temp\Azure Cosmos DB Emulator" + lessmsi x "$env:temp\azure-cosmosdb-emulator.msi" "$env:temp\Azure Cosmos DB Emulator\" + Write-Host "Starting Cosmos DB Emulator" -ForegroundColor green + Start-Process "$env:temp\Azure Cosmos DB Emulator\SourceDir\Azure Cosmos DB Emulator\CosmosDB.Emulator.exe" "/NoExplorer /NoUI /DisableRateLimiting /PartitionCount=100 /Consistency=Strong /enableRio /overrides=sqlAllowGroupByClause:true" -Verb RunAs + Import-Module "$env:temp\Azure Cosmos DB Emulator\SourceDir\Azure Cosmos DB Emulator\PSModules\Microsoft.Azure.CosmosDB.Emulator" + Get-Item env:* | Sort-Object -Property Name + for ($i=0; $i -lt 10; $i++) { + $status=Get-CosmosDbEmulatorStatus + if ($status -ne "Running") { + sleep 30; + Write-Host "Cosmos DB Emulator Status: $status" -ForegroundColor yellow + } else { + break; + } + } +- task: DotNetCoreCLI@2 + displayName: Build + inputs: + command: build + projects: '**/*.csproj' +- script: dotnet test ./src/DocumentDB.ChangeFeedProcessor.IntegrationTests/DocumentDB.ChangeFeedProcessor.IntegrationTests.csproj --logger trx + displayName: 'Running tests' +- task: PublishTestResults@2 + condition: succeededOrFailed() + inputs: + testRunner: VSTest + testResultsFiles: '**/*.trx' \ No newline at end of file diff --git a/pipeline/azure-pipelines.yml b/pipeline/azure-pipelines.yml new file mode 100644 index 0000000..fe21b89 --- /dev/null +++ b/pipeline/azure-pipelines.yml @@ -0,0 +1,29 @@ +trigger: none +pr: + branches: + include: + - master + - releases/* + +strategy: + matrix: + windows: + imageName: 'windows-latest' + +pool: + vmImage: $(imageName) + +steps: +- task: DotNetCoreCLI@2 + displayName: Build + inputs: + command: build + projects: '**/*.csproj' + arguments: '--configuration Release' +- script: dotnet test ./src/DocumentDB.ChangeFeedProcessor.UnitTests/DocumentDB.ChangeFeedProcessor.UnitTests.csproj --logger trx + displayName: 'Running tests' +- task: PublishTestResults@2 + condition: succeededOrFailed() + inputs: + testRunner: VSTest + testResultsFiles: '**/*.trx' \ No newline at end of file diff --git a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/DynamicCollectionTests.cs b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/DynamicCollectionTests.cs index 4891650..9b30817 100644 --- a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/DynamicCollectionTests.cs +++ b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/DynamicCollectionTests.cs @@ -25,14 +25,10 @@ public class DynamicCollectionTests : IntegrationTest { const int documentCount = 513; - public DynamicCollectionTests(IntegrationTestFixture fixture) : base(fixture, typeof(DynamicCollectionTests)) - { - } - [Fact] public async Task CountAddedDocuments() { - int partitionCount = await IntegrationTestsHelper.GetPartitionCount(this.ClassData.monitoredCollectionInfo); + int partitionCount = await IntegrationTestsHelper.GetPartitionCount(this.MonitoredCollectionInfo); int openedCount = 0, processedCount = 0; var allObserversStarted = new ManualResetEvent(false); var allDocsProcessed = new ManualResetEvent(false); @@ -54,7 +50,7 @@ public async Task CountAddedDocuments() var host = new ChangeFeedEventHost( Guid.NewGuid().ToString(), - this.ClassData.monitoredCollectionInfo, + this.MonitoredCollectionInfo, this.LeaseCollectionInfo, new ChangeFeedOptions { StartFromBeginning = false }, new ChangeFeedHostOptions()); @@ -63,11 +59,11 @@ public async Task CountAddedDocuments() var isStartOk = allObserversStarted.WaitOne(IntegrationTest.changeWaitTimeout + IntegrationTest.changeWaitTimeout); Assert.True(isStartOk, "Timed out waiting for observres to start"); - using (var client = new DocumentClient(this.ClassData.monitoredCollectionInfo.Uri, this.ClassData.monitoredCollectionInfo.MasterKey, this.ClassData.monitoredCollectionInfo.ConnectionPolicy)) + using (var client = new DocumentClient(this.MonitoredCollectionInfo.Uri, this.MonitoredCollectionInfo.MasterKey, this.MonitoredCollectionInfo.ConnectionPolicy)) { await IntegrationTestsHelper.CreateDocumentsAsync( client, - UriFactory.CreateDocumentCollectionUri(this.ClassData.monitoredCollectionInfo.DatabaseName, this.ClassData.monitoredCollectionInfo.CollectionName), + UriFactory.CreateDocumentCollectionUri(this.MonitoredCollectionInfo.DatabaseName, this.MonitoredCollectionInfo.CollectionName), documentCount); } @@ -86,8 +82,8 @@ await IntegrationTestsHelper.CreateDocumentsAsync( [Fact] public async Task TestStartTime() { - var collectionUri = UriFactory.CreateDocumentCollectionUri(this.ClassData.monitoredCollectionInfo.DatabaseName, this.ClassData.monitoredCollectionInfo.CollectionName); - using (var client = new DocumentClient(this.ClassData.monitoredCollectionInfo.Uri, this.ClassData.monitoredCollectionInfo.MasterKey, this.ClassData.monitoredCollectionInfo.ConnectionPolicy)) + var collectionUri = UriFactory.CreateDocumentCollectionUri(this.MonitoredCollectionInfo.DatabaseName, this.MonitoredCollectionInfo.CollectionName); + using (var client = new DocumentClient(this.MonitoredCollectionInfo.Uri, this.MonitoredCollectionInfo.MasterKey, this.MonitoredCollectionInfo.ConnectionPolicy)) { await client.CreateDocumentAsync(collectionUri, JsonConvert.DeserializeObject("{\"id\": \"doc1\"}")); @@ -99,7 +95,7 @@ public async Task TestStartTime() await client.CreateDocumentAsync(collectionUri, JsonConvert.DeserializeObject("{\"id\": \"doc2\"}")); - int partitionCount = await IntegrationTestsHelper.GetPartitionCount(this.ClassData.monitoredCollectionInfo); + int partitionCount = await IntegrationTestsHelper.GetPartitionCount(this.MonitoredCollectionInfo); var allDocsProcessed = new ManualResetEvent(false); var processedDocs = new List(); @@ -118,7 +114,7 @@ public async Task TestStartTime() var host = new ChangeFeedEventHost( Guid.NewGuid().ToString(), - this.ClassData.monitoredCollectionInfo, + this.MonitoredCollectionInfo, this.LeaseCollectionInfo, new ChangeFeedOptions { StartTime = timeInBeweeen }, new ChangeFeedHostOptions()); @@ -143,15 +139,15 @@ public async Task TestStartTime() public async Task TestReducePageSizeScenario() { // Use different colleciton: we need 1-partition collection to make sure all docs get to same partition. - var databaseUri = UriFactory.CreateDatabaseUri(this.ClassData.monitoredCollectionInfo.DatabaseName); + var databaseUri = UriFactory.CreateDatabaseUri(this.MonitoredCollectionInfo.DatabaseName); - DocumentCollectionInfo monitoredCollectionInfo = new DocumentCollectionInfo(this.ClassData.monitoredCollectionInfo); - monitoredCollectionInfo.CollectionName = this.ClassData.monitoredCollectionInfo.CollectionName + "_" + Guid.NewGuid().ToString(); + DocumentCollectionInfo monitoredCollectionInfo = new DocumentCollectionInfo(this.MonitoredCollectionInfo); + monitoredCollectionInfo.CollectionName = this.MonitoredCollectionInfo.CollectionName + "_" + Guid.NewGuid().ToString(); - var collectionUri = UriFactory.CreateDocumentCollectionUri(this.ClassData.monitoredCollectionInfo.DatabaseName, monitoredCollectionInfo.CollectionName); + var collectionUri = UriFactory.CreateDocumentCollectionUri(this.MonitoredCollectionInfo.DatabaseName, monitoredCollectionInfo.CollectionName); var monitoredCollection = new DocumentCollection { Id = monitoredCollectionInfo.CollectionName }; - using (var client = new DocumentClient(this.ClassData.monitoredCollectionInfo.Uri, this.ClassData.monitoredCollectionInfo.MasterKey, this.ClassData.monitoredCollectionInfo.ConnectionPolicy)) + using (var client = new DocumentClient(this.MonitoredCollectionInfo.Uri, this.MonitoredCollectionInfo.MasterKey, this.MonitoredCollectionInfo.ConnectionPolicy)) { await client.CreateDocumentCollectionAsync(databaseUri, monitoredCollection, new RequestOptions { OfferThroughput = 10000 }); @@ -169,7 +165,7 @@ public async Task TestReducePageSizeScenario() );}" }; - var sprocUri = UriFactory.CreateStoredProcedureUri(this.ClassData.monitoredCollectionInfo.DatabaseName, monitoredCollection.Id, sproc.Id); + var sprocUri = UriFactory.CreateStoredProcedureUri(this.MonitoredCollectionInfo.DatabaseName, monitoredCollection.Id, sproc.Id); await client.CreateStoredProcedureAsync(collectionUri, sproc); await client.ExecuteStoredProcedureAsync(sprocUri, 0); diff --git a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/EstimatorTests.cs b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/EstimatorTests.cs index 6a3e5ee..255d936 100644 --- a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/EstimatorTests.cs +++ b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/EstimatorTests.cs @@ -18,17 +18,15 @@ namespace Microsoft.Azure.Documents.ChangeFeedProcessor.IntegrationTests [Collection("Integration tests")] public class EstimatorTests : IntegrationTest { - public EstimatorTests(IntegrationTestFixture fixture) : base(fixture, typeof(EstimatorTests), false) + public EstimatorTests() : base(false) { } [Fact] public async Task CountPendingDocuments() { - // Cleanup the test collection to avoid other tests' documents causing issues with StartFromBeginning - await this.ResetTestCollection(); int documentCount = 1; - int partitionCount = await IntegrationTestsHelper.GetPartitionCount(this.ClassData.monitoredCollectionInfo); + int partitionCount = await IntegrationTestsHelper.GetPartitionCount(this.MonitoredCollectionInfo); int openedCount = 0, processedCount = 0; var allObserversStarted = new ManualResetEvent(false); var allDocsProcessed = new ManualResetEvent(false); @@ -52,7 +50,7 @@ public async Task CountPendingDocuments() var host = new ChangeFeedEventHost( hostName, - this.ClassData.monitoredCollectionInfo, + this.MonitoredCollectionInfo, this.LeaseCollectionInfo, new ChangeFeedOptions { StartFromBeginning = false }, new ChangeFeedHostOptions()); @@ -64,11 +62,11 @@ public async Task CountPendingDocuments() long estimation = await host.GetEstimatedRemainingWork(); Assert.Equal(0, estimation); - using (var client = new DocumentClient(this.ClassData.monitoredCollectionInfo.Uri, this.ClassData.monitoredCollectionInfo.MasterKey, this.ClassData.monitoredCollectionInfo.ConnectionPolicy)) + using (var client = new DocumentClient(this.MonitoredCollectionInfo.Uri, this.MonitoredCollectionInfo.MasterKey, this.MonitoredCollectionInfo.ConnectionPolicy)) { await IntegrationTestsHelper.CreateDocumentsAsync( client, - UriFactory.CreateDocumentCollectionUri(this.ClassData.monitoredCollectionInfo.DatabaseName, this.ClassData.monitoredCollectionInfo.CollectionName), + UriFactory.CreateDocumentCollectionUri(this.MonitoredCollectionInfo.DatabaseName, this.MonitoredCollectionInfo.CollectionName), 1); var isStartOk = allObserversStarted.WaitOne(IntegrationTest.changeWaitTimeout + IntegrationTest.changeWaitTimeout); @@ -84,7 +82,7 @@ await IntegrationTestsHelper.CreateDocumentsAsync( await IntegrationTestsHelper.CreateDocumentsAsync( client, - UriFactory.CreateDocumentCollectionUri(this.ClassData.monitoredCollectionInfo.DatabaseName, this.ClassData.monitoredCollectionInfo.CollectionName), + UriFactory.CreateDocumentCollectionUri(this.MonitoredCollectionInfo.DatabaseName, this.MonitoredCollectionInfo.CollectionName), 1); estimation = await host.GetEstimatedRemainingWork(); @@ -92,7 +90,7 @@ await IntegrationTestsHelper.CreateDocumentsAsync( await IntegrationTestsHelper.CreateDocumentsAsync( client, - UriFactory.CreateDocumentCollectionUri(this.ClassData.monitoredCollectionInfo.DatabaseName, this.ClassData.monitoredCollectionInfo.CollectionName), + UriFactory.CreateDocumentCollectionUri(this.MonitoredCollectionInfo.DatabaseName, this.MonitoredCollectionInfo.CollectionName), 10); estimation = await host.GetEstimatedRemainingWork(); @@ -101,7 +99,7 @@ await IntegrationTestsHelper.CreateDocumentsAsync( // Create a new host to process pending changes var newHost = new ChangeFeedEventHost( hostName, - this.ClassData.monitoredCollectionInfo, + this.MonitoredCollectionInfo, this.LeaseCollectionInfo, new ChangeFeedOptions { StartFromBeginning = false }, new ChangeFeedHostOptions()); @@ -132,13 +130,11 @@ await IntegrationTestsHelper.CreateDocumentsAsync( [Fact] public async Task WhenNoLeasesExistReturn1() { - // Cleanup the test collection to avoid other tests' documents causing issues with StartFromBeginning - await this.ResetTestCollection(); var hostName = Guid.NewGuid().ToString(); var host = new ChangeFeedEventHost( hostName, - this.ClassData.monitoredCollectionInfo, + this.MonitoredCollectionInfo, this.LeaseCollectionInfo, new ChangeFeedOptions { StartFromBeginning = false }, new ChangeFeedHostOptions()); @@ -155,10 +151,8 @@ public async Task WhenNoLeasesExistReturn1() [Fact] public async Task WhenLeasesHaveContinuationTokenNullReturn0() { - // Cleanup the test collection to avoid other tests' documents causing issues with StartFromBeginning - await this.ResetTestCollection(); int documentCount = 1; - int partitionCount = await IntegrationTestsHelper.GetPartitionCount(this.ClassData.monitoredCollectionInfo); + int partitionCount = await IntegrationTestsHelper.GetPartitionCount(this.MonitoredCollectionInfo); int openedCount = 0, processedCount = 0; var allObserversStarted = new ManualResetEvent(false); var allDocsProcessed = new ManualResetEvent(false); @@ -183,7 +177,7 @@ public async Task WhenLeasesHaveContinuationTokenNullReturn0() // We create a host to initialize the leases with ContinuationToken null var host = new ChangeFeedEventHost( hostName, - this.ClassData.monitoredCollectionInfo, + this.MonitoredCollectionInfo, this.LeaseCollectionInfo, new ChangeFeedOptions { StartFromBeginning = false }, new ChangeFeedHostOptions()); @@ -205,10 +199,8 @@ public async Task WhenLeasesHaveContinuationTokenNullReturn0() [Fact] public async Task WhenLeasesHaveContinuationTokenNullStartFromBeginning() { - // Cleanup the test collection to avoid other tests' documents causing issues with StartFromBeginning - await this.ResetTestCollection(); int documentCount = 1; - int partitionCount = await IntegrationTestsHelper.GetPartitionCount(this.ClassData.monitoredCollectionInfo); + int partitionCount = await IntegrationTestsHelper.GetPartitionCount(this.MonitoredCollectionInfo); int openedCount = 0, processedCount = 0; var allObserversStarted = new ManualResetEvent(false); var allDocsProcessed = new ManualResetEvent(false); @@ -233,7 +225,7 @@ public async Task WhenLeasesHaveContinuationTokenNullStartFromBeginning() // We create a host to initialize the leases with ContinuationToken null var host = new ChangeFeedEventHost( hostName, - this.ClassData.monitoredCollectionInfo, + this.MonitoredCollectionInfo, this.LeaseCollectionInfo, new ChangeFeedOptions { StartFromBeginning = false }, new ChangeFeedHostOptions()); @@ -244,14 +236,14 @@ public async Task WhenLeasesHaveContinuationTokenNullStartFromBeginning() await host.UnregisterObserversAsync(); using (var client = new DocumentClient( - this.ClassData.monitoredCollectionInfo.Uri, - this.ClassData.monitoredCollectionInfo.MasterKey, - this.ClassData.monitoredCollectionInfo.ConnectionPolicy)) + this.MonitoredCollectionInfo.Uri, + this.MonitoredCollectionInfo.MasterKey, + this.MonitoredCollectionInfo.ConnectionPolicy)) { // Insert documents await IntegrationTestsHelper.CreateDocumentsAsync( client, - UriFactory.CreateDocumentCollectionUri(this.ClassData.monitoredCollectionInfo.DatabaseName, this.ClassData.monitoredCollectionInfo.CollectionName), + UriFactory.CreateDocumentCollectionUri(this.MonitoredCollectionInfo.DatabaseName, this.MonitoredCollectionInfo.CollectionName), 10); // Since the leases have ContinuationToken null state, the estimator will use StartFromBeginning and pick-up the changes that happened from the start diff --git a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/IntegrationTest.cs b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/IntegrationTest.cs index deafa49..61ce16d 100644 --- a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/IntegrationTest.cs +++ b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/IntegrationTest.cs @@ -3,9 +3,6 @@ //---------------------------------------------------------------- using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Diagnostics; using System.Reflection; using System.Threading; @@ -17,25 +14,6 @@ namespace Microsoft.Azure.Documents.ChangeFeedProcessor.IntegrationTests { - public class TestClassData - { - internal readonly SemaphoreSlim classInitializeSyncRoot = new SemaphoreSlim(1, 1); - internal readonly object testContextSyncRoot = new object(); - internal readonly int testCount; - internal readonly bool isPartitionedMonitoredCollection; - internal readonly bool isPartitionedLeaseCollection; - internal volatile int executedTestCount; - internal DocumentCollectionInfo monitoredCollectionInfo; - internal DocumentCollectionInfo leaseCollectionInfoTemplate; - - internal TestClassData(int testCount, bool isPartitionedMonitoredCollection, bool isPartitionedLeaseCollection) - { - this.testCount = testCount; - this.isPartitionedMonitoredCollection = isPartitionedMonitoredCollection; - this.isPartitionedLeaseCollection = isPartitionedLeaseCollection; - } - } - /// /// Fixture is shared among all instances. https://xunit.github.io/docs/shared-context.html#collection-fixture /// @@ -46,8 +24,6 @@ public IntegrationTestFixture() System.Net.ServicePointManager.DefaultConnectionLimit = 1000; // Default is 2. ThreadPool.SetMinThreads(1000, 1000); // 32 ThreadPool.SetMaxThreads(5000, 5000); // 32 - Properties = new ConcurrentDictionary(); - testClasses = new ConcurrentDictionary(); } public void Dispose() @@ -68,9 +44,6 @@ public async Task DisposeAsync() await client.DeleteDatabaseAsync(UriFactory.CreateDatabaseUri(databaseName)); } } - - public IDictionary Properties { get; private set; } - public IDictionary testClasses { get; private set; } } [CollectionDefinition("Integration tests")] @@ -93,74 +66,50 @@ public class IntegrationTestCollection : ICollectionFixture [Trait("Category", "Integration")] [Collection("Integration tests")] - public class IntegrationTest: IDisposable + public class IntegrationTest: IAsyncLifetime { - private const string leaseCollectionInfoPropertyName = "leaseCollectionInfo"; protected static int monitoredOfferThroughput; protected static int leaseOfferThroughput; protected static readonly TimeSpan changeWaitTimeout = TimeSpan.FromSeconds(30); - /// - /// This dictionary has one entry per derived class. - /// - private static object testClassesSyncRoot = new object(); - IntegrationTestFixture fixture; protected DocumentCollectionInfo LeaseCollectionInfo { - get { return (DocumentCollectionInfo)this.fixture.Properties[leaseCollectionInfoPropertyName]; } - set - { - lock (this.ClassData.testContextSyncRoot) - { - this.fixture.Properties[leaseCollectionInfoPropertyName] = value; - } - } + get; + private set; } - public TestClassData ClassData + protected DocumentCollectionInfo MonitoredCollectionInfo { - get { return this.fixture.testClasses[this.GetType().Name]; } + get; + private set; } - + + protected readonly bool IsPartitionedMonitoredCollection; + + protected readonly bool IsPartitionedLeaseCollection; + public IntegrationTest( - IntegrationTestFixture fixture, - Type testClassType, - bool isPartitionedCollection = true, + bool isPartitionedMonitoredCollection = true, bool isPartitionedLeaseCollection = false) { - this.fixture = fixture; - if (!this.fixture.testClasses.ContainsKey(testClassType.Name)) - { - this.fixture.testClasses[testClassType.Name] = new TestClassData( - GetTestCount(testClassType), - isPartitionedCollection, - isPartitionedLeaseCollection); - } - - TestInitializeAsync().Wait(); + this.IsPartitionedMonitoredCollection = isPartitionedMonitoredCollection; + this.IsPartitionedLeaseCollection = isPartitionedLeaseCollection; } - public async Task TestInitializeAsync() + public async Task InitializeAsync() { - if (this.ClassData.monitoredCollectionInfo == null) + try { - try - { - if (this.ClassData.monitoredCollectionInfo == null) - { - this.ClassData.leaseCollectionInfoTemplate = await TestClassInitializeAsync(this, $"data_{this.GetType().Name}"); - } - } - catch(Exception ex) - { - Debug.Write(ex); - throw; - } + await this.CreateMonitoredCollectionAsync($"data_{this.GetType().Name}"); + } + catch(Exception ex) + { + Debug.WriteLine(ex); + throw; } - this.LeaseCollectionInfo = new DocumentCollectionInfo(this.ClassData.leaseCollectionInfoTemplate); this.LeaseCollectionInfo.CollectionName = $"leases_{this.GetType().Name}_{Guid.NewGuid().ToString()}"; var leaseCollection = new DocumentCollection @@ -168,7 +117,7 @@ public async Task TestInitializeAsync() Id = this.LeaseCollectionInfo.CollectionName, }; - if (this.ClassData.isPartitionedLeaseCollection) + if (this.IsPartitionedLeaseCollection) { leaseCollection.PartitionKey = new PartitionKeyDefinition { Paths = { "/id" } }; } @@ -179,61 +128,37 @@ public async Task TestInitializeAsync() } } - public void Dispose() - { - TestCleanupAsync().Wait(); - } - - public async Task TestCleanupAsync() + public async Task DisposeAsync() { Debug.Assert(this.LeaseCollectionInfo != null); using (var client = new DocumentClient(this.LeaseCollectionInfo.Uri, this.LeaseCollectionInfo.MasterKey, this.LeaseCollectionInfo.ConnectionPolicy)) { await client.DeleteDocumentCollectionAsync(UriFactory.CreateDocumentCollectionUri(this.LeaseCollectionInfo.DatabaseName, this.LeaseCollectionInfo.CollectionName)); + await client.DeleteDocumentCollectionAsync(UriFactory.CreateDocumentCollectionUri(this.MonitoredCollectionInfo.DatabaseName, this.MonitoredCollectionInfo.CollectionName)); } - - var executedTestCount = Interlocked.Increment(ref this.ClassData.executedTestCount); - if (this.ClassData.executedTestCount == this.ClassData.testCount) - { - await TestClassCleanupAsync(this); - } - } - - /// - /// Recreates the test collection - /// - /// - public async Task ResetTestCollection() - { - await IntegrationTest.TestClassCleanupAsync(this); - await IntegrationTest.TestClassInitializeAsync(this, $"data_{this.GetType().Name}"); - } - - protected virtual Task FinishTestClassInitializeAsync() - { - return Task.CompletedTask; } - private static async Task TestClassInitializeAsync(IntegrationTest test, string monitoredCollectionName) + private async Task CreateMonitoredCollectionAsync(string monitoredCollectionName) { - Debug.Assert(test != null); Debug.Assert(monitoredCollectionName != null); - DocumentCollectionInfo leaseCollectionInfo; IntegrationTestsHelper.GetConfigurationSettings( - out test.ClassData.monitoredCollectionInfo, - out leaseCollectionInfo, + out DocumentCollectionInfo baseMonitoredCollectionInfo, + out DocumentCollectionInfo baseLeaseCollectionInfo, out monitoredOfferThroughput, out leaseOfferThroughput); - test.ClassData.monitoredCollectionInfo.CollectionName = monitoredCollectionName; + this.MonitoredCollectionInfo = baseMonitoredCollectionInfo; + this.LeaseCollectionInfo = baseLeaseCollectionInfo; + + this.MonitoredCollectionInfo.CollectionName = monitoredCollectionName; var monitoredCollection = new DocumentCollection { - Id = test.ClassData.monitoredCollectionInfo.CollectionName, + Id = this.MonitoredCollectionInfo.CollectionName, }; - if (test.ClassData.isPartitionedMonitoredCollection) + if (this.IsPartitionedMonitoredCollection) { monitoredCollection.PartitionKey = new PartitionKeyDefinition { Paths = { "/id" } }; } @@ -245,38 +170,10 @@ private static async Task TestClassInitializeAsync(Integ } } - using (var client = new DocumentClient(test.ClassData.monitoredCollectionInfo.Uri, test.ClassData.monitoredCollectionInfo.MasterKey, test.ClassData.monitoredCollectionInfo.ConnectionPolicy)) + using (var client = new DocumentClient(this.MonitoredCollectionInfo.Uri, this.MonitoredCollectionInfo.MasterKey, this.MonitoredCollectionInfo.ConnectionPolicy)) { - await IntegrationTestsHelper.CreateDocumentCollectionAsync(client, test.ClassData.monitoredCollectionInfo.DatabaseName, monitoredCollection, monitoredOfferThroughput); + await IntegrationTestsHelper.CreateDocumentCollectionAsync(client, this.MonitoredCollectionInfo.DatabaseName, monitoredCollection, monitoredOfferThroughput); } - - test.FinishTestClassInitializeAsync().Wait(); - - return leaseCollectionInfo; - } - - private static async Task TestClassCleanupAsync(IntegrationTest test) - { - Debug.Assert(test != null); - - using (var client = new DocumentClient(test.ClassData.monitoredCollectionInfo.Uri, test.ClassData.monitoredCollectionInfo.MasterKey, test.ClassData.monitoredCollectionInfo.ConnectionPolicy)) - { - await client.DeleteDocumentCollectionAsync(UriFactory.CreateDocumentCollectionUri( - test.ClassData.monitoredCollectionInfo.DatabaseName, test.ClassData.monitoredCollectionInfo.CollectionName)); - } - } - - private static int GetTestCount(Type testType) - { - Debug.Assert(testType != null); - - int testMethodCount = 0; - foreach (var method in testType.GetMethods()) - { - if (method.GetCustomAttribute(typeof(FactAttribute)) != null) testMethodCount++; - } - - return testMethodCount; } } } \ No newline at end of file diff --git a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/StaticCollectionTests.cs b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/StaticCollectionTests.cs index 600dda0..a4374ac 100644 --- a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/StaticCollectionTests.cs +++ b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/StaticCollectionTests.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.Azure.Documents.ChangeFeedProcessor.IntegrationTests.Utils; using Microsoft.Azure.Documents.Client; +using Microsoft.Azure.Documents.Linq; using Xunit; namespace Microsoft.Azure.Documents.ChangeFeedProcessor.IntegrationTests @@ -27,17 +28,16 @@ public abstract class StaticCollectionTests : IntegrationTest const int documentCount = 1519; public StaticCollectionTests( - IntegrationTestFixture fixture, - Type testClassType, bool isPartitionedLeaseCollection) : - base(fixture, testClassType, isPartitionedLeaseCollection: isPartitionedLeaseCollection) + base(isPartitionedLeaseCollection: isPartitionedLeaseCollection) { } [Fact] public async Task CountDocumentsInCollection_NormalCase() { - int partitionKeyRangeCount = await IntegrationTestsHelper.GetPartitionCount(this.ClassData.monitoredCollectionInfo); + await this.InitializeDocumentsAsync(); + int partitionKeyRangeCount = await IntegrationTestsHelper.GetPartitionCount(this.MonitoredCollectionInfo); int openedCount = 0, closedCount = 0, processedCount = 0; var allDocsProcessed = new ManualResetEvent(false); @@ -56,7 +56,7 @@ public async Task CountDocumentsInCollection_NormalCase() var host = new ChangeFeedEventHost( Guid.NewGuid().ToString(), - this.ClassData.monitoredCollectionInfo, + this.MonitoredCollectionInfo, this.LeaseCollectionInfo, new ChangeFeedOptions { StartFromBeginning = true }, new ChangeFeedHostOptions()); @@ -67,7 +67,7 @@ public async Task CountDocumentsInCollection_NormalCase() try { Assert.True(partitionKeyRangeCount == openedCount, "Wrong openedCount"); - Assert.True(documentCount == processedCount, "Wrong processedCount"); + Assert.True(documentCount == processedCount, $"Wrong processedCount {documentCount} {processedCount}"); } finally { @@ -80,6 +80,7 @@ public async Task CountDocumentsInCollection_NormalCase() [Fact] public async Task CountDocumentsInCollection_ProcessChangesThrows() { + await this.InitializeDocumentsAsync(); int processedCount = 0; var allDocsProcessed = new ManualResetEvent(false); bool isFirstChangeNotification = false; // Make sure there was at least one throw. @@ -106,7 +107,7 @@ public async Task CountDocumentsInCollection_ProcessChangesThrows() var host = new ChangeFeedEventHost( Guid.NewGuid().ToString(), - this.ClassData.monitoredCollectionInfo, + this.MonitoredCollectionInfo, this.LeaseCollectionInfo, new ChangeFeedOptions { StartFromBeginning = true }, new ChangeFeedHostOptions()); @@ -127,7 +128,8 @@ public async Task CountDocumentsInCollection_ProcessChangesThrows() [Fact] public async Task CountDocumentsInCollection_TwoHosts() { - int partitionKeyRangeCount = await IntegrationTestsHelper.GetPartitionCount(this.ClassData.monitoredCollectionInfo); + await this.InitializeDocumentsAsync(); + int partitionKeyRangeCount = await IntegrationTestsHelper.GetPartitionCount(this.MonitoredCollectionInfo); Assert.True(partitionKeyRangeCount > 1, "Prerequisite failed: expected monitored collection with at least 2 partitions."); int processedCount = 0; @@ -146,7 +148,7 @@ public async Task CountDocumentsInCollection_TwoHosts() var host1 = new ChangeFeedEventHost( Guid.NewGuid().ToString(), - this.ClassData.monitoredCollectionInfo, + this.MonitoredCollectionInfo, this.LeaseCollectionInfo, new ChangeFeedOptions { StartFromBeginning = true }, new ChangeFeedHostOptions { MaxPartitionCount = partitionKeyRangeCount / 2 }); @@ -154,7 +156,7 @@ public async Task CountDocumentsInCollection_TwoHosts() var host2 = new ChangeFeedEventHost( Guid.NewGuid().ToString(), - this.ClassData.monitoredCollectionInfo, + this.MonitoredCollectionInfo, this.LeaseCollectionInfo, new ChangeFeedOptions { StartFromBeginning = true }, new ChangeFeedHostOptions { MaxPartitionCount = partitionKeyRangeCount - partitionKeyRangeCount / 2 }); @@ -164,7 +166,7 @@ public async Task CountDocumentsInCollection_TwoHosts() try { - Assert.True(documentCount == processedCount, "Wrong processedCount"); + Assert.True(documentCount == processedCount, $"Wrong processedCount {documentCount} {processedCount}"); } finally { @@ -176,7 +178,7 @@ public async Task CountDocumentsInCollection_TwoHosts() [Fact] public async Task StopAtFullSpeed() { - int partitionKeyRangeCount = await IntegrationTestsHelper.GetPartitionCount(this.ClassData.monitoredCollectionInfo); + int partitionKeyRangeCount = await IntegrationTestsHelper.GetPartitionCount(this.MonitoredCollectionInfo); int openedCount = 0, closedCount = 0, processedCount = 0; var quarterDocsProcessed = new ManualResetEvent(false); @@ -195,7 +197,7 @@ public async Task StopAtFullSpeed() var host = new ChangeFeedEventHost( Guid.NewGuid().ToString(), - this.ClassData.monitoredCollectionInfo, + this.MonitoredCollectionInfo, this.LeaseCollectionInfo, new ChangeFeedOptions { StartFromBeginning = true, MaxItemCount = 2 }, new ChangeFeedHostOptions()); @@ -209,11 +211,12 @@ public async Task StopAtFullSpeed() Assert.True(partitionKeyRangeCount == closedCount, "Wrong closedCount"); } - protected override async Task FinishTestClassInitializeAsync() + private async Task InitializeDocumentsAsync() { - using (var client = new DocumentClient(this.ClassData.monitoredCollectionInfo.Uri, this.ClassData.monitoredCollectionInfo.MasterKey, this.ClassData.monitoredCollectionInfo.ConnectionPolicy)) + using (var client = new DocumentClient(this.MonitoredCollectionInfo.Uri, this.MonitoredCollectionInfo.MasterKey, this.MonitoredCollectionInfo.ConnectionPolicy)) { - var collectionUri = UriFactory.CreateDocumentCollectionUri(this.ClassData.monitoredCollectionInfo.DatabaseName, this.ClassData.monitoredCollectionInfo.CollectionName); + var collectionUri = UriFactory.CreateDocumentCollectionUri(this.MonitoredCollectionInfo.DatabaseName, this.MonitoredCollectionInfo.CollectionName); + await IntegrationTestsHelper.CreateDocumentsAsync(client, collectionUri, documentCount); } } diff --git a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/StaticFixedLeaseCollectionTests.cs b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/StaticFixedLeaseCollectionTests.cs index 65ea1fa..8bd19a0 100644 --- a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/StaticFixedLeaseCollectionTests.cs +++ b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/StaticFixedLeaseCollectionTests.cs @@ -10,8 +10,8 @@ namespace Microsoft.Azure.Documents.ChangeFeedProcessor.IntegrationTests [Collection("Integration tests")] public class StaticFixedLeaseCollectionTests : StaticCollectionTests { - public StaticFixedLeaseCollectionTests(IntegrationTestFixture fixture) : - base(fixture, typeof(StaticFixedLeaseCollectionTests), false) + public StaticFixedLeaseCollectionTests() : + base(false) { } } diff --git a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/StaticPartitionedLeaseCollectionTests.cs b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/StaticPartitionedLeaseCollectionTests.cs index 1254c69..84f3ed1 100644 --- a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/StaticPartitionedLeaseCollectionTests.cs +++ b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/StaticPartitionedLeaseCollectionTests.cs @@ -10,8 +10,8 @@ namespace Microsoft.Azure.Documents.ChangeFeedProcessor.IntegrationTests [Collection("Integration tests")] public class StaticPartitionedLeaseCollectionTests : StaticCollectionTests { - public StaticPartitionedLeaseCollectionTests(IntegrationTestFixture fixture) : - base(fixture, typeof(StaticPartitionedLeaseCollectionTests), true) + public StaticPartitionedLeaseCollectionTests() : + base(true) { } } diff --git a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/Utils/IntegrationTestsHelper.cs b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/Utils/IntegrationTestsHelper.cs index 79b5d31..829271c 100644 --- a/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/Utils/IntegrationTestsHelper.cs +++ b/src/DocumentDB.ChangeFeedProcessor.IntegrationTests/Utils/IntegrationTestsHelper.cs @@ -14,6 +14,9 @@ namespace Microsoft.Azure.Documents.ChangeFeedProcessor.IntegrationTests.Utils { internal class IntegrationTestsHelper { + // Used when tests are running in CI/CD pipeline + private const string GatewayEndpointEnvironmentName = "COSMOSDBEMULATOR_ENDPOINT"; + static readonly string Endpoint; static readonly string MasterKey; static readonly string DatabaseId; @@ -26,7 +29,7 @@ static IntegrationTestsHelper() .AddJsonFile("appsettings.json") .Build(); - Endpoint = config["IntegrationTests:endpoint"]; + Endpoint = Environment.GetEnvironmentVariable(GatewayEndpointEnvironmentName) ?? config["IntegrationTests:endpoint"]; MasterKey = config["IntegrationTests:masterKey"]; DatabaseId = config["IntegrationTests:databaseId"]; MonitoredOfferThroughput = config["IntegrationTests:monitoredOfferThroughput"]; @@ -77,7 +80,23 @@ internal static async Task CreateDocumentCollectionAsync(DocumentClient client, var database = new Database { Id = databaseId }; database = await client.CreateDatabaseIfNotExistsAsync(database); - await client.CreateDocumentCollectionAsync(database.SelfLink, collection, new RequestOptions { OfferThroughput = offerThroughput }); + int retryCount = 3; + while (retryCount-- > 0) + { + try + { + await client.CreateDocumentCollectionAsync(database.SelfLink, collection, new RequestOptions { OfferThroughput = offerThroughput }); + break; + } + catch (DocumentClientException) + { + // Public emulator might have transient + if (retryCount == 0) + { + throw; + } + } + } } internal static async Task CreateDocumentsAsync(DocumentClient client, Uri collectionUri, int count)