private Func <MxHostTestDetails, Task <MxHostTestDetails> > CreateTlsTester(Guid testerId)
        {
            return(async testDetails =>
            {
                var tlsTest = testDetails.Test;

                using (_log.BeginScope(new Dictionary <string, object> {
                    ["TlsTesterId"] = testerId, [TlsHostLogPropertyName] = tlsTest.Id
                }))
                {
                    try
                    {
                        var stopwatch = Stopwatch.StartNew();
                        _log.LogInformation($"Starting TLS test run");
                        testDetails.TestResults = await _mxHostTester.Test(tlsTest);

                        _log.LogInformation($"Completed TLS test run, time taken : {stopwatch.ElapsedMilliseconds}ms");
                    }
                    catch (Exception e)
                    {
                        _log.LogError(e, $"Error occurred during TLS test run");
                    }

                    return testDetails;
                }
            });
        }
        public async Task <MxRecordTlsSecurityProfile> Test(MxRecordTlsSecurityProfile mxRecordTlsSecurityProfile)
        {
            if (_config.CachingEnabled)
            {
                string cachedStringResult = await _cache.GetString($"{KeyPrefix}-{mxRecordTlsSecurityProfile.MxRecord.Hostname?.ToLower()}");

                if (cachedStringResult != null)
                {
                    _log.Debug($"Successfully retrieved TLSSecurityProfile from cache for host {mxRecordTlsSecurityProfile.MxRecord.Hostname}");
                    TlsTestResults cachedResults = JsonConvert.DeserializeObject <TlsTestResults>(cachedStringResult);
                    return(new MxRecordTlsSecurityProfile(mxRecordTlsSecurityProfile.MxRecord,
                                                          new TlsSecurityProfile(mxRecordTlsSecurityProfile.TlsSecurityProfile.Id, null, cachedResults)));
                }
            }

            MxRecordTlsSecurityProfile result = await _tlsSecurityTesterAdaptor.Test(mxRecordTlsSecurityProfile);

            _log.Debug($"Successfully retrieved TLSSecurityProfile from tls tester for host {mxRecordTlsSecurityProfile.MxRecord.Hostname}");

            if (_config.CachingEnabled && (result.TlsSecurityProfile.TlsResults.FailureCount == 0 || result.TlsSecurityProfile.TlsResults.FailureCount >= FailureCountBeforeCaching))
            {
                string resultToCache = JsonConvert.SerializeObject(result.TlsSecurityProfile.TlsResults);

                await _cache.SetString($"{KeyPrefix}-{mxRecordTlsSecurityProfile.MxRecord.Hostname}", resultToCache,
                                       TimeSpan.FromSeconds(_config.RefreshIntervalSeconds *RefreshIntervalSecondsMultiplier));

                _log.Debug($"Successfully set TLSSecurityProfile to cache for host {mxRecordTlsSecurityProfile.MxRecord.Hostname}");
            }

            return(result);
        }
        public async Task CachingNotEnabledCacheNotUsed()
        {
            A.CallTo(() => _config.CachingEnabled).Returns(false);

            MxRecordTlsSecurityProfile securityProfile = CreateSecurityProfile();

            MxRecordTlsSecurityProfile updatedSecurityProfile =
                await _cachingTlsSecurityTesterAdaptor.Test(securityProfile);

            A.CallTo(() => _cache.GetString(A <string> ._)).MustNotHaveHappened();
            A.CallTo(() => _tlsSecurityTesterAdaptor.Test(securityProfile)).MustHaveHappened(Repeated.Exactly.Once);
            A.CallTo(() => _cache.SetString(A <string> ._, A <string> ._, A <TimeSpan> ._)).MustNotHaveHappened();
        }
        public async Task NoProfileToProcessNoProcessingOccurs()
        {
            A.CallTo(() => _mxQueueProcessor.GetMxHosts())
            .Returns(Task.FromResult(new List <TlsTestPending>()));

            Task process = _mxSecurityTesterProcessor.Process(cancellationTokenSource.Token);

            await _pipelineStartBlock.SendAsync(null);

            cancellationTokenSource.Cancel();

            await process;

            A.CallTo(() => _mxQueueProcessor.GetMxHosts()).MustHaveHappenedOnceExactly();
            A.CallTo(() => _mxHostTester.Test(A <TlsTestPending> ._)).MustNotHaveHappened();
            A.CallTo(() => _publisher.Publish(A <Message> ._, A <string> ._)).MustNotHaveHappened();
            A.CallTo(() => _mxQueueProcessor.DeleteMessage(A <string> ._, A <string> ._)).MustNotHaveHappened();
            A.CallTo(() => _processingFilter.Reserve(A <string> ._)).MustNotHaveHappened();
            A.CallTo(() => _processingFilter.ReleaseReservation(A <string> ._)).MustNotHaveHappened();
        }