B ㊇c0;@svddlZddlmZddlmZddlmZddlmZm Z m Z m Z ddl m Z GdddZeZGd d d ZdS) N)deque)pformat) AWSResponse)ParamValidationErrorStubAssertionErrorStubResponseErrorUnStubbedResponseError)validate_parametersc@s(eZdZdZddZddZddZdS) _ANYzZ A helper object that compares equal to everything. Copied from unittest.mock cCsdS)NT)selfotherr r h/private/var/folders/8c/hx9_v10d5x38qmnzt13b7b8j1k3n5b/T/pip-target-x6xd5gna/lib/python/botocore/stub.py__eq__!sz _ANY.__eq__cCsdS)NFr )r r r r r__ne__$sz _ANY.__ne__cCsdS)Nzr )r r r r__repr__'sz _ANY.__repr__N)__name__ __module__ __qualname____doc__rrrr r r rr sr c@seZdZdZddZddZddZdd Zd d Zd#d dZ ddZ d$ddZ ddZ ddZ ddZddZddZdd Zd!d"Zd S)%Stubbera This class will allow you to stub out requests so you don't have to hit an endpoint to write tests. Responses are returned first in, first out. If operations are called out of order, or are called with no remaining queued responses, an error will be raised. **Example:** :: import datetime import botocore.session from botocore.stub import Stubber s3 = botocore.session.get_session().create_client('s3') stubber = Stubber(s3) response = { 'IsTruncated': False, 'Name': 'test-bucket', 'MaxKeys': 1000, 'Prefix': '', 'Contents': [{ 'Key': 'test.txt', 'ETag': '"abc123"', 'StorageClass': 'STANDARD', 'LastModified': datetime.datetime(2016, 1, 20, 22, 9), 'Owner': {'ID': 'abc123', 'DisplayName': 'myname'}, 'Size': 14814 }], 'EncodingType': 'url', 'ResponseMetadata': { 'RequestId': 'abc123', 'HTTPStatusCode': 200, 'HostId': 'abc123' }, 'Marker': '' } expected_params = {'Bucket': 'test-bucket'} stubber.add_response('list_objects', response, expected_params) stubber.activate() service_response = s3.list_objects(Bucket='test-bucket') assert service_response == response This class can also be called as a context manager, which will handle activation / deactivation for you. **Example:** :: import datetime import botocore.session from botocore.stub import Stubber s3 = botocore.session.get_session().create_client('s3') response = { "Owner": { "ID": "foo", "DisplayName": "bar" }, "Buckets": [{ "CreationDate": datetime.datetime(2016, 1, 20, 22, 9), "Name": "baz" }] } with Stubber(s3) as stubber: stubber.add_response('list_buckets', response, {}) service_response = s3.list_buckets() assert service_response == response If you have an input parameter that is a randomly generated value, or you otherwise don't care about its value, you can use ``stub.ANY`` to ignore it in validation. **Example:** :: import datetime import botocore.session from botocore.stub import Stubber, ANY s3 = botocore.session.get_session().create_client('s3') stubber = Stubber(s3) response = { 'IsTruncated': False, 'Name': 'test-bucket', 'MaxKeys': 1000, 'Prefix': '', 'Contents': [{ 'Key': 'test.txt', 'ETag': '"abc123"', 'StorageClass': 'STANDARD', 'LastModified': datetime.datetime(2016, 1, 20, 22, 9), 'Owner': {'ID': 'abc123', 'DisplayName': 'myname'}, 'Size': 14814 }], 'EncodingType': 'url', 'ResponseMetadata': { 'RequestId': 'abc123', 'HTTPStatusCode': 200, 'HostId': 'abc123' }, 'Marker': '' } expected_params = {'Bucket': ANY} stubber.add_response('list_objects', response, expected_params) with stubber: service_response = s3.list_objects(Bucket='test-bucket') assert service_response == response cCs||_d|_d|_t|_dS)zA :param client: The client to add your stubs to. Z boto_stubberZboto_stubber_expected_paramsN)client _event_id_expected_params_event_idr_queue)r rr r r__init__szStubber.__init__cCs ||S)N)activate)r r r r __enter__szStubber.__enter__cCs |dS)N) deactivate)r Zexception_typeZexception_value tracebackr r r__exit__szStubber.__exit__cCs8|jjjjd|j|jd|jjjjd|j|jddS)z5 Activates the stubber on the client zbefore-parameter-build.*.*) unique_idzbefore-call.*.*N) rmetaeventsZregister_first_assert_expected_paramsrregister_get_response_handlerr)r r r rrs   zStubber.activatecCs8|jjjjd|j|jd|jjjjd|j|jddS)z7 Deactivates the stubber on the client zbefore-parameter-build.*.*)r!zbefore-call.*.*N)rr"r# unregisterr$rr&r)r r r rrs   zStubber.deactivateNcCs||||dS)ax Adds a service response to the response queue. This will be validated against the service model to ensure correctness. It should be noted, however, that while missing attributes are often considered correct, your code may not function properly if you leave them out. Therefore you should always fill in every value you see in a typical response for your particular request. :param method: The name of the client method to stub. :type method: str :param service_response: A dict response stub. Provided parameters will be validated against the service model. :type service_response: dict :param expected_params: A dictionary of the expected parameters to be called for the provided service response. The parameters match the names of keyword arguments passed to that client call. If any of the parameters differ a ``StubResponseError`` is thrown. You can use stub.ANY to indicate a particular parameter to ignore in validation. stub.ANY is only valid for top level params. N) _add_response)r methodservice_responseexpected_paramsr r r add_responseszStubber.add_responsecCsnt|j|s$td|jjjj|ftddid}|jjj|}| |||||f|d}|j |dS)Nz"Client %s does not have method: %s)operation_nameresponser+) hasattrr ValueErrorr" service_model service_namermethod_to_api_mappingget_validate_operation_responserappend)r r)r*r+ http_responser.r/r r rr(s  zStubber._add_responsec Cstd|id} d|i||dd} |dk r8| d||dk rN| d||dk r|jjj} | |} || || ||jjj|} | | | f|d}|j |dS)aG Adds a ``ClientError`` to the response queue. :param method: The name of the service method to return the error on. :type method: str :param service_error_code: The service error code to return, e.g. ``NoSuchBucket`` :type service_error_code: str :param service_message: The service message to return, e.g. 'The specified bucket does not exist.' :type service_message: str :param http_status_code: The HTTP status code to return, e.g. 404, etc :type http_status_code: int :param service_error_meta: Additional keys to be added to the service Error :type service_error_meta: dict :param expected_params: A dictionary of the expected parameters to be called for the provided service response. The parameters match the names of keyword arguments passed to that client call. If any of the parameters differ a ``StubResponseError`` is thrown. You can use stub.ANY to indicate a particular parameter to ignore in validation. :param response_meta: Additional keys to be added to the response's ResponseMetadata :type response_meta: dict :param modeled_fields: Additional keys to be added to the response based on fields that are modeled for the particular error code. These keys will be validated against the particular error shape designated by the error code. :type modeled_fields: dict NZHTTPStatusCode)MessageZCode)ResponseMetadataErrorr=r<)r.r/r+) rupdaterr"r2Zshape_for_error_code_validate_responser4r5rr7)r r)Zservice_error_codeZservice_messageZhttp_status_codeZservice_error_metar+Z response_metaZmodeled_fieldsr8Zparsed_responser2shaper.r/r r radd_client_errors"2    zStubber.add_client_errorcCs$t|j}|dkr t|ddS)z< Asserts that all expected calls were made. rz responses remaining in queue.N)lenrAssertionError)r remainingr r rassert_no_pending_responsesVs z#Stubber.assert_no_pending_responsescCsF|jst|jdd|jdd}||jkrBt|jd|dddS)NzUnexpected API Call: A call was made but no additional calls expected. Either the API Call was not stubbed or it was called multiple times.)r.reasonrr.z'Operation mismatch: found response for .)rrnamer)r modelparamsrHr r r_assert_expected_call_order^s z#Stubber._assert_expected_call_ordercKs||||jdS)Nr/)rKrpopleft)r rIrJcontextkwargsr r rr&ps zStubber._get_response_handlercKs||rdS||||jdd}|dkr4dSxJ|D]>\}}||ks^||||kr>t|jdt|t|fdq>Wt|t|krt|jdt|t|fddS)Nrr+z)Expected parameters: %s, but received: %s)r.rF) _should_not_stubrKritemsrrHrsortedkeys)r rIrJrMrNr+paramvaluer r rr$us"  zStubber._assert_expected_paramscCs|r|drdSdS)NZis_presign_requestT)r5)r rMr r rrOszStubber._should_not_stubcCsF|jjj}||}|j}|}d|kr6t|}|d=|||dS)Nr<)rr"r2operation_model output_shapecopyr?)r r.r*r2rUrVr/r r rr6s   z$Stubber._validate_operation_responsecCs&|dk rt||n|r"tdddS)Nz6Service response should only contain ResponseMetadata.)report)r r)r r@r/r r rr?s  zStubber._validate_response)N)r9r9r:NNNN)rrrrrrr rrr,r(rArErKr&r$rOr6r?r r r rr.s,x   Ir)rW collectionsrpprintrZbotocore.awsrequestrZbotocore.exceptionsrrrrZbotocore.validater r ANYrr r r r s