def test_stack_exists() -> None: """ Tests that stack actually was created. :return: No return. """ client = Credentials().boto_session.client('cloudformation') stacks = client.list_stacks( StackStatusFilter=['CREATE_COMPLETE'])['StackSummaries'] stacks = [stack['StackName'] for stack in stacks] assert TestingStack.name() in stacks
def test_stack_exists() -> None: """ Tests that stack actually was created. :return: No return. """ # The stack name is provided by the cf testing manager. stack_name = f'{TestingManager.get_global_prefix()}TestStack' client = Credentials().boto_session.client('cloudformation') stacks = client.list_stacks(StackStatusFilter=['CREATE_COMPLETE'])['StackSummaries'] stacks = [stack['StackName'] for stack in stacks] assert stack_name in stacks
def test_invoke_function() -> None: """ Invokes a backend lambda function and tests its response. :return: No return. """ function_name = Infrastructure.get_output( Infrastructure.LAMBDA_FUNCTION_NAME_KEY) logger.info(f'Invoking function: {function_name}.') session = Credentials().boto_session response = session.client('lambda').invoke( FunctionName=function_name, InvocationType='RequestResponse') logger.info(f'Response from lambda function: {response}.')
def test_RESOURCE_lambda_layer_WITH_deployed_lambda_function_4_EXPECT_execution_successful(): """ Test whether a layer provides necessary functionality. :return: No return. """ # Create client for Lambda service. lambda_client = Credentials().boto_session.client('lambda') # Invoke a specific lambda function. response = lambda_client.invoke( FunctionName=MainStack.get_output(MainStack.LAMBDA_FUNCTION_4_NAME_KEY), InvocationType='RequestResponse', Payload=json.dumps({'heartbeat': True}) ) # If Lambda function was not executed, it returns a string 'null'. data = response['Payload'].read().decode() assert data == 'null'
def test_RESOURCE_lambda_layer_WITH_deployed_lambda_function_2_EXPECT_execution_successful(): """ Test whether the layer provides necessary functionality. :return: No return. """ # Create client for lambda service. lambda_client = Credentials().boto_session.client('lambda') # Invoke specific lambda function. response = lambda_client.invoke( FunctionName=MainStack.get_output(MainStack.LAMBDA_FUNCTION_2_NAME_KEY), InvocationType='RequestResponse' ) # Parse the result. payload: StreamingBody = response['Payload'] data = [item.decode() for item in payload.iter_lines()] print(data)
def load_outputs( credentials: Optional[Credentials] = None) -> Dict[str, str]: """ Loads this stack's outputs. :param credentials: Optional credentials for AWS API commands. :return: All outputs in a form of a dictionary. """ credentials = credentials or Credentials() return CfOutputs(credentials.boto_session).get_outputs( TestingStack.name())[TestingStack.name()]
def test_RESOURCE_lambda_layer_WITH_with_unit_tests_EXPECT_execution_successful_tests_pass( ): """ Test whether the layer provides necessary functionality and unit tests pass. :return: No return. """ # Create client for lambda service. lambda_client = Credentials().boto_session.client('lambda') # Invoke specific lambda function. response = lambda_client.invoke(FunctionName=MainStack.get_output( MainStack.LAMBDA_FUNCTION_UNIT_TESTS_NAME_KEY), InvocationType='RequestResponse') # Parse the result. payload: StreamingBody = response['Payload'] data = [item.decode() for item in payload.iter_lines()] data = json.loads(''.join(data)) # Assert that the result is as expected i.e. all unit tests inside lambda function have passed. assert data.get('ExitCode') == 0, data
def test_RESOURCE_lambda_layer_WITH_deployed_lambda_function_1_EXPECT_execution_successful(): """ Test whether the layer provides necessary functionality. :return: No return. """ # Create client for lambda service. lambda_client = Credentials().boto_session.client('lambda') # Invoke specific lambda function. response = lambda_client.invoke( FunctionName=MainStack.get_output(MainStack.LAMBDA_FUNCTION_1_NAME_KEY), InvocationType='RequestResponse' ) # Parse the result. payload: StreamingBody = response['Payload'] data = [item.decode() for item in payload.iter_lines()] data = json.loads(''.join(data)) # Assert that the result is as expected. assert data['Boto3Version'] == '1.16.35', data assert data['BotocoreVersion'] == '1.19.35', data
class StackWaiter: """ Waiter class that waits for a cloud formation stack to stabilize. """ def __init__(self, stack_name: str): self.__stack_name = stack_name self.__client = Credentials().boto_session.client('cloudformation') def wait(self, current_iteration: int = 0, max_iterations: int = 100, sleep_time: int = 5) -> None: """ Waits for a given stack to stabilize. E.g. waits when CREATE_IN_PROGRESS turns into CREATE_COMPLETE. :param current_iteration: This is a recursive function. This parameter indicates current iteration. :param max_iterations: Specifies maximum amount of iterations allowed. :param sleep_time: Specifies how long to sleep between iterations. :return: No return. """ if current_iteration == max_iterations: raise RecursionError() stack_status = self.__get_stack_status() or '' logger.info(f'Stack status: {stack_status}.') if '_IN_PROGRESS' in stack_status: time.sleep(sleep_time) self.wait(current_iteration + 1, max_iterations, sleep_time) def __get_stack_status(self) -> Optional[str]: """ Gets given stack status e.g. CREATE_IN_PROGRESS. :return: Stack status. """ try: stack = self.__client.describe_stacks(StackName=self.__stack_name)['Stacks'][0] return stack['StackStatus'] except ClientError as ex: # Retrieve code and message from an error. code = ex.response['Error']['Code'] message = ex.response['Error']['Message'] # If stack does not exist, its fine, just return None. if code == 'ValidationError' and 'does not exist' in message.lower(): return # Otherwise throw an exception. raise
def test_deployed() -> None: """ Tests that deployments were created and stage was deployed. :return: No return. """ response = Credentials().boto_session.client( 'apigatewayv2').get_deployments( ApiId=TestingInfrastructure.get_output('ApiId'), MaxResults='25') items = response['Items'] print(len(items)) print(items) assert len(list(items)) >= 5 for deployment in items: assert deployment['AutoDeployed'] is False assert deployment['DeploymentStatus'] == 'DEPLOYED'
import os from b_aws_testing_framework.credentials import Credentials from b_aws_testing_framework.tools.cdk_testing.cdk_tool_config import CdkToolConfig from b_aws_testing_framework.tools.cdk_testing.testing_manager import TestingManager CDK_PATH = f'{os.path.dirname(os.path.abspath(__file__))}' MANAGER = TestingManager( Credentials(), CdkToolConfig(CDK_PATH, destroy_before_preparing=False)) def pytest_sessionstart(session): MANAGER.set_global_prefix() MANAGER.prepare_infrastructure() def pytest_sessionfinish(session, exitstatus): MANAGER.destroy_infrastructure()
def pytest_sessionstart(session): """ Called after the Session object has been created and before performing collection and entering the run test loop. """ TestingManager(Credentials(), CdkToolConfig(CDK_PATH)).prepare_infrastructure()
def __init__(self, stack_name: str): self.__stack_name = stack_name self.__client = Credentials().boto_session.client('cloudformation')
def pytest_configure(*args, **kwargs): """ Called after command line options have been parsed and all plugins and initial conftest files been loaded. """ TestingManager(Credentials(), CdkToolConfig(CDK_PATH)).prepare_infrastructure()
from os.path import abspath as apat from os.path import dirname as dirn from b_aws_testing_framework.credentials import Credentials from b_aws_testing_framework.tools.cdk_testing.cdk_tool_config import CdkToolConfig from b_aws_testing_framework.tools.cdk_testing.testing_manager import TestingManager CDK_PATH = dirn(apat(__file__)) MANAGER = TestingManager(Credentials(), CdkToolConfig(CDK_PATH)) def pytest_configure(*args, **kwargs): """ Called after command line options have been parsed and all plugins and initial conftest files been loaded. """ MANAGER.set_global_prefix() MANAGER.prepare_infrastructure() def pytest_unconfigure(*args, **kwargs): """ Called before test process is exited. """ MANAGER.destroy_infrastructure()
def pytest_unconfigure(*args, **kwargs): """ Called before test process is exited. """ TestingManager(Credentials(), CdkToolConfig(CDK_PATH)).destroy_infrastructure()
def pytest_sessionfinish(session, exitstatus): """ Called after whole test run finished, right before returning the exit status to the system. """ TestingManager(Credentials(), CdkToolConfig(CDK_PATH)).destroy_infrastructure()