コード例 #1
0
        public async Task GetGuidInfo_ExpiredGuidFromCache()
        {
            // use guid created in the past
            var cachedEntity = new GuidInfoEntity()
            {
                Guid   = System.Guid.NewGuid(),
                User   = "******",
                Expire = _now.AddDays(-10)
            };

            var mockRepo    = new Mock <IRepository <GuidInfoEntity> >();
            var mockContext = new Mock <IGuidRepositoryContext>();

            // return entity from cache
            var mockCache = new Mock <IEntityCache <GuidInfoEntity> >();

            mockCache.Setup(r => r.GetEntityAsync(It.IsAny <string>(), cachedEntity.Guid.ToString()))
            .ReturnsAsync(cachedEntity)
            .Verifiable();

            var controller = new GuidInfosController(mockContext.Object, mockCache.Object, _mockClock.Object);
            var info       = await controller.GetGuidInfoAsync(cachedEntity.Guid);

            Assert.IsType <ActionResult <GuidInfo> >(info);
            var result = Assert.IsType <ObjectResult>(info.Result);

            Assert.Equal(result.StatusCode, (int)HttpStatusCode.Gone);
            var value = Assert.IsType <GuidApiError>(result.Value);

            Assert.Equal((int)value.Code, (int)GuidErrorCode.GuidExpired);

            mockCache.Verify();
        }
コード例 #2
0
        public async Task CreateOrUpdateGuidInfo_Update()
        {
            // entity in database
            var dbEntity = new GuidInfoEntity()
            {
                Guid   = System.Guid.NewGuid(),
                User   = "******",
                Expire = new DateTime(2020, 2, 2, 2, 2, 2, DateTimeKind.Utc)
            };

            // modified properties
            var infoBase = new GuidInfoBase()
            {
                User   = "******",
                Expire = new DateTime(2022, 1, 1, 1, 1, 1, DateTimeKind.Utc)
            };

            // find entity in database
            var mockRepo = new Mock <IRepository <GuidInfoEntity> >();

            mockRepo.Setup(r => r.GetAsync(It.IsAny <Expression <Func <GuidInfoEntity, bool> > >()))
            .ReturnsAsync(new List <GuidInfoEntity>()
            {
                dbEntity
            })
            .Verifiable();

            // update it
            mockRepo.Setup(r => r.Update(It.IsAny <GuidInfoEntity>()))
            .Verifiable();

            // save it
            var mockContext = new Mock <IGuidRepositoryContext>();

            mockContext.Setup(r => r.SaveChangesAsync())
            .Returns(Task.CompletedTask)
            .Verifiable();
            mockContext.Setup(r => r.GuidInfos)
            .Returns(mockRepo.Object);

            // and invalidate cache
            var mockCache = new Mock <IEntityCache <GuidInfoEntity> >();

            mockCache.Setup(r => r.InvalidateEntityAsync(It.IsAny <string>(), dbEntity.Guid.ToString()))
            .Returns(Task.CompletedTask)
            .Verifiable();

            var controller = new GuidInfosController(mockContext.Object, mockCache.Object, _mockClock.Object);
            var info       = await controller.CreateOrUpdateGuidInfoAsync(dbEntity.Guid, infoBase);

            Assert.IsType <ActionResult <GuidInfo> >(info);
            var value = Assert.IsType <GuidInfo>(info.Value);

            Assert.Equal(value.User, infoBase.User);
            Assert.Equal(value.Expire, infoBase.Expire);

            mockRepo.Verify();
            mockContext.Verify();
            mockCache.Verify();
        }
コード例 #3
0
        private async Task <ActionResult <GuidInfo> > ProcessGuidInfo(GuidInfoEntity info, bool fromCache)
        {
            if (info.Expire < _clock.UtcNow)
            {
                // retrieved info has expired
                if (fromCache)
                {
                    // remove it from cache
                    await InvalidateCache(info.Guid);
                }

                // and return 410 code (Gone)
                return(StatusCode((int)HttpStatusCode.Gone, new GuidApiError(GuidErrorCode.GuidExpired)));
            }
            else
            {
                // this is a valid (not expired) guid
                if (!fromCache)
                {
                    // retrieved from database, add it to cache
                    // NOTE:  Assuming Redis LRU caching, see https://redis.io/topics/lru-cache
                    // NOTE:  Alternatively, we could set an expiration time for entries
                    await _cache.SetEntityAsync(_cachePrefix, info.Guid.ToString(), info);
                }

                return(info.ToGuidInfo());
            }
        }
