public async Task ValidatesAbsoluteExpiration() { DistributedCacheEntryOptions cacheOptions = new DistributedCacheEntryOptions(); cacheOptions.AbsoluteExpiration = DateTime.UtcNow.AddHours(-1); CosmosCacheSession existingSession = new CosmosCacheSession(); existingSession.SessionKey = "key"; existingSession.Content = new byte[0]; Mock <ItemResponse <CosmosCacheSession> > mockedItemResponse = new Mock <ItemResponse <CosmosCacheSession> >(); Mock <CosmosClient> mockedClient = new Mock <CosmosClient>(); Mock <Container> mockedContainer = new Mock <Container>(); Mock <Database> mockedDatabase = new Mock <Database>(); Mock <ContainerResponse> mockedResponse = new Mock <ContainerResponse>(); mockedResponse.Setup(c => c.StatusCode).Returns(HttpStatusCode.OK); mockedContainer.Setup(c => c.ReadContainerAsync(It.IsAny <ContainerRequestOptions>(), It.IsAny <CancellationToken>())).ReturnsAsync(mockedResponse.Object); mockedClient.Setup(c => c.GetContainer(It.IsAny <string>(), It.IsAny <string>())).Returns(mockedContainer.Object); mockedClient.Setup(c => c.GetDatabase(It.IsAny <string>())).Returns(mockedDatabase.Object); mockedClient.Setup(x => x.Endpoint).Returns(new Uri("http://localhost")); CosmosCache cache = new CosmosCache(Options.Create(new CosmosCacheOptions() { DatabaseName = "something", ContainerName = "something", CosmosClient = mockedClient.Object })); await Assert.ThrowsAsync <ArgumentOutOfRangeException>(() => cache.SetAsync(existingSession.SessionKey, existingSession.Content, cacheOptions)); }
public async Task StoreSessionData() { const string sessionId = "sessionId"; const int ttl = 1400; const int throughput = 2000; CosmosClientBuilder builder = new CosmosClientBuilder(ConfigurationManager.AppSettings["Endpoint"], ConfigurationManager.AppSettings["MasterKey"]); IOptions <CosmosCacheOptions> options = Options.Create(new CosmosCacheOptions() { ContainerName = "session", DatabaseName = CosmosCacheEmulatorTests.databaseName, ContainerThroughput = throughput, CreateIfNotExists = true, ClientBuilder = builder }); CosmosCache cache = new CosmosCache(options); DistributedCacheEntryOptions cacheOptions = new DistributedCacheEntryOptions(); cacheOptions.SlidingExpiration = TimeSpan.FromSeconds(ttl); await cache.SetAsync(sessionId, new byte[0], cacheOptions); // Verify that container has been created CosmosCacheSession storedSession = await this.testClient.GetContainer(CosmosCacheEmulatorTests.databaseName, "session").ReadItemAsync <CosmosCacheSession>(sessionId, new PartitionKey(sessionId)); Assert.Equal(sessionId, storedSession.SessionKey); }
public async Task SetAsyncCallsUpsert() { int ttl = 10; DistributedCacheEntryOptions cacheOptions = new DistributedCacheEntryOptions(); cacheOptions.SlidingExpiration = TimeSpan.FromSeconds(ttl); CosmosCacheSession existingSession = new CosmosCacheSession(); existingSession.SessionKey = "key"; existingSession.Content = new byte[0]; Mock <ItemResponse <CosmosCacheSession> > mockedItemResponse = new Mock <ItemResponse <CosmosCacheSession> >(); Mock <CosmosClient> mockedClient = new Mock <CosmosClient>(); Mock <Container> mockedContainer = new Mock <Container>(); Mock <Database> mockedDatabase = new Mock <Database>(); Mock <ContainerResponse> mockedResponse = new Mock <ContainerResponse>(); mockedResponse.Setup(c => c.StatusCode).Returns(HttpStatusCode.OK); mockedContainer.Setup(c => c.ReadContainerAsync(It.IsAny <ContainerRequestOptions>(), It.IsAny <CancellationToken>())).ReturnsAsync(mockedResponse.Object); mockedContainer.Setup(c => c.UpsertItemAsync <CosmosCacheSession>(It.Is <CosmosCacheSession>(item => item.SessionKey == existingSession.SessionKey && item.TimeToLive == ttl), It.IsAny <PartitionKey?>(), It.IsAny <ItemRequestOptions>(), It.IsAny <CancellationToken>())).ReturnsAsync(mockedItemResponse.Object); mockedClient.Setup(c => c.GetContainer(It.IsAny <string>(), It.IsAny <string>())).Returns(mockedContainer.Object); mockedClient.Setup(c => c.GetDatabase(It.IsAny <string>())).Returns(mockedDatabase.Object); mockedClient.Setup(x => x.Endpoint).Returns(new Uri("http://localhost")); CosmosCache cache = new CosmosCache(Options.Create(new CosmosCacheOptions() { DatabaseName = "something", ContainerName = "something", CosmosClient = mockedClient.Object })); await cache.SetAsync(existingSession.SessionKey, existingSession.Content, cacheOptions); mockedContainer.Verify(c => c.UpsertItemAsync <CosmosCacheSession>(It.Is <CosmosCacheSession>(item => item.SessionKey == existingSession.SessionKey && item.TimeToLive == ttl), It.IsAny <PartitionKey?>(), It.IsAny <ItemRequestOptions>(), It.IsAny <CancellationToken>()), Times.Once); }
public void ValidatesNullTtlDoesNotSerializeProperty() { CosmosCacheSession existingSession = new CosmosCacheSession(); existingSession.SessionKey = "key"; existingSession.Content = new byte[0]; string serialized = JsonConvert.SerializeObject(existingSession); Assert.False(serialized.Contains("\"ttl\""), "Session without expiration should not include ttl property."); }
public void ValidatesIsSlidingExpirationDoesSerializeProperty() { CosmosCacheSession existingSession = new CosmosCacheSession(); existingSession.SessionKey = "key"; existingSession.Content = new byte[0]; existingSession.IsSlidingExpiration = true; string serialized = JsonConvert.SerializeObject(existingSession); Assert.True(serialized.Contains("\"isSlidingExpiration\""), "Session with sliding expiration should include isSlidingExpiration property."); }
public void ValidatesCustomPartitionKeyCreatesProperty() { const string pkProperty = "notTheId"; CosmosCacheSession existingSession = new CosmosCacheSession(); existingSession.SessionKey = "key"; existingSession.Content = new byte[0]; existingSession.PartitionKeyAttribute = pkProperty; string serialized = JsonConvert.SerializeObject(existingSession); Assert.True(serialized.Contains($"\"{pkProperty}\""), "Missing custom partition key."); }
public void ValidatesContract() { const string expectedContract = "{\"id\":\"key\",\"content\":\"AQ==\",\"ttl\":5,\"isSlidingExpiration\":true}"; CosmosCacheSession existingSession = new CosmosCacheSession(); existingSession.SessionKey = "key"; existingSession.IsSlidingExpiration = true; existingSession.TimeToLive = 5; existingSession.Content = new byte[1] { 1 }; string serialized = JsonConvert.SerializeObject(existingSession); Assert.Equal(expectedContract, serialized); }
public async Task SlidingAndAbsoluteExpiration() { const string sessionId = "sessionId"; const int ttl = 10; const int absoluteTtl = 15; const int throughput = 400; CosmosClientBuilder builder = new CosmosClientBuilder(ConfigurationManager.AppSettings["Endpoint"], ConfigurationManager.AppSettings["MasterKey"]); IOptions <CosmosCacheOptions> options = Options.Create(new CosmosCacheOptions() { ContainerName = "session", DatabaseName = CosmosCacheEmulatorTests.databaseName, ContainerThroughput = throughput, CreateIfNotExists = true, ClientBuilder = builder }); CosmosCache cache = new CosmosCache(options); DistributedCacheEntryOptions cacheOptions = new DistributedCacheEntryOptions(); cacheOptions.SlidingExpiration = TimeSpan.FromSeconds(ttl); cacheOptions.AbsoluteExpiration = DateTimeOffset.UtcNow.AddSeconds(absoluteTtl); byte[] data = new byte[4] { 1, 2, 3, 4 }; await cache.SetAsync(sessionId, data, cacheOptions); // Verify that container has been created CosmosCacheSession storedSession = await this.testClient.GetContainer(CosmosCacheEmulatorTests.databaseName, "session").ReadItemAsync <CosmosCacheSession>(sessionId, new PartitionKey(sessionId)); Assert.Equal(ttl, storedSession.TimeToLive); await Task.Delay(8000); // Wait await cache.GetAsync(sessionId); storedSession = await this.testClient.GetContainer(CosmosCacheEmulatorTests.databaseName, "session").ReadItemAsync <CosmosCacheSession>(sessionId, new PartitionKey(sessionId)); // Since the absolute expiration is closer than the sliding value, the TTL should be lower Assert.True(storedSession.TimeToLive < ttl); }
public async Task GetObtainsSessionAndUpdatesCacheForSlidingExpirationWithAbsoluteExpirationWithHigherTime() { const int ttlSliding = 20; const int ttlAbsolute = 50; string etag = "etag"; CosmosCacheSession existingSession = new CosmosCacheSession(); existingSession.SessionKey = "key"; existingSession.Content = new byte[0]; existingSession.IsSlidingExpiration = true; existingSession.TimeToLive = ttlSliding; existingSession.AbsoluteSlidingExpiration = DateTimeOffset.UtcNow.AddSeconds(ttlAbsolute).ToUnixTimeSeconds(); Mock <ItemResponse <CosmosCacheSession> > mockedItemResponse = new Mock <ItemResponse <CosmosCacheSession> >(); Mock <CosmosClient> mockedClient = new Mock <CosmosClient>(); Mock <Container> mockedContainer = new Mock <Container>(); Mock <Database> mockedDatabase = new Mock <Database>(); Mock <ContainerResponse> mockedResponse = new Mock <ContainerResponse>(); mockedItemResponse.Setup(c => c.Resource).Returns(existingSession); mockedItemResponse.Setup(c => c.ETag).Returns(etag); mockedResponse.Setup(c => c.StatusCode).Returns(HttpStatusCode.OK); mockedContainer.Setup(c => c.ReadContainerAsync(It.IsAny <ContainerRequestOptions>(), It.IsAny <CancellationToken>())).ReturnsAsync(mockedResponse.Object); mockedContainer.Setup(c => c.ReadItemAsync <CosmosCacheSession>(It.Is <string>(id => id == "key"), It.IsAny <PartitionKey>(), It.IsAny <ItemRequestOptions>(), It.IsAny <CancellationToken>())).ReturnsAsync(mockedItemResponse.Object); mockedContainer.Setup(c => c.ReplaceItemAsync <CosmosCacheSession>(It.Is <CosmosCacheSession>(item => item == existingSession), It.Is <string>(id => id == "key"), It.IsAny <PartitionKey?>(), It.IsAny <ItemRequestOptions>(), It.IsAny <CancellationToken>())).ReturnsAsync(mockedItemResponse.Object); mockedClient.Setup(c => c.GetContainer(It.IsAny <string>(), It.IsAny <string>())).Returns(mockedContainer.Object); mockedClient.Setup(c => c.GetDatabase(It.IsAny <string>())).Returns(mockedDatabase.Object); mockedClient.Setup(x => x.Endpoint).Returns(new Uri("http://localhost")); CosmosCache cache = new CosmosCache(Options.Create(new CosmosCacheOptions() { DatabaseName = "something", ContainerName = "something", CreateIfNotExists = true, CosmosClient = mockedClient.Object })); Assert.Same(existingSession.Content, await cache.GetAsync("key")); // Checks for Db existence due to CreateIfNotExists mockedClient.Verify(c => c.CreateDatabaseIfNotExistsAsync(It.IsAny <string>(), It.IsAny <int?>(), It.IsAny <RequestOptions>(), It.IsAny <CancellationToken>()), Times.Once); mockedContainer.Verify(c => c.ReadItemAsync <CosmosCacheSession>(It.Is <string>(id => id == "key"), It.IsAny <PartitionKey>(), It.IsAny <ItemRequestOptions>(), It.IsAny <CancellationToken>()), Times.Once); mockedContainer.Verify(c => c.ReplaceItemAsync <CosmosCacheSession>(It.Is <CosmosCacheSession>(item => item.TimeToLive == ttlSliding), It.Is <string>(id => id == "key"), It.IsAny <PartitionKey?>(), It.IsAny <ItemRequestOptions>(), It.IsAny <CancellationToken>()), Times.Once); }
public async Task GetDoesRetryUpdateIfRetrySlidingExpirationUpdatesIsTrue() { string etag = "etag"; CosmosCacheSession existingSession = new CosmosCacheSession(); existingSession.SessionKey = "key"; existingSession.Content = new byte[0]; existingSession.IsSlidingExpiration = true; Mock <ItemResponse <CosmosCacheSession> > mockedItemResponse = new Mock <ItemResponse <CosmosCacheSession> >(); Mock <CosmosClient> mockedClient = new Mock <CosmosClient>(); Mock <Container> mockedContainer = new Mock <Container>(); Mock <Database> mockedDatabase = new Mock <Database>(); Mock <ContainerResponse> mockedResponse = new Mock <ContainerResponse>(); mockedItemResponse.Setup(c => c.Resource).Returns(existingSession); mockedItemResponse.Setup(c => c.ETag).Returns(etag); mockedResponse.Setup(c => c.StatusCode).Returns(HttpStatusCode.OK); mockedContainer.Setup(c => c.ReadContainerAsync(It.IsAny <ContainerRequestOptions>(), It.IsAny <CancellationToken>())).ReturnsAsync(mockedResponse.Object); mockedContainer.Setup(c => c.ReadItemAsync <CosmosCacheSession>(It.Is <string>(id => id == "key"), It.IsAny <PartitionKey>(), It.IsAny <ItemRequestOptions>(), It.IsAny <CancellationToken>())).ReturnsAsync(mockedItemResponse.Object); mockedContainer.SetupSequence(c => c.ReplaceItemAsync <CosmosCacheSession>(It.Is <CosmosCacheSession>(item => item == existingSession), It.Is <string>(id => id == "key"), It.IsAny <PartitionKey?>(), It.IsAny <ItemRequestOptions>(), It.IsAny <CancellationToken>())) .ThrowsAsync(new CosmosException("test", HttpStatusCode.PreconditionFailed, 0, "", 0)) .ReturnsAsync(mockedItemResponse.Object); mockedClient.Setup(c => c.GetContainer(It.IsAny <string>(), It.IsAny <string>())).Returns(mockedContainer.Object); mockedClient.Setup(c => c.GetDatabase(It.IsAny <string>())).Returns(mockedDatabase.Object); mockedClient.Setup(x => x.Endpoint).Returns(new Uri("http://localhost")); CosmosCache cache = new CosmosCache(Options.Create(new CosmosCacheOptions() { DatabaseName = "something", ContainerName = "something", CreateIfNotExists = true, CosmosClient = mockedClient.Object, RetrySlidingExpirationUpdates = true })); Assert.Same(existingSession.Content, await cache.GetAsync("key")); // Checks for Db existence due to CreateIfNotExists mockedClient.Verify(c => c.CreateDatabaseIfNotExistsAsync(It.IsAny <string>(), It.IsAny <int?>(), It.IsAny <RequestOptions>(), It.IsAny <CancellationToken>()), Times.Once); mockedContainer.Verify(c => c.ReadItemAsync <CosmosCacheSession>(It.Is <string>(id => id == "key"), It.IsAny <PartitionKey>(), It.IsAny <ItemRequestOptions>(), It.IsAny <CancellationToken>()), Times.Exactly(2)); mockedContainer.Verify(c => c.ReplaceItemAsync <CosmosCacheSession>(It.Is <CosmosCacheSession>(item => item == existingSession), It.Is <string>(id => id == "key"), It.IsAny <PartitionKey?>(), It.IsAny <ItemRequestOptions>(), It.IsAny <CancellationToken>()), Times.Exactly(2)); }
public async Task StoreSessionData_CustomPartitionKey() { const string sessionId = "sessionId"; const int ttl = 1400; const int throughput = 2000; const string partitionKeyAttribute = "notTheId"; CosmosClientBuilder builder = new CosmosClientBuilder(ConfigurationManager.AppSettings["Endpoint"], ConfigurationManager.AppSettings["MasterKey"]); IOptions <CosmosCacheOptions> options = Options.Create(new CosmosCacheOptions() { ContainerName = "session", DatabaseName = CosmosCacheEmulatorTests.databaseName, ContainerThroughput = throughput, CreateIfNotExists = true, ClientBuilder = builder, ContainerPartitionKeyAttribute = partitionKeyAttribute, }); CosmosCache cache = new CosmosCache(options); DistributedCacheEntryOptions cacheOptions = new DistributedCacheEntryOptions(); cacheOptions.SlidingExpiration = TimeSpan.FromSeconds(ttl); byte[] data = new byte[4] { 1, 2, 3, 4 }; await cache.SetAsync(sessionId, data, cacheOptions); // Verify that container has been created CosmosCacheSession storedSession = await this.testClient.GetContainer(CosmosCacheEmulatorTests.databaseName, "session").ReadItemAsync <CosmosCacheSession>(sessionId, new PartitionKey(sessionId)); Assert.Equal(sessionId, storedSession.SessionKey); Assert.Equal(data, storedSession.Content); ItemResponse <dynamic> dynamicSession = await this.testClient.GetContainer(CosmosCacheEmulatorTests.databaseName, "session").ReadItemAsync <dynamic>(sessionId, new PartitionKey(sessionId)); Assert.NotNull(dynamicSession.Resource.notTheId); Assert.Equal(sessionId, (string)dynamicSession.Resource.notTheId); }