Skip to content

Commit 179fdc5

Browse files
committed
Enhance CI workflow and testing setup for remote E2E tests
- Added a new job for running remote end-to-end tests in the CI workflow. - Updated Dockerfile and dockerfile-ci to use ARG for IRIS credentials. - Created a new script to start IRIS and initialize IOP for testing. - Modified launch configuration for debugging remote tests in VSCode. - Updated .gitignore to include .env.remote for environment variables. - Refactored _RemoteDirector methods to return response data for better error handling.
1 parent 3e05366 commit 179fdc5

8 files changed

Lines changed: 144 additions & 34 deletions

File tree

.github/workflows/pytest-iris.yml

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
paths-ignore:
66
- 'README.md'
77
- '.github/**'
8+
workflow_dispatch:
89

910

1011
jobs:
@@ -23,9 +24,83 @@ jobs:
2324
- run: docker pull $IMAGE
2425
- name: Run Tests
2526
run: |
26-
docker build --build-arg BASE=$IMAGE -t pytest-iris -f dockerfile-ci .
27+
docker build --build-arg BASE=$IMAGE \
28+
--build-arg IRISUSERNAME=${{ secrets.IRIS_USERNAME || 'SuperUser' }} \
29+
--build-arg IRISPASSWORD=${{ secrets.IRIS_PASSWORD || 'SYS' }} \
30+
-t pytest-iris -f dockerfile-ci .
2731
docker run -i --rm pytest-iris
2832
33+
test-e2e-remote:
34+
strategy:
35+
fail-fast: false
36+
matrix:
37+
image:
38+
- intersystemsdc/iris-community:latest
39+
runs-on: ubuntu-latest
40+
env:
41+
IMAGE: ${{ matrix.image }}
42+
IOP_URL: http://localhost:52773
43+
IOP_USERNAME: ${{ secrets.IRIS_USERNAME || 'SuperUser' }}
44+
IOP_PASSWORD: ${{ secrets.IRIS_PASSWORD || 'SYS' }}
45+
IOP_NAMESPACE: IRISAPP
46+
steps:
47+
- uses: actions/checkout@v3
48+
49+
- run: docker pull $IMAGE
50+
51+
- name: Build test image
52+
run: |
53+
docker build --build-arg BASE=$IMAGE \
54+
--build-arg IRISUSERNAME=${{ secrets.IRIS_USERNAME || 'SuperUser' }} \
55+
--build-arg IRISPASSWORD=${{ secrets.IRIS_PASSWORD || 'SYS' }} \
56+
-t pytest-iris -f dockerfile-ci .
57+
58+
- name: Start IRIS container
59+
run: |
60+
docker run -d --name iris-server \
61+
--entrypoint /irisdev/app/iris-start-and-wait.sh \
62+
pytest-iris
63+
64+
- name: Wait for IRIS REST API to be ready
65+
run: |
66+
echo "Waiting for IRIS REST API..."
67+
for i in $(seq 1 60); do
68+
if docker exec iris-server \
69+
curl -sf -u "$IOP_USERNAME:$IOP_PASSWORD" \
70+
"http://localhost:52773/api/iop/version?namespace=$IOP_NAMESPACE" \
71+
> /dev/null 2>&1; then
72+
echo "IRIS REST API is ready after $i attempts"
73+
break
74+
fi
75+
if [ "$i" = "60" ]; then
76+
echo "Timed out waiting for IRIS REST API"
77+
docker logs iris-server
78+
exit 1
79+
fi
80+
echo "Attempt $i/60 — retrying in 5s..."
81+
sleep 5
82+
done
83+
84+
- name: Run remote e2e tests
85+
run: |
86+
docker exec \
87+
-e IOP_URL="$IOP_URL" \
88+
-e IOP_USERNAME="$IOP_USERNAME" \
89+
-e IOP_PASSWORD="$IOP_PASSWORD" \
90+
-e IOP_NAMESPACE="$IOP_NAMESPACE" \
91+
-e PYTHONPATH=/irisdev/app/src \
92+
-w /irisdev/app \
93+
iris-server \
94+
python3 -m pytest src/tests/e2e/remote/ -v
95+
96+
- name: Dump container logs on failure
97+
if: failure()
98+
run: docker logs iris-server
99+
100+
- name: Stop IRIS container
101+
if: always()
102+
run: docker stop iris-server || true
103+
29104

30105

31106

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ dist
1515
build
1616
waitISC.log
1717
.env
18+
.env.remote
1819

1920
prof
2021
src/tests/bench/result.txt

