public async Task ExecuteAsync_UpdatesScanInfoManager()
        {
            int testScanBlobLimitPerPoll                = 6;
            BlobContainerClient     firstContainer      = _blobContainerMock.Object;
            BlobContainerClient     secondContainer     = _secondBlobContainerMock.Object;
            TestBlobScanInfoManager testScanInfoManager = new TestBlobScanInfoManager();
            string accountName = AccountName;

            testScanInfoManager.SetScanInfo(accountName, ContainerName, DateTime.MinValue);
            testScanInfoManager.SetScanInfo(accountName, SecondContainerName, DateTime.MinValue);
            IBlobListenerStrategy     product  = new ScanBlobScanLogHybridPollingStrategy(testScanInfoManager, _exceptionHandler, NullLogger <BlobListener> .Instance);
            LambdaBlobTriggerExecutor executor = new LambdaBlobTriggerExecutor();

            typeof(ScanBlobScanLogHybridPollingStrategy)
            .GetField("_scanBlobLimitPerPoll", BindingFlags.Instance | BindingFlags.NonPublic)
            .SetValue(product, testScanBlobLimitPerPoll);

            await product.RegisterAsync(_blobClientMock.Object, firstContainer, executor, CancellationToken.None);

            await product.RegisterAsync(_blobClientMock.Object, secondContainer, executor, CancellationToken.None);

            var firstExpectedNames = new List <string>();

            for (int i = 0; i < 3; i++)
            {
                firstExpectedNames.Add(CreateBlobAndUploadToContainer(_blobContainerMock, _blobItems));
            }
            RunExecuteWithMultiPollingInterval(firstExpectedNames, product, executor, testScanBlobLimitPerPoll / 2);

            // only expect the first container to have updated its scanInfo
            Assert.AreEqual(1, testScanInfoManager.UpdateCounts[accountName][ContainerName]);
            int count;

            testScanInfoManager.UpdateCounts[accountName].TryGetValue(SecondContainerName, out count);
            Assert.AreEqual(0, count);

            await Task.Delay(10);

            var secondExpectedNames = new List <string>();

            for (int i = 0; i < 7; i++)
            {
                secondExpectedNames.Add(CreateBlobAndUploadToContainer(_secondBlobContainerMock, _secondBlobItems));
            }
            RunExecuteWithMultiPollingInterval(secondExpectedNames, product, executor, testScanBlobLimitPerPoll / 2);

            // this time, only expect the second container to have updated its scanInfo
            Assert.AreEqual(1, testScanInfoManager.UpdateCounts[accountName][ContainerName]);
            Assert.AreEqual(1, testScanInfoManager.UpdateCounts[accountName][SecondContainerName]);
        }
        public async Task RegisterAsync_InitializesWithScanInfoManager()
        {
            var container = _blobContainerMock.Object;
            TestBlobScanInfoManager   scanInfoManager = new TestBlobScanInfoManager();
            IBlobListenerStrategy     product         = new ScanBlobScanLogHybridPollingStrategy(scanInfoManager, _exceptionHandler, NullLogger <BlobListener> .Instance);
            LambdaBlobTriggerExecutor executor        = new LambdaBlobTriggerExecutor();

            // Create a few blobs.
            for (int i = 0; i < 5; i++)
            {
                CreateBlobAndUploadToContainer(_blobContainerMock, _blobItems);
            }

            // delay slightly so we guarantee a later timestamp
            await Task.Delay(10);

            await scanInfoManager.UpdateLatestScanAsync(AccountName, ContainerName, DateTime.UtcNow);

            await product.RegisterAsync(_blobClientMock.Object, container, executor, CancellationToken.None);

            // delay slightly so we guarantee a later timestamp
            await Task.Delay(10);

            var expectedNames = new List <string>();

            expectedNames.Add(CreateBlobAndUploadToContainer(_blobContainerMock, _blobItems));

            RunExecuterWithExpectedBlobs(expectedNames, product, executor);
        }
        public async Task ExecuteAsync_UpdatesScanInfo_WithEarliestFailure()
        {
            int testScanBlobLimitPerPoll = 6;

            // we'll introduce multiple errors to make sure we take the earliest timestamp
            DateTime earliestErrorTime = DateTime.UtcNow;

            var container = _blobContainerMock.Object;

            TestBlobScanInfoManager testScanInfoManager = new TestBlobScanInfoManager();
            string accountName = AccountName;

            testScanInfoManager.SetScanInfo(accountName, ContainerName, DateTime.MinValue);
            IBlobListenerStrategy     product  = new ScanBlobScanLogHybridPollingStrategy(testScanInfoManager, _exceptionHandler, NullLogger <BlobListener> .Instance);
            LambdaBlobTriggerExecutor executor = new LambdaBlobTriggerExecutor();

            typeof(ScanBlobScanLogHybridPollingStrategy)
            .GetField("_scanBlobLimitPerPoll", BindingFlags.Instance | BindingFlags.NonPublic)
            .SetValue(product, testScanBlobLimitPerPoll);

            await product.RegisterAsync(_blobClientMock.Object, container, executor, CancellationToken.None);

            // Induce a failure to make sure the timestamp is earlier than the failure.
            var expectedNames = new List <string>();

            for (int i = 0; i < 7; i++)
            {
                string name;
                if (i % 3 == 0)
                {
                    name = CreateBlobAndUploadToContainer(_blobContainerMock, _blobItems, "throw", earliestErrorTime.AddMinutes(i));
                }
                else
                {
                    name = CreateBlobAndUploadToContainer(_blobContainerMock, _blobItems, "test", earliestErrorTime.AddMinutes(10));
                }
                expectedNames.Add(name);
            }

            RunExecuteWithMultiPollingInterval(expectedNames, product, executor, testScanBlobLimitPerPoll);

            DateTime?storedTime = await testScanInfoManager.LoadLatestScanAsync(accountName, ContainerName);

            Assert.True(storedTime < earliestErrorTime);
            Assert.AreEqual(1, testScanInfoManager.UpdateCounts[accountName][ContainerName]);
            _blobContainerMock.Verify(x => x.GetBlobsAsync(It.IsAny <BlobTraits>(), It.IsAny <BlobStates>(), It.IsAny <string>(), It.IsAny <CancellationToken>()),
                                      Times.Exactly(2));
        }