class SmokeTestApplication(object): # Number of seconds to wait after redeploy before starting # to poll for successful 200. _REDEPLOY_SLEEP = 20 # Seconds to wait between poll attempts after redeploy. _POLLING_DELAY = 5 def __init__(self, deployed_values, stage_name, app_name, app_dir, region): self._deployed_resources = DeployedResources(deployed_values) self.stage_name = stage_name self.app_name = app_name # The name of the tmpdir where the app is copied. self.app_dir = app_dir self._has_redeployed = False self._region = region @property def websocket_api_id(self): return self._deployed_resources.resource_values( 'websocket_api')['websocket_api_id'] @property def websocket_connect_url(self): return ("wss://{websocket_api_id}.execute-api.{region}.amazonaws.com/" "{api_gateway_stage}".format( websocket_api_id=self.websocket_api_id, region=self._region, api_gateway_stage='api', )) @property def websocket_message_handler_arn(self): return self._deployed_resources.resource_values( 'websocket_message')['lambda_arn'] @property def region(self): return self._region def redeploy_once(self): # Redeploy the application once. If a redeploy # has already happened, this function is a noop. if self._has_redeployed: return new_file = os.path.join(self.app_dir, 'app-redeploy.py') original_app_py = os.path.join(self.app_dir, 'app.py') shutil.move(original_app_py, original_app_py + '.bak') shutil.copy(new_file, original_app_py) self._clear_app_import() _deploy_app(self.app_dir) self._has_redeployed = True # Give it settling time before running more tests. time.sleep(self._REDEPLOY_SLEEP) def _clear_app_import(self): # Now that we're using `import` instead of `exec` we need # to clear out sys.modules in order to pick up the new # version of the app we just copied over. del sys.modules['app']
def test_deployed_api_mapping_resource(): deployed = DeployedResources( {'resources': [ {'name': 'foo'}, { "name": "api_gateway_custom_domain", "resource_type": "domain_name", "api_mapping": [ { "key": "path_key" } ] } ]} ) name = 'api_gateway_custom_domain.api_mapping.path_key' result = deployed.resource_values(name) assert result == { "name": "api_gateway_custom_domain", "resource_type": "domain_name", "api_mapping": [ { "key": "path_key" } ] }
def test_deployed_resource_exists(): deployed = DeployedResources({'resources': [{'name': 'foo'}]}) assert deployed.resource_values('foo') == {'name': 'foo'} assert deployed.resource_names() == ['foo']
def test_deployed_resource_does_not_exist(): deployed = DeployedResources({'resources': [{'name': 'foo'}]}) with pytest.raises(ValueError): deployed.resource_values('bar')
class SmokeTestApplication(object): # Number of seconds to wait after redeploy before starting # to poll for successful 200. _REDEPLOY_SLEEP = 20 # Seconds to wait between poll attempts after redeploy. _POLLING_DELAY = 5 def __init__(self, deployed_values, stage_name, app_name, app_dir, region): self._deployed_resources = DeployedResources(deployed_values) self.stage_name = stage_name self.app_name = app_name # The name of the tmpdir where the app is copied. self.app_dir = app_dir self._has_redeployed = False self._region = region @property def url(self): return ( "https://{rest_api_id}.execute-api.{region}.amazonaws.com/" "{api_gateway_stage}".format(rest_api_id=self.rest_api_id, region=self._region, api_gateway_stage='api') ) @property def rest_api_id(self): return self._deployed_resources.resource_values( 'rest_api')['rest_api_id'] def get_json(self, url): if not url.startswith('/'): url = '/' + url response = requests.get(self.url + url) response.raise_for_status() return response.json() def redeploy_once(self): # Redeploy the application once. If a redeploy # has already happened, this function is a noop. if self._has_redeployed: return new_file = os.path.join(self.app_dir, 'app-redeploy.py') original_app_py = os.path.join(self.app_dir, 'app.py') shutil.move(original_app_py, original_app_py + '.bak') shutil.copy(new_file, original_app_py) self._clear_app_import() _deploy_app(self.app_dir) self._has_redeployed = True # Give it settling time before running more tests. time.sleep(self._REDEPLOY_SLEEP) self._wait_for_stablize() @retry(max_attempts=10, delay=5) def _wait_for_stablize(self): # After a deployment we sometimes need to wait for # API Gateway to propagate all of its changes. # We're going to give it num_attempts to give us a # 200 response before failing. try: return self.get_json('/') except requests.exceptions.HTTPError: pass def _clear_app_import(self): # Now that we're using `import` instead of `exec` we need # to clear out sys.modules in order to pick up the new # version of the app we just copied over. del sys.modules['app']
class SmokeTestApplication(object): # Number of seconds to wait after redeploy before starting # to poll for successful 200. _REDEPLOY_SLEEP = 20 # Seconds to wait between poll attempts after redeploy. _POLLING_DELAY = 5 def __init__(self, deployed_values, stage_name, app_name, app_dir, region): self._deployed_resources = DeployedResources(deployed_values) self.stage_name = stage_name self.app_name = app_name # The name of the tmpdir where the app is copied. self.app_dir = app_dir self._has_redeployed = False self._region = region @property def url(self): return ("https://{rest_api_id}.execute-api.{region}.amazonaws.com/" "{api_gateway_stage}".format(rest_api_id=self.rest_api_id, region=self._region, api_gateway_stage='api')) @property def rest_api_id(self): return self._deployed_resources.resource_values( 'rest_api')['rest_api_id'] @property def websocket_api_id(self): return self._deployed_resources.resource_values( 'websocket_api')['websocket_api_id'] @property def websocket_connect_url(self): return ("wss://{websocket_api_id}.execute-api.{region}.amazonaws.com/" "{api_gateway_stage}".format( websocket_api_id=self.websocket_api_id, region=self._region, api_gateway_stage='api', )) def get_json(self, url): if not url.startswith('/'): url = '/' + url response = requests.get(self.url + url) response.raise_for_status() return response.json() def redeploy_once(self): # Redeploy the application once. If a redeploy # has already happened, this function is a noop. if self._has_redeployed: return new_file = os.path.join(self.app_dir, 'app-redeploy.py') original_app_py = os.path.join(self.app_dir, 'app.py') shutil.move(original_app_py, original_app_py + '.bak') shutil.copy(new_file, original_app_py) _deploy_app(self.app_dir) self._has_redeployed = True # Give it settling time before running more tests. time.sleep(self._REDEPLOY_SLEEP) self._wait_for_stablize() @retry(max_attempts=10, delay=5) def _wait_for_stablize(self): # After a deployment we sometimes need to wait for # API Gateway to propagate all of its changes. # We're going to give it num_attempts to give us a # 200 response before failing. try: return self.get_json('/') except requests.exceptions.HTTPError: pass
def test_deployed_resource_exists(): deployed = DeployedResources( {'resources': [{'name': 'foo'}]} ) assert deployed.resource_values('foo') == {'name': 'foo'} assert deployed.resource_names() == ['foo']
def test_deployed_resource_does_not_exist(): deployed = DeployedResources( {'resources': [{'name': 'foo'}]} ) with pytest.raises(ValueError): deployed.resource_values('bar')
class SmokeTestApplication(object): # Number of seconds to wait after redeploy before starting # to poll for successful 200. _REDEPLOY_SLEEP = 30 # Seconds to wait between poll attempts after redeploy. _POLLING_DELAY = 5 # Number of successful wait attempts before we consider the app # stabilized. _NUM_SUCCESS = 3 def __init__(self, deployed_values, stage_name, app_name, app_dir, region): self._deployed_resources = DeployedResources(deployed_values) self.stage_name = stage_name self.app_name = app_name # The name of the tmpdir where the app is copied. self.app_dir = app_dir self._has_redeployed = False self._region = region @property def url(self): return ("https://{rest_api_id}.execute-api.{region}.amazonaws.com/" "{api_gateway_stage}".format(rest_api_id=self.rest_api_id, region=self._region, api_gateway_stage='api')) @property def rest_api_id(self): return self._deployed_resources.resource_values( 'rest_api')['rest_api_id'] @property def websocket_api_id(self): return self._deployed_resources.resource_values( 'websocket_api')['websocket_api_id'] @property def websocket_connect_url(self): return ("wss://{websocket_api_id}.execute-api.{region}.amazonaws.com/" "{api_gateway_stage}".format( websocket_api_id=self.websocket_api_id, region=self._region, api_gateway_stage='api', )) @retry(max_attempts=10, delay=5) def get_json(self, url): try: return self._get_json(url) except requests.exceptions.HTTPError: pass def _get_json(self, url): if not url.startswith('/'): url = '/' + url response = requests.get(self.url + url) response.raise_for_status() return response.json() @retry(max_attempts=10, delay=5) def get_response(self, url, headers=None): try: return self._send_request('GET', url, headers=headers) except InternalServerError: pass def _send_request(self, http_method, url, headers=None, data=None): kwargs = {} if headers is not None: kwargs['headers'] = headers if data is not None: kwargs['data'] = data response = requests.request(http_method, self.url + url, **kwargs) if response.status_code >= 500: raise InternalServerError() return response @retry(max_attempts=10, delay=5) def post_response(self, url, headers=None, data=None): try: return self._send_request('POST', url, headers=headers, data=data) except InternalServerError: pass @retry(max_attempts=10, delay=5) def put_response(self, url): try: return self._send_request('PUT', url) except InternalServerError: pass @retry(max_attempts=10, delay=5) def options_response(self, url): try: return self._send_request('OPTIONS', url) except InternalServerError: pass def redeploy_once(self): # Redeploy the application once. If a redeploy # has already happened, this function is a noop. if self._has_redeployed: return new_file = os.path.join(self.app_dir, 'app-redeploy.py') original_app_py = os.path.join(self.app_dir, 'app.py') shutil.move(original_app_py, original_app_py + '.bak') shutil.copy(new_file, original_app_py) _deploy_app(self.app_dir) self._has_redeployed = True # Give it settling time before running more tests. time.sleep(self._REDEPLOY_SLEEP) for _ in range(self._NUM_SUCCESS): self._wait_for_stablize() time.sleep(self._POLLING_DELAY) def _wait_for_stablize(self): # After a deployment we sometimes need to wait for # API Gateway to propagate all of its changes. # We're going to give it num_attempts to give us a # 200 response before failing. return self.get_json('/')