Skip to content

Commit

Permalink
Integration test for network access of runner (#99)
Browse files Browse the repository at this point in the history
* Remove catching of base exception

* Change random string generation method

* Add integration test of reconcile_interval

* Add reconcile interval test

* Update interval config

* Add test for update-interval

* Fix merge issues

* Update the status during checking of update

* Fix usage of wrong fixture

* Fix reconcile_interval and update_interval for juju 3.x

* Run apt-get clean on runner setup

* Add juju 3.x support

* Add juju 2.9 integration tests

* Fix workflow

* Fix juju 2.9 integration test

* Fix test

* Add module for tests of scheduled events

* Split deployment and spawning of runner in test fixture

* Debugging juju 2.9 integration tests

* Fix juju 3 and juju 2 support

* Update reconcile-interval test

* Fix support for juju 2 integration test

* Fix support for juju 2 integration test

* Fix waiting for juju 2 integration test

* Fix action wait

* Fix juju 2 support

* Fix missing key from no stdout returned

* Fix typo during refactor

* Fix type problem due to juju 2 and juju 3 difference

* Fix type issues

* Fix conflict between juju 2 and juju 3 test running in parallel on github

* Debug workflow

* Debug github action

* Restrict concurrency of GitHub workflow for integration tests

* Fix typo

* Fix juju app name

* Update documentation

* Rename assert_num_runners

* Add tox param for juju version

* Use matrix job for integration tests

* Fix formatting

* Fix support for juju 2 and juju 3 tox

* Enable running integration tests in parallel

* Add integration test for reconcile interval and update interval config (#97)

* Remove catching of base exception

* Add integration test of reconcile_interval and update_interval

* Run apt-get clean on runner setup

* Add juju 3.x support

* Add juju 2.9 integration tests

* Update jitter to random_delay

---------

Co-authored-by: Yanks Yoon <[email protected]>

* Configure Renovate (#24)

* Add renovate.json

* Do not require license for json files

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: arturo-seijas <[email protected]>
Co-authored-by: arturo-seijas <[email protected]>

* Resolve conflicts

* Allow integration test to be ran in parallel

* Test confined LXD container with microk8s

* Revert to unconfined mode for apparmor during e2e testing

* Add test for network access

* Add waiting for HTTP server to start up

* Load HTTP service via bash

* Fix github api changes

* Remove unneed file

* Fix command string

* Fix typing issue

* Check for return code of curl

---------

Co-authored-by: Yanks Yoon <[email protected]>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: arturo-seijas <[email protected]>
Co-authored-by: arturo-seijas <[email protected]>
  • Loading branch information
5 people authored Oct 6, 2023
1 parent c09b986 commit 5127965
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 2 deletions.
52 changes: 52 additions & 0 deletions tests/integration/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""Utilities for integration test."""

import json
from asyncio import sleep
from typing import Any

import juju.version
Expand Down Expand Up @@ -172,6 +173,7 @@ async def run_in_unit(unit: Unit, command: str, timeout=None) -> tuple[int, str
Args:
unit: Juju unit to execute the command in.
command: Command to execute.
timeout: Amount of time to wait for the execution.
Returns:
Tuple of return code and stdout.
Expand All @@ -184,3 +186,53 @@ async def run_in_unit(unit: Unit, command: str, timeout=None) -> tuple[int, str

await action.wait()
return (action.results["return-code"], action.results.get("stdout", None))


async def run_in_lxd_instance(
unit: Unit, name: str, command: str, cwd=None, timeout=None
) -> tuple[int, str | None]:
"""Run command in LXD instance of a juju unit.
Args:
unit: Juju unit to execute the command in.
name: Name of LXD instance.
command: Command to execute.
cwd: Work directory of the command.
timeout: Amount of time to wait for the execution.
Returns:
Tuple of return code and stdout.
"""
lxc_cmd = f"/snap/bin/lxc exec {name}"
if cwd:
lxc_cmd += f" --cwd {cwd}"
lxc_cmd += f" -- {command}"
return await run_in_unit(unit, lxc_cmd, timeout)


async def start_test_http_server(unit: Unit, port: int):
await run_in_unit(
unit,
f"""cat <<EOT >> /etc/systemd/system/test-http-server.service
[Unit]
Description=Simple HTTP server for testing
After=network.target
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu
ExecStart=python3 -m http.server {port}
EOT""",
)
await run_in_unit(unit, "/usr/bin/systemctl daemon-reload")
await run_in_unit(unit, "/usr/bin/systemctl start test-http-server")

# Test the HTTP server
for _ in range(10):
return_code, stdout = await run_in_unit(unit, f"curl http://localhost:{port}")
if return_code == 0 and stdout:
break
await sleep(3)
else:
assert False, "Timeout waiting for HTTP server to start up"
32 changes: 32 additions & 0 deletions tests/integration/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,44 @@

from tests.integration.helpers import (
assert_resource_lxd_profile,
get_runner_names,
run_in_lxd_instance,
run_in_unit,
start_test_http_server,
wait_till_num_of_runners,
)
from tests.status_name import ACTIVE_STATUS_NAME


@pytest.mark.asyncio
@pytest.mark.abort_on_fail
async def test_network_access(app: Application) -> None:
"""
arrange: An working application with one runner. Setup a HTTP server in the juju unit.
act: Make HTTP call to the HTTP server from inside a runner.
assert: The HTTP call failed.
"""
unit = app.units[0]
port = 4040

await start_test_http_server(unit, port)

names = await get_runner_names(unit)
assert names

return_code, stdout = await run_in_unit(unit, "lxc network get lxdbr0 ipv4.address")
assert return_code == 0
assert stdout is not None
host_ip, _ = stdout.split("/", 1)

return_code, stdout = await run_in_lxd_instance(
unit, names[0], f"curl http://{host_ip}:{port}"
)

assert return_code == 7
assert stdout is None


@pytest.mark.asyncio
@pytest.mark.abort_on_fail
async def test_flush_runner_and_resource_config(app: Application) -> None:
Expand Down
4 changes: 3 additions & 1 deletion tests/integration/test_charm_fork_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,9 @@ async def test_dispatch_workflow_failure(
assert len(runners) == 1
runner_to_be_used = runners[0]

workflow = forked_github_repository.get_workflow(id_or_name=DISPATCH_TEST_WORKFLOW_FILENAME)
workflow = forked_github_repository.get_workflow(
id_or_file_name=DISPATCH_TEST_WORKFLOW_FILENAME
)

# The `create_dispatch` returns True on success.
assert workflow.create_dispatch(
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/test_charm_no_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ async def test_reconcile_runners(model: Model, app_no_runner: Application) -> No
act:
1. a. Set virtual-machines config to 1.
b. Run reconcile_runners action.
2. a. Set virtual-machiens config to 0.
2. a. Set virtual-machines config to 0.
b. Run reconcile_runners action.
assert:
1. One runner should exist.
Expand Down

0 comments on commit 5127965

Please sign in to comment.