public async void EnsureConfigCurrentWithUnchangedSignature() { var dbConfig = CreateDbConfig(); string signature = "sig"; var configDoc = CreateConfigDoc("Test", signature); _signatureGenerator.CreateSignature(Arg.Any <IList <DocumentStoreConfig> >()).Returns(signature); _documentClient.ReadDocumentAsync(Arg.Any <Uri>(), Arg.Is <RequestOptions>(x => x.PartitionKey != null)).Returns(WrapResource(configDoc)); // Existing index that should remain. var includeIdx1 = new IncludedPath(); includeIdx1.Path = "/content_Test_StoreA_DocA/*"; includeIdx1.Indexes.Add(new HashIndex(DataType.String, -1)); // Existing index that should be removed. It is no longer present. var includeIdx2 = new IncludedPath(); includeIdx2.Path = "/content_Test_StoreB_DocA/PropA/*"; includeIdx2.Indexes.Add(new RangeIndex(DataType.String)); var manager = new ServiceDbConfigManager("Test", _signatureGenerator); _documentClient.UpsertDocumentAsync(Arg.Any <Uri>(), Arg.Is <Document>(x => x.GetPropertyValue <string>("Signature") == signature)) .Returns(WrapResource(CreateConfigDoc(configDoc.Id, signature))); manager.RegisterStoreConfigSource(CreateConfigSource("A")); manager.RegisterStoreConfigSource(CreateConfigSource("B")); manager.EnsureConfigCurrent(_documentClient, dbConfig); await AssertNoUpdateTriggered(); }
public async void TestDocumentAttachments() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var store = new EmailStore(dbAccessProvider); await dbAccess.Open(new[] { store }); var email = new Email { Id = Guid.NewGuid(), Subject = "Re: Holiday" }; var attachment = new EmailAttachment { Data = "test" }; // Store without attachment. await store.Upsert(email, null); var actualAttachment = await store.GetEmailAttachment(email.Id); Assert.Null(actualAttachment); // Store with attachment. await store.Upsert(email, attachment); actualAttachment = await store.GetEmailAttachment(email.Id); Assert.Equal(attachment.Data, actualAttachment.Data); }
/// <summary> /// Initialises a new instance of the <see cref="DocumentDbAccess"/> class for testing. /// </summary> /// <param name="dbConfig">The database config,</param> /// <param name="configManager">The document config manager.</param> /// <param name="documentClient">The document client.</param> /// <param name="dbService">The document db service.</param> /// <param name="queryPolicy">The document query policy.</param> /// <remarks> /// <para>This constructor should be used for internal testing only.</para> /// </remarks> internal DocumentDbAccess( DocumentDbConfig dbConfig, ServiceDbConfigManager configManager, IDocumentClient documentClient, IDocumentDbService dbService, IDocumentQueryPolicy queryPolicy) { if (dbConfig == null) { throw new ArgumentNullException(nameof(dbConfig)); } if (configManager == null) { throw new ArgumentNullException(nameof(configManager)); } if (documentClient == null) { throw new ArgumentNullException(nameof(documentClient)); } if (dbService == null) { throw new ArgumentNullException(nameof(dbService)); } if (queryPolicy == null) { throw new ArgumentNullException(nameof(queryPolicy)); } _dbConfig = dbConfig; _configManager = configManager; _queryPolicy = queryPolicy; _client = documentClient; _dbService = dbService; }
public async void TestServiceRegistrationAndUpdateConcurrency() { // This test performs a concurrency check to ensure that multiple threads can successfully interact with // the same config manager. The config manager is thread safe so multiple stores registering and performing // actions on different threads should produce a consistent result. var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = await CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); List <Task> tasks = new List <Task> { Task.Run(async() => { var fruitStore = new FruitStore(dbAccessProvider); var gala = new Apple { Id = Guid.NewGuid(), Type = "Gala" }; await fruitStore.UpsertApple(gala); }), Task.Run(async() => { var flowerStore = new FlowerStore(dbAccessProvider); var daisy = new Daisy { Id = Guid.NewGuid(), Colour = "Red" }; await flowerStore.Upsert(daisy); }) }; Task.WaitAll(tasks.ToArray()); }
/// <summary> /// Initialises a new instance of the <see cref="DocumentDbService"/> class. /// </summary> /// <param name="configManager">The service config manager.</param> /// <param name="dbConfig">The document db config.</param> public DocumentDbService(ServiceDbConfigManager configManager, DocumentDbConfig dbConfig) { if (configManager == null) { throw new ArgumentNullException(nameof(configManager)); } if (dbConfig == null) { throw new ArgumentNullException(nameof(dbConfig)); } _configManager = configManager; _dbConfig = dbConfig; var connectionPolicy = new ConnectionPolicy { ConnectionMode = ConnectionMode.Direct, ConnectionProtocol = Protocol.Tcp, RetryOptions = new RetryOptions { MaxRetryAttemptsOnThrottledRequests = 20, MaxRetryWaitTimeInSeconds = 60 } }; _client = new DocumentClient(new Uri(dbConfig.ServiceEndpoint), dbConfig.AuthKey, connectionPolicy); }
protected DocumentDbAccess CreateDbAccess( ServiceDbConfigManager configManager, int collectionRuLimit = 1000) { var dbAccess = new DocumentDbAccess(CreateDbConfig(_databaseId, collectionRuLimit), configManager); _dbAccesses.Add(dbAccess); return(dbAccess); }
public void IsStoreConfigRegisteredFalseWhenNotRegistered() { var configDoc = CreateConfigDoc("Test", "sig"); _signatureGenerator.CreateSignature(Arg.Any <IList <DocumentStoreConfig> >()).Throws(new Exception()); _documentClient.ReadDocumentAsync(Arg.Any <Uri>()).Returns(WrapResource(configDoc)); var manager = new ServiceDbConfigManager("Test", _signatureGenerator); Assert.False(manager.IsStoreConfigRegistered(_configSourceA)); }
public async void TestLargeNumberOfVersionsPerformance() { // Test the performance of writing and reading a single document with a large number of versions. // // CosmosDb emulator setup // - 2000 RU/s collection // - Rate limiting. // // Current performance // - 2nd write: 0.04 sec // - 1000th write: 0.04 sec // - Read: 0.04 sec // // The current implementation does not work when thrashed with lower RU/s due to the RU cost of // the read and write operations. There is a timeout waiting for retries. An improved // implementation should be considered to lower the cost of versioned read and write against // latest documents. E.g., a @latest flag would solve this issue. const int collectionRuLimit = 2000; const int numberOfVersions = 1000; var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = await CreateDbAccess(configManager, collectionRuLimit); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var store = new LargeDocumentStore(dbAccessProvider); var attachment = JsonConvert.DeserializeObject <LargeDocument>(File.ReadAllText("TestData/LargeDocument.json")); var document = new SmallDocumentWithLargeAttachment(); document.Id = Guid.NewGuid(); Stopwatch sw = new Stopwatch(); sw.Start(); for (var i = 0; i < numberOfVersions; i++) { sw.Restart(); await store.UpsertDocument(document, attachment); TestOutputHelper.WriteLine("Write={0}", sw.Elapsed); } var result = await store.GetSmallDocument(document.Id); TestOutputHelper.WriteLine("Read={0}", sw.Elapsed); Assert.NotNull(result); }
private async Task SetupStore() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var store = new TestDocumentStore(dbAccessProvider); await dbAccess.Open(new[] { store }); _store = store; }
public async void TestLargeNumberOfDocuments() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var fruitStore = new FruitStore(dbAccessProvider); await dbAccess.Open(new[] { fruitStore }); var apples = new List <Apple>(); for (int i = 0; i < 800; i++) { var gala = new Apple { Id = Guid.NewGuid(), Type = "Gala" }; var fuji = new Apple { Id = Guid.NewGuid(), Type = "Fuji" }; await fruitStore.UpsertApple(gala); await fruitStore.UpsertApple(fuji); apples.AddRange(new[] { gala, fuji }); } var r1 = await fruitStore.GetAppleByQuery("[x].Type = 'Gala'"); Assert.Equal(800, r1.Length); Assert.True(r1.All(x => x.Type == "Gala")); var r2 = await fruitStore.GetAllApples(); Assert.Equal(1600, r2.Length); var lastApple = apples.Last(); var r3 = await fruitStore.GetAppleById(lastApple.Id); Assert.Equal(lastApple.Id, r3.Id); Assert.Equal(lastApple.Type, r3.Type); var r4 = await fruitStore.GetAppleByIds(apples.Select(x => x.Id.ToString())); Assert.Equal(1600, r4.Length); }
public async void TestDbParameterQueries() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var fruitStore = new FruitStore(dbAccessProvider); await dbAccess.Open(new[] { fruitStore }); var pears = new List <Pear>(); for (int i = 0; i < 50; i++) { var bartlett = new Pear { Id = Guid.NewGuid(), Colour = "Red" }; var comice = new Pear { Id = Guid.NewGuid(), Colour = "Green" }; await fruitStore.UpsertPear(bartlett); await fruitStore.UpsertPear(comice); pears.AddRange(new[] { bartlett, comice }); } var r1 = await fruitStore.GetPearByQuery("[x].Colour = @colour", new[] { new DbParameter("colour", "Red") }); Assert.Equal(50, r1.Length); Assert.True(r1.All(x => x.Colour == "Red")); var r2 = await fruitStore.GetPearByQuery("[x].Colour = @colour", new[] { new DbParameter("@colour", "Red") }); Assert.Equal(50, r2.Length); Assert.True(r2.All(x => x.Colour == "Red")); var r3 = await fruitStore.GetPearByQuery("[x].Colour = @colour", new[] { new DbParameter("colour", "Green") }); Assert.Equal(50, r3.Length); Assert.True(r3.All(x => x.Colour == "Green")); var r4 = await fruitStore.GetPearByQuery("[x].Colour = @colour", new[] { new DbParameter("colour", "Blue") }); Assert.Empty(r4); }
public async void TestMetadataQueries() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = await CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var fruitStore = new FruitStore(dbAccessProvider); var bartlett = new Pear { Id = Guid.NewGuid(), Colour = "Red" }; var comice = new Pear { Id = Guid.NewGuid(), Colour = "Green" }; for (int i = 0; i < 50; i++) { // Mutate the record. bartlett.Colour = i % 2 == 0 ? "Red" : "DarkRed"; await fruitStore.UpsertPear(bartlett); await fruitStore.UpsertPear(comice); } await fruitStore.DeletePearById(bartlett.Id); var r1 = await fruitStore.GetPearByQuery("[x].Colour = @colour", new[] { new DbParameter("colour", "Red") }); Assert.True(r1.All(x => x.Colour == "Red")); var r2 = await fruitStore.GetPearVersions(bartlett.Id.ToString()); Assert.NotNull(r2); Assert.Equal(51, r2.Metadata.Count); Assert.Equal(1, r2.Metadata[0].Version); Assert.False(r2.Metadata[0].IsDeleted); var lastVersion = r2.Metadata.Last(); Assert.Equal(51, lastVersion.Version); Assert.True(lastVersion.IsDeleted); Assert.True(lastVersion.CreatedTime < lastVersion.ModifiedTime); Assert.Equal(r2.Metadata[0].CreatedTime, lastVersion.CreatedTime); }
public async void TestWideQueryMultipleServices() { // This test ensures that a wide query (e.g., 'true OR true') does not return or attempt // to return documents from other services. var configManager1 = new ServiceDbConfigManager("TestService1"); var dbAccess1 = CreateDbAccess(configManager1); var dbAccessProvider1 = new TestDocumentDbAccessProvider(dbAccess1); var configManager2 = new ServiceDbConfigManager("TestService2"); var dbAccess2 = CreateDbAccess(configManager2); var dbAccessProvider2 = new TestDocumentDbAccessProvider(dbAccess2); var fruitStore1 = new FruitStore(dbAccessProvider1); var fruitStore2 = new FruitStore(dbAccessProvider2); await dbAccess1.Open(new[] { fruitStore1 }); await dbAccess2.Open(new[] { fruitStore2 }); var gala = new Apple { Id = Guid.NewGuid(), Type = "Gala" }; var fuji = new Apple { Id = Guid.NewGuid(), Type = "Fuji" }; await fruitStore1.UpsertApple(gala); await fruitStore2.UpsertApple(fuji); var r1 = await fruitStore1.GetApplesByQuery("true OR true"); Assert.Equal(1, r1.Loaded.Count); Assert.Empty(r1.Failed); Assert.Equal(gala.Id, r1.Loaded[0].Document.Id); var r2 = await fruitStore2.GetApplesByQuery("true OR true"); Assert.Equal(1, r2.Loaded.Count); Assert.Empty(r2.Failed); Assert.Equal(fuji.Id, r2.Loaded[0].Document.Id); }
public void EnsureConfigCurrentThrowsForSignatureFailure() { var dbConfig = CreateDbConfig(); var configDoc = CreateConfigDoc("Test", "sig"); _signatureGenerator.CreateSignature(Arg.Any <IList <DocumentStoreConfig> >()).Throws(new Exception()); _documentClient.ReadDocumentAsync(Arg.Any <Uri>()).Returns(WrapResource(configDoc)); var manager = new ServiceDbConfigManager("Test", _signatureGenerator); manager.RegisterStoreConfigSource(_configSourceA); var ex = Assert.Throws <NebulaConfigException>(() => manager.EnsureConfigCurrent(_documentClient, dbConfig)); Assert.Contains("signature generation failed", ex.Message); }
public async void TestLargeDocumentAsAttachmentWithMultipleVersionsPerformance() { // Test the performance of writing and reading a single document with multiple versions and attachment data. // // CosmosDb emulator setup // - 1000 RU/s collection. // - Rate limiting. // // Current performance // - Write: 1.9sec // - Read: 0.1sec const int numberOfVersions = 20; var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = await CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var store = new LargeDocumentStore(dbAccessProvider); var attachment = JsonConvert.DeserializeObject <LargeDocument>(File.ReadAllText("TestData/LargeDocument.json")); var document = new SmallDocumentWithLargeAttachment(); document.Id = Guid.NewGuid(); Stopwatch sw = new Stopwatch(); sw.Start(); // The same document is stored multiple times to simulate multiple versions. for (var i = 0; i < numberOfVersions; i++) { await store.UpsertDocument(document, attachment); } TestOutputHelper.WriteLine("Write={0}", sw.Elapsed); sw.Restart(); var result = await store.GetSmallDocumentAttachment(document.Id); TestOutputHelper.WriteLine("Read={0}", sw.Elapsed); Assert.NotNull(result); }
public async void EnsureConfigCurrentWithDuplicateStoreConfigRegistrationsAndNoSignatureChange() { var dbConfig = CreateDbConfig(); var configDoc = CreateConfigDoc("Test", "sig"); _signatureGenerator.CreateSignature(Arg.Any <IList <DocumentStoreConfig> >()).Returns("sig"); _documentClient.ReadDocumentAsync(Arg.Any <Uri>(), Arg.Is <RequestOptions>(x => x.PartitionKey != null)).Returns(WrapResource(configDoc)); var manager = new ServiceDbConfigManager("Test", _signatureGenerator); manager.RegisterStoreConfigSource(CreateConfigSource("A")); manager.RegisterStoreConfigSource(CreateConfigSource("A")); manager.EnsureConfigCurrent(_documentClient, dbConfig); await AssertNoUpdateTriggered(); }
private async Task <DocumentDbAccess> CreateDbAccess(IDocumentClient documentClient) { var signatureGenerator = Substitute.For <IServiceConfigSignatureGenerator>(); var configManager = new ServiceDbConfigManager("Test", signatureGenerator); var queryPolicy = Substitute.For <IDocumentQueryPolicy>(); queryPolicy.GetIdSearchLimit(Arg.Any <ICollection <string> >()).Returns(1000); queryPolicy.IsQueryValid(Arg.Any <string>()).Returns(true); var dbService = Substitute.For <IDocumentDbService>(); var documentDbAccess = new DocumentDbAccess(CreateDbConfig(), configManager, documentClient, dbService, queryPolicy); await documentDbAccess.Open(new IDocumentStoreConfigSource[0]); return(documentDbAccess); }
/// <summary> /// Initialises a new instance of the <see cref="DocumentDbAccess"/> class. /// </summary> /// <param name="dbConfig">The database config.</param> /// <param name="configManager">The document config manager.</param> public DocumentDbAccess(DocumentDbConfig dbConfig, ServiceDbConfigManager configManager) { if (dbConfig == null) { throw new ArgumentNullException(nameof(dbConfig)); } if (configManager == null) { throw new ArgumentNullException(nameof(configManager)); } _dbConfig = dbConfig; _configManager = configManager; _queryPolicy = new DocumentQueryPolicy(); var dbService = new DocumentDbService(configManager, dbConfig); _dbService = dbService; _client = dbService.Client; }
public async void TestSingleLargeDocumentPerformance() { // Test the performance of writing and reading a single large, complex document. // // CosmosDb emulator setup // - 1000 RU/s collection. // - Rate limiting. // // Current performance // - Write: 0.5sec // - Read: 0.9sec var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = await CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var store = new LargeDocumentStore(dbAccessProvider); var document = JsonConvert.DeserializeObject <LargeDocument>(File.ReadAllText("TestData/LargeDocument.json")); document.Id = Guid.NewGuid(); Stopwatch sw = new Stopwatch(); sw.Start(); await store.UpsertDocument(document); TestOutputHelper.WriteLine("Write={0}", sw.Elapsed); sw.Restart(); var result = await store.GetLargeDocument(document.Id); TestOutputHelper.WriteLine("Read={0}", sw.Elapsed); Assert.NotNull(result); }
public async void TestCustomDocumentMetadata() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var metadataSource = new TestDocumentMetadataSource("User1"); var fruitStore = new FruitStore(dbAccessProvider, metadataSource); await dbAccess.Open(new[] { fruitStore }); var bartlett = new Pear { Id = Guid.NewGuid(), Colour = "Red" }; await fruitStore.UpsertPear(bartlett); metadataSource.ActorId = "User2"; await fruitStore.UpsertPear(bartlett); metadataSource.ActorId = "User3"; await fruitStore.DeletePearById(bartlett.Id); var r1 = await fruitStore.GetPearById(bartlett.Id, 1); Assert.Equal("User1", r1.Metadata.ActorId); var r2 = await fruitStore.GetPearById(bartlett.Id, 2); Assert.Equal("User2", r2.Metadata.ActorId); var r3 = await fruitStore.GetPearById(bartlett.Id, 3); Assert.True(r3.Metadata.IsDeleted); Assert.Equal("User3", r3.Metadata.ActorId); }
public async void TestDbConcurrency() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var fruitStore = new FruitStore(dbAccessProvider); await dbAccess.Open(new[] { fruitStore }); var gala = new Apple { Id = Guid.NewGuid(), Type = "Gala" }; await fruitStore.UpsertApple(gala); var t1 = Task.Run(async() => await SeedCounterAsync(gala.Id, fruitStore)); var t2 = Task.Run(async() => await SeedCounterAsync(gala.Id, fruitStore, shouldSleep: true)); await Assert.ThrowsAsync <NebulaStoreConcurrencyException>(() => Task.WhenAll(t1, t2)); }
public async void TestDbConcurrency() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = await CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var fruitStore = new FruitStore(dbAccessProvider); var gala = new Apple { Id = Guid.NewGuid(), Type = "Gala" }; await fruitStore.UpsertApple(gala); var t1 = Task.Run(async() => await SeedCounterAsync(gala.Id, fruitStore)); var t2 = Task.Run(async() => await SeedCounterAsync(gala.Id, fruitStore, shouldSleep: true)); var exception = Assert.Throws <AggregateException>(() => Task.WaitAll(t1, t2)); Assert.Equal(typeof(NebulaStoreConcurrencyException), exception.InnerException.GetType()); }
public async void TestDocumentPurge() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var fruitStore = new FruitStore(dbAccessProvider); await dbAccess.Open(new[] { fruitStore }); var gala = new Apple { Id = Guid.NewGuid(), Type = "Gala" }; var opal = new Apple { Id = Guid.NewGuid(), Type = "Opal" }; var redBartlett = new Pear { Id = Guid.NewGuid(), Colour = "Red" }; var darkRedBartlett = new Pear { Id = Guid.NewGuid(), Colour = "DarkRed" }; await fruitStore.UpsertApple(gala); await fruitStore.UpsertApple(gala); await fruitStore.UpsertApple(gala); await fruitStore.UpsertApple(opal); await fruitStore.UpsertPear(redBartlett); await fruitStore.UpsertPear(darkRedBartlett); await fruitStore.UpsertPear(darkRedBartlett); await fruitStore.DeletePearById(darkRedBartlett.Id); var galaResult = await fruitStore.GetAppleVersions(gala.Id); var opalResult = await fruitStore.GetAppleVersions(opal.Id); var redBartlettResult = await fruitStore.GetPearVersions(redBartlett.Id); var darkRedBartlettResult = await fruitStore.GetPearVersions(redBartlett.Id); Assert.NotNull(galaResult); Assert.NotNull(opalResult); Assert.NotNull(redBartlettResult); Assert.NotNull(darkRedBartlettResult); await fruitStore.PurgeAllPears(); galaResult = await fruitStore.GetAppleVersions(gala.Id); opalResult = await fruitStore.GetAppleVersions(opal.Id); redBartlettResult = await fruitStore.GetPearVersions(redBartlett.Id); darkRedBartlettResult = await fruitStore.GetPearVersions(redBartlett.Id); Assert.NotNull(galaResult); Assert.NotNull(opalResult); Assert.Null(redBartlettResult); Assert.Null(darkRedBartlettResult); await fruitStore.PurgeApple(gala.Id); galaResult = await fruitStore.GetAppleVersions(gala.Id); opalResult = await fruitStore.GetAppleVersions(opal.Id); Assert.Null(galaResult); Assert.NotNull(opalResult); await fruitStore.UpsertApple(gala); var versionedGalaResult = await fruitStore.GetVersionedAppleById(gala.Id); Assert.NotNull(versionedGalaResult); Assert.Equal(1, versionedGalaResult.Metadata.Version); }
public async void TestVersionedQueries() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var fruitStore = new FruitStore(dbAccessProvider); await dbAccess.Open(new[] { fruitStore }); var bartlett = new Pear { Id = Guid.NewGuid(), Colour = "Red" }; var comice = new Pear { Id = Guid.NewGuid(), Colour = "Green" }; for (int i = 0; i < 50; i++) { // Mutate the record. bartlett.Colour = i % 2 == 0 ? "Red" : "DarkRed"; await fruitStore.UpsertPear(bartlett); await fruitStore.UpsertPear(comice); } await fruitStore.DeletePearById(bartlett.Id); const int lastVersion = 51; var r1 = await fruitStore.GetPearById(bartlett.Id, lastVersion); Assert.Equal(lastVersion, r1.Metadata.Version); Assert.True(r1.Metadata.IsDeleted); Assert.Equal("DarkRed", r1.Document.Colour); var r2 = await fruitStore.GetPearById(bartlett.Id, lastVersion - 1); Assert.Equal(lastVersion - 1, r2.Metadata.Version); Assert.False(r2.Metadata.IsDeleted); Assert.Equal("DarkRed", r2.Document.Colour); var r3 = await fruitStore.GetPearById(bartlett.Id, lastVersion - 2); Assert.Equal(lastVersion - 2, r3.Metadata.Version); Assert.False(r3.Metadata.IsDeleted); Assert.Equal("Red", r3.Document.Colour); var r4 = await fruitStore.GetPearById(bartlett.Id, 1); Assert.Equal(1, r4.Metadata.Version); Assert.False(r4.Metadata.IsDeleted); Assert.Equal("Red", r4.Document.Colour); var r5 = await fruitStore.GetPearById(comice.Id, 1); Assert.Equal(1, r5.Metadata.Version); Assert.False(r5.Metadata.IsDeleted); Assert.Equal("Green", r5.Document.Colour); }
public async void TestMetadataQueries() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var fruitStore = new FruitStore(dbAccessProvider); await dbAccess.Open(new[] { fruitStore }); var bartlett = new Pear { Id = Guid.NewGuid(), Colour = "Red" }; var comice = new Pear { Id = Guid.NewGuid(), Colour = "Green" }; for (int i = 0; i < 5; i++) { // Mutate the record. bartlett.Colour = i % 2 == 0 ? "Red" : "DarkRed"; await fruitStore.UpsertPear(bartlett); await fruitStore.UpsertPear(comice); Thread.Sleep(1000); } await fruitStore.DeletePearById(bartlett.Id); var r1 = await fruitStore.GetPearByQuery("[x].Colour = @colour", new[] { new DbParameter("colour", "Red") }); Assert.True(r1.All(x => x.Colour == "Red")); var r2 = await fruitStore.GetPearVersions(bartlett.Id); Assert.NotNull(r2); Assert.Equal(6, r2.Metadata.Count); Assert.Equal(1, r2.Metadata[0].Version); Assert.False(r2.Metadata[0].IsDeleted); var lastVersion = r2.Metadata.Last(); Assert.Equal(6, lastVersion.Version); Assert.True(lastVersion.IsDeleted); Assert.True(lastVersion.CreatedTime < lastVersion.ModifiedTime); Assert.Equal(r2.Metadata[0].CreatedTime, lastVersion.CreatedTime); for (var i = 1; i < r2.Metadata.Count; i++) { var prev = r2.Metadata[i - 1]; var current = r2.Metadata[i]; Assert.True(current.ModifiedTime > prev.ModifiedTime); Assert.True(current.ModifiedTime - prev.ModifiedTime >= TimeSpan.FromSeconds(1)); Assert.True(current.ModifiedTime > prev.CreatedTime); Assert.Equal(current.CreatedTime, prev.CreatedTime); Assert.False(prev.IsDeleted); } }
public async void EnsureConfigCurrentWithChangedSignature() { var dbConfig = CreateDbConfig(); string oldSig = "old_sig"; string newSig = "new_sig"; var configDoc = CreateConfigDoc("Test", oldSig); DocumentStoreConfigBuilder storeABuilder = new DocumentStoreConfigBuilder("StoreA"); storeABuilder.AddDocument("DocA"); DocumentStoreConfigBuilder storeBBuilder = new DocumentStoreConfigBuilder("StoreB"); storeBBuilder.AddDocument("DocA"); storeBBuilder.AddDocument("DocB"); var configSourceA = CreateConfigSource(storeABuilder); var configSourceB = CreateConfigSource(storeBBuilder); _signatureGenerator.CreateSignature(Arg.Any <IList <DocumentStoreConfig> >()).Returns(newSig); _documentClient.ReadDocumentAsync(Arg.Any <Uri>(), Arg.Is <RequestOptions>(x => x.PartitionKey != null)).Returns(WrapResource(configDoc)); // Existing index that should remain. var includeIdx1 = new IncludedPath(); includeIdx1.Path = "/content_Test_StoreA_DocA/*"; includeIdx1.Indexes.Add(new HashIndex(DataType.String, -1)); // Existing index that should be removed. It is no longer present. var includeIdx2 = new IncludedPath(); includeIdx2.Path = "/content_Test_StoreB_DocA/PropA/*"; includeIdx2.Indexes.Add(new RangeIndex(DataType.String)); var col1 = new DocumentCollection(); col1.IndexingPolicy.IncludedPaths.Add(includeIdx1); col1.IndexingPolicy.IncludedPaths.Add(includeIdx2); _documentClient.ReadDocumentCollectionAsync(Arg.Any <Uri>()).Returns(WrapResource(col1)); var manager = new ServiceDbConfigManager("Test", _signatureGenerator); var foo = WrapResource(col1); _documentClient.ReplaceDocumentCollectionAsync(Arg.Any <DocumentCollection>(), Arg.Any <RequestOptions>()).Returns(foo); _documentClient.UpsertDocumentAsync( Arg.Any <Uri>(), Arg.Is <object>(r => ((ServiceDbConfigManager.ServiceConfigRecord)r).Signature == newSig), Arg.Any <RequestOptions>()) .Returns(WrapResource(CreateConfigDoc(configDoc.Id, newSig))); manager.RegisterStoreConfigSource(configSourceA); manager.RegisterStoreConfigSource(configSourceB); manager.EnsureConfigCurrent(_documentClient, dbConfig); await _documentClient.Received(1).UpsertDocumentAsync(Arg.Any <Uri>(), Arg.Any <object>(), Arg.Any <RequestOptions>()); await _documentClient.Received().ReplaceDocumentCollectionAsync( Arg.Is <DocumentCollection>(c => IncludedPathCheck( c.IndexingPolicy.IncludedPaths, "/content_Test_StoreA_DocA/*", "/content_Test_StoreB_DocA/*", "/content_Test_StoreB_DocB/*")), Arg.Any <RequestOptions>()); }
public VersionedStorePerformanceTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { _configManager = new ServiceDbConfigManager("TestService"); }
public async void TestMultipleServicesDocumentPurge() { var configManager1 = new ServiceDbConfigManager("TestService1"); var dbAccess1 = CreateDbAccess(configManager1); var dbAccessProvider1 = new TestDocumentDbAccessProvider(dbAccess1); var configManager2 = new ServiceDbConfigManager("TestService2"); var dbAccess2 = CreateDbAccess(configManager2); var dbAccessProvider2 = new TestDocumentDbAccessProvider(dbAccess2); var fruitStore1 = new FruitStore(dbAccessProvider1); var fruitStore2 = new FruitStore(dbAccessProvider2); await dbAccess1.Open(new[] { fruitStore1 }); await dbAccess2.Open(new[] { fruitStore2 }); var apples = new List <Apple>(); for (int i = 0; i < 20; i++) { var gala = new Apple { Id = Guid.NewGuid(), Type = "Gala" }; var fuji = new Apple { Id = Guid.NewGuid(), Type = "Fuji" }; await fruitStore1.UpsertApple(gala); await fruitStore1.UpsertApple(fuji); await fruitStore2.UpsertApple(gala); await fruitStore2.UpsertApple(fuji); apples.AddRange(new[] { gala, fuji }); } var r1 = await fruitStore1.GetAppleByQuery("[x].Type = 'Gala'"); Assert.Equal(20, r1.Length); Assert.True(r1.All(x => x.Type == "Gala")); var r2 = await fruitStore1.GetAllApples(); Assert.Equal(40, r2.Length); var lastApple = apples.Last(); var r3 = await fruitStore1.GetAppleById(lastApple.Id); Assert.Equal(lastApple.Id, r3.Id); Assert.Equal(lastApple.Type, r3.Type); var r4 = await fruitStore1.GetAppleByIds(apples.Select(x => x.Id.ToString())); Assert.Equal(40, r4.Length); ServiceManager serviceManager1 = new ServiceManager(dbAccess1); ServiceManager serviceManager2 = new ServiceManager(dbAccess2); // Purge a service's docs. await serviceManager1.PurgeDocumentsAsync(); Assert.Empty(await fruitStore1.GetAllApples()); Assert.NotEmpty(await fruitStore2.GetAllApples()); // Purge other service's docs. await serviceManager2.PurgeDocumentsAsync(); Assert.Empty(await fruitStore1.GetAllApples()); Assert.Empty(await fruitStore2.GetAllApples()); }
public async void TestMultipleStoreDocumentTypes() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var fruitStore = new FruitStore(dbAccessProvider); await dbAccess.Open(new[] { fruitStore }); var apples = new List <Apple>(); var pears = new List <Pear>(); for (int i = 0; i < 50; i++) { var gala = new Apple { Id = Guid.NewGuid(), Type = "Gala" }; var fuji = new Apple { Id = Guid.NewGuid(), Type = "Fuji" }; await fruitStore.UpsertApple(gala); await fruitStore.UpsertApple(fuji); apples.AddRange(new[] { gala, fuji }); var bartlett = new Pear { Id = Guid.NewGuid(), Colour = "Red" }; var comice = new Pear { Id = Guid.NewGuid(), Colour = "Green" }; await fruitStore.UpsertPear(bartlett); await fruitStore.UpsertPear(comice); pears.AddRange(new[] { bartlett, comice }); } var r1 = await fruitStore.GetAppleByQuery("[x].Type = 'Gala'"); Assert.Equal(50, r1.Length); Assert.True(r1.All(x => x.Type == "Gala")); var r2 = await fruitStore.GetAllApples(); Assert.Equal(100, r2.Length); var lastApple = apples.Last(); var r3 = await fruitStore.GetAppleById(lastApple.Id); Assert.Equal(lastApple.Id, r3.Id); Assert.Equal(lastApple.Type, r3.Type); var r4 = await fruitStore.GetAppleByIds(apples.Select(x => x.Id.ToString())); Assert.Equal(100, r4.Length); var r5 = await fruitStore.GetPearByQuery("[x].Colour = @colour", new[] { new DbParameter("colour", "Red") }); Assert.Equal(50, r5.Length); Assert.True(r5.All(x => x.Colour == "Red")); var r6 = await fruitStore.GetAllPears(); Assert.Equal(100, r6.Length); var lastPear = pears.Last(); var r7 = await fruitStore.GetPearById(lastPear.Id); Assert.Equal(lastPear.Id, r7.Id); Assert.Equal(lastPear.Colour, r7.Colour); }
public async void TestMultipleServiceStores() { var configManager = new ServiceDbConfigManager("TestService"); var dbAccess = CreateDbAccess(configManager); var dbAccessProvider = new TestDocumentDbAccessProvider(dbAccess); var fruitStore = new FruitStore(dbAccessProvider); var flowerStore = new FlowerStore(dbAccessProvider); await dbAccess.Open(new VersionedDocumentStore[] { fruitStore, flowerStore }); var apples = new List <Apple>(); var daisies = new List <Daisy>(); for (int i = 0; i < 10; i++) { var gala = new Apple { Id = Guid.NewGuid(), Type = "Gala" }; var fuji = new Apple { Id = Guid.NewGuid(), Type = "Fuji" }; await fruitStore.UpsertApple(gala); await fruitStore.UpsertApple(fuji); apples.AddRange(new[] { gala, fuji }); var daisy = new Daisy { Id = Guid.NewGuid(), Colour = "Red" }; await flowerStore.Upsert(daisy); daisies.Add(daisy); } var r1 = await fruitStore.GetAppleByQuery("[x].Type = 'Gala'"); Assert.Equal(10, r1.Length); Assert.True(r1.All(x => x.Type == "Gala")); var r2 = await fruitStore.GetAllApples(); Assert.Equal(20, r2.Length); var lastApple = apples.Last(); var r3 = await fruitStore.GetAppleById(lastApple.Id); Assert.Equal(lastApple.Id, r3.Id); Assert.Equal(lastApple.Type, r3.Type); var r4 = await fruitStore.GetAppleByIds(apples.Select(x => x.Id.ToString())); Assert.Equal(20, r4.Length); var lastDaisy = daisies.Last(); var r5 = await flowerStore.GetById(lastDaisy.Id); Assert.Equal(lastDaisy.Id, r5.Id); Assert.Equal(lastDaisy.Colour, r5.Colour); }