public async Task ExecuteBatchAsync_LogsError()
        {
            IEnvironment testEnvironment = new TestEnvironment();

            testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "0");

            DiagnosticEventTableStorageRepository repository =
                new DiagnosticEventTableStorageRepository(_configuration, _hostIdProvider, testEnvironment, _logger);

            var tableClient = repository.TableClient;
            var table       = tableClient.GetTableReference("aa");

            var dateTime        = DateTime.UtcNow;
            var diagnosticEvent = new DiagnosticEvent("hostId", dateTime);

            var events = new ConcurrentDictionary <string, DiagnosticEvent>();

            events.TryAdd("EC123", diagnosticEvent);
            await repository.ExecuteBatchAsync(events, table);

            ExecuteQuery(table, new TableQuery());
            string message = _loggerProvider.GetAllLogMessages()[0].FormattedMessage;

            Assert.True(message.StartsWith("Unable to write diagnostic events to table storage"));
        }
        public async Task ExecuteBatchAsync_WritesToTableStorage()
        {
            IEnvironment testEnvironment = new TestEnvironment();

            testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "0");

            DiagnosticEventTableStorageRepository repository =
                new DiagnosticEventTableStorageRepository(_configuration, _hostIdProvider, testEnvironment, _logger);

            var table = repository.GetDiagnosticEventsTable();
            await TableStorageHelpers.CreateIfNotExistsAsync(table, 2);

            await EmptyTableAsync(table);

            var dateTime        = DateTime.UtcNow;
            var diagnosticEvent = new DiagnosticEvent("hostId", dateTime);
            var events          = new ConcurrentDictionary <string, DiagnosticEvent>();

            events.TryAdd("EC123", diagnosticEvent);
            await repository.ExecuteBatchAsync(events, table);

            var results = ExecuteQuery(table, new TableQuery());

            Assert.Equal(results.Count(), 1);
        }
        public void WriteDiagnostic_LogsError_whenHostIdNotSet()
        {
            IEnvironment testEnvironment = new TestEnvironment();

            DiagnosticEventTableStorageRepository repository =
                new DiagnosticEventTableStorageRepository(_configuration, null, testEnvironment, _logger);

            repository.WriteDiagnosticEvent(DateTime.UtcNow, "eh1", LogLevel.Information, "This is the message", "https://fwlink/", new Exception("exception message"));

            var messages = _loggerProvider.GetAllLogMessages();

            Assert.Equal(messages[0].FormattedMessage, "Unable to write diagnostic events. Host id is set to null.");
        }
        public void GetDiagnosticEventsTable_ReturnsExpectedValue_WhenSpecialized()
        {
            IEnvironment testEnvironment = new TestEnvironment();

            testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "0");

            DiagnosticEventTableStorageRepository repository =
                new DiagnosticEventTableStorageRepository(_configuration, _hostIdProvider, testEnvironment, _logger);
            DateTime dateTime   = new DateTime(2021, 1, 1);
            var      cloudTable = repository.GetDiagnosticEventsTable(dateTime);

            Assert.NotNull(cloudTable);
            Assert.NotNull(repository.TableClient);
            Assert.Equal(cloudTable.Name, $"{DiagnosticEventTableStorageRepository.TableNamePrefix}202101");
        }
        public void GetDiagnosticEventsTable_LogsError_StorageConnectionStringIsNotPresent()
        {
            IEnvironment testEnvironment = new TestEnvironment();

            testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "0");

            var configuration = new ConfigurationBuilder().Build();
            DiagnosticEventTableStorageRepository repository =
                new DiagnosticEventTableStorageRepository(configuration, _hostIdProvider, testEnvironment, _logger);
            DateTime dateTime   = new DateTime(2021, 1, 1);
            var      cloudTable = repository.GetDiagnosticEventsTable(dateTime);

            Assert.Null(cloudTable);
            var messages = _loggerProvider.GetAllLogMessages();

            Assert.Equal(messages[0].FormattedMessage, "Azure Storage connection string is empty or invalid. Unable to write diagnostic events.");
        }
        public async Task WriteDiagnostic_HasTheCorrectHitCount_WhenCalledFromMultipleThreadsConcurrently()
        {
            IEnvironment testEnvironment = new TestEnvironment();

            testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "0");

            DiagnosticEventTableStorageRepository repository =
                new DiagnosticEventTableStorageRepository(_configuration, _hostIdProvider, testEnvironment, _logger);

            var eventTask1 = Task.Run(() =>
            {
                for (int i = 0; i < 200; i++)
                {
                    Thread.Sleep(10);
                    repository.WriteDiagnosticEvent(DateTime.UtcNow, "fn0001", LogLevel.Information, "This is the message", "https://fwlink/", new Exception("exception message"));
                    repository.WriteDiagnosticEvent(DateTime.UtcNow, "fn0002", LogLevel.Information, "This is the message", "https://fwlink/", new Exception("exception message"));
                }
            });

            var eventTask2 = Task.Run(() =>
            {
                for (int i = 0; i < 200; i++)
                {
                    Thread.Sleep(10);
                    repository.WriteDiagnosticEvent(DateTime.UtcNow, "fn0001", LogLevel.Information, "This is the message", "https://fwlink/", new Exception("exception message"));
                    repository.WriteDiagnosticEvent(DateTime.UtcNow, "fn0003", LogLevel.Information, "This is the message", "https://fwlink/", new Exception("exception message"));
                }
            });

            var eventTask3 = Task.Run(() =>
            {
                for (int i = 0; i < 200; i++)
                {
                    Thread.Sleep(10);
                    repository.WriteDiagnosticEvent(DateTime.UtcNow, "fn0001", LogLevel.Information, "This is the message", "https://fwlink/", new Exception("exception message"));
                    repository.WriteDiagnosticEvent(DateTime.UtcNow, "fn0002", LogLevel.Information, "This is the message", "https://fwlink/", new Exception("exception message"));
                }
            });

            await Task.WhenAll(eventTask1, eventTask2, eventTask3);

            Assert.Equal(600, repository.Events["fn0001"].HitCount);
            Assert.Equal(400, repository.Events["fn0002"].HitCount);
            Assert.Equal(200, repository.Events["fn0003"].HitCount);
        }
        public async Task QueueBackgroundDiagnosticsEventsTablePurge_PurgesTables()
        {
            IEnvironment testEnvironment = new TestEnvironment();

            testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "0");

            DiagnosticEventTableStorageRepository repository =
                new DiagnosticEventTableStorageRepository(_configuration, _hostIdProvider, testEnvironment, _logger);

            // delete any existing non-current diagnostics events tables
            string tablePrefix  = DiagnosticEventTableStorageRepository.TableNamePrefix;
            var    currentTable = repository.GetDiagnosticEventsTable();
            var    tables       = await TableStorageHelpers.ListOldTablesAsync(currentTable, repository.TableClient, tablePrefix);

            foreach (var table in tables)
            {
                await table.DeleteIfExistsAsync();
            }

            // create 3 old tables
            for (int i = 0; i < 3; i++)
            {
                var table = repository.TableClient.GetTableReference($"{tablePrefix}Test{i}");
                await TableStorageHelpers.CreateIfNotExistsAsync(table, 2);
            }

            // verify tables were created
            tables = await TableStorageHelpers.ListOldTablesAsync(currentTable, repository.TableClient, tablePrefix);

            Assert.Equal(3, tables.Count());

            // queue the background purge
            TableStorageHelpers.QueueBackgroundTablePurge(currentTable, repository.TableClient, tablePrefix, NullLogger.Instance, 0);

            // wait for the purge to complete
            await TestHelpers.Await(async() =>
            {
                tables = await TableStorageHelpers.ListOldTablesAsync(currentTable, repository.TableClient, tablePrefix);
                return(tables.Count() == 0);
            }, timeout : 5000);
        }
        public async Task TimerFlush_CalledOnExpectedInterval()
        {
            IEnvironment testEnvironment = new TestEnvironment();
            int          flushInterval   = 10;
            Mock <DiagnosticEventTableStorageRepository> mockDiagnosticEventTableStorageRepository = new Mock <DiagnosticEventTableStorageRepository>
                                                                                                         (_configuration, _hostIdProvider, testEnvironment, NullLogger <DiagnosticEventTableStorageRepository> .Instance, flushInterval);

            DiagnosticEventTableStorageRepository repository = mockDiagnosticEventTableStorageRepository.Object;

            int numFlushes = 0;

            mockDiagnosticEventTableStorageRepository.Protected().Setup("OnFlushLogs", ItExpr.IsAny <object>())
            .Callback <object>((state) =>
            {
                numFlushes++;
            });

            await TestHelpers.Await(() => numFlushes >= 5, timeout : 2000, pollingInterval : 100, userMessageCallback : () => $"Expected numFlushes >= 5; Actual: {numFlushes}");

            mockDiagnosticEventTableStorageRepository.VerifyAll();
        }
        public async Task FlushLogs_LogsErrorAndClearsEvents_WhenTableCreatingFails()
        {
            // Clear events by flush logs if table creation attempts fail
            IEnvironment testEnvironment = new TestEnvironment();

            testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "0");

            DiagnosticEventTableStorageRepository repository =
                new DiagnosticEventTableStorageRepository(_configuration, _hostIdProvider, testEnvironment, _logger);

            var tableClient = repository.TableClient;
            var cloudTable  = tableClient.GetTableReference("aa");

            repository.WriteDiagnosticEvent(DateTime.UtcNow, "eh1", LogLevel.Information, "This is the message", "https://fwlink/", new Exception("exception message"));

            Assert.Equal(1, repository.Events.Values.Count());

            await repository.FlushLogs(cloudTable);

            Assert.Equal(0, repository.Events.Values.Count());
            var logMessage = _loggerProvider.GetAllLogMessages()[0];

            Assert.True(logMessage.FormattedMessage.StartsWith("Unable to create table 'aa'"));
        }