public async Task <DomainTlsEvaluatorResults> GetDomainTlsEvaluatorResults(string domain) { MxEntityState mxState = await _mxApiDao.GetMxEntityState(domain); if (mxState == null) { _log.LogInformation($"Domain {domain} not found - publishing DomainMissing"); await _messagePublisher.Publish(new DomainMissing(domain), _config.MicroserviceOutputSnsTopicArn); return(null); } if (mxState.HostMxRecords == null) { return(_domainTlsEvaluatorResultsFactory.CreatePending(domain)); } List <string> hostNames = mxState.HostMxRecords.Select(x => x.Id).ToList(); Dictionary <string, TlsEntityState> tlsEntityStates = await _mxApiDao.GetTlsEntityStates(hostNames); DomainTlsEvaluatorResults result = _domainTlsEvaluatorResultsFactory.Create(mxState, tlsEntityStates); return(result); }
public async Task <MxEntityState> Get(string domain) { MxEntityState result = null; using (var connection = await CreateAndOpenConnection()) using (DbDataReader reader = await MySqlHelper.ExecuteReaderAsync(connection, MxStateDaoResources.GetMxRecord, new MySqlParameter("domain", ReverseUrl(domain)))) { while (await reader.ReadAsync()) { result = result ?? new MxEntityState(domain) { Error = JsonConvert.DeserializeObject <Message>(reader.GetString("error")), LastUpdated = reader.GetDateTimeNullable("lastUpdated"), MxState = (MxState)reader.GetInt32("mxState"), HostMxRecords = new List <HostMxRecord>() }; string hostMxRecord = reader.GetString("hostMxRecord"); if (!string.IsNullOrEmpty(hostMxRecord)) { result.HostMxRecords.Add(JsonConvert.DeserializeObject <HostMxRecord>(hostMxRecord)); } } } return(result); }
public async Task ShouldHandleChangeSaveAndDispatchWhenMxRecordsPolledReceived() { string snsTopicArn = "SnsTopicArn"; A.CallTo(() => _mxEntityConfig.SnsTopicArn).Returns(snsTopicArn); string domainName = "testDomainName"; MxEntityState stateFromDb = new MxEntityState(domainName.ToLower()) { MxState = MxState.Created }; A.CallTo(() => _dao.Get(domainName.ToLower())).Returns(Task.FromResult(stateFromDb)); A.CallTo(() => _mxEntityConfig.NextScheduledInSeconds).Returns(33); A.CallTo(() => _clock.GetDateTimeUtc()).Returns(DateTime.MinValue); MxRecordsPolled message = new MxRecordsPolled(domainName, new List <HostMxRecord>(), null) { Timestamp = DateTime.UnixEpoch }; await _mxEntity.Handle(message); Assert.AreEqual(stateFromDb.MxState, MxState.Evaluated); Assert.AreEqual(stateFromDb.HostMxRecords, message.Records); Assert.AreEqual(stateFromDb.LastUpdated, message.Timestamp); A.CallTo(() => _changeNotifiersComposite.Handle(stateFromDb, message)).MustHaveHappenedOnceExactly(); A.CallTo(() => _dao.Save(stateFromDb)).MustHaveHappenedOnceExactly(); A.CallTo(() => _dispatcher.Dispatch(A <MxRecordsUpdated> .That.Matches(a => a.Id == message.Id.ToLower() && a.Records.Count == 0), snsTopicArn)).MustHaveHappenedOnceExactly(); A.CallTo(() => _dispatcher.Dispatch(A <CreateScheduledReminder> .That.Matches(a => a.ResourceId == domainName.ToLower() && a.Service == "Mx" && a.ScheduledTime.Second == 33), snsTopicArn)).MustHaveHappenedOnceExactly(); }
public void DoesNotNotifyWhenNoChanges() { string testDomain = "domain"; string testHostName = "hostname"; MxEntityState state = new MxEntityState(testDomain); HostMxRecord record = new HostMxRecord(testHostName, 5, new List <string> { "192.168.0.1", "192.168.0.2" }); state.HostMxRecords = new List <HostMxRecord> { new HostMxRecord(testHostName, 5, new List <string> { "192.168.0.1" }) }; List <HostMxRecord> hostMxRecords = new List <HostMxRecord> { record }; MxRecordsPolled mxRecordsPolled = new MxRecordsPolled(testDomain, hostMxRecords, TimeSpan.MinValue); _recordChangedNotifier.Handle(state, mxRecordsPolled); A.CallTo(() => _dispatcher.Dispatch(A <MxRecordAdded> ._, A <string> ._)).MustNotHaveHappened(); A.CallTo(() => _dispatcher.Dispatch(A <MxRecordRemoved> ._, A <string> ._)).MustNotHaveHappened(); }
public void DoesNotNotifyWhenNoChangesWithDifferentCaseType() { string testDomain = "domain"; MxEntityState state = new MxEntityState(testDomain) { HostMxRecords = new List <HostMxRecord> { new HostMxRecord("HOSTNAME", 5, new List <string> { "192.168.0.1" }) } }; List <HostMxRecord> hostMxRecords = new List <HostMxRecord> { new HostMxRecord("hostname", 5, new List <string> { "192.168.0.1" }) }; MxRecordsPolled mxRecordsPolled = new MxRecordsPolled(testDomain, hostMxRecords, TimeSpan.MinValue); _recordChangedNotifier.Handle(state, mxRecordsPolled); A.CallTo(() => _dispatcher.Dispatch(A <MxRecordAdded> ._, A <string> ._)).MustNotHaveHappened(); A.CallTo(() => _dispatcher.Dispatch(A <MxRecordRemoved> ._, A <string> ._)).MustNotHaveHappened(); }
public void Handle(MxEntityState state, Common.Messaging.Abstractions.Message message) { foreach (IChangeNotifier changeNotifier in _notifiers) { changeNotifier.Handle(state, message); } }
public async Task Handle(DomainDeleted message) { string domainName = message.Id.ToLower(); MxEntityState state = await LoadState(domainName, nameof(message)); if (state.HostMxRecords != null && state.HostMxRecords.Count > 0) { List <string> uniqueHosts = await _dao.GetHostsUniqueToDomain(domainName); if (uniqueHosts.Count > 0) { await _dao.DeleteHosts(uniqueHosts); foreach (string host in uniqueHosts) { _dispatcher.Dispatch(new MxHostDeleted(host), _mxEntityConfig.SnsTopicArn); _log.LogInformation($"An MxHostDeleted message for Host: {host} has been dispatched to the SnsTopic: {_mxEntityConfig.SnsTopicArn}"); } } } await _dao.Delete(domainName); _log.LogInformation($"Deleted MX entity with id: {message.Id}."); }
public async Task Handle(DomainCreated message) { string domainName = message.Id.ToLower(); MxEntityState state = await _dao.Get(domainName); if (state != null) { _log.LogInformation($"Ignoring {nameof(DomainCreated)} as MxEntity already exists for {domainName}."); return; } await _dao.Save(new MxEntityState(domainName)); _log.LogInformation($"Created MxEntity for {domainName}."); MxEntityCreated mxEntityCreated = new MxEntityCreated(domainName); _dispatcher.Dispatch(mxEntityCreated, _mxEntityConfig.SnsTopicArn); _log.LogInformation( $"An MxEntityCreated message for Domain: {domainName} has been dispatched to SnsTopic: {_mxEntityConfig.SnsTopicArn}"); Message createScheduledReminder = new CreateScheduledReminder(Guid.NewGuid().ToString(), "Mx", domainName, _clock.GetDateTimeUtc()); _dispatcher.Dispatch(createScheduledReminder, _mxEntityConfig.SnsTopicArn); _log.LogInformation( $"A CreateScheduledReminder message for Domain: {domainName} has been dispatched to SnsTopic: {_mxEntityConfig.SnsTopicArn}"); }
public async Task ShouldDispatchMultipleMxHostDeletedMessagesWhenDomainDeletedReceivedAndMultipleHosts() { string domainName = "test.gov.uk"; string hostName1 = "test-host-inbound1.com"; string hostName2 = "test-host-inbound2.com"; DomainDeleted message = new DomainDeleted(domainName); MxEntityState stateFromDb = new MxEntityState(domainName.ToLower()) { MxState = MxState.Created, HostMxRecords = new List <HostMxRecord> { new HostMxRecord(hostName1, 0, new List <string>()), new HostMxRecord(hostName2, 0, new List <string>()) } }; List <string> uniqueHosts = new List <string> { hostName1, hostName2 }; A.CallTo(() => _dao.Get(domainName.ToLower())).Returns(Task.FromResult(stateFromDb)); A.CallTo(() => _dao.GetHostsUniqueToDomain(domainName.ToLower())).Returns(Task.FromResult(uniqueHosts)); await _mxEntity.Handle(message); A.CallTo(() => _dao.DeleteHosts(uniqueHosts)).MustHaveHappenedOnceExactly(); A.CallTo(() => _dispatcher.Dispatch(A <MxHostDeleted> .That.Matches(a => a.Id == stateFromDb.HostMxRecords[0].Id), A <string> ._)).MustHaveHappenedOnceExactly(); A.CallTo(() => _dispatcher.Dispatch(A <MxHostDeleted> .That.Matches(a => a.Id == stateFromDb.HostMxRecords[1].Id), A <string> ._)).MustHaveHappenedOnceExactly(); A.CallTo(() => _dao.Delete(domainName.ToLower())).MustHaveHappenedOnceExactly(); }
public DomainTlsEvaluatorResults Create(MxEntityState mxState, Dictionary <string, TlsEntityState> tlsEntityStates) { List <MxTlsEvaluatorResults> mxTlsEvaluatorResults = new List <MxTlsEvaluatorResults>(); List <MxTlsCertificateEvaluatorResults> mxTlsCertificateEvaluatorResults = new List <MxTlsCertificateEvaluatorResults>(); foreach (HostMxRecord hostMxRecord in mxState.HostMxRecords) { // tlsEntityStates keys are always lowercase due to ReverseUrl() in MxApiDao.GetTlsEntityStates TlsEntityState tlsEntityState = tlsEntityStates[hostMxRecord.Id.ToLower()]; List <TlsRecord> records = new List <TlsRecord>(); TlsRecords tlsRecords = tlsEntityState.TlsRecords; if (tlsRecords != null) { records.Add(tlsRecords.Tls12AvailableWithBestCipherSuiteSelected); records.Add(tlsRecords.Tls12AvailableWithBestCipherSuiteSelectedFromReverseList); records.Add(tlsRecords.Tls12AvailableWithSha2HashFunctionSelected); records.Add(tlsRecords.Tls12AvailableWithWeakCipherSuiteNotSelected); records.Add(tlsRecords.Tls11AvailableWithBestCipherSuiteSelected); records.Add(tlsRecords.Tls11AvailableWithWeakCipherSuiteNotSelected); records.Add(tlsRecords.Tls10AvailableWithBestCipherSuiteSelected); records.Add(tlsRecords.Tls10AvailableWithWeakCipherSuiteNotSelected); records.Add(tlsRecords.Ssl3FailsWithBadCipherSuite); records.Add(tlsRecords.TlsSecureEllipticCurveSelected); records.Add(tlsRecords.TlsSecureDiffieHellmanGroupSelected); records.Add(tlsRecords.TlsWeakCipherSuitesRejected); records.Add(tlsRecords.Tls12Available); records.Add(tlsRecords.Tls11Available); records.Add(tlsRecords.Tls10Available); } List <string> warnings = records.Where(_ => _.TlsEvaluatedResult.Result == EvaluatorResult.WARNING) .Select(_ => _.TlsEvaluatedResult.Description).ToList(); List <string> failures = records.Where(_ => _.TlsEvaluatedResult.Result == EvaluatorResult.FAIL) .Select(_ => _.TlsEvaluatedResult.Description).ToList(); List <string> informational = records .Where(_ => _.TlsEvaluatedResult.Result == EvaluatorResult.INFORMATIONAL || _.TlsEvaluatedResult.Result == EvaluatorResult.INCONCLUSIVE) .Select(_ => _.TlsEvaluatedResult.Description).ToList(); mxTlsEvaluatorResults.Add( new MxTlsEvaluatorResults( hostMxRecord.Id, hostMxRecord.Preference ?? 0, mxState.LastUpdated ?? DateTime.MinValue, warnings, failures, informational)); mxTlsCertificateEvaluatorResults.Add(CreateMxTlsCertificateEvaluatorResults(hostMxRecord.Id, hostMxRecord.Preference ?? 0, mxState.LastUpdated ?? DateTime.MinValue, tlsEntityState.CertificateResults)); } return(new DomainTlsEvaluatorResults(mxState.Id, mxState.MxState == MxState.PollPending, mxTlsEvaluatorResults, mxTlsCertificateEvaluatorResults)); }
public async Task Handle(MxRecordsPolled message) { string domainName = message.Id.ToLower(); MxEntityState state = await LoadState(domainName, nameof(message)); MxState oldState = state.MxState; int oldRecordCount = state.HostMxRecords?.Count ?? 0; int newRecordCount = message.Records?.Count ?? 0; _changeNotifiersComposite.Handle(state, message); List <HostMxRecord> validHostRecords = new List <HostMxRecord>(); if (message.Records != null) { foreach (HostMxRecord hostRecord in message.Records) { if (Uri.CheckHostName(hostRecord.Id) != UriHostNameType.Unknown) { validHostRecords.Add(hostRecord); } else { _log.LogInformation($"Erroneous host: {hostRecord.Id} found for domain: {domainName}"); } } } if (message.Error == null) { state.HostMxRecords = validHostRecords; } state.LastUpdated = message.Timestamp; state.Error = message.Error; state.MxState = MxState.Evaluated; await _dao.Save(state); _log.LogInformation($"Updated MxEntity from {oldState} to {MxState.Evaluated} and MX records before: {oldRecordCount} after: {newRecordCount} for {domainName}."); Message mxRecordsUpdated = new MxRecordsUpdated(domainName, validHostRecords); _dispatcher.Dispatch(mxRecordsUpdated, _mxEntityConfig.SnsTopicArn); _log.LogInformation($"An MxRecordsUpdated message for Domain: {domainName} has been dispatched to SnsTopic: {_mxEntityConfig.SnsTopicArn}"); // Should probably change this so it only happens for a new host validHostRecords?.ForEach(mxRecord => { _dispatcher.Dispatch(new MxHostTestPending(mxRecord.Id), _mxEntityConfig.SnsTopicArn); _log.LogInformation($"An MxHostTestPending message for Host: {mxRecord.Id} has been dispatched to SnsTopic: {_mxEntityConfig.SnsTopicArn}"); }); Message createScheduledReminder = new CreateScheduledReminder(Guid.NewGuid().ToString(), "Mx", domainName, _clock.GetDateTimeUtc().AddSeconds(_mxEntityConfig.NextScheduledInSeconds)); _dispatcher.Dispatch(createScheduledReminder, _mxEntityConfig.SnsTopicArn); _log.LogInformation($"A CreateScheduledReminder message for Domain: {domainName} has been dispatched to SnsTopic: {_mxEntityConfig.SnsTopicArn}"); }
private async Task <MxEntityState> LoadState(string domainName, string messageType) { MxEntityState state = await _dao.Get(domainName); if (state == null) { _log.LogError("Ignoring {EventName} as MX Entity does not exist for {Id}.", messageType, domainName); throw new MailCheckException( $"Cannot handle event {messageType} as MX Entity doesnt exists for {domainName}."); } return(state); }
public async Task MissingHostMxRecordsReturnPending() { MxEntityState mxStateFromDao = new MxEntityState(""); DomainTlsEvaluatorResults pendingEvaluatorResultFromFactory = new DomainTlsEvaluatorResults("", true); A.CallTo(() => _mxApiDao.GetMxEntityState("testDomain")).Returns(mxStateFromDao); A.CallTo(() => _domainTlsEvaluatorResultsFactory.CreatePending("testDomain")).Returns(pendingEvaluatorResultFromFactory); DomainTlsEvaluatorResults result = await _mxService.GetDomainTlsEvaluatorResults("testDomain"); A.CallTo(() => _messagePublisher.Publish(A <DomainMissing> ._, A <string> ._)).MustNotHaveHappened(); Assert.AreSame(pendingEvaluatorResultFromFactory, result); }
public async Task Handle(MxScheduledReminder message) { string domainName = message.ResourceId.ToLower(); MxEntityState state = await LoadState(domainName, nameof(message)); await _dao.UpdateState(domainName, MxState.PollPending); _log.LogInformation($"Updated MxEntity.MxState from {state.MxState} to {MxState.PollPending} for {domainName}."); Message mxPollPending = new MxPollPending(domainName); _dispatcher.Dispatch(mxPollPending, _mxEntityConfig.SnsTopicArn); _log.LogInformation( $"An MxPollPending message for Domain: {domainName} has been dispatched to SnsTopic: {_mxEntityConfig.SnsTopicArn}"); }
public async Task MxLookupFailed_EnsureSqlAndParametersBuiltCorrectly() { var fakeConnectionInfo = A.Fake <IConnectionInfoAsync>(); string capturedSql = null; IDictionary <string, object> capturedParameters = null; var fakeLogger = A.Fake <ILogger <MxEntityDao> >(); var fakeSaveOperation = A.Fake <Func <string, IDictionary <string, object>, Task <int> > >(); A.CallTo(() => fakeSaveOperation.Invoke(A <string> .Ignored, A <IDictionary <string, object> > .Ignored)) .Invokes((string sql, IDictionary <string, object> parameters) => { capturedSql = sql; capturedParameters = parameters; }) .Returns(Task.FromResult(10)); var dao = new MxEntityDao( fakeConnectionInfo, fakeLogger, fakeSaveOperation ); var mxEntityState = new MxEntityState("google.com") { MxState = MxState.Created, LastUpdated = new DateTime(2020, 3, 4, 5, 6, 7), Error = new Message(Guid.Empty, "DNS", MessageType.error, "DNS lookup failed", "DNS lookup failed"), HostMxRecords = null }; var expectedParameters = new Dictionary <string, object> { ["domain"] = "com.google", ["mxState"] = MxState.Created, ["error"] = @"{""Id"":""00000000-0000-0000-0000-000000000000"",""Source"":""DNS"",""MessageType"":2,""Text"":""DNS lookup failed"",""MarkDown"":""DNS lookup failed"",""MessageDisplay"":0}", ["lastUpdated"] = new DateTime(2020, 3, 4, 5, 6, 7) }; await dao.Save(mxEntityState); A.CallTo(() => fakeSaveOperation(A <string> .Ignored, A <IDictionary <string, object> > .Ignored)) .MustHaveHappenedOnceExactly(); Assert.That(capturedSql, Is.EqualTo(ExpectedDnsErrorSql)); Assert.That(capturedParameters, Is.EquivalentTo(expectedParameters)); }
public async Task NoMxRecords_EnsureSqlAndParametersBuiltCorrectly() { var fakeConnectionInfo = A.Fake <IConnectionInfoAsync>(); string capturedSql = null; IDictionary <string, object> capturedParameters = null; var fakeLogger = A.Fake <ILogger <MxEntityDao> >(); var fakeSaveOperation = A.Fake <Func <string, IDictionary <string, object>, Task <int> > >(); A.CallTo(() => fakeSaveOperation.Invoke(A <string> .Ignored, A <IDictionary <string, object> > .Ignored)) .Invokes((string sql, IDictionary <string, object> parameters) => { capturedSql = sql; capturedParameters = parameters; }) .Returns(Task.FromResult(10)); var dao = new MxEntityDao( fakeConnectionInfo, fakeLogger, fakeSaveOperation ); var mxEntityState = new MxEntityState("google.com") { MxState = MxState.Created, LastUpdated = new DateTime(2020, 3, 4, 5, 6, 7), HostMxRecords = new List <Contracts.Poller.HostMxRecord>() }; var expectedParameters = new Dictionary <string, object> { ["domain"] = "com.google", ["mxState"] = MxState.Created, ["error"] = "null", ["lastUpdated"] = new DateTime(2020, 3, 4, 5, 6, 7) }; await dao.Save(mxEntityState); A.CallTo(() => fakeSaveOperation(A <string> .Ignored, A <IDictionary <string, object> > .Ignored)) .MustHaveHappenedOnceExactly(); Assert.That(capturedSql, Is.EqualTo(ExpectedNoMxSql)); Assert.That(capturedParameters, Is.EquivalentTo(expectedParameters)); }
public async Task ShouldOmitErroneousHostsFound() { string domainName = "test.gov.uk"; string hostName1 = "test-host-inbound1 .com"; string hostName2 = "test-host-inbound2.com"; string snsTopicArn = "SnsTopicArn"; A.CallTo(() => _mxEntityConfig.SnsTopicArn).Returns(snsTopicArn); List <HostMxRecord> hostMxRecords = new List <HostMxRecord> { new HostMxRecord(hostName1, 0, new List <string>()), new HostMxRecord(hostName2, 0, new List <string>()), }; MxEntityState stateFromDb = new MxEntityState(domainName.ToLower()) { MxState = MxState.Created, HostMxRecords = hostMxRecords, }; A.CallTo(() => _dao.Get(domainName.ToLower())).Returns(Task.FromResult(stateFromDb)); A.CallTo(() => _mxEntityConfig.NextScheduledInSeconds).Returns(33); A.CallTo(() => _clock.GetDateTimeUtc()).Returns(DateTime.MinValue); MxRecordsPolled message = new MxRecordsPolled(domainName, hostMxRecords, null) { Timestamp = DateTime.UnixEpoch }; List <HostMxRecord> validRecords = new List <HostMxRecord> { new HostMxRecord(hostName2, 0, new List <string>()) }; await _mxEntity.Handle(message); Assert.AreEqual(stateFromDb.MxState, MxState.Evaluated); Assert.AreEqual(stateFromDb.HostMxRecords[0], message.Records[1]); // Make sure erroneous host is ommitted Assert.AreEqual(stateFromDb.LastUpdated, message.Timestamp); A.CallTo(() => _changeNotifiersComposite.Handle(stateFromDb, message)).MustHaveHappenedOnceExactly(); A.CallTo(() => _dao.Save(stateFromDb)).MustHaveHappenedOnceExactly(); A.CallTo(() => _dispatcher.Dispatch(A <MxHostTestPending> .That.Matches(a => a.Id == hostName1.ToLower()), snsTopicArn)).MustNotHaveHappened(); A.CallTo(() => _dispatcher.Dispatch(A <MxHostTestPending> .That.Matches(a => a.Id == hostName2.ToLower()), snsTopicArn)).MustHaveHappenedOnceExactly(); }
public async Task Save(MxEntityState mxEntityState) { string domain = ReverseUrl(mxEntityState.Id); var parameters = new Dictionary <string, object>(); parameters.Add("domain", domain); parameters.Add("mxState", mxEntityState.MxState); parameters.Add("error", JsonConvert.SerializeObject(mxEntityState.Error)); parameters.Add("lastUpdated", mxEntityState.LastUpdated); var builder = new SqlBuilder(); string updateMxTables = String.Empty; if (mxEntityState.HostMxRecords != null) { updateMxTables = MxStateDaoResources.DeleteMxRecord; if (mxEntityState.HostMxRecords.Count > 0) { updateMxTables += MxStateDaoResources.UpsertMxHost + MxStateDaoResources.UpsertMxRecord; builder.SetToken("MxHostValues", MxHostFields.ToValuesParameterListSql(mxEntityState.HostMxRecords.Count)); builder.SetToken("MxRecordValues", MxRecordFields.ToValuesParameterListSql(mxEntityState.HostMxRecords.Count)); mxEntityState.HostMxRecords.Select((hostMxRecord, index) => { string host = ReverseUrl(hostMxRecord.Id); parameters.Add($"domain_{index}", domain); parameters.Add($"hostname_{index}", host); parameters.Add($"hostMxRecord_{index}", JsonConvert.SerializeObject(hostMxRecord)); parameters.Add($"lastUpdated_{index}", mxEntityState.LastUpdated); parameters.Add($"preference_{index}", hostMxRecord.Preference); return(index); }).ToArray(); } } var commandText = builder.Build($"{MxStateDaoResources.UpsertDomain}{updateMxTables}"); await _saveOperation(commandText, parameters); }
public void Handle(MxEntityState state, Message message) { string domainName = message.Id; if (message is MxRecordsPolled mxRecordsPolled) { List <HostMxRecord> recordsInMessage = mxRecordsPolled.Records ?? new List <HostMxRecord>(); List <HostMxRecord> recordsInState = state.HostMxRecords ?? new List <HostMxRecord>(); List <HostMxRecord> added = recordsInMessage.Except(recordsInState, _comparer).ToList(); List <HostMxRecord> removed = recordsInState.Except(recordsInMessage, _comparer).ToList(); bool hasAddedRecords = added.Any(); bool hasRemovedRecords = removed.Any(); if (hasAddedRecords) { MxRecordAdded mxRecordAdded = new MxRecordAdded(domainName, added.ToList()); _dispatcher.Dispatch(mxRecordAdded, _mxEntityConfig.SnsTopicArn); } if (hasRemovedRecords) { MxRecordRemoved mxRecordRemoved = new MxRecordRemoved(domainName, removed.ToList()); _dispatcher.Dispatch(mxRecordRemoved, _mxEntityConfig.SnsTopicArn); } if (hasAddedRecords || hasRemovedRecords) { _logger.LogInformation($"recordsInMessage: {JsonConvert.SerializeObject(recordsInMessage)} for domain: {domainName}"); _logger.LogInformation($"recordsInState: {JsonConvert.SerializeObject(recordsInState)} for domain: {domainName}"); if (hasAddedRecords) { _logger.LogInformation($"added records: {JsonConvert.SerializeObject(added)} for domain: {domainName}"); } if (hasRemovedRecords) { _logger.LogInformation($"removed records: {JsonConvert.SerializeObject(removed)} for domain: {domainName}"); } } } }
public async Task ShouldDeleteWhenDomainDeletedReceived() { string domainName = "testDomainName"; string hostName = "testHostName"; DomainDeleted message = new DomainDeleted(domainName); MxEntityState stateFromDb = new MxEntityState(domainName.ToLower()) { MxState = MxState.Created, HostMxRecords = new List <HostMxRecord> { new HostMxRecord(hostName, 0, new List <string>()) } }; A.CallTo(() => _dao.Get(domainName.ToLower())).Returns(Task.FromResult(stateFromDb)); await _mxEntity.Handle(message); A.CallTo(() => _dao.Delete(domainName.ToLower())).MustHaveHappenedOnceExactly(); }
public async Task ShouldDispatchPollPendingWhenScheduledReminderReceived() { string domainName = "testDomainName"; string snsTopicArn = "SnsTopicArn"; MxEntityState stateFromDb = new MxEntityState(domainName.ToLower()) { MxState = MxState.Created }; string expectedDomainName = "testdomainname"; A.CallTo(() => _dao.Get(expectedDomainName)).Returns(stateFromDb); A.CallTo(() => _mxEntityConfig.SnsTopicArn).Returns(snsTopicArn); await _mxEntity.Handle(new MxScheduledReminder(Guid.NewGuid().ToString(), domainName)); A.CallTo(() => _dao.UpdateState(expectedDomainName, MxState.PollPending)).MustHaveHappenedOnceExactly(); A.CallTo(() => _dispatcher.Dispatch(A <MxPollPending> .That.Matches(entity => entity.Id == domainName.ToLower()), snsTopicArn)).MustHaveHappenedOnceExactly(); }
public async Task EvaluatorResultsAreReturned() { MxEntityState mxStateFromDao = new MxEntityState("") { HostMxRecords = new List <HostMxRecord> { new HostMxRecord("testHost1", 0, null) } }; Dictionary <string, TlsEntityState> tlsEntityStatesFromDao = new Dictionary <string, TlsEntityState>(); DomainTlsEvaluatorResults evaluatorResultFromFactory = new DomainTlsEvaluatorResults("", false); A.CallTo(() => _mxApiDao.GetMxEntityState("testDomain")).Returns(mxStateFromDao); A.CallTo(() => _mxApiDao.GetTlsEntityStates(A <List <string> > ._)).Returns(tlsEntityStatesFromDao); A.CallTo(() => _domainTlsEvaluatorResultsFactory.Create(mxStateFromDao, tlsEntityStatesFromDao)).Returns(evaluatorResultFromFactory); DomainTlsEvaluatorResults result = await _mxService.GetDomainTlsEvaluatorResults("testDomain"); A.CallTo(() => _messagePublisher.Publish(A <DomainMissing> ._, A <string> ._)).MustNotHaveHappened(); Assert.AreSame(evaluatorResultFromFactory, result); }
public void NotifiesWhenRecordAddedAndRemoved() { string testDomain = "domain"; string testHostName1 = "hostname1"; string testHostName2 = "hostname2"; MxEntityState state = new MxEntityState(testDomain); HostMxRecord record1 = new HostMxRecord(testHostName1, 5, new List <string> { "192.168.0.1" }); HostMxRecord record2 = new HostMxRecord(testHostName2, 5, new List <string> { "192.168.0.1" }); state.HostMxRecords = new List <HostMxRecord> { record1 }; List <HostMxRecord> hostMxRecords = new List <HostMxRecord> { record2 }; MxRecordsPolled mxRecordsPolled = new MxRecordsPolled(testDomain, hostMxRecords, TimeSpan.MinValue); _recordChangedNotifier.Handle(state, mxRecordsPolled); A.CallTo(() => _dispatcher.Dispatch(A <MxRecordRemoved> ._, A <string> ._)) .MustHaveHappenedOnceExactly(); A.CallTo(() => _dispatcher.Dispatch( A <MxRecordRemoved> .That.Matches(x => x.Id == testDomain && x.Records[0].Id == testHostName1), A <string> ._)).MustHaveHappenedOnceExactly(); A.CallTo(() => _dispatcher.Dispatch(A <MxRecordAdded> ._, A <string> ._)) .MustHaveHappenedOnceExactly(); A.CallTo(() => _dispatcher.Dispatch( A <MxRecordAdded> .That.Matches(x => x.Id == testDomain && x.Records[0].Id == testHostName2), A <string> ._)).MustHaveHappenedOnceExactly(); }
public void NotifiesWhenMxPreferenceChanges() { string testDomain = "domain"; string testHostName = "hostname"; MxEntityState state = new MxEntityState(testDomain); state.HostMxRecords = new List <HostMxRecord> { new HostMxRecord(testHostName, 5, new List <string> { "192.168.0.1" }) }; List <HostMxRecord> hostMxRecords = new List <HostMxRecord> { new HostMxRecord(testHostName, 10, new List <string> { "192.168.0.1" }), }; MxRecordsPolled mxRecordsPolled = new MxRecordsPolled(testDomain, hostMxRecords, TimeSpan.MinValue); _recordChangedNotifier.Handle(state, mxRecordsPolled); A.CallTo(() => _dispatcher.Dispatch(A <MxRecordAdded> ._, A <string> ._)) .MustHaveHappenedOnceExactly(); A.CallTo(() => _dispatcher.Dispatch(A <MxRecordAdded> .That.Matches(x => x.Id == testDomain), A <string> ._)) .MustHaveHappenedOnceExactly(); A.CallTo(() => _dispatcher.Dispatch(A <MxRecordRemoved> ._, A <string> ._)) .MustHaveHappenedOnceExactly(); A.CallTo(() => _dispatcher.Dispatch(A <MxRecordRemoved> .That.Matches(x => x.Id == testDomain), A <string> ._)) .MustHaveHappenedOnceExactly(); }
public void CaseMismatchDoesNotBreakResultsConstruction() { _domainTlsEvaluatorResultsFactory = new DomainTlsEvaluatorResultsFactory(); MxEntityState mxState = new MxEntityState("exampledomain.co.uk"); mxState.HostMxRecords = new List <HostMxRecord>() { new HostMxRecord("MAILHOST.GOOGLE.COM.", 1, new List <string> { "" }) }; Dictionary <string, TlsEntityState> tlsEntityStates = new Dictionary <string, TlsEntityState> { ["mailhost.google.com."] = new TlsEntityState("Mailhost.google.com") }; DomainTlsEvaluatorResults domainTlsEvaluatorResults = _domainTlsEvaluatorResultsFactory.Create(mxState, tlsEntityStates); Assert.AreEqual("exampledomain.co.uk", domainTlsEvaluatorResults.Id); Assert.AreEqual(1, domainTlsEvaluatorResults.MxTlsEvaluatorResults.Count); Assert.AreEqual("mailhost.google.com.", domainTlsEvaluatorResults.MxTlsEvaluatorResults[0].Hostname.ToLower()); }
public async Task SomeMxRecords_EnsureSqlAndParametersBuiltCorrectly() { var fakeConnectionInfo = A.Fake <IConnectionInfoAsync>(); string capturedSql = null; IDictionary <string, object> capturedParameters = null; var fakeLogger = A.Fake <ILogger <MxEntityDao> >(); var fakeSaveOperation = A.Fake <Func <string, IDictionary <string, object>, Task <int> > >(); A.CallTo(() => fakeSaveOperation.Invoke(A <string> .Ignored, A <IDictionary <string, object> > .Ignored)) .Invokes((string sql, IDictionary <string, object> parameters) => { capturedSql = sql; capturedParameters = parameters; }) .Returns(Task.FromResult(10)); var dao = new MxEntityDao( fakeConnectionInfo, fakeLogger, fakeSaveOperation ); var mxEntityState = new MxEntityState("google.com") { MxState = MxState.Created, LastUpdated = new DateTime(2020, 3, 4, 5, 6, 7), HostMxRecords = new List <Contracts.Poller.HostMxRecord> { new Contracts.Poller.HostMxRecord("mx1.com.", 1, new List <string> { "1.1.1.1" }), new Contracts.Poller.HostMxRecord("mx2.com.", 2, new List <string> { "1.1.2.1", "1.1.2.2" }), new Contracts.Poller.HostMxRecord("mx3.com.", 3, new List <string> { "1.1.3.1", "1.1.3.2", "1.1.3.3" }) } }; var expectedParameters = new Dictionary <string, object> { ["domain"] = "com.google", ["mxState"] = MxState.Created, ["error"] = "null", ["lastUpdated"] = new DateTime(2020, 3, 4, 5, 6, 7), ["domain_0"] = "com.google", ["hostname_0"] = ".com.mx1", ["hostMxRecord_0"] = @"{""Preference"":1,""IpAddresses"":[""1.1.1.1""],""Id"":""mx1.com."",""CorrelationId"":null,""CausationId"":null,""Type"":null,""MessageId"":null,""Timestamp"":""0001-01-01T00:00:00""}", ["lastUpdated_0"] = new DateTime(2020, 3, 4, 5, 6, 7), ["preference_0"] = 1, ["domain_1"] = "com.google", ["hostname_1"] = ".com.mx2", ["hostMxRecord_1"] = @"{""Preference"":2,""IpAddresses"":[""1.1.2.1"",""1.1.2.2""],""Id"":""mx2.com."",""CorrelationId"":null,""CausationId"":null,""Type"":null,""MessageId"":null,""Timestamp"":""0001-01-01T00:00:00""}", ["lastUpdated_1"] = new DateTime(2020, 3, 4, 5, 6, 7), ["preference_1"] = 2, ["domain_2"] = "com.google", ["hostname_2"] = ".com.mx3", ["hostMxRecord_2"] = @"{""Preference"":3,""IpAddresses"":[""1.1.3.1"",""1.1.3.2"",""1.1.3.3""],""Id"":""mx3.com."",""CorrelationId"":null,""CausationId"":null,""Type"":null,""MessageId"":null,""Timestamp"":""0001-01-01T00:00:00""}", ["lastUpdated_2"] = new DateTime(2020, 3, 4, 5, 6, 7), ["preference_2"] = 3 }; await dao.Save(mxEntityState); A.CallTo(() => fakeSaveOperation(A <string> .Ignored, A <IDictionary <string, object> > .Ignored)) .MustHaveHappenedOnceExactly(); Assert.That(capturedSql, Is.EqualTo(ExpectedMxPresentSql)); Assert.That(capturedParameters, Is.EquivalentTo(expectedParameters)); }