Skip to content

Commit 0138345

Browse files
committed
Github Action for GlobusComputeExecutor (#3619)
* Support for testing GlobusComputeExecutor in a github action * Adding shared_fs and staging_required tags to tests * Adding GlobusComputeExecutor test config
1 parent 372f1c6 commit 0138345

26 files changed

+189
-15
lines changed

.github/workflows/gce_test.yaml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
name: GlobusComputeExecutor tests
2+
3+
on:
4+
pull_request:
5+
types:
6+
- opened
7+
- synchronize
8+
9+
workflow_dispatch:
10+
inputs:
11+
tags:
12+
description: 'Test scenario tags'
13+
required: false
14+
type: boolean
15+
16+
jobs:
17+
main-test-suite:
18+
strategy:
19+
matrix:
20+
python-version: ["3.11"]
21+
runs-on: ubuntu-20.04
22+
timeout-minutes: 60
23+
24+
steps:
25+
- uses: actions/checkout@master
26+
27+
- name: Set up Python ${{ matrix.python-version }}
28+
uses: actions/setup-python@v4
29+
with:
30+
python-version: ${{ matrix.python-version }}
31+
32+
- name: Collect Job Information
33+
id: job-info
34+
run: |
35+
echo "Python Version: ${{ matrix.python-version }}" >> ci_job_info.txt
36+
echo "CI Triggering Event: ${{ github.event_name }}" >> ci_job_info.txt
37+
echo "Triggering Git Ref: ${{ github.ref }}" >> ci_job_info.txt
38+
echo "Triggering Git SHA: ${{ github.sha }}" >> ci_job_info.txt
39+
echo "Workflow Run: ${{ github.run_number }}" >> ci_job_info.txt
40+
echo "Workflow Attempt: ${{ github.run_attempt }}" >> ci_job_info.txt
41+
as_ascii="$(echo "${{ github.ref_name }}" | perl -pe "s/[^A-z0-9-]+/-/g; s/^-+|-+\$//g; s/--+/-/g;")"
42+
echo "as-ascii=$as_ascii" >> $GITHUB_OUTPUT
43+
44+
- name: Non-requirements based install
45+
run: |
46+
# libpython3.5: make workqueue binary installer happy
47+
# mpich: required by radical executor
48+
sudo apt-get update -q
49+
sudo apt-get install -qy libpython3.5 mpich
50+
51+
- name: setup virtual env
52+
run: |
53+
make virtualenv
54+
source .venv/bin/activate
55+
56+
- name: make deps clean_coverage
57+
run: |
58+
source .venv/bin/activate
59+
make deps
60+
make clean_coverage
61+
62+
# Temporary fix, until changes make it into compute releases
63+
git clone -b configure_tasks_working_dir https://github.com/globus/globus-compute.git
64+
pip3 install globus-compute/compute_sdk globus-compute/compute_endpoint
65+
66+
- name: start globus_compute_endpoint
67+
env:
68+
GLOBUS_COMPUTE_CLIENT_ID: ${{ secrets.GLOBUS_COMPUTE_CLIENT_ID }}
69+
GLOBUS_COMPUTE_CLIENT_SECRET: ${{ secrets.GLOBUS_COMPUTE_SECRET_KEY }}
70+
run: |
71+
source /home/runner/work/parsl/parsl/.venv/bin/activate
72+
globus-compute-endpoint configure default
73+
which globus-compute-endpoint
74+
python3 -c "import globus_compute_sdk; print(globus_compute_sdk.__version__)"
75+
python3 -c "import globus_compute_endpoint; print(globus_compute_endpoint.__version__)"
76+
cat << EOF > /home/runner/.globus_compute/default/config.yaml
77+
engine:
78+
type: ThreadPoolEngine
79+
max_workers: 4
80+
working_dir: /home/runner/.globus_compute/default/tasks_working_dir
81+
EOF
82+
cat /home/runner/.globus_compute/default/config.yaml
83+
mkdir ~/.globus_compute/default/tasks_working_dir
84+
globus-compute-endpoint start default
85+
globus-compute-endpoint list
86+
- name: make test
87+
env:
88+
GLOBUS_COMPUTE_CLIENT_ID: ${{ secrets.GLOBUS_COMPUTE_CLIENT_ID }}
89+
GLOBUS_COMPUTE_CLIENT_SECRET: ${{ secrets.GLOBUS_COMPUTE_SECRET_KEY }}
90+
run: |
91+
source .venv/bin/activate
92+
export GLOBUS_COMPUTE_ENDPOINT=$(globus-compute-endpoint list | grep default | cut -c 3-38)
93+
echo "GLOBUS_COMPUTE_ENDPOINT = $GLOBUS_COMPUTE_ENDPOINT"
94+
95+
# temporary; until test-matrixification
96+
export PARSL_TEST_PRESERVE_NUM_RUNS=7
97+
98+
make gce_test
99+
ln -s .pytest/parsltest-current test_runinfo
100+
101+
- name: Archive runinfo logs
102+
if: ${{ always() }}
103+
uses: actions/upload-artifact@v4
104+
with:
105+
name: runinfo-${{ matrix.python-version }}-${{ steps.job-info.outputs.as-ascii }}-${{ github.sha }}
106+
path: |
107+
runinfo/
108+
.pytest/
109+
ci_job_info.txt
110+
compression-level: 9

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ clean_coverage:
5151
mypy: ## run mypy checks
5252
MYPYPATH=$(CWD)/mypy-stubs mypy parsl/
5353

54+
.PHONY: gce_test
55+
gce_test: ## Run tests with GlobusComputeExecutor
56+
pytest -v -k "not shared_fs and not issue_3620 and not staging_required" --config parsl/tests/configs/globus_compute.py parsl/tests/ --random-order --durations 10
57+
5458
.PHONY: local_thread_test
5559
local_thread_test: ## run all tests with local_thread config
5660
pytest parsl/tests/ -k "not cleannet" --config parsl/tests/configs/local_threads.py --random-order --durations 10

docs/reference.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Executors
7777
parsl.executors.taskvine.TaskVineExecutor
7878
parsl.executors.FluxExecutor
7979
parsl.executors.radical.RadicalPilotExecutor
80+
parsl.executors.globus_compute.GlobusComputeExecutor
8081

8182
Manager Selectors
8283
=================

parsl/executors/globus_compute.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,13 @@
22
from concurrent.futures import Future
33
from typing import Any, Callable, Dict, Optional, Union
44

5-
import typeguard
6-
75
from parsl.errors import OptionalModuleMissing
86
from parsl.executors.base import ParslExecutor
97
from parsl.utils import RepresentationMixin
108

119
UUID_LIKE_T = Union[uuid.UUID, str]
1210

1311

14-
1512
class GlobusComputeExecutor(ParslExecutor, RepresentationMixin):
1613
""" GlobusComputeExecutor enables remote execution on Globus Compute endpoints
1714
@@ -25,15 +22,14 @@ def __init__(
2522
self,
2623
endpoint_id: Optional[UUID_LIKE_T] = None,
2724
task_group_id: Optional[UUID_LIKE_T] = None,
28-
resource_specification: Optional[dict[str, Any]] = None,
29-
user_endpoint_config: Optional[dict[str, Any]] = None,
25+
resource_specification: Optional[Dict[str, Any]] = None,
26+
user_endpoint_config: Optional[Dict[str, Any]] = None,
3027
label: str = "GlobusComputeExecutor",
3128
batch_size: int = 128,
3229
amqp_port: Optional[int] = None,
3330
**kwargs,
34-
):
31+
):
3532
"""
36-
3733
Parameters
3834
----------
3935
@@ -141,5 +137,3 @@ def shutdown(self, wait=True, *, cancel_futures=False):
141137
Tasks cannot be cancelled once they are registered.
142138
"""
143139
return self._executor.shutdown()
144-
145-
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import os
2+
3+
from parsl.config import Config
4+
from parsl.executors import GlobusComputeExecutor
5+
6+
7+
def fresh_config():
8+
9+
endpoint_id = os.environ["GLOBUS_COMPUTE_ENDPOINT"]
10+
11+
return Config(
12+
executors=[
13+
GlobusComputeExecutor(
14+
label="globus_compute",
15+
endpoint_id=endpoint_id
16+
)
17+
]
18+
)

parsl/tests/conftest.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,18 @@ def pytest_configure(config):
163163
'markers',
164164
'executor_supports_std_stream_tuples: Marks tests that require tuple support for stdout/stderr'
165165
)
166+
config.addinivalue_line(
167+
'markers',
168+
'globus_compute: Marks tests that require a valid globus_compute target'
169+
)
170+
config.addinivalue_line(
171+
'markers',
172+
'shared_fs: Marks tests that require a shared_fs between the workers are the test client'
173+
)
174+
config.addinivalue_line(
175+
'markers',
176+
'issue_3620: Marks tests that do not work correctly on GlobusComputeExecutor (ref: issue 3620)'
177+
)
166178

167179

168180
@pytest.fixture(autouse=True, scope='session')

parsl/tests/test_bash_apps/test_basic.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def foo(x, y, z=10, stdout=None, label=None):
2424
return f"echo {x} {y} {z}"
2525

2626

27+
@pytest.mark.shared_fs
2728
def test_command_format_1(tmpd_cwd):
2829
"""Testing command format for BashApps"""
2930

@@ -38,6 +39,7 @@ def test_command_format_1(tmpd_cwd):
3839
assert so_content == "1 4 10"
3940

4041

42+
@pytest.mark.shared_fs
4143
def test_auto_log_filename_format(caplog):
4244
"""Testing auto log filename format for BashApps
4345
"""
@@ -66,6 +68,7 @@ def test_auto_log_filename_format(caplog):
6668
assert record.levelno < logging.ERROR
6769

6870

71+
@pytest.mark.shared_fs
6972
def test_parallel_for(tmpd_cwd, n=3):
7073
"""Testing a simple parallel for loop"""
7174
outdir = tmpd_cwd / "outputs/test_parallel"

parsl/tests/test_bash_apps/test_error_codes.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def bad_format(stderr='std.err', stdout='std.out'):
5858
whitelist = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'configs', '*threads*')
5959

6060

61+
@pytest.mark.shared_fs
6162
def test_div_0(test_fn=div_0):
6263
err_code = test_matrix[test_fn]['exit_code']
6364
f = test_fn()
@@ -73,6 +74,7 @@ def test_div_0(test_fn=div_0):
7374
os.remove('std.out')
7475

7576

77+
@pytest.mark.shared_fs
7678
def test_bash_misuse(test_fn=bash_misuse):
7779
err_code = test_matrix[test_fn]['exit_code']
7880
f = test_fn()
@@ -87,6 +89,7 @@ def test_bash_misuse(test_fn=bash_misuse):
8789
os.remove('std.out')
8890

8991

92+
@pytest.mark.shared_fs
9093
def test_command_not_found(test_fn=command_not_found):
9194
err_code = test_matrix[test_fn]['exit_code']
9295
f = test_fn()
@@ -103,6 +106,7 @@ def test_command_not_found(test_fn=command_not_found):
103106
return True
104107

105108

109+
@pytest.mark.shared_fs
106110
def test_not_executable(test_fn=not_executable):
107111
err_code = test_matrix[test_fn]['exit_code']
108112
f = test_fn()

parsl/tests/test_bash_apps/test_kwarg_storage.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ def foo(z=2, stdout=None):
88
return f"echo {z}"
99

1010

11+
@pytest.mark.shared_fs
1112
def test_command_format_1(tmpd_cwd):
1213
"""Testing command format for BashApps
1314
"""

parsl/tests/test_bash_apps/test_memoize.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ def fail_on_presence(outputs=()):
99
return 'if [ -f {0} ] ; then exit 1 ; else touch {0}; fi'.format(outputs[0])
1010

1111

12-
# This test is an oddity that requires a shared-FS and simply
13-
# won't work if there's a staging provider.
14-
# @pytest.mark.sharedFS_required
12+
@pytest.mark.shared_fs
1513
def test_bash_memoization(tmpd_cwd, n=2):
1614
"""Testing bash memoization
1715
"""
@@ -29,9 +27,7 @@ def fail_on_presence_kw(outputs=(), foo=None):
2927
return 'if [ -f {0} ] ; then exit 1 ; else touch {0}; fi'.format(outputs[0])
3028

3129

32-
# This test is an oddity that requires a shared-FS and simply
33-
# won't work if there's a staging provider.
34-
# @pytest.mark.sharedFS_required
30+
@pytest.mark.shared_fs
3531
def test_bash_memoization_keywords(tmpd_cwd, n=2):
3632
"""Testing bash memoization
3733
"""

0 commit comments

Comments
 (0)