Add certbot-apache tests and mypy type hints

This commit is contained in:
Joona Hoikkala 2020-01-27 15:10:04 +02:00
parent dd9f76c60c
commit 4138259c51
No known key found for this signature in database
GPG key ID: D5AA86BBF9B29A5C
3 changed files with 38 additions and 12 deletions

View file

@ -145,7 +145,7 @@ class OCSPPrefetchMixin(object):
if next_update:
now = time.time()
res_ttl = int(next_update.total_seconds() - now)
res_ttl = int(time.mktime(next_update.timetuple()) - now)
if res_ttl > 0:
return res_ttl/2
return constants.OCSP_APACHE_TTL

View file

@ -1,5 +1,7 @@
"""Test for certbot_apache._internal.configurator OCSP Prefetching functionality"""
import base64
from datetime import datetime
from datetime import timedelta
import json
import unittest
import sys
@ -16,7 +18,6 @@ from certbot.compat import os
import util
class MockDBM(object):
# pylint: disable=missing-docstring
"""Main mock DBM class for Py3 dbm module"""
@ -178,10 +179,15 @@ class OCSPPrefetchTest(util.ApacheTest):
fh.write("MOCKRESPONSE")
return False
ocsp_path = "certbot._internal.ocsp.RevocationChecker.revoked"
ocsp_path = "certbot._internal.ocsp.RevocationChecker.ocsp_revoked_cert"
with mock.patch(ocsp_path, side_effect=ocsp_req_mock):
self.call_mocked_py2(self.config.enable_ocsp_prefetch,
self.lineage, ["ocspvhost.com"])
with mock.patch('certbot._internal.ocsp.RevocationChecker.ocsp_times') as mock_times:
produced_at = datetime.today() - timedelta(days=1)
this_update = datetime.today() - timedelta(days=2)
next_update = datetime.today() + timedelta(days=2)
mock_times.return_value = produced_at, this_update, next_update
self.call_mocked_py2(self.config.enable_ocsp_prefetch,
self.lineage, ["ocspvhost.com"])
odbm = self.config._ocsp_dbm_open(self.db_path)
self.assertEqual(len(odbm.keys()), 1)
# The actual response data is prepended by Apache timestamp
@ -189,8 +195,13 @@ class OCSPPrefetchTest(util.ApacheTest):
self.config._ocsp_dbm_close(odbm)
with mock.patch(ocsp_path, side_effect=ocsp_req_mock) as mock_ocsp:
self.call_mocked_py2(self.config.update_ocsp_prefetch, None)
self.assertTrue(mock_ocsp.called)
with mock.patch('certbot._internal.ocsp.RevocationChecker.ocsp_times') as mock_times:
produced_at = datetime.today() - timedelta(days=1)
this_update = datetime.today() - timedelta(days=2)
next_update = datetime.today() + timedelta(days=2)
mock_times.return_value = produced_at, this_update, next_update
self.call_mocked_py2(self.config.update_ocsp_prefetch, None)
self.assertTrue(mock_ocsp.called)
def test_ocsp_prefetch_refresh_noop(self):
def ocsp_req_mock(_cert, _chain, workfile):
@ -199,7 +210,7 @@ class OCSPPrefetchTest(util.ApacheTest):
fh.write("MOCKRESPONSE")
return True
ocsp_path = "certbot._internal.ocsp.RevocationChecker.revoked"
ocsp_path = "certbot._internal.ocsp.RevocationChecker.ocsp_revoked_cert"
with mock.patch(ocsp_path, side_effect=ocsp_req_mock):
self.call_mocked_py2(self.config.enable_ocsp_prefetch,
self.lineage, ["ocspvhost.com"])
@ -250,7 +261,7 @@ class OCSPPrefetchTest(util.ApacheTest):
@mock.patch("certbot_apache._internal.prefetch_ocsp.OCSPPrefetchMixin.restart")
def test_ocsp_prefetch_refresh_fail(self, _mock_restart):
ocsp_path = "certbot._internal.ocsp.RevocationChecker.revoked"
ocsp_path = "certbot._internal.ocsp.RevocationChecker.ocsp_revoked_cert"
log_path = "certbot_apache._internal.prefetch_ocsp.logger.warning"
with mock.patch(ocsp_path) as mock_ocsp:
mock_ocsp.return_value = True
@ -328,6 +339,15 @@ class OCSPPrefetchTest(util.ApacheTest):
db2 = self.call_mocked_py3(self.config._ocsp_dbm_open, self.db_path)
self.assertEqual(db2[b'key'], expected_val)
@mock.patch("certbot_apache._internal.constants.OCSP_APACHE_TTL", 1234)
def test_ttl(self):
self.assertEqual(self.config._ocsp_ttl(None), 1234)
next_update = datetime.today() + timedelta(days=6)
ttl = self.config._ocsp_ttl(next_update)
# ttl should be roughly 3 days
self.assertTrue(ttl > 86400*2)
self.assertTrue(ttl < 86400*4)
@mock.patch("certbot_apache._internal.prefetch_ocsp.OCSPPrefetchMixin._ocsp_prefetch_fetch_state")
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator.config_test")
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator._reload")

View file

@ -21,6 +21,7 @@ from acme.magic_typing import Tuple # pylint: disable=unused-import, no-name-in
from certbot import crypto_util
from certbot import errors
from certbot import util
from certbot._internal.storage import RenewableCert # pylint: disable=unused-import
try:
# Only cryptography>=2.5 has ocsp module
@ -99,14 +100,16 @@ class RevocationChecker(object):
return _check_ocsp_cryptography(cert_path, chain_path, url, response_file)
def ocsp_times(self, response_file):
# type: (str) -> Tuple[Optional[datetime], Optional[datetime], Optional[datetime]]
"""
Reads OCSP response file and returns producedAt, thisUpdate
and nextUpdate values in datetime format.
and nextUpdate values in datetime format, or None if an error
occures.
:param str response_file: File path to OCSP response
:returns: tuple of producedAt, thisUpdate and nextUpdate values
:rtype: tuple of datetime
:rtype: tuple of datetime or None
"""
if self.use_openssl_binary:
@ -169,6 +172,7 @@ def _determine_ocsp_server(cert_path):
def _ocsp_times_openssl_bin(response_file):
# type: (str) -> Tuple[Optional[datetime], Optional[datetime], Optional[datetime]]
"""
Reads OCSP response file using OpenSSL binary and returns
producedAt, thisUpdate and nextUpdate values in datetime format.
@ -182,7 +186,7 @@ def _ocsp_times_openssl_bin(response_file):
logger.debug("Reading OCSP response from temp file: %s", response_file)
logger.debug(" ".join(cmd))
try:
output, err = util.run_script(cmd, log=logger.debug)
output, _ = util.run_script(cmd, log=logger.debug)
except errors.SubprocessError:
logger.info("Reading OCSP response from file failed.")
return None, None, None
@ -195,6 +199,7 @@ def _ocsp_times_openssl_bin(response_file):
def _ocsp_times_cryptography(response_file):
# type: (str) -> Tuple[Optional[datetime], Optional[datetime], Optional[datetime]]
"""
Reads OCSP response using cryptography and returns producedAt,
thisUpdate and nextUpdate values in datetime format, or None
@ -379,6 +384,7 @@ def _translate_ocsp_query(cert_path, ocsp_output, ocsp_errors):
def _translate_ocsp_response_times(response):
# type: (str) -> Tuple[str, str, str]
"""
Parse openssl OCSP response output and return producedAt,
thisUpdate and nextUpdate values.