.vscode/launch.json

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,28 @@
11
{
22
"version": "0.2.0",
33
"configurations": [
4+
{
5+
"name": "Run Remote E2E Tests",
6+
"type": "debugpy",
7+
"request": "launch",
8+
"module": "pytest",
9+
"args": ["src/tests/e2e/remote/", "-v"],
10+
"envFile": "${workspaceFolder}/.env.remote",
11+
"env": {
12+
"PYTHONPATH": "${workspaceFolder}/src"
13+
},
14+
"justMyCode": false,
15+
"console": "integratedTerminal"
16+
},
17+
{
18+
"name": "Python Debugger: Remote Attach",
19+
"type": "debugpy",
20+
"request": "attach",
21+
"connect": {
22+
"host": "localhost",
23+
"port": 54132
24+
}
25+
},
426
{
527
"name": "Debug Unit Test",
628
"type": "python",
@@ -13,7 +35,7 @@
1335
"request": "launch",
1436
"program": "${file}",
1537
"console": "integratedTerminal",
16-
"justMyCode": false
38+
"justMyCode": false,
1739
},
1840
{
1941
"type": "objectscript",

.vscode/settings.json

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,19 @@
66
},
77
"objectscript.conn" :{
88
"ns": "IRISAPP",
9-
"username": "_SYSTEM",
10-
"password": "SYS",
11-
"docker-compose": {
12-
"service": "iris",
13-
"internalPort": 52773
14-
},
9+
"username": "_IRIS_USERNAME_",
10+
"password": "_IRIS_PASSWORD_",
1511
"active": true,
1612
"links": {
1713
"Production": "http://localhost:${port}/csp/irisapp/EnsPortal.ProductionConfig.zen?PRODUCTION=PEX.Production"
1814
},
1915
"server": "iris"
2016
},
21-
"sqltools.connections": [
22-
{
23-
"namespace": "IRISAPP",
24-
"connectionMethod": "Server and Port",
25-
"showSystem": false,
26-
"previewLimit": 50,
27-
"server": "localhost",
28-
"port": 52795,
29-
"askForPassword": false,
30-
"driver": "InterSystems IRIS",
31-
"name": "IRISAPP",
32-
"username": "_SYSTEM",
33-
"password": "SYS"
34-
}
35-
]
36-
17+
"python.testing.pytestArgs": [
18+
"src/tests"
19+
],
20+
"python.testing.unittestEnabled": false,
21+
"python.testing.pytestEnabled": true,
22+
"python-envs.defaultEnvManager": "ms-python.python:venv",
23+
"python-envs.pythonProjects": []
3724
}

Dockerfile

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ FROM $IMAGE
44
WORKDIR /irisdev/app
55

66
## Python stuff
7-
ENV IRISUSERNAME "SuperUser"
8-
ENV IRISPASSWORD "SYS"
9-
ENV IRISNAMESPACE "IRISAPP"
7+
ARG IRISUSERNAME
8+
ARG IRISPASSWORD
9+
ENV IRISUSERNAME=${IRISUSERNAME}
10+
ENV IRISPASSWORD=${IRISPASSWORD}
11+
ENV IRISNAMESPACE="IRISAPP"
1012
ENV PYTHON_PATH=/usr/irissys/bin/
1113
ENV LD_LIBRARY_PATH=${ISC_PACKAGE_INSTALLDIR}/bin:${LD_LIBRARY_PATH}
1214
ENV PATH "/home/irisowner/.local/bin:/usr/irissys/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/irisowner/bin"

dockerfile-ci

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ RUN ln -s /irisdev/app/src/iop /usr/irissys/mgr/python/iop
1111
RUN ln -s /irisdev/app/src/grongier /usr/irissys/mgr/python/grongier
1212

1313
## Python stuff
14-
ENV IRISUSERNAME="SuperUser"
15-
ENV IRISPASSWORD="SYS"
14+
ARG IRISUSERNAME
15+
ARG IRISPASSWORD
16+
ENV IRISUSERNAME=${IRISUSERNAME}
17+
ENV IRISPASSWORD=${IRISPASSWORD}
1618
ENV IRISNAMESPACE="IRISAPP"
1719
ENV PYTHON_PATH=/usr/irissys/bin/
1820
ENV LD_LIBRARY_PATH=${ISC_PACKAGE_INSTALLDIR}/bin

iris-start-and-wait.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/bash
2+
# Starts IRIS, initialises IOP (registers the /api/iop REST web app),
3+
# then idles indefinitely. Used as the container entrypoint in CI so
4+
# that remote e2e tests can be run against it from the outside via
5+
# `docker exec`.
6+
7+
set -e
8+
9+
iris start iris
10+
iris merge iris merge.cpf
11+
12+
cd /irisdev/app/src
13+
python3 -m iop --init
14+
15+
echo "IRIS is ready — /api/iop REST API available on port 52773"
16+
17+
# Block forever; the container will be stopped explicitly by the CI job.
18+
tail -f /dev/null

src/iop/_remote.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,11 @@ def stop_production(self) -> None:
131131
def shutdown_production(self) -> None:
132132
self._check_error(self._post("/kill"))
133133

134-
def restart_production(self) -> None:
135-
self._check_error(self._post("/restart"))
134+
def restart_production(self) -> dict:
135+
return self._check_error(self._post("/restart"))
136136

137-
def update_production(self) -> None:
138-
self._check_error(self._post("/update"))
137+
def update_production(self) -> dict:
138+
return self._check_error(self._post("/update"))
139139

140140
# ------------------------------------------------------------------
141141
# Logging
@@ -198,7 +198,10 @@ def test_component(
198198
payload["classname"] = classname
199199
if body:
200200
payload["body"] = body
201-
return self._check_error(self._post("/test", payload))
201+
try:
202+
return self._check_error(self._post("/test", payload))
203+
except requests.exceptions.HTTPError as exc:
204+
raise RuntimeError(str(exc)) from exc
202205

203206
# ------------------------------------------------------------------
204207
# Export

0 commit comments

Comments
 (0)