mirror of
https://github.com/ansible-collections/community.crypto.git
synced 2026-05-07 05:43:06 +00:00
Revert "Revert all non-bugfixes merged since the last release."
This reverts commit 82251c2d80.
This commit is contained in:
@@ -9,8 +9,10 @@ __metaclass__ = type
|
||||
import base64
|
||||
import datetime
|
||||
import os
|
||||
import sys
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.backends import (
|
||||
CertificateInformation,
|
||||
CryptoBackend,
|
||||
)
|
||||
|
||||
@@ -79,6 +81,12 @@ TEST_CSRS = [
|
||||
|
||||
|
||||
TEST_CERT = load_fixture("cert_1.pem")
|
||||
TEST_CERT_2 = load_fixture("cert_2.pem")
|
||||
|
||||
|
||||
TEST_CERT_OPENSSL_OUTPUT = load_fixture("cert_1.txt") # OpenSSL 3.3.0 output
|
||||
TEST_CERT_OPENSSL_OUTPUT_2 = load_fixture("cert_2.txt") # OpenSSL 3.3.0 output
|
||||
TEST_CERT_OPENSSL_OUTPUT_2B = load_fixture("cert_2-b.txt") # OpenSSL 1.1.1f output
|
||||
|
||||
|
||||
TEST_CERT_DAYS = [
|
||||
@@ -88,6 +96,81 @@ TEST_CERT_DAYS = [
|
||||
]
|
||||
|
||||
|
||||
TEST_CERT_INFO = CertificateInformation(
|
||||
not_valid_after=datetime.datetime(2018, 11, 26, 15, 28, 24),
|
||||
not_valid_before=datetime.datetime(2018, 11, 25, 15, 28, 23),
|
||||
serial_number=1,
|
||||
subject_key_identifier=b'\x98\xD2\xFD\x3C\xCC\xCD\x69\x45\xFB\xE2\x8C\x30\x2C\x54\x62\x18\x34\xB7\x07\x73',
|
||||
authority_key_identifier=None,
|
||||
)
|
||||
|
||||
|
||||
TEST_CERT_INFO_2 = CertificateInformation(
|
||||
not_valid_before=datetime.datetime(2024, 5, 4, 20, 42, 21),
|
||||
not_valid_after=datetime.datetime(2029, 5, 4, 20, 42, 20),
|
||||
serial_number=4218235397573492796,
|
||||
subject_key_identifier=b'\x17\xE5\x83\x22\x14\xEF\x74\xD3\xBE\x7E\x30\x76\x56\x1F\x51\x74\x65\x1F\xE9\xF0',
|
||||
authority_key_identifier=b'\x13\xC3\x4C\x3E\x59\x45\xDD\xE3\x63\x51\xA3\x46\x80\xC4\x08\xC7\x14\xC0\x64\x4E',
|
||||
)
|
||||
|
||||
|
||||
TEST_CERT_INFO = [
|
||||
(TEST_CERT, TEST_CERT_INFO, TEST_CERT_OPENSSL_OUTPUT),
|
||||
(TEST_CERT_2, TEST_CERT_INFO_2, TEST_CERT_OPENSSL_OUTPUT_2),
|
||||
(TEST_CERT_2, TEST_CERT_INFO_2, TEST_CERT_OPENSSL_OUTPUT_2B),
|
||||
]
|
||||
|
||||
|
||||
TEST_PARSE_ACME_TIMESTAMP = [
|
||||
(
|
||||
'2024-01-01T00:11:22Z',
|
||||
dict(year=2024, month=1, day=1, hour=0, minute=11, second=22),
|
||||
),
|
||||
(
|
||||
'2024-01-01T00:11:22.123Z',
|
||||
dict(year=2024, month=1, day=1, hour=0, minute=11, second=22, microsecond=123000),
|
||||
),
|
||||
(
|
||||
'2024-04-17T06:54:13.333333334Z',
|
||||
dict(year=2024, month=4, day=17, hour=6, minute=54, second=13, microsecond=333333),
|
||||
),
|
||||
]
|
||||
|
||||
if sys.version_info >= (3, 5):
|
||||
TEST_PARSE_ACME_TIMESTAMP.extend([
|
||||
(
|
||||
'2024-01-01T00:11:22+0100',
|
||||
dict(year=2023, month=12, day=31, hour=23, minute=11, second=22),
|
||||
),
|
||||
(
|
||||
'2024-01-01T00:11:22.123+0100',
|
||||
dict(year=2023, month=12, day=31, hour=23, minute=11, second=22, microsecond=123000),
|
||||
),
|
||||
])
|
||||
|
||||
|
||||
TEST_INTERPOLATE_TIMESTAMP = [
|
||||
(
|
||||
dict(year=2024, month=1, day=1, hour=0, minute=0, second=0),
|
||||
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
|
||||
0.0,
|
||||
dict(year=2024, month=1, day=1, hour=0, minute=0, second=0),
|
||||
),
|
||||
(
|
||||
dict(year=2024, month=1, day=1, hour=0, minute=0, second=0),
|
||||
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
|
||||
0.5,
|
||||
dict(year=2024, month=1, day=1, hour=0, minute=30, second=0),
|
||||
),
|
||||
(
|
||||
dict(year=2024, month=1, day=1, hour=0, minute=0, second=0),
|
||||
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
|
||||
1.0,
|
||||
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class FakeBackend(CryptoBackend):
|
||||
def parse_key(self, key_file=None, key_content=None, passphrase=None):
|
||||
raise BackendException('Not implemented in fake backend')
|
||||
@@ -98,6 +181,9 @@ class FakeBackend(CryptoBackend):
|
||||
def create_mac_key(self, alg, key):
|
||||
raise BackendException('Not implemented in fake backend')
|
||||
|
||||
def get_ordered_csr_identifiers(self, csr_filename=None, csr_content=None):
|
||||
raise BackendException('Not implemented in fake backend')
|
||||
|
||||
def get_csr_identifiers(self, csr_filename=None, csr_content=None):
|
||||
raise BackendException('Not implemented in fake backend')
|
||||
|
||||
@@ -106,3 +192,6 @@ class FakeBackend(CryptoBackend):
|
||||
|
||||
def create_chain_matcher(self, criterium):
|
||||
raise BackendException('Not implemented in fake backend')
|
||||
|
||||
def get_cert_information(self, cert_filename=None, cert_content=None):
|
||||
raise BackendException('Not implemented in fake backend')
|
||||
|
||||
38
tests/unit/plugins/module_utils/acme/fixtures/cert_1.txt
Normal file
38
tests/unit/plugins/module_utils/acme/fixtures/cert_1.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 1 (0x1)
|
||||
Signature Algorithm: ecdsa-with-SHA256
|
||||
Issuer: CN=ansible.com
|
||||
Validity
|
||||
Not Before: Nov 25 15:28:23 2018 GMT
|
||||
Not After : Nov 26 15:28:24 2018 GMT
|
||||
Subject: CN=ansible.com
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: id-ecPublicKey
|
||||
Public-Key: (256 bit)
|
||||
pub:
|
||||
04:00:9c:f4:c8:00:17:03:01:26:3a:14:d1:92:35:
|
||||
f1:c2:07:9d:6d:63:ba:82:86:d8:33:79:56:b3:3a:
|
||||
d2:eb:c1:bc:41:2c:e1:5d:1e:80:99:0d:c8:cd:90:
|
||||
e2:9a:74:d3:5c:ee:d7:85:5c:a5:0d:3f:12:2f:31:
|
||||
38:e3:f1:29:9b
|
||||
ASN1 OID: prime256v1
|
||||
NIST CURVE: P-256
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:example.com, DNS:example.org
|
||||
X509v3 Basic Constraints: critical
|
||||
CA:FALSE
|
||||
X509v3 Key Usage: critical
|
||||
Digital Signature
|
||||
X509v3 Extended Key Usage:
|
||||
TLS Web Server Authentication
|
||||
X509v3 Subject Key Identifier:
|
||||
98:D2:FD:3C:CC:CD:69:45:FB:E2:8C:30:2C:54:62:18:34:B7:07:73
|
||||
Signature Algorithm: ecdsa-with-SHA256
|
||||
Signature Value:
|
||||
30:46:02:21:00:bc:fb:52:bf:7a:93:2d:0e:7c:ce:43:f4:cc:
|
||||
05:98:28:36:8d:c7:2a:9b:f5:20:94:62:3d:fb:82:9e:38:42:
|
||||
32:02:21:00:c0:55:f8:b5:d9:65:41:2a:dd:d4:76:3f:8c:cb:
|
||||
07:c1:d2:b9:c0:7d:c9:90:af:fd:f9:f1:b0:c9:13:f5:d5:52
|
||||
@@ -0,0 +1,3 @@
|
||||
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
SPDX-FileCopyrightText: Ansible Project
|
||||
57
tests/unit/plugins/module_utils/acme/fixtures/cert_2-b.txt
Normal file
57
tests/unit/plugins/module_utils/acme/fixtures/cert_2-b.txt
Normal file
@@ -0,0 +1,57 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 4218235397573492796 (0x3a8a2ebeb358c03c)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: CN = Pebble Intermediate CA 734609
|
||||
Validity
|
||||
Not Before: May 4 20:42:21 2024 GMT
|
||||
Not After : May 4 20:42:20 2029 GMT
|
||||
Subject: CN = example.com
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
RSA Public-Key: (1024 bit)
|
||||
Modulus:
|
||||
00:c1:43:a5:f9:ad:00:b7:bb:1b:73:27:00:b3:a2:
|
||||
4e:27:0d:ff:ae:64:3e:a0:7e:f9:28:56:48:47:21:
|
||||
9e:0f:d8:fb:69:b5:21:e8:98:84:60:6c:aa:73:b9:
|
||||
6e:d9:f6:19:ad:85:e0:c2:f6:80:d3:22:b8:5a:d6:
|
||||
3a:89:3e:2a:7a:fc:1d:bf:fc:69:20:e5:91:b8:34:
|
||||
52:26:c8:15:74:e1:36:0c:cd:ab:01:4a:ad:83:f5:
|
||||
0b:77:96:31:cf:1c:ea:6f:88:75:23:ac:51:a6:d8:
|
||||
77:43:1b:b3:44:93:2c:8d:05:25:fb:77:41:36:94:
|
||||
81:d5:ca:56:ff:b5:23:b2:a5
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Key Usage: critical
|
||||
Digital Signature, Key Encipherment
|
||||
X509v3 Extended Key Usage:
|
||||
TLS Web Server Authentication, TLS Web Client Authentication
|
||||
X509v3 Basic Constraints: critical
|
||||
CA:FALSE
|
||||
X509v3 Subject Key Identifier:
|
||||
17:E5:83:22:14:EF:74:D3:BE:7E:30:76:56:1F:51:74:65:1F:E9:F0
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:13:C3:4C:3E:59:45:DD:E3:63:51:A3:46:80:C4:08:C7:14:C0:64:4E
|
||||
|
||||
Authority Information Access:
|
||||
OCSP - URI:http://10.88.0.74:5000/ocsp
|
||||
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:example.com
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
31:43:de:b6:48:f4:b8:30:46:25:65:e6:91:22:33:1b:d1:ba:
|
||||
3f:60:f8:c3:18:32:72:e9:f8:d1:88:11:5a:0a:86:dc:1d:6d:
|
||||
a5:ea:58:cd:05:ea:cd:5e:40:86:c1:ae:d5:cd:2e:8a:ca:50:
|
||||
ee:df:bd:cf:6c:d9:20:3b:4b:49:f8:d5:8a:e3:be:f3:dd:24:
|
||||
b2:7f:3f:3b:bf:e6:8d:7a:f8:8f:4b:6e:25:60:80:33:6f:0f:
|
||||
53:b7:7d:94:2a:d2:4a:db:3a:2f:70:79:d7:bf:05:ed:df:10:
|
||||
61:e7:24:ac:b2:fc:03:bd:ad:8c:e1:f3:1d:cc:78:99:e3:22:
|
||||
59:bf:c5:92:57:95:92:56:35:fc:05:8b:26:10:c5:1b:87:17:
|
||||
64:0b:bd:33:a9:54:d5:c0:2b:43:56:1b:52:d3:4f:8b:6f:25:
|
||||
06:58:7f:6f:aa:27:35:05:d5:57:6d:83:a0:73:de:40:3f:67:
|
||||
1c:5a:92:c6:37:e6:8f:c7:b8:91:d7:50:b9:4d:d4:f2:92:1f:
|
||||
8b:93:0c:e2:b4:b8:d7:1d:8e:ce:6d:19:dc:8f:12:8e:c0:f2:
|
||||
92:3b:95:5a:8c:c8:69:0e:0b:f7:fa:1f:55:62:80:7c:e2:f6:
|
||||
41:3f:7d:69:36:9e:7c:90:7e:d7:3b:e6:a3:15:de:a4:7d:95:
|
||||
13:46:c6:1a
|
||||
@@ -0,0 +1,3 @@
|
||||
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
SPDX-FileCopyrightText: Ansible Project
|
||||
19
tests/unit/plugins/module_utils/acme/fixtures/cert_2.pem
Normal file
19
tests/unit/plugins/module_utils/acme/fixtures/cert_2.pem
Normal file
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDDjCCAfagAwIBAgIIOoouvrNYwDwwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UE
|
||||
AxMdUGViYmxlIEludGVybWVkaWF0ZSBDQSA3MzQ2MDkwHhcNMjQwNTA0MjA0MjIx
|
||||
WhcNMjkwNTA0MjA0MjIwWjAWMRQwEgYDVQQDEwtleGFtcGxlLmNvbTCBnzANBgkq
|
||||
hkiG9w0BAQEFAAOBjQAwgYkCgYEAwUOl+a0At7sbcycAs6JOJw3/rmQ+oH75KFZI
|
||||
RyGeD9j7abUh6JiEYGyqc7lu2fYZrYXgwvaA0yK4WtY6iT4qevwdv/xpIOWRuDRS
|
||||
JsgVdOE2DM2rAUqtg/ULd5Yxzxzqb4h1I6xRpth3QxuzRJMsjQUl+3dBNpSB1cpW
|
||||
/7UjsqUCAwEAAaOB0TCBzjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB
|
||||
BQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFBflgyIU73TT
|
||||
vn4wdlYfUXRlH+nwMB8GA1UdIwQYMBaAFBPDTD5ZRd3jY1GjRoDECMcUwGROMDcG
|
||||
CCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovLzEwLjg4LjAuNzQ6NTAw
|
||||
MC9vY3NwMBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IB
|
||||
AQAxQ962SPS4MEYlZeaRIjMb0bo/YPjDGDJy6fjRiBFaCobcHW2l6ljNBerNXkCG
|
||||
wa7VzS6KylDu373PbNkgO0tJ+NWK477z3SSyfz87v+aNeviPS24lYIAzbw9Tt32U
|
||||
KtJK2zovcHnXvwXt3xBh5ySssvwDva2M4fMdzHiZ4yJZv8WSV5WSVjX8BYsmEMUb
|
||||
hxdkC70zqVTVwCtDVhtS00+LbyUGWH9vqic1BdVXbYOgc95AP2ccWpLGN+aPx7iR
|
||||
11C5TdTykh+LkwzitLjXHY7ObRncjxKOwPKSO5VajMhpDgv3+h9VYoB84vZBP31p
|
||||
Np58kH7XO+ajFd6kfZUTRsYa
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,3 @@
|
||||
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
SPDX-FileCopyrightText: Ansible Project
|
||||
56
tests/unit/plugins/module_utils/acme/fixtures/cert_2.txt
Normal file
56
tests/unit/plugins/module_utils/acme/fixtures/cert_2.txt
Normal file
@@ -0,0 +1,56 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 4218235397573492796 (0x3a8a2ebeb358c03c)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: CN=Pebble Intermediate CA 734609
|
||||
Validity
|
||||
Not Before: May 4 20:42:21 2024 GMT
|
||||
Not After : May 4 20:42:20 2029 GMT
|
||||
Subject: CN=example.com
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (1024 bit)
|
||||
Modulus:
|
||||
00:c1:43:a5:f9:ad:00:b7:bb:1b:73:27:00:b3:a2:
|
||||
4e:27:0d:ff:ae:64:3e:a0:7e:f9:28:56:48:47:21:
|
||||
9e:0f:d8:fb:69:b5:21:e8:98:84:60:6c:aa:73:b9:
|
||||
6e:d9:f6:19:ad:85:e0:c2:f6:80:d3:22:b8:5a:d6:
|
||||
3a:89:3e:2a:7a:fc:1d:bf:fc:69:20:e5:91:b8:34:
|
||||
52:26:c8:15:74:e1:36:0c:cd:ab:01:4a:ad:83:f5:
|
||||
0b:77:96:31:cf:1c:ea:6f:88:75:23:ac:51:a6:d8:
|
||||
77:43:1b:b3:44:93:2c:8d:05:25:fb:77:41:36:94:
|
||||
81:d5:ca:56:ff:b5:23:b2:a5
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Key Usage: critical
|
||||
Digital Signature, Key Encipherment
|
||||
X509v3 Extended Key Usage:
|
||||
TLS Web Server Authentication, TLS Web Client Authentication
|
||||
X509v3 Basic Constraints: critical
|
||||
CA:FALSE
|
||||
X509v3 Subject Key Identifier:
|
||||
17:E5:83:22:14:EF:74:D3:BE:7E:30:76:56:1F:51:74:65:1F:E9:F0
|
||||
X509v3 Authority Key Identifier:
|
||||
13:C3:4C:3E:59:45:DD:E3:63:51:A3:46:80:C4:08:C7:14:C0:64:4E
|
||||
Authority Information Access:
|
||||
OCSP - URI:http://10.88.0.74:5000/ocsp
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:example.com
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Signature Value:
|
||||
31:43:de:b6:48:f4:b8:30:46:25:65:e6:91:22:33:1b:d1:ba:
|
||||
3f:60:f8:c3:18:32:72:e9:f8:d1:88:11:5a:0a:86:dc:1d:6d:
|
||||
a5:ea:58:cd:05:ea:cd:5e:40:86:c1:ae:d5:cd:2e:8a:ca:50:
|
||||
ee:df:bd:cf:6c:d9:20:3b:4b:49:f8:d5:8a:e3:be:f3:dd:24:
|
||||
b2:7f:3f:3b:bf:e6:8d:7a:f8:8f:4b:6e:25:60:80:33:6f:0f:
|
||||
53:b7:7d:94:2a:d2:4a:db:3a:2f:70:79:d7:bf:05:ed:df:10:
|
||||
61:e7:24:ac:b2:fc:03:bd:ad:8c:e1:f3:1d:cc:78:99:e3:22:
|
||||
59:bf:c5:92:57:95:92:56:35:fc:05:8b:26:10:c5:1b:87:17:
|
||||
64:0b:bd:33:a9:54:d5:c0:2b:43:56:1b:52:d3:4f:8b:6f:25:
|
||||
06:58:7f:6f:aa:27:35:05:d5:57:6d:83:a0:73:de:40:3f:67:
|
||||
1c:5a:92:c6:37:e6:8f:c7:b8:91:d7:50:b9:4d:d4:f2:92:1f:
|
||||
8b:93:0c:e2:b4:b8:d7:1d:8e:ce:6d:19:dc:8f:12:8e:c0:f2:
|
||||
92:3b:95:5a:8c:c8:69:0e:0b:f7:fa:1f:55:62:80:7c:e2:f6:
|
||||
41:3f:7d:69:36:9e:7c:90:7e:d7:3b:e6:a3:15:de:a4:7d:95:
|
||||
13:46:c6:1a
|
||||
@@ -0,0 +1,3 @@
|
||||
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
SPDX-FileCopyrightText: Ansible Project
|
||||
@@ -16,11 +16,22 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.backend_cryp
|
||||
CryptographyBackend,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.support import (
|
||||
ensure_utc_timezone,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import (
|
||||
CRYPTOGRAPHY_TIMEZONE,
|
||||
)
|
||||
|
||||
from .backend_data import (
|
||||
TEST_KEYS,
|
||||
TEST_CSRS,
|
||||
TEST_CERT,
|
||||
TEST_CERT_DAYS,
|
||||
TEST_CERT_INFO,
|
||||
TEST_PARSE_ACME_TIMESTAMP,
|
||||
TEST_INTERPOLATE_TIMESTAMP,
|
||||
)
|
||||
|
||||
|
||||
@@ -64,3 +75,49 @@ def test_certdays_cryptography(now, expected_days, tmpdir):
|
||||
assert days == expected_days
|
||||
days = backend.get_cert_days(cert_content=TEST_CERT, now=now)
|
||||
assert days == expected_days
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cert_content, expected_cert_info, openssl_output", TEST_CERT_INFO)
|
||||
def test_get_cert_information(cert_content, expected_cert_info, openssl_output, tmpdir):
|
||||
fn = tmpdir / 'test-cert.pem'
|
||||
fn.write(cert_content)
|
||||
module = MagicMock()
|
||||
backend = CryptographyBackend(module)
|
||||
|
||||
if CRYPTOGRAPHY_TIMEZONE:
|
||||
expected_cert_info = expected_cert_info._replace(
|
||||
not_valid_after=ensure_utc_timezone(expected_cert_info.not_valid_after),
|
||||
not_valid_before=ensure_utc_timezone(expected_cert_info.not_valid_before),
|
||||
)
|
||||
|
||||
cert_info = backend.get_cert_information(cert_filename=str(fn))
|
||||
assert cert_info == expected_cert_info
|
||||
cert_info = backend.get_cert_information(cert_content=cert_content)
|
||||
assert cert_info == expected_cert_info
|
||||
|
||||
|
||||
def test_now():
|
||||
module = MagicMock()
|
||||
backend = CryptographyBackend(module)
|
||||
now = backend.get_now()
|
||||
assert CRYPTOGRAPHY_TIMEZONE == (now.tzinfo is not None)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input, expected", TEST_PARSE_ACME_TIMESTAMP)
|
||||
def test_parse_acme_timestamp(input, expected):
|
||||
module = MagicMock()
|
||||
backend = CryptographyBackend(module)
|
||||
ts_expected = backend.get_utc_datetime(**expected)
|
||||
timestamp = backend.parse_acme_timestamp(input)
|
||||
assert ts_expected == timestamp
|
||||
|
||||
|
||||
@pytest.mark.parametrize("start, end, percentage, expected", TEST_INTERPOLATE_TIMESTAMP)
|
||||
def test_interpolate_timestamp(start, end, percentage, expected):
|
||||
module = MagicMock()
|
||||
backend = CryptographyBackend(module)
|
||||
ts_start = backend.get_utc_datetime(**start)
|
||||
ts_end = backend.get_utc_datetime(**end)
|
||||
ts_expected = backend.get_utc_datetime(**expected)
|
||||
timestamp = backend.interpolate_timestamp(ts_start, ts_end, percentage)
|
||||
assert ts_expected == timestamp
|
||||
|
||||
@@ -18,6 +18,12 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.backend_open
|
||||
from .backend_data import (
|
||||
TEST_KEYS,
|
||||
TEST_CSRS,
|
||||
TEST_CERT,
|
||||
TEST_CERT_OPENSSL_OUTPUT,
|
||||
TEST_CERT_DAYS,
|
||||
TEST_CERT_INFO,
|
||||
TEST_PARSE_ACME_TIMESTAMP,
|
||||
TEST_INTERPOLATE_TIMESTAMP,
|
||||
)
|
||||
|
||||
|
||||
@@ -61,3 +67,56 @@ def test_normalize_ip(ip, result):
|
||||
module = MagicMock()
|
||||
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
|
||||
assert backend._normalize_ip(ip) == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize("now, expected_days", TEST_CERT_DAYS)
|
||||
def test_certdays_cryptography(now, expected_days, tmpdir):
|
||||
fn = tmpdir / 'test-cert.pem'
|
||||
fn.write(TEST_CERT)
|
||||
module = MagicMock()
|
||||
module.run_command = MagicMock(return_value=(0, TEST_CERT_OPENSSL_OUTPUT, 0))
|
||||
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
|
||||
days = backend.get_cert_days(cert_filename=str(fn), now=now)
|
||||
assert days == expected_days
|
||||
days = backend.get_cert_days(cert_content=TEST_CERT, now=now)
|
||||
assert days == expected_days
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cert_content, expected_cert_info, openssl_output", TEST_CERT_INFO)
|
||||
def test_get_cert_information(cert_content, expected_cert_info, openssl_output, tmpdir):
|
||||
fn = tmpdir / 'test-cert.pem'
|
||||
fn.write(cert_content)
|
||||
module = MagicMock()
|
||||
module.run_command = MagicMock(return_value=(0, openssl_output, 0))
|
||||
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
|
||||
cert_info = backend.get_cert_information(cert_filename=str(fn))
|
||||
assert cert_info == expected_cert_info
|
||||
cert_info = backend.get_cert_information(cert_content=cert_content)
|
||||
assert cert_info == expected_cert_info
|
||||
|
||||
|
||||
def test_now():
|
||||
module = MagicMock()
|
||||
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
|
||||
now = backend.get_now()
|
||||
assert now.tzinfo is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input, expected", TEST_PARSE_ACME_TIMESTAMP)
|
||||
def test_parse_acme_timestamp(input, expected):
|
||||
module = MagicMock()
|
||||
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
|
||||
ts_expected = backend.get_utc_datetime(**expected)
|
||||
timestamp = backend.parse_acme_timestamp(input)
|
||||
assert ts_expected == timestamp
|
||||
|
||||
|
||||
@pytest.mark.parametrize("start, end, percentage, expected", TEST_INTERPOLATE_TIMESTAMP)
|
||||
def test_interpolate_timestamp(start, end, percentage, expected):
|
||||
module = MagicMock()
|
||||
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
|
||||
ts_start = backend.get_utc_datetime(**start)
|
||||
ts_end = backend.get_utc_datetime(**end)
|
||||
ts_expected = backend.get_utc_datetime(**expected)
|
||||
timestamp = backend.interpolate_timestamp(ts_start, ts_end, percentage)
|
||||
assert ts_expected == timestamp
|
||||
|
||||
@@ -6,12 +6,20 @@ from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.backends import (
|
||||
CertificateInformation,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.utils import (
|
||||
nopad_b64,
|
||||
pem_to_der,
|
||||
process_links,
|
||||
parse_retry_after,
|
||||
compute_cert_id,
|
||||
)
|
||||
|
||||
from .backend_data import (
|
||||
@@ -27,6 +35,73 @@ NOPAD_B64 = [
|
||||
]
|
||||
|
||||
|
||||
TEST_LINKS_HEADER = [
|
||||
(
|
||||
{},
|
||||
[],
|
||||
),
|
||||
(
|
||||
{
|
||||
'link': '<foo>; rel="bar"'
|
||||
},
|
||||
[
|
||||
('foo', 'bar'),
|
||||
],
|
||||
),
|
||||
(
|
||||
{
|
||||
'link': '<foo>; rel="bar", <baz>; rel="bam"'
|
||||
},
|
||||
[
|
||||
('foo', 'bar'),
|
||||
('baz', 'bam'),
|
||||
],
|
||||
),
|
||||
(
|
||||
{
|
||||
'link': '<https://one.example.com>; rel="preconnect", <https://two.example.com>; rel="preconnect", <https://three.example.com>; rel="preconnect"'
|
||||
},
|
||||
[
|
||||
('https://one.example.com', 'preconnect'),
|
||||
('https://two.example.com', 'preconnect'),
|
||||
('https://three.example.com', 'preconnect'),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
TEST_RETRY_AFTER_HEADER = [
|
||||
('120', datetime.datetime(2024, 4, 29, 0, 2, 0)),
|
||||
('Wed, 21 Oct 2015 07:28:00 GMT', datetime.datetime(2015, 10, 21, 7, 28, 0)),
|
||||
]
|
||||
|
||||
|
||||
TEST_COMPUTE_CERT_ID = [
|
||||
(
|
||||
CertificateInformation(
|
||||
not_valid_after=datetime.datetime(2018, 11, 26, 15, 28, 24),
|
||||
not_valid_before=datetime.datetime(2018, 11, 25, 15, 28, 23),
|
||||
serial_number=1,
|
||||
subject_key_identifier=None,
|
||||
authority_key_identifier=b'\x00\xff',
|
||||
),
|
||||
'AP8.AQ',
|
||||
),
|
||||
(
|
||||
# AKI, serial number, and expected result taken from
|
||||
# https://letsencrypt.org/2024/04/25/guide-to-integrating-ari-into-existing-acme-clients.html#step-3-constructing-the-ari-certid
|
||||
CertificateInformation(
|
||||
not_valid_after=datetime.datetime(2018, 11, 26, 15, 28, 24),
|
||||
not_valid_before=datetime.datetime(2018, 11, 25, 15, 28, 23),
|
||||
serial_number=0x87654321,
|
||||
subject_key_identifier=None,
|
||||
authority_key_identifier=b'\x69\x88\x5B\x6B\x87\x46\x40\x41\xE1\xB3\x7B\x84\x7B\xA0\xAE\x2C\xDE\x01\xC8\xD4',
|
||||
),
|
||||
'aYhba4dGQEHhs3uEe6CuLN4ByNQ.AIdlQyE',
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value, result", NOPAD_B64)
|
||||
def test_nopad_b64(value, result):
|
||||
assert nopad_b64(value.encode('utf-8')) == result
|
||||
@@ -37,3 +112,25 @@ def test_pem_to_der(pem, der, tmpdir):
|
||||
fn = tmpdir / 'test.pem'
|
||||
fn.write(pem)
|
||||
assert pem_to_der(str(fn)) == der
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value, expected_result", TEST_LINKS_HEADER)
|
||||
def test_process_links(value, expected_result):
|
||||
data = []
|
||||
|
||||
def callback(url, rel):
|
||||
data.append((url, rel))
|
||||
|
||||
process_links(value, callback)
|
||||
|
||||
assert expected_result == data
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value, expected_result", TEST_RETRY_AFTER_HEADER)
|
||||
def test_parse_retry_after(value, expected_result):
|
||||
assert expected_result == parse_retry_after(value, now=datetime.datetime(2024, 4, 29, 0, 0, 0))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cert_info, expected_result", TEST_COMPUTE_CERT_ID)
|
||||
def test_compute_cert_id(cert_info, expected_result):
|
||||
assert expected_result == compute_cert_id(backend=None, cert_info=cert_info)
|
||||
|
||||
@@ -15,6 +15,7 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.math impor
|
||||
quick_is_not_prime,
|
||||
convert_int_to_bytes,
|
||||
convert_int_to_hex,
|
||||
convert_bytes_to_int,
|
||||
)
|
||||
|
||||
|
||||
@@ -100,3 +101,17 @@ def test_convert_int_to_hex(no, digits, result):
|
||||
value = convert_int_to_hex(no, digits=digits)
|
||||
print(value)
|
||||
assert value == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize('data, result', [
|
||||
(b'', 0),
|
||||
(b'\x00', 0),
|
||||
(b'\x00\x01', 1),
|
||||
(b'\x01', 1),
|
||||
(b'\xff', 255),
|
||||
(b'\x01\x00', 256),
|
||||
])
|
||||
def test_convert_bytes_to_int(data, result):
|
||||
value = convert_bytes_to_int(data)
|
||||
print(value)
|
||||
assert value == result
|
||||
|
||||
323
tests/unit/plugins/module_utils/test_time.py
Normal file
323
tests/unit/plugins/module_utils/test_time.py
Normal file
@@ -0,0 +1,323 @@
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.time import (
|
||||
add_or_remove_timezone,
|
||||
get_now_datetime,
|
||||
convert_relative_to_datetime,
|
||||
ensure_utc_timezone,
|
||||
from_epoch_seconds,
|
||||
get_epoch_seconds,
|
||||
get_relative_time_option,
|
||||
remove_timezone,
|
||||
UTC,
|
||||
)
|
||||
|
||||
|
||||
TEST_REMOVE_TIMEZONE = [
|
||||
(
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2),
|
||||
),
|
||||
(
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2),
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2),
|
||||
),
|
||||
]
|
||||
|
||||
TEST_UTC_TIMEZONE = [
|
||||
(
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2),
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
|
||||
),
|
||||
(
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
|
||||
),
|
||||
]
|
||||
|
||||
TEST_EPOCH_SECONDS = [
|
||||
(0, dict(year=1970, day=1, month=1, hour=0, minute=0, second=0, microsecond=0)),
|
||||
(1E-6, dict(year=1970, day=1, month=1, hour=0, minute=0, second=0, microsecond=1)),
|
||||
(1E-3, dict(year=1970, day=1, month=1, hour=0, minute=0, second=0, microsecond=1000)),
|
||||
(3691.2, dict(year=1970, day=1, month=1, hour=1, minute=1, second=31, microsecond=200000)),
|
||||
]
|
||||
|
||||
TEST_EPOCH_TO_SECONDS = [
|
||||
(datetime.datetime(1970, 1, 1, 0, 1, 2, 0), 62),
|
||||
(datetime.datetime(1970, 1, 1, 0, 1, 2, 0, tzinfo=UTC), 62),
|
||||
]
|
||||
|
||||
TEST_CONVERT_RELATIVE_TO_DATETIME = [
|
||||
(
|
||||
'+0',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
),
|
||||
(
|
||||
'+1s',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC),
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 1),
|
||||
),
|
||||
(
|
||||
'-10w20d30h40m50s',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC),
|
||||
datetime.datetime(2023, 10, 1, 17, 19, 10),
|
||||
),
|
||||
(
|
||||
'+0',
|
||||
True,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC),
|
||||
),
|
||||
(
|
||||
'+1s',
|
||||
True,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC),
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 1, tzinfo=UTC),
|
||||
),
|
||||
(
|
||||
'-10w20d30h40m50s',
|
||||
True,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2023, 10, 1, 17, 19, 10, tzinfo=UTC),
|
||||
),
|
||||
]
|
||||
|
||||
TEST_GET_RELATIVE_TIME_OPTION = [
|
||||
(
|
||||
'+1d2h3m4s',
|
||||
'foo',
|
||||
'cryptography',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2024, 1, 2, 2, 3, 4),
|
||||
),
|
||||
(
|
||||
'-1w10d24h',
|
||||
'foo',
|
||||
'cryptography',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2023, 12, 14, 0, 0, 0),
|
||||
),
|
||||
(
|
||||
'20240102040506Z',
|
||||
'foo',
|
||||
'cryptography',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2024, 1, 2, 4, 5, 6),
|
||||
),
|
||||
(
|
||||
'202401020405Z',
|
||||
'foo',
|
||||
'cryptography',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2024, 1, 2, 4, 5, 0),
|
||||
),
|
||||
(
|
||||
'+1d2h3m4s',
|
||||
'foo',
|
||||
'cryptography',
|
||||
True,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2024, 1, 2, 2, 3, 4, tzinfo=UTC),
|
||||
),
|
||||
(
|
||||
'-1w10d24h',
|
||||
'foo',
|
||||
'cryptography',
|
||||
True,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2023, 12, 14, 0, 0, 0, tzinfo=UTC),
|
||||
),
|
||||
(
|
||||
'20240102040506Z',
|
||||
'foo',
|
||||
'cryptography',
|
||||
True,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2024, 1, 2, 4, 5, 6, tzinfo=UTC),
|
||||
),
|
||||
(
|
||||
'202401020405Z',
|
||||
'foo',
|
||||
'cryptography',
|
||||
True,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2024, 1, 2, 4, 5, 0, tzinfo=UTC),
|
||||
),
|
||||
(
|
||||
'+1d2h3m4s',
|
||||
'foo',
|
||||
'pyopenssl',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
'20240102020304Z',
|
||||
),
|
||||
(
|
||||
'-1w10d24h',
|
||||
'foo',
|
||||
'pyopenssl',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
'20231214000000Z',
|
||||
),
|
||||
(
|
||||
'20240102040506Z',
|
||||
'foo',
|
||||
'pyopenssl',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
'20240102040506Z',
|
||||
),
|
||||
(
|
||||
'202401020405Z',
|
||||
'foo',
|
||||
'pyopenssl',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
'202401020405Z',
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
if sys.version_info >= (3, 5):
|
||||
ONE_HOUR_PLUS = datetime.timezone(datetime.timedelta(hours=1))
|
||||
|
||||
TEST_REMOVE_TIMEZONE.extend([
|
||||
(
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=ONE_HOUR_PLUS),
|
||||
datetime.datetime(2023, 12, 31, 23, 1, 2),
|
||||
),
|
||||
])
|
||||
TEST_UTC_TIMEZONE.extend([
|
||||
(
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=ONE_HOUR_PLUS),
|
||||
datetime.datetime(2023, 12, 31, 23, 1, 2, tzinfo=UTC),
|
||||
),
|
||||
])
|
||||
TEST_EPOCH_TO_SECONDS.extend([
|
||||
(datetime.datetime(1970, 1, 1, 0, 1, 2, 0, tzinfo=ONE_HOUR_PLUS), 62 - 3600),
|
||||
])
|
||||
TEST_GET_RELATIVE_TIME_OPTION.extend([
|
||||
(
|
||||
'20240102040506+0100',
|
||||
'foo',
|
||||
'cryptography',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2024, 1, 2, 3, 5, 6),
|
||||
),
|
||||
(
|
||||
'202401020405+0100',
|
||||
'foo',
|
||||
'cryptography',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2024, 1, 2, 3, 5, 0),
|
||||
),
|
||||
(
|
||||
'20240102040506+0100',
|
||||
'foo',
|
||||
'cryptography',
|
||||
True,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2024, 1, 2, 3, 5, 6, tzinfo=UTC),
|
||||
),
|
||||
(
|
||||
'202401020405+0100',
|
||||
'foo',
|
||||
'cryptography',
|
||||
True,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2024, 1, 2, 3, 5, 0, tzinfo=UTC),
|
||||
),
|
||||
(
|
||||
'20240102040506+0100',
|
||||
'foo',
|
||||
'pyopenssl',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
'20240102040506+0100',
|
||||
),
|
||||
(
|
||||
'202401020405+0100',
|
||||
'foo',
|
||||
'pyopenssl',
|
||||
False,
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
'202401020405+0100',
|
||||
),
|
||||
])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input, expected", TEST_REMOVE_TIMEZONE)
|
||||
def test_remove_timezone(input, expected):
|
||||
output_1 = remove_timezone(input)
|
||||
assert expected == output_1
|
||||
output_2 = add_or_remove_timezone(input, with_timezone=False)
|
||||
assert expected == output_2
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input, expected", TEST_UTC_TIMEZONE)
|
||||
def test_utc_timezone(input, expected):
|
||||
output_1 = ensure_utc_timezone(input)
|
||||
assert expected == output_1
|
||||
output_2 = add_or_remove_timezone(input, with_timezone=True)
|
||||
assert expected == output_2
|
||||
|
||||
|
||||
def test_get_now_datetime():
|
||||
output_1 = get_now_datetime(with_timezone=False)
|
||||
assert output_1.tzinfo is None
|
||||
output_2 = get_now_datetime(with_timezone=True)
|
||||
assert output_2.tzinfo is not None
|
||||
assert output_2.tzinfo == UTC
|
||||
|
||||
|
||||
@pytest.mark.parametrize("seconds, timestamp", TEST_EPOCH_SECONDS)
|
||||
def test_epoch_seconds(seconds, timestamp):
|
||||
ts_wo_tz = datetime.datetime(**timestamp)
|
||||
assert seconds == get_epoch_seconds(ts_wo_tz)
|
||||
timestamp_w_tz = dict(timestamp)
|
||||
timestamp_w_tz['tzinfo'] = UTC
|
||||
ts_w_tz = datetime.datetime(**timestamp_w_tz)
|
||||
assert seconds == get_epoch_seconds(ts_w_tz)
|
||||
output_1 = from_epoch_seconds(seconds, with_timezone=False)
|
||||
assert ts_wo_tz == output_1
|
||||
output_2 = from_epoch_seconds(seconds, with_timezone=True)
|
||||
assert ts_w_tz == output_2
|
||||
|
||||
|
||||
@pytest.mark.parametrize("timestamp, expected_seconds", TEST_EPOCH_TO_SECONDS)
|
||||
def test_epoch_to_seconds(timestamp, expected_seconds):
|
||||
assert expected_seconds == get_epoch_seconds(timestamp)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("relative_time_string, with_timezone, now, expected", TEST_CONVERT_RELATIVE_TO_DATETIME)
|
||||
def test_convert_relative_to_datetime(relative_time_string, with_timezone, now, expected):
|
||||
output = convert_relative_to_datetime(relative_time_string, with_timezone=with_timezone, now=now)
|
||||
assert expected == output
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input_string, input_name, backend, with_timezone, now, expected", TEST_GET_RELATIVE_TIME_OPTION)
|
||||
def test_get_relative_time_option(input_string, input_name, backend, with_timezone, now, expected):
|
||||
output = get_relative_time_option(input_string, input_name, backend=backend, with_timezone=with_timezone, now=now)
|
||||
assert expected == output
|
||||
Reference in New Issue
Block a user