コード例 #4
0
        public async Task GetGuidInfo_FromDatabase()
        {
            var dbEntity = new GuidInfoEntity()
            {
                Guid   = System.Guid.NewGuid(),
                User   = "******",
                Expire = _now.AddDays(10)
            };

            // return entity from database
            var mockRepo = new Mock <IRepository <GuidInfoEntity> >();

            mockRepo.Setup(r => r.GetAsync(It.IsAny <Expression <Func <GuidInfoEntity, bool> > >()))
            .ReturnsAsync(new List <GuidInfoEntity>()
            {
                dbEntity
            })
            .Verifiable();

            var mockContext = new Mock <IGuidRepositoryContext>();

            mockContext.Setup(r => r.GuidInfos)
            .Returns(mockRepo.Object);

            // return no hit from cache
            var mockCache = new Mock <IEntityCache <GuidInfoEntity> >();

            mockCache.Setup(r => r.GetEntityAsync(It.IsAny <string>(), dbEntity.Guid.ToString()))
            .ReturnsAsync((GuidInfoEntity)null)
            .Verifiable();

            // make sure we cache found database entry
            mockCache.Setup(r => r.SetEntityAsync(It.IsAny <string>(), dbEntity.Guid.ToString(), dbEntity))
            .Returns(Task.CompletedTask)
            .Verifiable();

            var controller = new GuidInfosController(mockContext.Object, mockCache.Object, _mockClock.Object);
            var info       = await controller.GetGuidInfoAsync(dbEntity.Guid);

            Assert.IsType <ActionResult <GuidInfo> >(info);
            var value = Assert.IsType <GuidInfo>(info.Value);

            Assert.Equal(value.Guid, dbEntity.Guid.ToString("N").ToUpper());
            Assert.Equal(value.User, dbEntity.User);
            Assert.Equal(value.Expire, dbEntity.Expire);

            // verify we read cache once (which returned null)
            mockCache.Verify(r => r.GetEntityAsync(It.IsAny <string>(), dbEntity.Guid.ToString()), Times.Once);

            // and accessed database once
            mockRepo.Verify(r => r.GetAsync(It.IsAny <Expression <Func <GuidInfoEntity, bool> > >()), Times.Once);

            // and stored in cache once
            mockCache.Verify(r => r.SetEntityAsync(It.IsAny <string>(), dbEntity.Guid.ToString(), dbEntity), Times.Once);
        }
コード例 #5
0
        public async Task GetGuidInfo_ExpiredGuidFromDatabase()
        {
            // use guid created in the past
            var dbEntity = new GuidInfoEntity()
            {
                Guid   = System.Guid.NewGuid(),
                User   = "******",
                Expire = _now.AddDays(-10)
            };

            // retrieve entity from database
            var mockRepo = new Mock <IRepository <GuidInfoEntity> >();

            mockRepo.Setup(r => r.GetAsync(It.IsAny <Expression <Func <GuidInfoEntity, bool> > >()))
            .ReturnsAsync(new List <GuidInfoEntity>()
            {
                dbEntity
            })
            .Verifiable();

            var mockContext = new Mock <IGuidRepositoryContext>();

            mockContext.Setup(r => r.GuidInfos)
            .Returns(mockRepo.Object);

            // make sure we get no cache hits
            var mockCache = new Mock <IEntityCache <GuidInfoEntity> >();

            mockCache.Setup(r => r.GetEntityAsync(It.IsAny <string>(), dbEntity.Guid.ToString()))
            .ReturnsAsync((GuidInfoEntity)null)
            .Verifiable();

            var controller = new GuidInfosController(mockContext.Object, mockCache.Object, _mockClock.Object);
            var info       = await controller.GetGuidInfoAsync(dbEntity.Guid);

            Assert.IsType <ActionResult <GuidInfo> >(info);
            var result = Assert.IsType <ObjectResult>(info.Result);

            Assert.Equal(result.StatusCode, (int)HttpStatusCode.Gone);
            var value = Assert.IsType <GuidApiError>(result.Value);

            Assert.Equal((int)value.Code, (int)GuidErrorCode.GuidExpired);

            mockRepo.Verify();
            mockCache.Verify();
        }
