Skip to content

Commit 9123aae

Browse files
Maurizio Brancaumbynos
Maurizio Branca
andauthoredFeb 3, 2021
[EDITOR-527] E2E testing infrastructure (#591)
* Bootstrap E2E testing infrastructure * add e2e tests in taskfile and in CI * fix deprecation warning when running pytest * Run e2e tests only with GUI version on macos (Github runners are basically mac mini with GUI support)" * add first draft of tests for certs and v2 APIs * add logs to .gitignore * skip update, currently no way of testing this on gh runners Co-authored-by: umbynos <[email protected]>
1 parent d09803d commit 9123aae

11 files changed

+457
-0
lines changed
 

‎.github/workflows/release.yml

+13
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,19 @@ jobs:
123123
run: task build
124124
if: matrix.os == 'macos-10.15'
125125

126+
- name: Install Python
127+
uses: actions/setup-python@v2
128+
with:
129+
python-version: '3.9'
130+
architecture: 'x64'
131+
if: matrix.os == 'macos-10.15'
132+
133+
- name: Run e2e tests
134+
run: |
135+
pip install poetry
136+
task test-e2e
137+
if: matrix.os == 'macos-10.15'
138+
126139
# this will create `public/` dir with compressed full bin (<version>/<os>-<arch>.gz) and a json file
127140
- name: Create autoupdate files
128141
run: go-selfupdate arduino-create-agent${{ matrix.ext }} ${TAG_VERSION}

‎.github/workflows/test.yml

+13
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,19 @@ jobs:
9191
run: task build
9292
if: matrix.os == 'macos-10.15'
9393

94+
- name: Install Python
95+
uses: actions/setup-python@v2
96+
with:
97+
python-version: '3.9'
98+
architecture: 'x64'
99+
if: matrix.os == 'macos-10.15'
100+
101+
- name: Run e2e tests
102+
run: |
103+
pip install poetry
104+
task test-e2e
105+
if: matrix.os == 'macos-10.15'
106+
94107
# config.ini is required by the executable when it's run
95108
- name: Upload artifacts
96109
uses: actions/upload-artifact@v2

‎.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ rsrc.syso
77
snapshot/*
88
public/
99
artifacts*
10+
logs/
1011

1112
# IDEs config
1213
.idea
14+
.vscode
1315

1416
# macOS
1517
.DS_Store
18+
19+
# Python
20+
__pycache__

‎Taskfile.yml

+6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ tasks:
3333
cmds:
3434
- go test -short -run '{{ default ".*" .TEST_REGEX }}' {{ default "-v" .GOFLAGS }} -coverprofile=coverage_unit.txt {{ default .DEFAULT_TARGETS .TARGETS }} {{.TEST_LDFLAGS}}
3535

36+
test-e2e:
37+
desc: Run end 2 end tests
38+
cmds:
39+
- poetry install --no-root
40+
- poetry run pytest test
41+
3642
check:
3743
desc: Check fmt and lint
3844
cmds:

‎poetry.lock

+280
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎pyproject.toml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[tool.poetry]
2+
name = "arduino-create-agent"
3+
version = "0.1.0"
4+
description = "Project used to run end-to-end test for the Arduino Create Agent"
5+
authors = ["Umberto Baldi <u.baldi@arduino.cc>", "Maurizio Branca <m.branca@arduino.cc>"]
6+
license = "GPLv2"
7+
8+
[tool.poetry.dependencies]
9+
python = "^3.9"
10+
psutil = "^5.8.0"
11+
12+
[tool.poetry.dev-dependencies]
13+
pytest = "^6.2.1"
14+
requests = "^2.25.1"
15+
invoke = "^1.5.0"
16+
17+
[build-system]
18+
requires = ["poetry-core>=1.0.0"]
19+
build-backend = "poetry.core.masonry.api"
20+
21+
[tool.pytest.ini_options]
22+
filterwarnings = [
23+
"ignore::DeprecationWarning:invoke.loader" # https://github.com/pyinvoke/invoke/issues/675
24+
]

‎test/conftest.py

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import os
2+
import platform
3+
import signal
4+
import time
5+
from pathlib import Path
6+
7+
import pytest
8+
from invoke import Local
9+
from invoke.context import Context
10+
11+
12+
@pytest.fixture(scope="function")
13+
def agent(pytestconfig):
14+
15+
agent_cli = str(Path(pytestconfig.rootdir) / "arduino-create-agent")
16+
env = {
17+
# "ARDUINO_DATA_DIR": data_dir,
18+
# "ARDUINO_DOWNLOADS_DIR": downloads_dir,
19+
# "ARDUINO_SKETCHBOOK_DIR": data_dir,
20+
}
21+
run_context = Context()
22+
23+
runner = Local(run_context) # execute a command on the local filesystem
24+
25+
cd_command = "cd"
26+
with run_context.prefix(f'{cd_command} ..'):
27+
runner.run(agent_cli, echo=True, hide=True, warn=True, env=env, asynchronous=True)
28+
29+
# we give some time to the agent to start and listen to
30+
# incoming requests
31+
time.sleep(.5)
32+
33+
# we block here until the test function using this fixture has returned
34+
yield runner
35+
36+
# Kill the runner's process as we finished our test (platform dependent)
37+
os_signal = signal.SIGTERM
38+
if platform.system() != "Windows":
39+
os_signal = signal.SIGKILL
40+
os.kill(runner.process.pid, os_signal)
41+
42+
43+
@pytest.fixture(scope="session")
44+
def base_url():
45+
return "http://127.0.0.1:8991"

‎test/test_certs.py

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import requests
2+
3+
4+
def test_get_cert(base_url, agent):
5+
6+
resp = requests.get(f"{base_url}/certificate.crt")
7+
assert resp.status_code == 200
8+
9+
cert = resp.text
10+
assert "<!DOCTYPE html>" in cert
11+
12+
13+
def test_del_cert(base_url, agent):
14+
15+
resp = requests.delete(f"{base_url}/certificate.crt")
16+
assert resp.status_code == 200
17+
18+
# Should rm "ca.cert.pem", "ca.cert.cer", "ca.key.pem"

‎test/test_info.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import re
2+
import requests
3+
4+
5+
def test_version(base_url, agent):
6+
7+
resp = requests.get(f"{base_url}/info")
8+
assert resp.status_code == 200
9+
10+
info = resp.json()
11+
assert re.match("[0-9]+.[0-9]+.[0-9]+", info["version"]) is not None

‎test/test_update.py

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# import json
2+
import psutil
3+
import requests
4+
import pytest
5+
6+
# test if the update process succeeds in terminating the binary
7+
@pytest.mark.skip(reason="no way of currently testing this")
8+
def test_update_shutdown(base_url, agent):
9+
10+
procs=[]
11+
for p in psutil.process_iter():
12+
if p.name() == "arduino-create-agent":
13+
procs.append(p)
14+
15+
resp = requests.post(f"{base_url}/update")
16+
# assert resp.status_code == 200
17+
# assert "Please wait a moment while the agent reboots itself" in info['success'] # failing on macos see https://github.com/arduino/arduino-create-agent/issues/608
18+
gone, alive = psutil.wait_procs(procs, timeout=3, callback=on_terminate) # wait for "arduino-create-agent" to terminate
19+
20+
def on_terminate(proc):
21+
print("process {} terminated with exit code {}".format(proc, proc.returncode))
22+
assert True
23+
24+
# the version currently running is the latest available
25+
@pytest.mark.skip(reason="no way of currently testing this")
26+
def test_latest_version(base_url, agent):
27+
resp = requests.get(f"{base_url}/info")
28+
assert resp.status_code == 200
29+
latest_version = requests.get("https://s3.amazonaws.com/arduino-create-static/agent-metadata/agent-version.json") # get the latest version available
30+
31+
version = latest_version.json()
32+
info = resp.json()
33+
assert info["version"] == version["Version"]

‎test/test_v2.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import requests
2+
3+
4+
def test_get_tools(base_url, agent):
5+
6+
resp = requests.get(f"{base_url}/v2/pkgs/tools/installed")
7+
assert resp.status_code == 200
8+
9+
tools = resp.json()

0 commit comments

Comments
 (0)
Please sign in to comment.