Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add examples folder #48

Merged
merged 12 commits into from
Jul 25, 2023
4 changes: 1 addition & 3 deletions .github/workflows/code-quality-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ name: Code Quality Check
push:
branches:
- main
- 'feature/**'
pull_request:
branches:
- main
- 'feature/**'

env:
FLAKE8_VERSION: 5.0.4
Expand Down Expand Up @@ -43,7 +41,7 @@ jobs:
env/bin/python -m pip install flake8==${{ env.FLAKE8_VERSION }}
- name: Black Format Check
run: |
env/bin/python -m black --check controller tests minimal_example.py
env/bin/python -m black --check controller tests examples
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
Expand Down
30 changes: 23 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
# Authored by Alexandra N. Walker <[email protected]> ☀️

name: tests
name: Tests
"on":
push:
branches:
- main
pull_request:
branches:
- main
- feature/**
- feat/**

env:
POETRY_VERSION: 1.1.11
POETRY_VERSION: 1.5.1

jobs:
test:
name: Tests
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Test with docker-compose
- uses: actions/checkout@v3
- name: Run integration tests for protocols
run: |
docker-compose run tests
docker-compose run tests tests/

examples:
name: Check examples
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install poetry
run: pipx install poetry==${{ env.POETRY_VERSION}}
- name: setup python
uses: actions/setup-python@v4
with:
python-version: 3.9
cache: poetry
- name: Install dependencies
run: poetry install
- name: Run examples
run: |
poetry run pytest -m examples
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,19 @@ This controller differs from these in a few key ways:
- This controller provides a system for capturing webhooks/events that is well
suited for a testing or demonstration scenario.


## Examples

A number of examples can be found in the [examples](./examples) directory. Each
of these contains a `docker-compose.yml` and a `example.py`. You can run each
example by `cd`ing into the directory and running:

```sh
$ cd examples/example_to_try_out
$ docker-compose run example
$ docker-compose down -v
```

## Instructions on Running Tests

To run the tests:
Expand All @@ -90,6 +103,18 @@ docker-compose down
> things are currently set up but doing so should give the cleanest state
> possible for inspection after the tests complete

## Testing the Examples

Pytest has been configured to run checks on the [examples](./examples). You can
run these with:

```
poetry run pytest -m examples
```

This will run the `example` service of each docker-compose file in each
directory inside of the `examples` folder.

### Custom ACA-Py Images/Versions

Presently, ACA-Py version 0.7.4 is used. This can be changed by modifying the
Expand Down
15 changes: 0 additions & 15 deletions configs/alice.yml

This file was deleted.

16 changes: 0 additions & 16 deletions configs/bob.yml

This file was deleted.

120 changes: 120 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
from pathlib import Path
import subprocess
from typing import Union

from py._path.local import LocalPath
import pytest
from pytest import Session


EXAMPLES_DIR = Path(__file__).parent / "examples"


class ExampleFailedException(Exception):
"""Raised when an example fails."""

def __init__(self, message: str, exit_status: int):
super().__init__(message)
self.exit_status = exit_status


class ExampleRunner:
"""Run the docker-compose of a given example."""

def __init__(self, compose_file: str):
self.compose_file = compose_file

def compose(self, *command: str) -> int:
"""Runs docker-compose using subprocess with the given command.

Returns exit status and output.
"""
try:
subprocess.run(
["docker-compose", "-f", self.compose_file, *command],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on my m1 system, I run docker compose not docker-compose on the command line.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right. Fun lol. I'll try to figure out if there's a straightforward way to account for that.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a silly comment along these lines, @dbluhm wasn't this mentioned during the ACA-Pug meeting today? Might be able to be reconciled in the future (very possible I'm off on this)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking it might be simplest to just alias docker-compose for docker compose locally if you want to run these directly. Else, we can always just let the action run it and not worry about local environments.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I heard mention of docker-compose vs docker compose on the ACA-PUG call today 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, no wait you're right, I was confusing it with the amd vs. arm thingy/separate thing, my bad

check=True,
)
return 0
except subprocess.CalledProcessError as e:
return e.returncode

def cleanup(self):
"""Runs docker-compose down -v for cleanup"""
exit_status = self.compose("down", "-v")
if exit_status != 0:
raise ExampleFailedException(
f"Cleanup failed with exit status {exit_status}", exit_status
)

def handle_run(self, *command: str):
"""Handles the run of docker-compose/

raises exception if exit status is non-zero.
"""
try:
exit_status = self.compose(*command)
if exit_status != 0:
raise ExampleFailedException(
f"Command failed with exit status: {exit_status}",
exit_status=exit_status,
)
finally:
self.cleanup()


def pytest_collect_file(parent: Session, path: Union[LocalPath, Path]):
"""Pytest collection hook.

This will collect the docker-compose.yml files from the examples and create
pytest items to run them.
"""
file = Path(str(path))

# Skip certain examples
if (file.parent / "__skip__").exists():
return

if file.suffix == ".yml" and file.parent.parent == EXAMPLES_DIR:
return ExampleFile.from_parent(parent, path=file.parent)


class ExampleFile(pytest.File):
"""Pytest file for example."""

def collect(self):
"""Collect tests from example file."""
path = Path(self.fspath)
item = ExmapleItem.from_parent(
self, name=path.name, compose_file=str(path / "docker-compose.yml")
)
item.add_marker(pytest.mark.examples)
yield item


class ExmapleItem(pytest.Item):
"""Example item.

Runs the docker-compose.yml file of the example and reports failure if the
exit status is non-zero.
"""

def __init__(self, name: str, parent: pytest.File, compose_file: str):
super().__init__(name, parent)
self.compose_file = compose_file

def runtest(self) -> None:
ExampleRunner(self.compose_file).handle_run("run", "example")

def repr_failure(self, excinfo):
"""Called when self.runtest() raises an exception."""
if isinstance(excinfo.value, ExampleFailedException):
return "\n".join(
[
"Example failed!",
f" {excinfo.value}",
]
)
return f"Some other exectpion happened: {excinfo.value}"

def reportinfo(self):
return self.fspath, 0, f"example: {self.name}"
59 changes: 35 additions & 24 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# This docker-compose file is used for tests only

version: "3"
services:
alice:
Expand All @@ -16,8 +18,20 @@ services:
- ./configs:/configs:ro,z
command: >
start
--arg-file /configs/alice.yml
--inbound-transport http 0.0.0.0 3000
--outbound-transport http
--endpoint http://alice:3000
--admin 0.0.0.0 3001
--admin-insecure-mode
--webhook-url http://webhook-listener:8080
--tails-server-base-url http://tails:6543
--genesis-url https://raw.githubusercontent.com/Indicio-tech/indicio-network/main/genesis_files/pool_transactions_testnet_genesis
--wallet-type askar
--wallet-name alice
--wallet-key insecure
--auto-provision
--log-level debug
--debug-webhooks
healthcheck:
test: curl -s -o /dev/null -w '%{http_code}' "http://localhost:3001/status/live" | grep "200" > /dev/null
start_period: 30s
Expand Down Expand Up @@ -46,8 +60,22 @@ services:
- ./configs:/configs:ro,z
command: >
start
--arg-file /configs/bob.yml
--inbound-transport http 0.0.0.0 3000
--outbound-transport http
--endpoint http://bob:3000
--admin 0.0.0.0 3001
--admin-insecure-mode
--webhook-url http://webhook-listener:8080
--tails-server-base-url http://tails:6543
--genesis-url https://raw.githubusercontent.com/Indicio-tech/indicio-network/main/genesis_files/pool_transactions_testnet_genesis
--wallet-type askar
--wallet-name bob
--wallet-key insecure
--auto-provision
--log-level debug
--debug-webhooks
--webhook-url http://webhook-listener:8080
--monitor-revocation-notification
healthcheck:
test: curl -s -o /dev/null -w '%{http_code}' "http://localhost:3001/status/live" | grep "200" > /dev/null
start_period: 30s
Expand All @@ -58,28 +86,6 @@ services:
webhook-listener:
condition: service_started

example:
container_name: controller
build:
context: .
environment:
- ALICE=http://alice:3001
- BOB=http://bob:3001
volumes:
- ./controller:/usr/src/app/controller:ro,z
- ./minimal_example.py:/usr/src/app/minimal_example.py:ro,z
command: python -m minimal_example
depends_on:
alice:
condition: service_healthy
bob:
condition: service_healthy

webhook-listener:
image: mendhak/http-https-echo:18
environment:
- HTTP_PORT=8080

tails:
image: ghcr.io/bcgov/tails-server:latest
ports:
Expand All @@ -93,6 +99,11 @@ services:
--storage-path /tmp/tails-files
--log-level INFO

webhook-listener:
image: mendhak/http-https-echo:18
environment:
- HTTP_PORT=8080

tests:
container_name: juggernaut
build:
Expand Down
Loading
Loading