Compare commits

...

109 Commits

Author SHA1 Message Date
Jacob Hoffman-Andrews
2b102913ab Apply review feedback.
Also turn raises of bare Exceptions into typed exceptions.
2018-02-14 18:21:54 -08:00
Jacob Hoffman-Andrews
77f7cf2c2e Split up poll_order_and_request_issuance. 2018-02-13 17:25:25 -08:00
Jacob Hoffman-Andrews
2a430bb7a5 Merge branch 'v2-orders' of github.com:certbot/certbot into v2-orders 2018-02-12 18:19:26 -08:00
Jacob Hoffman-Andrews
0649bbaa8f Merge branch 'master' of github.com:certbot/certbot into v2-orders 2018-02-12 18:18:23 -08:00
Jacob Hoffman-Andrews
94f0d150d2 Use pycryptography. 2018-02-07 17:31:48 -08:00
Jacob Hoffman-Andrews
105ec41257 lint 2018-02-07 17:03:23 -08:00
Jacob Hoffman-Andrews
d7c9cbb278 Update documentation. 2018-02-07 16:53:11 -08:00
Jacob Hoffman-Andrews
9c1c5653db Merge branch 'master' into v2-orders 2018-02-07 16:51:04 -08:00
Jacob Hoffman-Andrews
9776175556 Use camelCase for newOrder 2018-01-05 19:03:30 -08:00
Jacob Hoffman-Andrews
244bb188e2 Merge branch 'v2-client' into v2-orders 2018-01-05 19:03:01 -08:00
Jacob Hoffman-Andrews
399a2af6bb Use camelCase for newAccount. 2018-01-05 19:02:52 -08:00
Jacob Hoffman-Andrews
c27bcb83b8 Fix directory fetching. 2018-01-05 18:29:16 -08:00
Jacob Hoffman-Andrews
06a5b2c838 Fix directory fetching. 2018-01-05 18:29:03 -08:00
Jacob Hoffman-Andrews
fb88bf5b06 Close docstring. 2018-01-05 18:21:04 -08:00
Jacob Hoffman-Andrews
5cc4778221 Remove print. 2018-01-05 18:13:19 -08:00
Jacob Hoffman-Andrews
924fbdf84e Fix whitespace. 2018-01-05 18:12:18 -08:00
Jacob Hoffman-Andrews
f0a9b81cf1 Revert camelCase automagic 2018-01-05 18:11:27 -08:00
Jacob Hoffman-Andrews
89a73d6e26 Merge branch 'acme-v2' into v2-orders 2018-01-05 18:07:14 -08:00
Jacob Hoffman-Andrews
80e2ec993a Remove duplicate methods. 2018-01-05 17:57:51 -08:00
Jacob Hoffman-Andrews
c48450c1dc Merge branch 'v2-client' into v2-orders 2018-01-05 17:56:12 -08:00
Jacob Hoffman-Andrews
5c5cd489bc Remove new_account check for coverage. 2018-01-05 15:41:22 -08:00
Jacob Hoffman-Andrews
d17340f23b Split Client into ClientBase / Client / ClientV2 2018-01-05 15:33:54 -08:00
Jacob Hoffman-Andrews
30efbbe457 Merge branch 'master' of github.com:certbot/certbot into v2-client 2018-01-05 14:21:50 -08:00
Jacob Hoffman-Andrews
0bca64adf6 Merge branch 'master' of github.com:certbot/certbot into acme-v2 2018-01-05 14:12:21 -08:00
Jacob Hoffman-Andrews
5ee065ef20 Add acme-v2 branches to Travis. 2018-01-03 08:41:14 -08:00
Jacob Hoffman-Andrews
3e0b3beebd authz -> authzr 2018-01-02 15:45:59 -08:00
Jacob Hoffman-Andrews
8ec6b7c6e2 authz -> authzr 2018-01-02 10:55:06 -08:00
Jacob Hoffman-Andrews
c0841ca485 Make pip loud. 2017-12-14 14:53:14 -08:00
Jacob Hoffman-Andrews
b42c23d896 Make chisel2 use josepy. 2017-12-14 14:42:57 -08:00
Jacob Hoffman-Andrews
6cf656a68f Merge branch 'master' of github.com:certbot/certbot into acme-v2 2017-12-14 14:28:10 -08:00
Jacob Hoffman-Andrews
ac956eb08d Use camelCase for directory and other identifiers. 2017-12-14 13:26:04 -08:00
Jacob Hoffman-Andrews
15a8a1e7d8 Remove verify_ssl=False. 2017-12-14 12:54:33 -08:00
Jacob Hoffman-Andrews
37dcbebb1c Implement order finalization. 2017-12-13 18:22:01 -08:00
Jacob Hoffman-Andrews
584bcec337 Add deadline. 2017-12-13 17:41:27 -08:00
Jacob Hoffman-Andrews
40e039176e Move csr initialization. 2017-12-13 17:04:47 -08:00
Jacob Hoffman-Andrews
c751d8ad72 Re-add too-many-public-methods. 2017-12-11 18:03:04 -08:00
Jacob Hoffman-Andrews
f32aa7921f Fix tests. 2017-12-08 19:35:08 -08:00
Jacob Hoffman-Andrews
210009bbfe Review feedback. 2017-12-08 19:28:05 -08:00
Jacob Hoffman-Andrews
540d55c4f8 Add csr. 2017-12-08 19:23:19 -08:00
Jacob Hoffman-Andrews
2916ec896c Use identifiers flow, and poll differently. 2017-12-05 22:47:04 -08:00
Jacob Hoffman-Andrews
d9616c44f4 Remove noisy print. 2017-12-05 15:59:56 -08:00
Jacob Hoffman-Andrews
6a8906509f Merge branch 'master' into acme-v2 2017-12-05 14:58:56 -08:00
Jacob Hoffman-Andrews
abc78641ea Fix syntax 2017-12-04 14:43:01 -08:00
Jacob Hoffman-Andrews
40392918db Tidy 2017-12-04 14:39:48 -08:00
Jacob Hoffman-Andrews
400a174d5a Simplify _from_response 2017-12-04 14:32:14 -08:00
Jacob Hoffman-Andrews
47a96218d6 Fix lint. 2017-12-04 13:57:18 -08:00
Jacob Hoffman-Andrews
7063f38463 Merge branch 'master' of github.com:certbot/certbot into v2-orders 2017-12-04 13:47:27 -08:00
Jacob Hoffman-Andrews
28228aae09 Merge branch 'master' of github.com:certbot/certbot into acme-v2 2017-12-04 12:45:47 -08:00
Jacob Hoffman-Andrews
2517269a2c Merge branch 'master' of github.com:certbot/certbot into acme-v2 2017-12-01 17:27:25 -08:00
Jacob Hoffman-Andrews
51d3c7f03e Add OrderResourceTest. 2017-12-01 16:51:21 -08:00
Jacob Hoffman-Andrews
78bf67aa56 Merge branch 'master' of github.com:certbot/certbot into v2-orders 2017-12-01 16:30:21 -08:00
Jacob Hoffman-Andrews
36bdc3d8c9 Merge branch 'master' of github.com:certbot/certbot into v2-client 2017-12-01 16:17:12 -08:00
Jacob Hoffman-Andrews
cbde2c2ec7 Fix pylint. 2017-12-01 16:04:00 -08:00
Jacob Hoffman-Andrews
b4eb906274 Remove chisel2.py. 2017-12-01 15:56:21 -08:00
Jacob Hoffman-Andrews
4c2c10f388 Merge branch 'master' of github.com:certbot/certbot into v2-orders 2017-12-01 15:22:23 -08:00
Jacob Hoffman-Andrews
3667c1e7d8 Merge branch 'master' of github.com:certbot/certbot into v2-client 2017-12-01 12:00:58 -08:00
Jacob Hoffman-Andrews
fb1c45671d Split out wrap_in_jws_v2 test. 2017-12-01 11:55:52 -08:00
Jacob Hoffman-Andrews
e59408ca25 Add terms_of_service_agreed. 2017-11-27 17:13:30 -08:00
Jacob Hoffman-Andrews
1436323371 Remove unnecessaries. 2017-11-27 17:12:04 -08:00
Jacob Hoffman-Andrews
4e7b930d4b Merge branch 'master' of github.com:certbot/certbot into v2-client 2017-11-27 16:17:20 -08:00
Jacob Hoffman-Andrews
ffd64adf82 Rename to add v2. 2017-11-27 15:57:02 -08:00
Jacob Hoffman-Andrews
7b92d6dc95 Fix up test. 2017-11-27 15:49:38 -08:00
Jacob Hoffman-Andrews
6a8d78c5a3 Remove separate NewAccount. 2017-11-27 15:09:51 -08:00
Jacob Hoffman-Andrews
acaf858fdb Add explicit versioning. 2017-11-27 15:08:50 -08:00
Jacob Hoffman-Andrews
f009296669 Remove separate NewAccount. 2017-11-27 15:04:00 -08:00
Jacob Hoffman-Andrews
04cc1f4fa7 Partial test. 2017-11-27 15:02:59 -08:00
Jacob Hoffman-Andrews
63f8dff67f Add account, and make acme_version explicit. 2017-11-27 14:35:02 -08:00
Jacob Hoffman-Andrews
1cf5b9f43e Fix lint. 2017-11-27 14:23:48 -08:00
Jacob Hoffman-Andrews
a1d4f47ccc Implement ACMEv2 signing of POST bodies. 2017-11-27 14:03:56 -08:00
Jacob Hoffman-Andrews
2070bfa433 Fix resource_type. 2017-11-27 13:54:05 -08:00
Jacob Hoffman-Andrews
b9d7f5ad59 Hide chall body uri, improve challr uri. 2017-11-22 13:11:25 -08:00
Jacob Hoffman-Andrews
92409279d0 Add certificate fetching. 2017-11-21 17:58:00 -08:00
Jacob Hoffman-Andrews
b21b3208df Handle failed authorizations. 2017-11-21 15:34:28 -08:00
Jacob Hoffman-Andrews
cdaba6df33 Fix uri/url distinction in challenges. 2017-11-21 15:34:07 -08:00
Jacob Hoffman-Andrews
e09efb0029 Fix minor dysfunctions. 2017-11-20 17:22:16 -08:00
Jacob Hoffman-Andrews
d5607a7b34 Merge branch 'acme-v2' of github.com:certbot/certbot into acme-v2 2017-11-08 16:36:14 -08:00
Roland Bracewell Shoemaker
6a8f9c387f Small fixes 2017-11-03 14:16:33 -04:00
Roland Bracewell Shoemaker
38982eeedf Merge branch 'master' into acme-v2 2017-11-01 14:26:50 -07:00
Roland Shoemaker
590044ac77 Register new-account in the directory class 2017-10-16 14:14:02 -07:00
Roland Shoemaker
307f4e5c42 Remove tool/chisel2.py (should live in boulder repo) 2017-10-16 14:08:23 -07:00
Roland Shoemaker
1f979dd37b Fix registration endpoint selection + challenge decoding 2017-10-16 14:07:44 -07:00
Roland Shoemaker
5ae60088df revert breaking changes 2017-10-10 12:17:29 -07:00
Jacob Hoffman-Andrews
324caf2def Tweak field names. 2017-08-09 21:14:35 -07:00
Jacob Hoffman-Andrews
9cec48c711 Merge branch 'master' into acme-v2 2017-08-09 21:11:45 -07:00
Jacob Hoffman-Andrews
6bdb87d718 Use kid after register; provide key for signing 2017-05-16 11:55:40 -07:00
Jacob Hoffman-Andrews
3c7b59f730 Merge branch 'master' of github.com:certbot/certbot into acme-v2 2017-04-25 17:26:33 -07:00
Jacob Hoffman-Andrews
db249c9e19 Add polling for order status. 2017-04-25 10:55:01 -07:00
Jacob Hoffman-Andrews
d550542a94 Merge branch 'url-kid' into acme-v2 2017-04-20 17:27:27 -07:00
Jacob Hoffman-Andrews
89ffd76f4b Enforce mutual exclusivity of jwk and kid. 2017-04-20 17:22:20 -07:00
Jacob Hoffman-Andrews
52cb9d9421 Merge branch 'master' of github.com:certbot/certbot into acme-v2 2017-04-05 15:19:59 -07:00
Jacob Hoffman-Andrews
f1bbf87d30 Updates for acme-v2 2017-03-17 12:50:45 -07:00
Jacob Hoffman-Andrews
d35a23d378 Add chisel2 from Boulder master's chisel.py. 2017-03-17 12:49:50 -07:00
Jacob Hoffman-Andrews
34840b7933 Merge branch 'master' into acme-v2 2017-03-15 11:47:04 -07:00
Jacob Hoffman-Andrews
2ddba14d2e Add comments and fix lint. 2017-03-14 15:54:59 -07:00
Jacob Hoffman-Andrews
44c761cb68 Add url and kid to jws.
This will be required in order to implement the latest ACME spec, which uses
these protected header fields.
2017-03-13 18:55:48 -07:00
Jacob Hoffman-Andrews
23ce0c3129 Add authorizations parameter to order resource. 2017-03-13 18:41:42 -07:00
Jacob Hoffman-Andrews
dd52573bcf Fix new_order and make it fetch authzs. 2017-03-13 18:32:20 -07:00
Jacob Hoffman-Andrews
8b1c58bd8e Implement new-order / order. 2017-03-13 17:32:20 -07:00
Jacob Hoffman-Andrews
eff001547a Add url and kid to client. 2017-03-13 17:28:25 -07:00
Jacob Hoffman-Andrews
1e112fa936 Add url and kid to jws. 2017-03-13 17:28:25 -07:00
Jacob Hoffman-Andrews
d806714769 Fix terms-of-service-agreed. 2017-03-13 17:28:25 -07:00
Jacob Hoffman-Andrews
3cfaafb4c2 Merge branch 'master' of github.com:certbot/certbot into unrevert-new-authzr-uri 2017-03-13 17:28:16 -07:00
Jacob Hoffman-Andrews
9ce078bfd1 Add test for deprecated URI argument to request_challenges. 2017-03-10 16:25:20 -08:00
Jacob Hoffman-Andrews
a9e111d5f4 Fix account_test. 2017-03-10 15:04:21 -08:00
Jacob Hoffman-Andrews
bd09d60246 Merge branch 'master' of github.com:certbot/certbot into unrevert-new-authzr-uri 2017-03-09 18:39:32 -08:00
Jacob Hoffman-Andrews
d172a142aa Restore backwards compatibility for new_authzr_uri. 2017-03-09 16:33:42 -08:00
Jacob Hoffman-Andrews
24fd264c9c Add test that new_authzr_uri exists in regr. 2017-03-08 17:27:18 -08:00
Jacob Hoffman-Andrews
fd598d8d19 Save new_authzr_uri with account for older clients. 2017-03-06 14:30:59 -08:00
Jacob Hoffman-Andrews
31e68137cd Revert "Revert "Remove Link rel=next for authzs and new-certs." (#4277)"
This reverts commit 11ec1eb911.
2017-03-06 14:30:34 -08:00
4 changed files with 174 additions and 13 deletions

