python-botocore/tests/unit/test_waiters.py

789 lines
31 KiB
Python
Raw Normal View History

# Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import os
2021-09-22 22:53:42 +02:00
from tests import mock, unittest, BaseEnvVar
import botocore
from botocore.compat import six
from botocore.exceptions import ClientError, WaiterConfigError, WaiterError
from botocore.waiter import Waiter, WaiterModel, SingleWaiterConfig
from botocore.waiter import create_waiter_with_client
from botocore.waiter import NormalizedOperationMethod
from botocore.loaders import Loader
from botocore.model import ServiceModel
class TestWaiterModel(unittest.TestCase):
def setUp(self):
self.boiler_plate_config = {
'description': 'Waiter description',
'operation': 'HeadBucket',
'delay': 5,
'maxAttempts': 20,
}
def create_acceptor_function(self, for_config):
single_waiter = {
'acceptors': [for_config]
}
single_waiter.update(self.boiler_plate_config)
config = SingleWaiterConfig(single_waiter)
return config.acceptors[0].matcher_func
def test_waiter_version(self):
self.assertEqual(WaiterModel({'version': 2, 'waiters': {}}).version, 2)
def test_wont_load_missing_version_in_config(self):
# We only load waiter configs if we know for sure that we're
# loading version 2 of the format.
waiters = {
# Missing the 'version' key.
'waiters': {}
}
with self.assertRaises(WaiterConfigError):
WaiterModel(waiters)
def test_unsupported_waiter_version(self):
waiters = {
'version': 1,
'waiters': {}
}
with self.assertRaises(WaiterConfigError):
WaiterModel(waiters)
def test_waiter_names(self):
waiters = {
'version': 2,
'waiters': {
'BarWaiter': {},
'FooWaiter': {},
}
}
self.assertEqual(WaiterModel(waiters).waiter_names, ['BarWaiter',
'FooWaiter'])
def test_get_single_waiter_config(self):
single_waiter = {
'description': 'Waiter description',
'operation': 'HeadBucket',
'delay': 5,
'maxAttempts': 20,
'acceptors': [
{'state': 'success', 'matcher': 'status', 'expected': 200},
{'state': 'retry', 'matcher': 'status', 'expected': 404},
],
}
waiters = {
'version': 2,
'waiters': {
'BucketExists': single_waiter,
}
}
model = WaiterModel(waiters)
config = model.get_waiter('BucketExists')
self.assertEqual(config.operation, 'HeadBucket')
def test_get_waiter_does_not_exist(self):
waiters = {
'version': 2,
'waiters': {}
}
model = WaiterModel(waiters)
with self.assertRaises(ValueError):
model.get_waiter('UnknownWaiter')
def test_single_waiter_config_attributes(self):
single_waiter = {
'description': 'Waiter description',
'operation': 'HeadBucket',
'delay': 5,
'maxAttempts': 20,
'acceptors': [
],
}
config = SingleWaiterConfig(single_waiter)
self.assertEqual(config.description, 'Waiter description')
self.assertEqual(config.operation, 'HeadBucket')
self.assertEqual(config.delay, 5)
self.assertEqual(config.max_attempts, 20)
def test_single_waiter_acceptors_built_with_matcher_func(self):
# When the list of acceptors are requested, we actually will transform
# them into values that are easier to use.
single_waiter = {
'acceptors': [
{'state': 'success', 'matcher': 'status', 'expected': 200},
],
}
single_waiter.update(self.boiler_plate_config)
config = SingleWaiterConfig(single_waiter)
success_acceptor = config.acceptors[0]
self.assertEqual(success_acceptor.state, 'success')
self.assertEqual(success_acceptor.matcher, 'status')
self.assertEqual(success_acceptor.expected, 200)
self.assertTrue(callable(success_acceptor.matcher_func))
def test_single_waiter_acceptor_matches_jmespath(self):
single_waiter = {
'acceptors': [
{'state': 'success', 'matcher': 'path',
'argument': 'Table.TableStatus', 'expected': 'ACCEPTED'},
],
}
single_waiter.update(self.boiler_plate_config)
config = SingleWaiterConfig(single_waiter)
success_acceptor = config.acceptors[0].matcher_func
# success_acceptor is a callable that takes a response dict and returns
# True or False.
self.assertTrue(
success_acceptor({'Table': {'TableStatus': 'ACCEPTED'}}))
self.assertFalse(
success_acceptor({'Table': {'TableStatus': 'CREATING'}}))
def test_single_waiter_supports_status_code(self):
single_waiter = {
'acceptors': [
{'state': 'success', 'matcher': 'status',
'expected': 200}
],
}
single_waiter.update(self.boiler_plate_config)
config = SingleWaiterConfig(single_waiter)
success_acceptor = config.acceptors[0].matcher_func
self.assertTrue(
success_acceptor({'ResponseMetadata': {'HTTPStatusCode': 200}}))
self.assertFalse(
success_acceptor({'ResponseMetadata': {'HTTPStatusCode': 404}}))
def test_single_waiter_supports_error(self):
single_waiter = {
'acceptors': [
{'state': 'success', 'matcher': 'error',
'expected': 'DoesNotExistError'}
],
}
single_waiter.update(self.boiler_plate_config)
config = SingleWaiterConfig(single_waiter)
success_acceptor = config.acceptors[0].matcher_func
self.assertTrue(
success_acceptor({'Error': {'Code': 'DoesNotExistError'}}))
self.assertFalse(
success_acceptor({'Error': {'Code': 'DoesNotExistErorr'}}))
def test_unknown_matcher(self):
unknown_type = 'arbitrary_type'
single_waiter = {
'acceptors': [
{'state': 'success', 'matcher': unknown_type,
'expected': 'foo'}
]
}
single_waiter.update(self.boiler_plate_config)
config = SingleWaiterConfig(single_waiter)
with self.assertRaises(WaiterConfigError):
config.acceptors
def test_single_waiter_supports_path_all(self):
matches = self.create_acceptor_function(
for_config={'state': 'success', 'matcher': 'pathAll',
'argument': 'Tables[].State', 'expected': 'GOOD'})
self.assertTrue(
matches({'Tables': [{"State": "GOOD"}]}))
self.assertTrue(
matches({'Tables': [{"State": "GOOD"}, {"State": "GOOD"}]}))
def test_single_waiter_supports_path_any(self):
matches = self.create_acceptor_function(
for_config={'state': 'failure', 'matcher': 'pathAny',
'argument': 'Tables[].State', 'expected': 'FAIL'})
self.assertTrue(
matches({'Tables': [{"State": "FAIL"}]}))
self.assertTrue(
matches({'Tables': [{"State": "GOOD"}, {"State": "FAIL"}]}))
def test_waiter_handles_error_responses_with_path_matchers(self):
path_any = self.create_acceptor_function(
for_config={'state': 'success', 'matcher': 'pathAny',
'argument': 'length(Tables) > `0`',
'expected': True})
path_all = self.create_acceptor_function(
for_config={'state': 'success', 'matcher': 'pathAll',
'argument': 'length(Tables) > `0`',
'expected': True})
path = self.create_acceptor_function(
for_config={'state': 'success', 'matcher': 'path',
'argument': 'length(Tables) > `0`',
'expected': True})
self.assertFalse(path_any({'Error': {'Code': 'DoesNotExist'}}))
self.assertFalse(path_all({'Error': {'Code': 'DoesNotExist'}}))
self.assertFalse(path({'Error': {'Code': 'DoesNotExist'}}))
def test_single_waiter_does_not_match_path_all(self):
matches = self.create_acceptor_function(
for_config={'state': 'success', 'matcher': 'pathAll',
'argument': 'Tables[].State', 'expected': 'GOOD'})
self.assertFalse(
matches({'Tables': [{"State": "GOOD"}, {"State": "BAD"}]}))
self.assertFalse(
matches({'Tables': [{"State": "BAD"}, {"State": "GOOD"}]}))
self.assertFalse(
matches({'Tables': [{"State": "BAD"}, {"State": "BAD"}]}))
self.assertFalse(
matches({'Tables': []}))
self.assertFalse(
matches({'Tables': [{"State": "BAD"},
{"State": "BAD"},
{"State": "BAD"},
{"State": "BAD"}]}))
def test_path_all_missing_field(self):
matches = self.create_acceptor_function(
for_config={'state': 'success', 'matcher': 'pathAll',
'argument': 'Tables[].State', 'expected': 'GOOD'})
self.assertFalse(
matches({'Tables': [{"NotState": "GOOD"}, {"NotState": "BAD"}]}))
def test_path_all_matcher_does_not_receive_list(self):
matches = self.create_acceptor_function(
for_config={'state': 'success', 'matcher': 'pathAll',
'argument': 'Tables[].State', 'expected': 'GOOD'})
self.assertFalse(
matches({"NotTables": []}))
def test_single_waiter_supports_all_three_states(self):
single_waiter = {
'acceptors': [
{'state': 'success', 'matcher': 'error',
'expected': 'DoesNotExistError'},
{'state': 'success', 'matcher': 'status',
'expected': 200},
{'state': 'success', 'matcher': 'path',
'argument': 'Foo.Bar', 'expected': 'baz'},
],
}
single_waiter.update(self.boiler_plate_config)
config = SingleWaiterConfig(single_waiter)
acceptors = config.acceptors
# Each acceptors should be able to handle not matching
# any type of response.
matches_nothing = {}
self.assertFalse(acceptors[0].matcher_func(matches_nothing))
self.assertFalse(acceptors[1].matcher_func(matches_nothing))
self.assertFalse(acceptors[2].matcher_func(matches_nothing))
class TestWaitersObjects(unittest.TestCase):
def setUp(self):
pass
def client_responses_are(self, *responses, **kwargs):
operation_method = kwargs['for_operation']
operation_method.side_effect = responses
return operation_method
def create_waiter_config(self, operation='MyOperation',
delay=0, max_attempts=3,
acceptors=None):
if acceptors is None:
# Create some arbitrary acceptor that will never match.
acceptors = [{'state': 'success', 'matcher': 'status',
'expected': 1000}]
waiter_config = {
'operation': operation,
'delay': delay,
'maxAttempts': max_attempts,
'acceptors': acceptors
}
config = SingleWaiterConfig(waiter_config)
return config
def test_waiter_waits_until_acceptor_matches(self):
config = self.create_waiter_config(
max_attempts=3,
acceptors=[{'state': 'success', 'matcher': 'path',
'argument': 'Foo', 'expected': 'SUCCESS'}])
# Simulate the client having two calls that don't
# match followed by a third call that matches the
# acceptor.
operation_method = mock.Mock()
waiter = Waiter('MyWaiter', config, operation_method)
self.client_responses_are(
{'Foo': 'FAILURE'},
{'Foo': 'FAILURE'},
{'Foo': 'SUCCESS'},
for_operation=operation_method
)
waiter.wait()
self.assertEqual(operation_method.call_count, 3)
2021-08-18 17:45:16 +02:00
def test_waiter_matches_with_invalid_error_response(self):
# Verify that the call will not raise WaiterError
# because of 'Error' key in success response.
config = self.create_waiter_config(
max_attempts=3,
acceptors=[{'state': 'success', 'matcher': 'path',
'argument': 'Foo', 'expected': 'SUCCESS'}])
operation_method = mock.Mock()
waiter = Waiter('MyWaiter', config, operation_method)
self.client_responses_are(
{'Foo': 'SUCCESS', 'Error': 'foo'},
for_operation=operation_method
)
waiter.wait()
self.assertEqual(operation_method.call_count, 1)
def test_waiter_never_matches(self):
# Verify that a matcher will fail after max_attempts
# is exceeded.
config = self.create_waiter_config(max_attempts=3)
operation_method = mock.Mock()
self.client_responses_are(
{'Foo': 'FAILURE'},
{'Foo': 'FAILURE'},
{'Foo': 'FAILURE'},
for_operation=operation_method
)
waiter = Waiter('MyWaiter', config, operation_method)
with self.assertRaises(WaiterError):
waiter.wait()
def test_unspecified_errors_stops_waiter(self):
# If a waiter receives an error response, then the
# waiter immediately stops.
config = self.create_waiter_config()
operation_method = mock.Mock()
self.client_responses_are(
# This is an unknown error that's not called out
# in any of the waiter config, so when the
# waiter encounters this response it will transition
# to the failure state.
{'Error': {'Code': 'UnknownError', 'Message': 'bad error'}},
for_operation=operation_method
)
waiter = Waiter('MyWaiter', config, operation_method)
with self.assertRaises(WaiterError):
waiter.wait()
def test_last_response_available_on_waiter_error(self):
last_response = {'Error': {'Code': 'UnknownError', 'Message': 'bad error'}}
config = self.create_waiter_config()
operation_method = mock.Mock()
self.client_responses_are(last_response,
for_operation=operation_method)
waiter = Waiter('MyWaiter', config, operation_method)
with self.assertRaises(WaiterError) as e:
waiter.wait()
self.assertEqual(e.exception.last_response, last_response)
def test_unspecified_errors_propagate_error_code(self):
# If a waiter receives an error response, then the
# waiter should pass along the error code
config = self.create_waiter_config()
operation_method = mock.Mock()
error_code = 'error_message'
error_message = 'error_message'
self.client_responses_are(
# This is an unknown error that's not called out
# in any of the waiter config, so when the
# waiter encounters this response it will transition
# to the failure state.
{'Error': {'Code': error_code, 'Message': error_message}},
for_operation=operation_method
)
waiter = Waiter('MyWaiter', config, operation_method)
2021-09-22 22:53:42 +02:00
with self.assertRaisesRegex(WaiterError, error_message):
waiter.wait()
2021-01-26 16:12:20 +01:00
def _assert_failure_state_error_raised(self, acceptors, responses, expected_msg):
config = self.create_waiter_config(
acceptors=acceptors)
operation_method = mock.Mock()
waiter = Waiter('MyWaiter', config, operation_method)
self.client_responses_are(
*responses,
for_operation=operation_method
)
2021-09-22 22:53:42 +02:00
with self.assertRaisesRegex(WaiterError, expected_msg):
2021-01-26 16:12:20 +01:00
waiter.wait()
def test_waiter_failure_state_error(self):
test_cases = [
([{'state': 'failure', 'matcher': 'path',
'argument': 'Foo', 'expected': 'FAILURE'}],
[{'Foo': 'FAILURE'}],
'FAILURE'),
([{'state': 'failure', 'matcher': 'pathAll',
'argument': 'Tables[].State', 'expected': 'FAILURE'}],
[{'Tables': [{"State": "FAILURE"}]}],
'FAILURE'),
([{'state': 'failure', 'matcher': 'pathAny',
'argument': 'Tables[].State', 'expected': 'FAILURE'}],
[{'Tables': [{"State": "FAILURE"}]}],
'FAILURE'),
([{'state': 'failure', 'matcher': 'status', 'expected': 404}],
[{'ResponseMetadata': {'HTTPStatusCode': 404}}],
'404'),
([{'state': 'failure', 'matcher': 'error', 'expected': 'FailError'}],
[{'Error': {'Code': 'FailError', 'Message': 'foo'}}],
'FailError'),
([{'state': 'retry', 'matcher': 'error', 'expected': 'RetryMe'}],
[{'Success': False}]*4,
'Max attempts exceeded'),
([
{'state': 'success', 'matcher': 'status', 'expected': 200},
{'state': 'retry', 'matcher': 'error', 'expected': 'RetryMe'},
],
[{'Success': False},
{'Error': {'Code': 'RetryMe', 'Message': 'foo'}},
{'Success': False},
{'Success': False},
],
'Previously accepted state'),
]
for acceptors, responses, expected_msg in test_cases:
self._assert_failure_state_error_raised(acceptors, responses, expected_msg)
def test_waiter_transitions_to_failure_state(self):
acceptors = [
# A success state that will never be hit.
{'state': 'success', 'matcher': 'status', 'expected': 1000},
{'state': 'failure', 'matcher': 'error', 'expected': 'FailError'},
]
config = self.create_waiter_config(acceptors=acceptors)
operation_method = mock.Mock()
self.client_responses_are(
{'Nothing': 'foo'},
# And on the second attempt, a FailError is seen, which
# causes the waiter to fail fast.
{'Error': {'Code': 'FailError', 'Message': 'foo'}},
{'WillNeverGetCalled': True},
for_operation=operation_method
)
waiter = Waiter('MyWaiter', config, operation_method)
with self.assertRaises(WaiterError):
waiter.wait()
# Not only should we raise an exception, but we should have
# only called the operation_method twice because the second
# response triggered a fast fail.
self.assertEqual(operation_method.call_count, 2)
def test_waiter_handles_retry_state(self):
acceptor_with_retry_state = [
{'state': 'success', 'matcher': 'status', 'expected': 200},
{'state': 'retry', 'matcher': 'error', 'expected': 'RetryMe'},
]
config = self.create_waiter_config(
acceptors=acceptor_with_retry_state)
operation_method = mock.Mock()
self.client_responses_are(
{'Nothing': 'foo'},
{'Error': {'Code': 'RetryMe', 'Message': 'foo'}},
{'Success': True,
'ResponseMetadata': {'HTTPStatusCode': 200}},
{'NeverCalled': True},
for_operation=operation_method
)
waiter = Waiter('MyWaiter', config, operation_method)
waiter.wait()
self.assertEqual(operation_method.call_count, 3)
def test_kwargs_are_passed_through(self):
acceptors = [
{'state': 'success', 'matcher': 'error', 'expected': 'MyError'},
]
config = self.create_waiter_config(acceptors=acceptors)
operation_method = mock.Mock()
self.client_responses_are(
{'Error': {'Code': 'MyError'}},
for_operation=operation_method)
waiter = Waiter('MyWaiter', config, operation_method)
waiter.wait(Foo='foo', Bar='bar', Baz='baz')
operation_method.assert_called_with(Foo='foo', Bar='bar',
Baz='baz')
@mock.patch('time.sleep')
def test_waiter_honors_delay_time_between_retries(self, sleep_mock):
delay_time = 5
config = self.create_waiter_config(delay=delay_time)
operation_method = mock.Mock()
self.client_responses_are(
# This is an unknown error that's not called out
# in any of the waiter config, so when the
# waiter encounters this response it will transition
# to the failure state.
{'Success': False},
{'Success': False},
{'Success': False},
for_operation=operation_method
)
waiter = Waiter('MyWaiter', config, operation_method)
with self.assertRaises(WaiterError):
waiter.wait()
# We attempt three times, which means we need to sleep
# twice, once before each subsequent request.
self.assertEqual(sleep_mock.call_count, 2)
sleep_mock.assert_called_with(delay_time)
2018-01-15 17:34:17 +01:00
@mock.patch('time.sleep')
def test_waiter_invocation_config_honors_delay(self, sleep_mock):
config = self.create_waiter_config()
operation_method = mock.Mock()
self.client_responses_are(
{'Success': False},
{'Success': False},
{'Success': False},
for_operation=operation_method
)
waiter = Waiter('MyWaiter', config, operation_method)
custom_delay = 3
with self.assertRaises(WaiterError):
waiter.wait(WaiterConfig={'Delay': custom_delay})
# We attempt three times, which means we need to sleep
# twice, once before each subsequent request.
self.assertEqual(sleep_mock.call_count, 2)
sleep_mock.assert_called_with(custom_delay)
def test_waiter_invocation_config_honors_max_attempts(self):
config = self.create_waiter_config()
operation_method = mock.Mock()
self.client_responses_are(
{'Success': False},
{'Success': False},
for_operation=operation_method
)
waiter = Waiter('MyWaiter', config, operation_method)
custom_max = 2
with self.assertRaises(WaiterError):
waiter.wait(WaiterConfig={'MaxAttempts': custom_max})
self.assertEqual(operation_method.call_count, 2)
class TestCreateWaiter(unittest.TestCase):
def setUp(self):
self.waiter_config = {
'version': 2,
'waiters': {
'WaiterName': {
'operation': 'Foo',
'delay': 1,
'maxAttempts': 1,
'acceptors': [],
},
},
}
self.waiter_model = WaiterModel(self.waiter_config)
self.service_json_model = {
'metadata': {
'serviceFullName': 'Amazon MyService'
},
'operations': {
'Foo': {
'name': 'Foo',
'input': {'shape': 'FooInputOutput'},
'output': {'shape': 'FooInputOutput'}
}
},
'shapes': {
'FooInputOutput': {
'type': 'structure',
'members': {
'bar': {
'shape': 'String',
'documentation': 'Documents bar'
}
}
},
'String': {
'type': 'string'
}
}
}
self.service_model = ServiceModel(self.service_json_model, 'myservice')
self.client = mock.Mock()
self.client.meta.service_model = self.service_model
def test_can_create_waiter_from_client(self):
waiter_name = 'WaiterName'
waiter = create_waiter_with_client(
waiter_name, self.waiter_model, self.client)
self.assertIsInstance(waiter, Waiter)
def test_waiter_class_name(self):
waiter_name = 'WaiterName'
waiter = create_waiter_with_client(
waiter_name, self.waiter_model, self.client)
self.assertEqual(
waiter.__class__.__name__,
'MyService.Waiter.WaiterName'
)
def test_waiter_help_documentation(self):
waiter_name = 'WaiterName'
waiter = create_waiter_with_client(
waiter_name, self.waiter_model, self.client)
with mock.patch('sys.stdout', six.StringIO()) as mock_stdout:
help(waiter.wait)
content = mock_stdout.getvalue()
lines = [
(' Polls :py:meth:`MyService.Client.foo` every 1 '
'seconds until a successful state is reached. An error '
'is returned after 1 failed checks.'),
' **Request Syntax** ',
' ::',
' waiter.wait(',
" bar='string'",
' )',
' :type bar: string',
' :param bar: Documents bar',
' :returns: None',
]
for line in lines:
self.assertIn(line, content)
class TestOperationMethods(unittest.TestCase):
def test_normalized_op_method_makes_call(self):
client_method = mock.Mock()
op = NormalizedOperationMethod(client_method)
op(Foo='a', Bar='b')
client_method.assert_called_with(Foo='a', Bar='b')
def test_normalized_op_returns_error_response(self):
# Client objects normally throw exceptions when an error
# occurs, but we need to return the parsed error response.
client_method = mock.Mock()
op = NormalizedOperationMethod(client_method)
parsed_response = {
'Error': {'Code': 'Foo', 'Message': 'bar'}
}
exception = ClientError(parsed_response, 'OperationName')
client_method.side_effect = exception
actual_response = op(Foo='a', Bar='b')
self.assertEqual(actual_response, parsed_response)
class ServiceWaiterFunctionalTest(BaseEnvVar):
"""
This class is used as a base class if you want to functionally test the
waiters for a specific service.
"""
def setUp(self):
super(ServiceWaiterFunctionalTest, self).setUp()
self.data_path = os.path.join(
os.path.dirname(botocore.__file__), 'data')
self.environ['AWS_DATA_PATH'] = self.data_path
self.loader = Loader([self.data_path])
def get_waiter_model(self, service, api_version=None):
"""Get the waiter model for the service."""
with mock.patch('botocore.loaders.Loader.list_available_services',
return_value=[service]):
return WaiterModel(self.loader.load_service_model(
service, type_name='waiters-2', api_version=api_version))
def get_service_model(self, service, api_version=None):
"""Get the service model for the service."""
with mock.patch('botocore.loaders.Loader.list_available_services',
return_value=[service]):
return ServiceModel(
self.loader.load_service_model(
service, type_name='service-2', api_version=api_version),
service_name=service
)
class CloudFrontWaitersTest(ServiceWaiterFunctionalTest):
def setUp(self):
super(CloudFrontWaitersTest, self).setUp()
self.client = mock.Mock()
self.service = 'cloudfront'
self.old_api_versions = ['2014-05-31']
def assert_distribution_deployed_call_count(self, api_version=None):
waiter_name = 'DistributionDeployed'
waiter_model = self.get_waiter_model(self.service, api_version)
self.client.meta.service_model = self.get_service_model(
self.service, api_version)
self.client.get_distribution.side_effect = [
{'Distribution': {'Status': 'Deployed'}}
]
waiter = create_waiter_with_client(waiter_name, waiter_model,
self.client)
waiter.wait()
self.assertEqual(self.client.get_distribution.call_count, 1)
def assert_invalidation_completed_call_count(self, api_version=None):
waiter_name = 'InvalidationCompleted'
waiter_model = self.get_waiter_model(self.service, api_version)
self.client.meta.service_model = self.get_service_model(
self.service, api_version)
self.client.get_invalidation.side_effect = [
{'Invalidation': {'Status': 'Completed'}}
]
waiter = create_waiter_with_client(waiter_name, waiter_model,
self.client)
waiter.wait()
self.assertEqual(self.client.get_invalidation.call_count, 1)
def assert_streaming_distribution_deployed_call_count(
self, api_version=None):
waiter_name = 'StreamingDistributionDeployed'
waiter_model = self.get_waiter_model(self.service, api_version)
self.client.meta.service_model = self.get_service_model(
self.service, api_version)
self.client.get_streaming_distribution.side_effect = [
{'StreamingDistribution': {'Status': 'Deployed'}}
]
waiter = create_waiter_with_client(waiter_name, waiter_model,
self.client)
waiter.wait()
self.assertEqual(self.client.get_streaming_distribution.call_count, 1)
def test_distribution_deployed(self):
# Test the latest version.
self.assert_distribution_deployed_call_count()
self.client.reset_mock()
# Test previous api versions.
for api_version in self.old_api_versions:
self.assert_distribution_deployed_call_count(api_version)
self.client.reset_mock()
def test_invalidation_completed(self):
# Test the latest version.
self.assert_invalidation_completed_call_count()
self.client.reset_mock()
# Test previous api versions.
for api_version in self.old_api_versions:
self.assert_invalidation_completed_call_count(api_version)
self.client.reset_mock()
def test_streaming_distribution_deployed(self):
# Test the latest version.
self.assert_streaming_distribution_deployed_call_count()
self.client.reset_mock()
# Test previous api versions.
for api_version in self.old_api_versions:
self.assert_streaming_distribution_deployed_call_count(api_version)
self.client.reset_mock()