def test_dr_clone(self): setup_stack() dr_stack = aws_stack.Stack(CONF_CLONE_STACKNAME, REGION) clone_params = get_stack_params() next(param for param in clone_params if param['ParameterKey'] == 'DeployEnvironment')['ParameterValue'] = 'dr' clone_params.append({ 'ParameterKey': 'StackName', 'ParameterValue': CONF_CLONE_STACKNAME }) # setup mocks dr_stack.run_sql = MagicMock(return_value=False) dr_stack.validate_service_responding = MagicMock(return_value=True) dr_stack.wait_stack_action_complete = MagicMock(return_value=True) with app.app_context(): outcome = dr_stack.clone( stack_params=clone_params, template_file=TEMPLATE_FILE_CLONE, app_type='confluence', clustered='true', creator='test-user', region=REGION, cloned_from=CONF_STACKNAME, ) assert outcome dr_stack.run_sql.assert_not_called()
def test_execute_changeset(self): setup_stack() cfn = boto3.client('cloudformation', REGION) stack = cfn.describe_stacks(StackName=CONF_STACKNAME) mystack = aws_stack.Stack(CONF_STACKNAME, REGION) params_for_update = stack['Stacks'][0]['Parameters'] for param in params_for_update: if param['ParameterKey'] == 'TomcatConnectionTimeout': param['ParameterValue'] = '20001' # for other params, delete the value and set UsePreviousValue to true else: del param['ParameterValue'] param['UsePreviousValue'] = True with app.app_context(): change_set = mystack.create_change_set(params_for_update, TEMPLATE_FILE) change_set_name = change_set['Id'] mystack.validate_service_responding = MagicMock(return_value=True) result = mystack.execute_change_set(change_set_name) assert result is True cfn = boto3.client('cloudformation', REGION) stacks = cfn.describe_stacks(StackName=CONF_STACKNAME) assert [ param for param in stacks['Stacks'][0]['Parameters'] if param['ParameterKey'] == 'TomcatConnectionTimeout' ][0]['ParameterValue'] == '20001'
def test_clone(self): setup_stack() clone_stack = aws_stack.Stack(CONF_CLONE_STACKNAME, REGION) clone_params = get_stack_params() clone_params.append({ 'ParameterKey': 'StackName', 'ParameterValue': CONF_CLONE_STACKNAME }) # setup mocks clone_stack.full_restart = MagicMock(return_value=True) clone_stack.get_stacknodes = MagicMock( return_value=[{ 'i-0bcf57c789637b10f': '10.111.22.333' }, { 'i-0fdacb1ab66016786': '10.111.22.444' }]) clone_stack.get_sql = MagicMock( return_value='Select * from cwd_user limit 1;') clone_stack.validate_service_responding = MagicMock(return_value=True) clone_stack.wait_stack_action_complete = MagicMock(return_value=True) with app.app_context(): outcome = clone_stack.clone( stack_params=clone_params, template_file=TEMPLATE_FILE_CLONE, app_type='confluence', clustered='true', creator='test-user', region=REGION, cloned_from=CONF_STACKNAME, ) assert outcome stacks = boto3.client( 'cloudformation', REGION).describe_stacks(StackName=CONF_CLONE_STACKNAME) assert stacks['Stacks'][0]['StackName'] == CONF_CLONE_STACKNAME
def test_upgrade(self): setup_stack() mystack = aws_stack.Stack(CONF_STACKNAME, REGION) assert mystack.get_param_value('ProductVersion') == '6.11.0' # mock status mystack.check_service_status = MagicMock(return_value='RUNNING') # upgrade with app.app_context(): mystack.upgrade('6.11.1') assert mystack.get_param_value('ProductVersion') == '6.11.1'
def test_thread_dump_links(self): setup_stack() mystack = aws_stack.Stack(CONF_STACKNAME, REGION) # upload a dummy thread dump s3 = boto3.client('s3') s3.upload_file(os.path.relpath(DUMMY_FILE), app.config['S3_BUCKET'], f'diagnostics/{mystack.stack_name}/threaddump.zip') with app.app_context(): thread_dump_links = mystack.get_thread_dump_links() assert len(thread_dump_links) > 0
def test_node_cpu(self): setup_stack() mystack = aws_stack.Stack(CONF_STACKNAME, REGION) mystack.get_stacknodes = MagicMock( return_value=[{ 'i-0bcf57c789637b10f': '10.111.22.333' }, { 'i-0fdacb1ab66016786': '10.111.22.444' }]) result = mystack.get_node_cpu('10.111.22.333') # moto returns no metrics, but this proves that the function completed successfully assert result == {}
def test_restarts(self): setup_stack() mystack = aws_stack.Stack(CONF_STACKNAME, REGION) # setup mocks mystack.check_service_status = MagicMock(return_value='RUNNING') mystack.check_node_status = MagicMock(return_value='RUNNING') mystack.get_tag = MagicMock(return_value='Confluence') mystack.is_app_clustered = MagicMock(return_value=True) drain_target_states = [ 'healthy', 'draining', 'notregistered', 'initial', 'initial', 'healthy', 'healthy', 'draining', 'notregistered', 'initial', 'initial', 'healthy' ] no_drain_target_states = [ 'initial', 'initial', 'healthy', 'initial', 'initial', 'healthy' ] with app.app_context(): # perform restarts # expect failures as node count is 0 rolling_result = mystack.rolling_restart(False) assert rolling_result is False full_result = mystack.full_restart() assert full_result is False # mock nodes and target states mystack.get_stacknodes = MagicMock( return_value=[{ 'i-0bcf57c789637b10f': '10.111.22.333' }, { 'i-0fdacb1ab66016786': '10.111.22.444' }]) mystack.get_target_state = MagicMock( side_effect=no_drain_target_states) # test rolling restart with and without draining rolling_result = mystack.rolling_restart(False) assert rolling_result is True mystack.get_target_state = MagicMock( side_effect=drain_target_states) rolling_drain_result = mystack.rolling_restart(True) assert rolling_drain_result is True # test full restart full_result = mystack.full_restart() assert full_result is True # test node restart with and without draining mystack.get_target_state = MagicMock( side_effect=no_drain_target_states) restart_node_result = mystack.restart_node('10.111.22.333', False) assert restart_node_result is True mystack.get_target_state = MagicMock( side_effect=drain_target_states) restart_node_drain_result = mystack.restart_node( '10.111.22.444', True) assert restart_node_drain_result is True
def test_tagging(self): setup_stack() mystack = aws_stack.Stack(CONF_STACKNAME, REGION) tags_to_add = [{ 'Key': 'Tag1', 'Value': 'Value1' }, { 'Key': 'Tag2', 'Value': 'Value2' }] tagged = mystack.tag(tags_to_add) assert tagged tags = mystack.get_tags() assert tags == tags_to_add
def test_toggle_node(self): setup_stack() mystack = aws_stack.Stack(CONF_STACKNAME, REGION) # setup mocks mystack.check_service_status = MagicMock(return_value='RUNNING') mystack.check_node_status = MagicMock(return_value='RUNNING') mystack.get_tag = MagicMock(return_value='Confluence') mystack.is_app_clustered = MagicMock(return_value=True) deregister_target_states = [ 'healthy', 'healthy', 'draining', 'draining', 'notregistered' ] register_target_states = [ 'notregistered', 'notregistered', 'initial', 'initial', 'healthy' ] with app.app_context(): with app.test_request_context(''): session = {'saml': {'subject': 'UserA'}} # mock nodes mystack.get_stacknodes = MagicMock( return_value=[{ 'i-0bcf57c789637b10f': '10.111.22.333' }, { 'i-0fdacb1ab66016786': '10.111.22.444' }]) # register node initially mystack.get_target_state = MagicMock( side_effect=register_target_states) register_result = mystack.toggle_node_registration( node='10.111.22.333') assert register_result is True # deregister node mystack.get_target_state = MagicMock( side_effect=deregister_target_states) deregister_result = mystack.toggle_node_registration( node='10.111.22.333') assert deregister_result is True # re-register node mystack.get_target_state = MagicMock( side_effect=register_target_states) register_result = mystack.toggle_node_registration( node='10.111.22.333') assert register_result is True # confirm a draining node re-registers mystack.get_target_state = MagicMock(side_effect=['draining']) mystack.wait_node_registered = MagicMock(return_value=True) mystack.toggle_node_registration(node='10.111.22.333') assert mystack.wait_node_registered.called
def test_sns(self): setup_stack() mystack = aws_stack.Stack(CONF_STACKNAME, REGION) action_msg = 'test msg' with app.test_request_context(''): session = {'saml': {'subject': 'UserA'}} topic_arn = mystack.get_sns_topic_arn() # confirm there is no topic for forge msgs assert topic_arn is None # send a msg published_msg = mystack.send_sns_msg(action_msg) topic_arn = mystack.get_sns_topic_arn() # confirm a topic has been created for forge msgs assert topic_arn is not None # confirm the message was sent successfully assert published_msg is not None assert published_msg['MessageId'] is not None
def setup_stack(): # not using pytest.setup_class or a fixture here as the moto environment does not persist - it tears itself down # each test must call this at the start with app.app_context(): setup_env_resources() mystack = aws_stack.Stack(CONF_STACKNAME, REGION) # setup mocks mystack.validate_service_responding = MagicMock(return_value=True) mystack.wait_stack_action_complete = MagicMock(return_value=True) # create stack outcome = mystack.create(get_stack_params(), TEMPLATE_FILE, 'confluence', 'true', 'test_user', REGION, cloned_from=False) assert outcome
def test_thread_and_heap_dumps(self): setup_stack() mystack = aws_stack.Stack(CONF_STACKNAME, REGION) # setup mocks mystack.get_stacknodes = MagicMock( return_value=[{ 'i-0bcf57c789637b10f': '10.111.22.333' }, { 'i-0fdacb1ab66016786': '10.111.22.444' }]) with app.app_context(): # test thread dumps thread_result = mystack.thread_dump(alsoHeaps=False) assert thread_result is True single_node_thread_result = mystack.thread_dump( node='10.111.22.333', alsoHeaps=False) assert single_node_thread_result is True # test heap dumps heap_result = mystack.heap_dump() assert heap_result is True single_node_heap_result = mystack.heap_dump(node='10.111.22.333') assert single_node_heap_result is True
def test_destroy(self): setup_stack() s3_bucket = app.config['S3_BUCKET'] mystack = aws_stack.Stack(CONF_STACKNAME, REGION) with app.app_context(): # upload a changelog and thread dump s3 = boto3.client('s3') s3.upload_file(os.path.relpath(DUMMY_FILE), s3_bucket, f'changelogs/{mystack.stack_name}') s3.upload_file(os.path.relpath(DUMMY_FILE), s3_bucket, f'changelogs/{mystack.stack_name}/changelog.log') s3.upload_file(os.path.relpath(DUMMY_FILE), s3_bucket, f'diagnostics/{mystack.stack_name}') s3.upload_file(os.path.relpath(DUMMY_FILE), s3_bucket, f'diagnostics/{mystack.stack_name}/threaddump.zip') # confirm files exist changelogs = s3.list_objects_v2( Bucket=s3_bucket, Prefix=f'changelogs/{mystack.stack_name}/') assert len(changelogs['Contents']) == 1 diagnostics = s3.list_objects_v2( Bucket=s3_bucket, Prefix=f'diagnostics/{mystack.stack_name}/') assert len(diagnostics['Contents']) == 1 # confirm stack exists cfn = boto3.client('cloudformation', REGION) stacks = cfn.describe_stacks() assert len(stacks['Stacks']) == 1 # confirm stack has been deleted mystack.destroy(delete_changelogs=True, delete_threaddumps=True) stacks = cfn.describe_stacks() assert len(stacks['Stacks']) == 0 # confirm changelogs have been deleted changelogs = s3.list_objects_v2( Bucket=s3_bucket, Prefix=f'changelogs/{mystack.stack_name}/') assert 'Contents' not in changelogs # confirm threaddumps have been deleted diagnostics = s3.list_objects_v2( Bucket=s3_bucket, Prefix=f'diagnostics/{mystack.stack_name}/') assert 'Contents' not in diagnostics
def test_clone_destroy_failed(self): setup_stack() clone_stack = aws_stack.Stack(CONF_CLONE_STACKNAME, REGION) clone_params = get_stack_params() clone_params.append({ 'ParameterKey': 'StackName', 'ParameterValue': CONF_CLONE_STACKNAME }) # setup mocks clone_stack.wait_stack_action_complete = MagicMock(return_value=False) clone_stack.create = MagicMock(return_value=True) with app.app_context(): outcome = clone_stack.clone( stack_params=clone_params, template_file=TEMPLATE_FILE_CLONE, app_type='confluence', clustered='true', creator='test-user', region=REGION, cloned_from=CONF_STACKNAME, ) assert not outcome clone_stack.create.assert_not_called()
def test_create_changeset(self): setup_stack() cfn = boto3.client('cloudformation', REGION) stack = cfn.describe_stacks(StackName=CONF_STACKNAME) mystack = aws_stack.Stack(CONF_STACKNAME, REGION) params_for_update = stack['Stacks'][0]['Parameters'] for param in params_for_update: if param['ParameterKey'] == 'TomcatConnectionTimeout': param['ParameterValue'] = '20001' # for other params, delete the value and set UsePreviousValue to true else: del param['ParameterValue'] param['UsePreviousValue'] = True with app.app_context(): result = mystack.create_change_set(params_for_update, TEMPLATE_FILE) assert result['ResponseMetadata']['HTTPStatusCode'] == 200 cfn = boto3.client('cloudformation', REGION) change_set = cfn.describe_change_set(ChangeSetName=result['Id'], StackName=CONF_STACKNAME) assert [ param for param in change_set['Parameters'] if param['ParameterKey'] == 'TomcatConnectionTimeout' ][0]['ParameterValue'] == '20001'