コード例 #6
0
        public async Task DeleteGuidInfo_Found()
        {
            var dbEntity = new GuidInfoEntity()
            {
                Guid   = System.Guid.NewGuid(),
                User   = "******",
                Expire = new DateTime(2020, 2, 2, 2, 2, 2, DateTimeKind.Utc)
            };

            // find entity in database
            var mockRepo = new Mock <IRepository <GuidInfoEntity> >();

            mockRepo.Setup(r => r.GetAsync(It.IsAny <Expression <Func <GuidInfoEntity, bool> > >()))
            .ReturnsAsync(new List <GuidInfoEntity>()
            {
                dbEntity
            })
            .Verifiable();

            // remove it from database
            mockRepo.Setup(r => r.Delete(It.IsAny <GuidInfoEntity>()))
            .Verifiable();

            var mockContext = new Mock <IGuidRepositoryContext>();

            mockContext.Setup(r => r.GuidInfos)
            .Returns(mockRepo.Object);

            // and invalidate cache
            var mockCache = new Mock <IEntityCache <GuidInfoEntity> >();

            mockCache.Setup(r => r.InvalidateEntityAsync(It.IsAny <string>(), dbEntity.Guid.ToString()))
            .Returns(Task.CompletedTask)
            .Verifiable();

            var controller = new GuidInfosController(mockContext.Object, mockCache.Object, _mockClock.Object);
            var info       = await controller.DeleteGuidInfoAsync(dbEntity.Guid);

            var result = Assert.IsType <OkResult>(info);

            Assert.Equal(result.StatusCode, (int)HttpStatusCode.OK);

            mockRepo.Verify();
            mockCache.Verify();
        }
コード例 #7
0
        public async Task GetGuidInfo_FromCache()
        {
            // return no hits from database
            var mockRepo = new Mock <IRepository <GuidInfoEntity> >();

            mockRepo.Setup(r => r.GetAsync(It.IsAny <Expression <Func <GuidInfoEntity, bool> > >()))
            .ReturnsAsync(new List <GuidInfoEntity>())
            .Verifiable();

            var mockContext = new Mock <IGuidRepositoryContext>();

            mockContext.Setup(r => r.GuidInfos)
            .Returns(mockRepo.Object);

            var cachedEntity = new GuidInfoEntity()
            {
                Guid   = System.Guid.NewGuid(),
                User   = "******",
                Expire = _now.AddDays(10)
            };

            // return entity from cache
            var mockCache = new Mock <IEntityCache <GuidInfoEntity> >();

            mockCache.Setup(r => r.GetEntityAsync(It.IsAny <string>(), cachedEntity.Guid.ToString()))
            .ReturnsAsync(cachedEntity)
            .Verifiable();

            var controller = new GuidInfosController(mockContext.Object, mockCache.Object, _mockClock.Object);
            var info       = await controller.GetGuidInfoAsync(cachedEntity.Guid);

            Assert.IsType <ActionResult <GuidInfo> >(info);
            var value = Assert.IsType <GuidInfo>(info.Value);

            Assert.Equal(value.Guid, cachedEntity.Guid.ToString("N").ToUpper());
            Assert.Equal(value.User, cachedEntity.User);
            Assert.Equal(value.Expire, cachedEntity.Expire);

            // verify we accessed cache
            mockCache.Verify(r => r.GetEntityAsync(It.IsAny <string>(), cachedEntity.Guid.ToString()), Times.Once);

            // but not database
            mockRepo.Verify(r => r.GetAsync(It.IsAny <Expression <Func <GuidInfoEntity, bool> > >()), Times.Never);
        }
コード例 #8
0
        private async Task <ActionResult <GuidInfo> > CreateGuidInfo(System.Guid guid, GuidInfoBase info)
        {
            if (string.IsNullOrWhiteSpace(info.User))
            {
                return(BadRequest(new GuidApiError(GuidErrorCode.InvalidUser)));
            }
            else
            {
                var entity = new GuidInfoEntity()
                {
                    Guid   = guid,
                    Expire = info.Expire ?? GetDefaultExpireDate(),
                    User   = info.User
                };

                await _context.GuidInfos.AddAsync(entity);

                await _context.SaveChangesAsync();

                var guidInfo = entity.ToGuidInfo();
                return(CreatedAtRoute("GetGuidInfo", new { id = guidInfo.Guid }, guidInfo));
            }
        }