Skip to content

Commit

Permalink
Merge pull request #5 from waterbear-cloud/ftest-more
Browse files Browse the repository at this point in the history
Ftest more
  • Loading branch information
kteague committed Jul 9, 2019
2 parents 4852c0b + dc97116 commit 4e0fc43
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 65 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Changelog for aim

- CLI reports human readable validation errors from AIM project configuration files

- "aim ftest" command added to run functional tests on the "aim init project"
templates. This command will be expanded in the future so you can test your
own aim projects.


1.0.0 (2019-07-06)
------------------
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
'console_scripts': [
'aim = aim.commands.cli:cli',
'aim_doc = aim.doc.docschema:aim_schema_generate',
'aim_ftest = aim.tests.functional:main',
]
},
extras_require={
Expand Down
2 changes: 2 additions & 0 deletions src/aim/commands/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from aim.commands.cmd_describe import describe_command
from aim.commands.cmd_validate import validate_command
from aim.commands.cmd_shell import shell_command
from aim.commands.cmd_ftest import ftest_command
from aim.commands.helpers import pass_aim_context

@click.group()
Expand All @@ -28,3 +29,4 @@ def cli(ctx, verbose):
cli.add_command(describe_command)
cli.add_command(validate_command)
cli.add_command(shell_command)
cli.add_command(ftest_command)
24 changes: 24 additions & 0 deletions src/aim/commands/cmd_ftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
Functional test suite for AIM for the cookiecutter generated "aim init project" AIM projects
"""

import click
from aim.commands.helpers import pass_aim_context, handle_exceptions
from aim.config.aim_context import AimContext
from aim.commands.cookiecutter_test import test_cookiecutter_template, starting_template_mapping

@click.command('ftest', short_help='Functional testing of an AIM project', help="""
Tests an AIM project by first creating a project with 'aim init project',
provisions an environment, then does real-world functional testing on the environment,
then deletes all the AWS resources.
STARTING_TEMPLATE must be the name of a aim init starting_template, e.g. 'simple-web-app'""")
@click.argument('starting_template', default='')
@pass_aim_context
@handle_exceptions
def ftest_command(ctx, starting_template):
"""Functional testing of an AIM project"""
print("Starting AIM functional tests")
template_number = starting_template_mapping[starting_template]
test_cookiecutter_template(starting_template, template_number, ctx.verbose)

110 changes: 110 additions & 0 deletions src/aim/commands/cookiecutter_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""
Test harnesses for aim init cookiecutter templates
"""

import aim.models
import boto3
import os
import pexpect
import requests
import shutil
import sys
import subprocess


starting_template_mapping = {
'simple-web-app': '2',
}

def test_cookiecutter_template(starting_template, template_number, verbose):
init_test_dir()
test_cmd_init(verbose)
test_cmd_provision_keypair(verbose)
test_cmd_provision_netenv(verbose)
fname = starting_template.replace('-','_')
function = getattr(aim.commands.cookiecutter_test, 'test_provisioned_{}'.format(fname))
function(verbose)
test_delete_netenv(verbose)

def init_test_dir():
"""Create a tmpdir for tests to run in"""
# ToDo: make a real tmpdir ...
subprocess.call(["mkdir","aim_ftest"])
os.chdir('aim_ftest')
try:
shutil.rmtree('tproj')
except FileNotFoundError:
pass

def test_cmd_init(verbose):
print("Testing 'aim init project'")
child = pexpect.spawn('aim init project')
if verbose:
child.logfile = sys.stdout.buffer
child.expect('.*Choose.*')
child.sendline('2')
child.expect('project_name .*: ')
child.sendline('tproj')
child.expect('project_title .*: ')
child.sendline('Test Project')
child.expect('network_environment_name .*: ')
child.sendline('tnet')
child.expect('network_environment_title .*: ')
child.sendline('Test Network')
child.expect('application_name .*: ')
child.sendline('tapp')
child.expect('application_title .*: ')
child.sendline('Test Application')
child.expect('aws_default_region .*: ')
child.sendline('us-west-2')
child.expect('master_account_id .*: ')
child.sendline(os.environ['AIM_MASTER_ACCOUNT_ID'])
child.expect('master_admin_iam_username .*: ')
child.sendline(os.environ['AIM_MASTER_ADMIN_IAM_USERNAME'])
child.expect('aws_access_key_id .*: ')
child.sendline(os.environ['AIM_AWS_ACCESS_KEY_ID'])
child.expect('aws_secret_access_key .*: ')
child.sendline(os.environ['AIM_AWS_SECRET_ACCESS_KEY'])
child.interact()

def test_cmd_provision_keypair(verbose):
print("Testing 'aim provision EC2 keypair'")
child = pexpect.spawn('aim provision EC2 keypair aimkeypair --home tproj')
if verbose:
child.logfile = sys.stdout.buffer
child.interact()

def test_cmd_provision_netenv(verbose):
print("Testing 'aim provsion NetEnv tnet'")
child = pexpect.spawn('aim provision NetEnv tnet --home tproj')
if verbose:
child.logfile = sys.stdout.buffer
child.interact()

def test_delete_netenv(verbose):
print("Deleting 'aim delete NetEnv tnet --home tproj'")
child = pexpect.spawn('aim delete NetEnv tnet --home tproj')
if verbose:
child.logfile = sys.stdout.buffer
child.expect('.*Proceed with deletion.*')
child.sendline('y')
child.interact()

# Tests for simple-web-app

def test_web_server_responds(verbose):
project = aim.models.load_project_from_yaml(AimReference(), 'tproj')
web_asg = project['ne']['tnet']['dev']['us-west-2'].applications['tapp'].groups['site'].resources['alb']
aim_ctx = AimContext('tproj')
aim_ctx.init_project()
account = aim_ctx.get_account_context(account_name='master')
client = account.get_aws_client('elbv2')
response = client.describe_load_balancers(Names=[web_asg.resource_name])
dns_name = response['LoadBalancers'][0]['DNSName']
response = requests.get('http://' + dns_name)
assert response.text, '<html><body><h1>Hello world!</h1></body></html>\n'

def test_provisioned_simple_web_app(verbose):
test_web_server_responds(verbose)


64 changes: 0 additions & 64 deletions src/aim/tests/functional.py

This file was deleted.

0 comments on commit 4e0fc43

Please sign in to comment.