From: Tim Van Steenburgh Date: Wed, 1 Mar 2017 05:44:06 +0000 (-0500) Subject: Add integration tests. X-Git-Tag: 0.4.0~19^2 X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FN2VC.git;a=commitdiff_plain;h=f33ed4d2e1efc9e479445da842d08256ceaccac8 Add integration tests. - Covers most of what is demonstrated in the examples/ directory. - The integration tests are not run by default (with the 'tox' command), but they are run by TravisCI. - Each integration test gets its own clean model in which to run, which is destroyed at the end of the test. See tests.base.CleanModel. - Includes charmstore and local bundle tests (local bundle has machine and placement directives). Fixes #27. --- diff --git a/.travis.yml b/.travis.yml index b7e82d2..9716fea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,6 @@ before_install: install: pip install tox-travis before_script: - sudo -E sudo -u $USER -E bash -c "juju bootstrap localhost test" -script: tox +script: tox -e py35,integration after_script: - sudo -E sudo -u $USER -E bash -c "juju destroy-controller --destroy-all-models -y test" diff --git a/examples/config.py b/examples/config.py index 579308b..b823758 100644 --- a/examples/config.py +++ b/examples/config.py @@ -13,7 +13,8 @@ from juju.model import Model log = logging.getLogger(__name__) -MB = 1024 * 1024 +MB = 1 + async def run(): model = Model() diff --git a/examples/relate.py b/examples/relate.py index 01cee37..3aa9c5f 100644 --- a/examples/relate.py +++ b/examples/relate.py @@ -78,7 +78,8 @@ async def run(): application_name='nrpe', series='trusty', channel='stable', - num_units=1, + # subordinates must be deployed without units + num_units=0, ) my_relation = await model.add_relation( 'ubuntu', diff --git a/tests/bundle/bundle.yaml b/tests/bundle/bundle.yaml new file mode 100644 index 0000000..19a45ec --- /dev/null +++ b/tests/bundle/bundle.yaml @@ -0,0 +1,28 @@ +series: xenial +services: + wordpress: + charm: "cs:trusty/wordpress-2" + num_units: 1 + annotations: + "gui-x": "339.5" + "gui-y": "-171" + to: + - "0" + mysql: + charm: "cs:trusty/mysql-26" + num_units: 1 + annotations: + "gui-x": "79.5" + "gui-y": "-142" + to: + - "1" +relations: + - - "wordpress:db" + - "mysql:db" +machines: + "0": + series: trusty + constraints: "arch=amd64 cores=1 cpu-power=100 mem=1740 root-disk=8192" + "1": + series: trusty + constraints: "arch=amd64 cores=1 cpu-power=100 mem=1740 root-disk=8192" diff --git a/tests/client/__init__.py b/tests/client/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/client/test_client.py b/tests/client/test_client.py deleted file mode 100644 index ca2637f..0000000 --- a/tests/client/test_client.py +++ /dev/null @@ -1,22 +0,0 @@ -import pytest - -from juju.client import client - -from .. import base - - -@base.bootstrapped -@pytest.mark.asyncio -async def test_user_info(event_loop): - async with base.CleanModel() as model: - controller_conn = await model.connection.controller() - - um = client.UserManagerFacade() - um.connect(controller_conn) - result = await um.UserInfo( - [client.Entity('user-admin')], True) - await controller_conn.close() - - assert isinstance(result, client.UserInfoResults) - for r in result.results: - assert isinstance(r, client.UserInfoResult) diff --git a/tests/client/test_connection.py b/tests/client/test_connection.py deleted file mode 100644 index 9c61759..0000000 --- a/tests/client/test_connection.py +++ /dev/null @@ -1,14 +0,0 @@ -import pytest - -from juju.client.connection import Connection -from .. import base - - -@base.bootstrapped -@pytest.mark.asyncio -async def test_connect_current(event_loop): - async with base.CleanModel(): - conn = await Connection.connect_current() - - assert isinstance(conn, Connection) - await conn.close() diff --git a/tests/functional/__init__.py b/tests/functional/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/functional/test_model.py b/tests/functional/test_model.py deleted file mode 100644 index 9ae9204..0000000 --- a/tests/functional/test_model.py +++ /dev/null @@ -1,45 +0,0 @@ -import pytest - -from .. import base - -MB = 1 -GB = 1024 - - -@base.bootstrapped -@pytest.mark.asyncio -async def test_add_machine(event_loop): - from juju.machine import Machine - - async with base.CleanModel() as model: - # add a new default machine - machine1 = await model.add_machine() - - # add a machine with constraints, disks, and series - machine2 = await model.add_machine( - constraints={ - 'mem': 256 * MB, - }, - disks=[{ - 'pool': 'rootfs', - 'size': 10 * GB, - 'count': 1, - }], - series='xenial', - ) - - # add a lxd container to machine2 - machine3 = await model.add_machine( - 'lxd:{}'.format(machine2.id)) - - for m in (machine1, machine2, machine3): - assert isinstance(m, Machine) - - assert len(model.machines) == 3 - - await machine3.destroy(force=True) - await machine2.destroy(force=True) - res = await machine1.destroy(force=True) - - assert res is None - assert len(model.machines) == 0 diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/integration/test_application.py b/tests/integration/test_application.py new file mode 100644 index 0000000..1618a5a --- /dev/null +++ b/tests/integration/test_application.py @@ -0,0 +1,52 @@ +import pytest + +from .. import base + +MB = 1 + + +@base.bootstrapped +@pytest.mark.asyncio +async def test_action(event_loop): + async with base.CleanModel() as model: + ubuntu_app = await model.deploy( + 'mysql', + application_name='mysql', + series='trusty', + channel='stable', + config={ + 'tuning-level': 'safest', + }, + constraints={ + 'mem': 256 * MB, + }, + ) + + # update and check app config + await ubuntu_app.set_config({'tuning-level': 'fast'}) + config = await ubuntu_app.get_config() + assert config['tuning-level']['value'] == 'fast' + + # update and check app constraints + await ubuntu_app.set_constraints({'mem': 512 * MB}) + constraints = await ubuntu_app.get_constraints() + assert constraints['mem'] == 512 * MB + + +@base.bootstrapped +@pytest.mark.asyncio +async def test_add_units(event_loop): + from juju.unit import Unit + + async with base.CleanModel() as model: + app = await model.deploy( + 'ubuntu-0', + application_name='ubuntu', + series='trusty', + channel='stable', + ) + units = await app.add_units(count=2) + + assert len(units) == 2 + for unit in units: + assert isinstance(unit, Unit) diff --git a/tests/integration/test_client.py b/tests/integration/test_client.py new file mode 100644 index 0000000..ca2637f --- /dev/null +++ b/tests/integration/test_client.py @@ -0,0 +1,22 @@ +import pytest + +from juju.client import client + +from .. import base + + +@base.bootstrapped +@pytest.mark.asyncio +async def test_user_info(event_loop): + async with base.CleanModel() as model: + controller_conn = await model.connection.controller() + + um = client.UserManagerFacade() + um.connect(controller_conn) + result = await um.UserInfo( + [client.Entity('user-admin')], True) + await controller_conn.close() + + assert isinstance(result, client.UserInfoResults) + for r in result.results: + assert isinstance(r, client.UserInfoResult) diff --git a/tests/integration/test_connection.py b/tests/integration/test_connection.py new file mode 100644 index 0000000..9c61759 --- /dev/null +++ b/tests/integration/test_connection.py @@ -0,0 +1,14 @@ +import pytest + +from juju.client.connection import Connection +from .. import base + + +@base.bootstrapped +@pytest.mark.asyncio +async def test_connect_current(event_loop): + async with base.CleanModel(): + conn = await Connection.connect_current() + + assert isinstance(conn, Connection) + await conn.close() diff --git a/tests/integration/test_model.py b/tests/integration/test_model.py new file mode 100644 index 0000000..2fe97d0 --- /dev/null +++ b/tests/integration/test_model.py @@ -0,0 +1,97 @@ +import pytest + +from .. import base + +MB = 1 +GB = 1024 + + +@base.bootstrapped +@pytest.mark.asyncio +async def test_deploy_local_bundle(event_loop): + from pathlib import Path + tests_dir = Path(__file__).absolute().parent.parent + bundle_path = tests_dir / 'bundle' + + async with base.CleanModel() as model: + await model.deploy(str(bundle_path)) + + for app in ('wordpress', 'mysql'): + assert app in model.applications + + +@base.bootstrapped +@pytest.mark.asyncio +async def test_deploy_bundle(event_loop): + async with base.CleanModel() as model: + await model.deploy('bundle/wiki-simple') + + for app in ('wiki', 'mysql'): + assert app in model.applications + + +@base.bootstrapped +@pytest.mark.asyncio +async def test_add_machine(event_loop): + from juju.machine import Machine + + async with base.CleanModel() as model: + # add a new default machine + machine1 = await model.add_machine() + + # add a machine with constraints, disks, and series + machine2 = await model.add_machine( + constraints={ + 'mem': 256 * MB, + }, + disks=[{ + 'pool': 'rootfs', + 'size': 10 * GB, + 'count': 1, + }], + series='xenial', + ) + + # add a lxd container to machine2 + machine3 = await model.add_machine( + 'lxd:{}'.format(machine2.id)) + + for m in (machine1, machine2, machine3): + assert isinstance(m, Machine) + + assert len(model.machines) == 3 + + await machine3.destroy(force=True) + await machine2.destroy(force=True) + res = await machine1.destroy(force=True) + + assert res is None + assert len(model.machines) == 0 + + +@base.bootstrapped +@pytest.mark.asyncio +async def test_relate(event_loop): + from juju.relation import Relation + + async with base.CleanModel() as model: + await model.deploy( + 'ubuntu', + application_name='ubuntu', + series='trusty', + channel='stable', + ) + await model.deploy( + 'nrpe', + application_name='nrpe', + series='trusty', + channel='stable', + # subordinates must be deployed without units + num_units=0, + ) + my_relation = await model.add_relation( + 'ubuntu', + 'nrpe', + ) + + assert isinstance(my_relation, Relation) diff --git a/tests/integration/test_unit.py b/tests/integration/test_unit.py new file mode 100644 index 0000000..e9116ce --- /dev/null +++ b/tests/integration/test_unit.py @@ -0,0 +1,46 @@ +import pytest + +from .. import base + + +@base.bootstrapped +@pytest.mark.asyncio +async def test_run(event_loop): + from juju.action import Action + + async with base.CleanModel() as model: + app = await model.deploy( + 'ubuntu-0', + application_name='ubuntu', + series='trusty', + channel='stable', + ) + + for unit in app.units: + action = await unit.run('unit-get public-address') + assert isinstance(action, Action) + assert 'Stdout' in action.results + break + + +@base.bootstrapped +@pytest.mark.asyncio +async def test_run_action(event_loop): + async def run_action(unit): + # unit.run() returns a juju.action.Action instance + action = await unit.run_action('add-repo', repo='myrepo') + # wait for the action to complete + return await action.wait() + + async with base.CleanModel() as model: + app = await model.deploy( + 'git', + application_name='git', + series='trusty', + channel='stable', + ) + + for unit in app.units: + action = await run_action(unit) + assert action.results == {'dir': '/var/git/myrepo.git'} + break diff --git a/tox.ini b/tox.ini index b4fec3d..8c4b0cd 100644 --- a/tox.ini +++ b/tox.ini @@ -11,9 +11,15 @@ skipsdist=True usedevelop=True passenv = HOME -commands = py.test -ra -s -x -n auto deps = pytest pytest-asyncio pytest-xdist mock + +[testenv:py35] +# default tox env excludes integration tests +commands = py.test -ra -s -x -n auto -k 'not integration' + +[testenv:integration] +commands = py.test -ra -s -x -n auto