def test_repeat_scheduling(self): self.mock_result.stdout = 'Maybe Certbot got updated' subdomain1 = Subdomain('unknown-1', 'unit.test') subdomain2 = Subdomain('unknown-2', 'unit.test') self.assertTrue(self.manager.needs_update(subdomain1)) result = self.manager.update(subdomain1) self.assertEqual(result, 'Unknown') self.assertTrue(self.manager.needs_update(subdomain2)) result = self.manager.update(subdomain2) self.assertEqual(result, 'Unknown') self.assertFalse(self.manager.needs_update(subdomain1)) self.assertFalse(self.manager.needs_update(subdomain2)) self.manager.last_run[subdomain1.full] = datetime.now() - timedelta( seconds=6 * 60 * 60) self.assertFalse(self.manager.needs_update(subdomain1)) self.assertFalse(self.manager.needs_update(subdomain2)) self.manager.last_run[subdomain1.full] = datetime.now() - timedelta( days=0.5, seconds=30) self.assertTrue(self.manager.needs_update(subdomain1)) result = self.manager.update(subdomain1) self.assertEqual(result, 'Unknown') self.assertFalse(self.manager.needs_update(subdomain1))
def _to_subdomain(self, name): if name == self.default_domain: return Subdomain('', self.default_domain) elif name.endswith(self.default_domain): return Subdomain(name.replace('.%s' % self.default_domain, ''), self.default_domain) else: return Subdomain(name, self.default_domain)
def test_update(self): self.cf.zones.dns_records.base = 'sample.com' self.cf.zones.items.append({'id': 'abcd1234', 'name': 'sample.com'}) result = self.manager.update(Subdomain('mock', 'sample.com'), '8.8.4.4') self.assertEqual('OK, created [8.8.4.4]', result) result = self.manager.update(Subdomain('mock', 'sample.com'), '8.8.8.8') self.assertEqual('OK, updated [8.8.8.8]', result)
def test_new_certificate(self): self.mock_result.stdout = 'Congratulations! It worked!' self.mock_result.stderr = 'Obtaining a new certificate' result = self.manager.update(Subdomain('new-domain', 'unit.test')) self.assertEqual(result, 'OK, new certificate') self.assertIn('certbot certonly -n --keep', ' '.join(self.mock_result.args)) self.assertIn('-d new-domain.unit.test', ' '.join(self.mock_result.args)) self.assertIn('--email [email protected]', ' '.join(self.mock_result.args)) self.assertIn('--dns-cloudflare', ' '.join(self.mock_result.args)) self.assertIn('--dns-cloudflare-credentials .cloudflare.ini', ' '.join(self.mock_result.args)) self.assertIn('--dns-cloudflare-propagation-seconds 30', ' '.join(self.mock_result.args)) self.assertIn(('timeout', 120), self.mock_result.kwargs.items()) self.assertIn(('stdout', subprocess.PIPE), self.mock_result.kwargs.items()) self.assertIn(('stderr', subprocess.PIPE), self.mock_result.kwargs.items()) self.assertNotIn('--staging', self.mock_result.args)
def test_unknown_result(self): self.mock_result.stdout = 'Maybe Certbot got updated' result = self.manager.update(Subdomain('unknown', 'unit.test')) self.assertEqual(result, 'Unknown') self.assertIn('-d unknown.unit.test', ' '.join(self.mock_result.args))
def test_give_up_retries(self): self.client.response = {'ok': False, 'headers': {'Retry-After': '3'}} # slack_message.time.sleep = lambda x: x slack_message.threading.Timer = MockTimer message = '`[DNS update]` *give.up.update.test* : Failing' with self.assertLogs('slack-notification', 'DEBUG') as logs: self.manager.dns_updated(Subdomain('give.up', 'update.test'), 'Failing') self.client.assert_call('chat.postMessage', channel='unittest', text=message, as_user=False, username='******') self.assertEqual(len(logs.output), 4) for idx in range(3): self.assertEqual( logs.output[idx], 'DEBUG:slack-notification:Retrying Slack message after 3 seconds' ) self.assertEqual( logs.output[3], 'ERROR:slack-notification:Giving up on Slack message: %s' % message)
def test_not_yet_due_for_renewal(self): self.mock_result.stdout = 'The certificate is not yet due for renewal, skipping.' result = self.manager.update(Subdomain('still-valid', 'unit.test')) self.assertEqual(result, 'Not yet due for renewal') self.assertIn('-d still-valid.unit.test', ' '.join(self.mock_result.args))
def test_failing_swarm_mode(self): self.client.swarm_mode = True self.manager.label_name = 'test.failing' self.manager.ssl_updated(Subdomain('swarm'), 'Failed') self.assertIsNone(self.client.service) docker_signal.get_current_container_id = lambda: None self.manager.ssl_updated(Subdomain('swarm'), 'OK') self.assertIsNone(self.client.service) docker_signal.get_current_container_id = lambda: 'c-self' self.manager.ssl_updated(Subdomain('swarm'), 'OK') self.assertIsNone(self.client.service) self.client.items.append(MockContainer('c-self', 'own-container')) self.manager.ssl_updated(Subdomain('swarm'), 'OK') self.assertIsNone(self.client.service) self.client.items[0].image = 'test/image' self.client.tasks.append({ 'DesiredState': 'shutdown', 'Status': { 'State': 'failed' } }) self.client.service_logs[:] = ['failed to send signal'] with self.assertLogs('docker-signal', level='INFO') as logs: self.manager.ssl_updated(Subdomain('swarm'), 'OK') self.assertEqual(len(logs.output), 2) self.assertEqual( logs.output[0], 'INFO:docker-signal:Signalled containers with label %s - result: %s' % ('test.failing', 'failed')) self.assertEqual( logs.output[1], 'INFO:docker-signal:Signal logs: %s' % 'failed to send signal') self.assertIsNotNone(self.client.service)
def test_existing_certificate(self): self.mock_result.stdout = 'Congratulations! It worked!' self.mock_result.stderr = 'Renewing an existing certificate' result = self.manager.update(Subdomain('existing-domain', 'unit.test')) self.assertEqual(result, 'OK, renewed') self.assertIn('-d existing-domain.unit.test', ' '.join(self.mock_result.args))
def test_update_non_swarm(self): self.client.swarm_mode = False self.client.items.extend([ MockContainer('c1', 'container-term', {'test.label': 'TERM'}), MockContainer('c2', 'container-kill', {'test.label': 'KILL'}) ]) self.manager.ssl_updated(Subdomain('test'), 'OK') self.assertEqual(self.client.items[0].killed_with, 'TERM') self.assertEqual(self.client.items[1].killed_with, 'KILL')
def test_update_swarm_mode(self): self.client.swarm_mode = True container = MockContainer('c-self', 'test-automation-container') container.image = 'domain/automation' container.log_driver = 'custom' container.log_config = {'x-opt': 'abcd'} self.client.items.append(container) self.client.tasks.append({ 'DesiredState': 'running', 'Status': { 'State': 'running' } }) docker_signal.get_current_container_id = lambda: 'c-self' def mock_sleep(seconds): # change the task state instead self.client.tasks[0]['DesiredState'] = 'shutdown' self.client.tasks[0]['Status']['State'] = 'complete' docker_signal.time.sleep = mock_sleep self.manager.label_name = 'test.label' with self.assertLogs('docker-signal', level='INFO') as logs: self.manager.ssl_updated(Subdomain('swarm'), 'OK') self.assertIsNotNone(self.client.service) self.assertEqual(self.client.service.image, 'domain/automation') self.assertEqual(self.client.service.command[-2:], ['--label', 'test.label']) self.assertIn('domain-automation-', self.client.service.name) self.assertGreater(len(self.client.service.env), 0) self.assertIn('PYTHONPATH=', self.client.service.env[0]) self.assertEqual(self.client.service.log_driver, 'custom') self.assertEqual(self.client.service.log_driver_options, {'x-opt': 'abcd'}) self.assertEqual(self.client.service.mode.mode, 'global') self.assertEqual(self.client.service.restart_policy['Condition'], 'none') self.assertEqual(self.client.service.restart_policy['MaxAttempts'], 0) self.assertTrue(self.client.service.removed) self.assertEqual(len(logs.output), 2) self.assertEqual( logs.output[0], 'INFO:docker-signal:Signalled containers with label %s - result: %s' % ('test.label', 'complete')) self.assertEqual( logs.output[1], 'INFO:docker-signal:Signal logs: %s' % 'output-1\noutput-2')
def test_current_ip(self): self.cf.zones.items.append({'id': 'abcd1234', 'name': 'sample.com'}) self.cf.zones.dns_records.records['abcd1234'] = [{ 'zone_id': 'abcd1234', 'type': 'A', 'name': 'test.sample.com', 'content': '9.9.9.9' }] address = self.manager.get_current_ip(Subdomain('test', 'sample.com')) self.assertIsNotNone(address) self.assertEqual(address, '9.9.9.9')
def test_dns_update(self): message = '`[DNS update]` *dns.update.test* : OK, test' with self.assertLogs('slack-notification', 'DEBUG') as logs: self.manager.dns_updated(Subdomain('dns', 'update.test'), 'OK, test') self.client.assert_call('chat.postMessage', channel='unittest', text=message, as_user=False, username='******') self.assertEqual(len(logs.output), 1) self.assertEqual( logs.output[0], 'INFO:slack-notification:Slack message sent: %s' % message)
def test_retry_once(self): original_send_message = self.manager.send_message def send_message(*args, **kwargs): if kwargs.get('retry', 1) > 1: self.client.response = {'ok': True} else: self.client.response = { 'ok': False, 'headers': { 'Retry-After': '12' } } original_send_message(*args, **kwargs) self.manager.send_message = send_message # slack_message.time.sleep = lambda x: x slack_message.threading.Timer = MockTimer message = '`[DNS update]` *retry.update.test* : With retries' with self.assertLogs('slack-notification', 'DEBUG') as logs: self.manager.dns_updated(Subdomain('retry', 'update.test'), 'With retries') self.client.assert_call('chat.postMessage', channel='unittest', text=message, as_user=False, username='******') self.assertEqual(len(logs.output), 2) self.assertEqual( logs.output[0], 'DEBUG:slack-notification:Retrying Slack message after 12 seconds') self.assertEqual( logs.output[1], 'INFO:slack-notification:Slack message sent: %s' % message)
def test_failing_certbot(self): self.mock_result.returncode = 1 result = self.manager.update(Subdomain('failing.unit.test')) self.assertEqual(result, 'Failed with exit code: 1')
def test_use_staging_servers(self): self.manager.use_staging = True self.manager.update(Subdomain('staging', 'unit.test')) self.assertIn('--staging', self.mock_result.args)
def test_skip_ssl_notification(self): self.manager.ssl_updated(Subdomain('skip', 'cert.renewal'), SSLManager.RESULT_NOT_YET_DUE_FOR_RENEWAL) self.assertIsNone(self.client.last_call)