View File

@@ -1,6 +1,7 @@
"""ACME client API."""
import base64
import collections
import cryptography
import datetime
from email.utils import parsedate_tz
import heapq
@@ -119,11 +120,11 @@ class ClientBase(object): # pylint: disable=too-many-instance-attributes
"""
return self._send_recv_regr(regr, messages.UpdateRegistration())
def _authzr_from_response(self, response, identifier, uri=None):
def _authzr_from_response(self, response, identifier=None, uri=None):
authzr = messages.AuthorizationResource(
body=messages.Authorization.from_json(response.json()),
uri=response.headers.get('Location', uri))
if authzr.body.identifier != identifier:
if identifier is not None and authzr.body.identifier != identifier:
raise errors.UnexpectedUpdate(authzr)
return authzr
@@ -233,8 +234,8 @@ class Client(ClientBase):
instances of `.DeserializationError` raised in `from_json()`.
:ivar messages.Directory directory:
:ivar key: `.JWK` (private)
:ivar alg: `.JWASignature`
:ivar key: `josepy.JWK` (private)
:ivar alg: `josepy.JWASignature`
:ivar bool verify_ssl: Verify SSL certificates?
:ivar .ClientNetwork net: Client network. Useful for testing. If not
supplied, it will be initialized using `key`, `alg` and
@@ -550,7 +551,6 @@ class ClientV2(ClientBase):
:returns: Registration Resource.
:rtype: `.RegistrationResource`
"""
response = self.net.post(self.directory['newAccount'], new_account,
acme_version=2)
@@ -560,6 +560,83 @@ class ClientV2(ClientBase):
self.net.account = regr
return regr
def new_order(self, csr_pem):
"""Request a new Order object from the server.
:param str csr_pem: A CSR in PEM format.
:returns: The newly created order.
:rtype: OrderResource
"""
csr = cryptography.x509.load_pem_x509_csr(csr_pem,
cryptography.hazmat.backends.default_backend())
san_extension = next(ext for ext in csr.extensions
if ext.oid == cryptography.x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
dnsNames = san_extension.value.get_values_for_type(cryptography.x509.DNSName)
identifiers = []
for name in dnsNames:
identifiers.append(messages.Identifier(typ=messages.IDENTIFIER_FQDN,
value=name))
order = messages.NewOrder(identifiers=identifiers)
response = self.net.post(self.directory['newOrder'], order)
body = messages.Order.from_json(response.json())
authorizations = []
for url in body.authorizations:
authorizations.append(self._authzr_from_response(self.net.get(url)))
return messages.OrderResource(
body=body,
uri=response.headers.get('Location', uri),
fullchain_pem=fullchain_pem,
authorizations=authorizations,
csr_pem=csr_pem)
def poll_and_finalize(self, orderr, deadline=None):
if deadline is None:
deadline = datetime.datetime.now() + datetime.timedelta(seconds=90)
orderr = self.poll_authorizations(orderr, deadline)
return self.finalize_order(orderr, deadline)
def poll_authorizations(self, orderr, deadline):
"""Poll Order Resource for status."""
responses = []
for url in orderr.body.authorizations:
while datetime.datetime.now() < deadline:
authzr = self._authzr_from_response(self.net.get(url), uri=url)
if authzr.body.status != messages.STATUS_PENDING:
responses.append(authzr)
break
time.sleep(1)
# If we didn't get a response for every authorization, we fell through
# the bottom of the loop due to hitting the deadline.
if len(responses) > orderr.body.authorizations:
raise TimeoutError()
failed = []
for authzr in responses:
if authzr.body.status != messages.STATUS_VALID:
for chall in authzr.body.challenges:
if chall.error != None:
failed.append(authzr)
if len(failed) > 0:
raise ValidationError(failed)
return orderr.update(authorizations=responses)
def finalize_order(self, orderr, deadline):
csr = OpenSSL.crypto.load_certificate_request(
OpenSSL.crypto.FILETYPE_PEM, orderr.csr_pem)
wrapped_csr = messages.CertificateRequest(csr=jose.ComparableX509(csr))
self.net.post(latest.body.finalize, wrapped_csr)
while datetime.datetime.now() < deadline:
time.sleep(1)
response = self.net.get(orderr.uri)
body = messages.Order.from_json(response.json())
if body.error is not None:
raise IssuanceError(body.error)
if body.certificate is not None:
certificate_response = self.net.get(body.certificate).text
return orderr.update(fullchain_pem=certificate_response)
raise TimeoutError()
class ClientNetwork(object): # pylint: disable=too-many-instance-attributes
"""Wrapper around requests that signs POSTs for authentication.
@@ -572,10 +649,10 @@ class ClientNetwork(object): # pylint: disable=too-many-instance-attributes
"""Initialize.
:param key: Account private key
:param josepy.JWK key: Account private key
:param messages.RegistrationResource account: Account object. Required if you are
planning to use .post() with acme_version=2 for anything other than creating a new
account; may be set later after registering.
planning to use .post() with acme_version=2 for anything other than
creating a new account; may be set later after registering.
:param josepy.JWASignature alg: Algoritm to use in signing JWS.
:param bool verify_ssl: Whether to verify certificates on SSL connections.
:param str user_agent: String to send as User-Agent header.
@@ -606,10 +683,10 @@ class ClientNetwork(object): # pylint: disable=too-many-instance-attributes
.. todo:: Implement ``acmePath``.
:param .JSONDeSerializable obj:
:param josepy.JSONDeSerializable obj:
:param str url: The URL to which this object will be POSTed
:param bytes nonce:
:rtype: `.JWS`
:rtype: `josepy.JWS`
"""
jobj = obj.json_dumps(indent=2).encode()

View File

@@ -83,6 +83,27 @@ class PollError(ClientError):
return '{0}(exhausted={1!r}, updated={2!r})'.format(
self.__class__.__name__, self.exhausted, self.updated)
class ValidationError(Error):
"""Error for authorization failures. Contains a list of authorization
resources, each of which is invalid and should have an error field.
"""
def __init__(self, failed_authzrs):
self.failed_authzrs = failed_authzrs
super(ClientError, self).__init__()
class TimeoutError(Error):
"""Error for when polling an authorization or an order times out."""
class IssuanceError(Error):
"""Error sent by the server after requesting issuance of a certificate."""
def __init__(self, error):
"""Initialize.
:param messages.Error error: The error provided by the server.
"""
self.error = error
class ConflictError(ClientError):
"""Error for when the server returns a 409 (Conflict) HTTP status.

View File

@@ -172,8 +172,9 @@ class Directory(jose.JSONDeSerializable):
class Meta(jose.JSONObjectWithFields):
"""Directory Meta."""
terms_of_service = jose.Field('terms-of-service', omitempty=True)
terms_of_service_v2 = jose.Field('termsOfService', omitempty=True)
website = jose.Field('website', omitempty=True)
caa_identities = jose.Field('caa-identities', omitempty=True)
caa_identities = jose.Field('caaIdentities', omitempty=True)
@classmethod
def _canon_key(cls, key):
@@ -251,7 +252,7 @@ class Registration(ResourceBody):
contact = jose.Field('contact', omitempty=True, default=())
agreement = jose.Field('agreement', omitempty=True)
status = jose.Field('status', omitempty=True)
terms_of_service_agreed = jose.Field('terms-of-service-agreed', omitempty=True)
terms_of_service_agreed = jose.Field('termsOfServiceAgreed', omitempty=True)
phone_prefix = 'tel:'
email_prefix = 'mailto:'
@@ -483,3 +484,49 @@ class Revocation(jose.JSONObjectWithFields):
certificate = jose.Field(
'certificate', decoder=jose.decode_cert, encoder=jose.encode_cert)
reason = jose.Field('reason')
class Order(ResourceBody):
"""Order Resource Body.
.. note:: Parsing of identifiers on response doesn't work right now; to make
it work we would need to set up the equivalent of Identifier.from_json, but
for a list.
:ivar list of .Identifier: List of identifiers for the certificate.
:ivar acme.messages.Status status:
:ivar list of str authorizations: URLs of authorizations.
:ivar str certificate: URL to download certificate as a fullchain PEM.
:ivar str finalize: URL to POST to to request issuance once all
authorizations have "valid" status.
:ivar datetime.datetime expires: When the order expires.
:ivar .Error error: Any error that occurred during finalization, if applicable.
"""
identifiers = jose.Field('identifiers', omitempty=True)
status = jose.Field('status', decoder=Status.from_json,
omitempty=True, default=STATUS_PENDING)
authorizations = jose.Field('authorizations', omitempty=True)
certificate = jose.Field('certificate', omitempty=True)
finalize = jose.Field('finalize', omitempty=True)
expires = fields.RFC3339Field('expires', omitempty=True)
error = jose.Field('error', omitempty=True, decoder=Error.from_json)
class OrderResource(ResourceWithURI):
"""Order Resource.
:ivar acme.messages.Order body:
:ivar str csr_pem: The CSR this Order will be finalized with.
:ivar list of acme.messages.AuthorizationResource authorizations:
Fully-fetched AuthorizationResource objects.
:ivar str fullchain_pem: The fetched contents of the certificate URL
produced once the order was finalized, if it's present.
"""
body = jose.Field('body', decoder=Order.from_json)
csr_pem = jose.Field('csr_pem', omitempty=True)
authorizations = jose.Field('authorizations')
fullchain_pem = jose.Field('fullchain_pem', omitempty=True)
@Directory.register
class NewOrder(Order):
"""New order."""
resource_type = 'new-order'
resource = fields.Resource(resource_type)

View File

@@ -157,7 +157,7 @@ class DirectoryTest(unittest.TestCase):
'meta': {
'terms-of-service': 'https://example.com/acme/terms',
'website': 'https://www.example.com/',
'caa-identities': ['example.com'],
'caaIdentities': ['example.com'],
},
})
@@ -401,5 +401,21 @@ class RevocationTest(unittest.TestCase):
hash(Revocation.from_json(self.rev.to_json()))
class OrderResourceTest(unittest.TestCase):
"""Tests for acme.messages.OrderResource."""
def setUp(self):
from acme.messages import OrderResource
self.regr = OrderResource(
body=mock.sentinel.body, uri=mock.sentinel.uri)
def test_to_partial_json(self):
self.assertEqual(self.regr.to_json(), {
'body': mock.sentinel.body,
'uri': mock.sentinel.uri,
'authorizations': None,
})
if __name__ == '__main__':
unittest.main() # pragma: no cover