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']
示例#2
0
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')
示例#5
0
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']
示例#6
0
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
示例#7
0
def test_deployed_resource_exists():
    deployed = DeployedResources(
        {'resources': [{'name': 'foo'}]}
    )
    assert deployed.resource_values('foo') == {'name': 'foo'}
    assert deployed.resource_names() == ['foo']
示例#8
0
def test_deployed_resource_does_not_exist():
    deployed = DeployedResources(
        {'resources': [{'name': 'foo'}]}
    )
    with pytest.raises(ValueError):
        deployed.resource_values('bar')
示例#9
0
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('/')