Skip to content

Commit

Permalink
refactor(ci/test): switch to awvwgk/setup-fortran, use pytest tempdir…
Browse files Browse the repository at this point in the history
… fixtures
  • Loading branch information
wpbonelli committed Jul 25, 2023
1 parent 8f804f9 commit 540b659
Show file tree
Hide file tree
Showing 14 changed files with 518 additions and 946 deletions.
11 changes: 8 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ on:
schedule:
- cron: '0 7 * * *' # run at 7 AM UTC every day
push:
branches: [ master ]
branches:
- master
- test*
pull_request:
branches:
- master
Expand All @@ -25,8 +27,11 @@ jobs:
- name: Checkout repo
uses: actions/checkout@v3

- name: Setup Intel OneAPI Compilers
uses: modflowpy/install-intelfortran-action@v1
- name: Setup Intel Fortran Classic
uses: awvwgk/setup-fortran@main
with:
compiler: intel-classic
version: 2021.7.0

- name: Setup Graphviz
if: runner.os == 'Linux'
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/pymake-gcc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ jobs:
python -m pip install --upgrade pip
pip install ".[test]"
- name: Install GNU Fortran
uses: modflowpy/install-gfortran-action@v1
- name: Setup GNU Fortran
uses: awvwgk/setup-fortran@main
with:
compiler: gcc
version: 11

- name: Download examples for pytest runs
run: |
Expand Down
1 change: 1 addition & 0 deletions pytest.ini → autotest/pytest.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[pytest]
markers =
base: base tests
dependency: tests that depend on other tests (via pytest-dependency)
regression: regression tests
requests: usgsprograms requests tests
schedule: tests to run if a scheduled job
48 changes: 9 additions & 39 deletions autotest/test_cli_cmds.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import os
import pathlib as pl
import shutil
import subprocess

import pytest
Expand All @@ -13,12 +11,6 @@
"crt",
)

# set up paths
dstpth = pl.Path(
f"temp_{os.path.basename(__file__).replace('.py', '')}"
).resolve()
dstpth.mkdir(parents=True, exist_ok=True)


def run_cli_cmd(cmd: list) -> None:
process = subprocess.Popen(
Expand All @@ -39,38 +31,29 @@ def run_cli_cmd(cmd: list) -> None:
return


def clean_up() -> None:
print("Removing temporary build directories")
dirs_temp = [dstpth]
for d in dirs_temp:
if os.path.isdir(d):
shutil.rmtree(d)
return


@flaky(max_runs=RERUNS)
@pytest.mark.dependency(name="make_program")
@pytest.mark.base
@flaky(max_runs=RERUNS)
@pytest.mark.parametrize("target", targets)
def test_make_program(target: str) -> None:
def test_make_program(module_tmpdir, target: str) -> None:
cmd = [
"make-program",
target,
"--appdir",
str(dstpth),
str(module_tmpdir),
"--verbose",
]
run_cli_cmd(cmd)


@pytest.mark.dependency(name="make_program_all")
@pytest.mark.schedule
def test_make_program_all() -> None:
def test_make_program_all(module_tmpdir) -> None:
cmd = [
"make-program",
":",
"--appdir",
str(dstpth / "all"),
str(module_tmpdir / "all"),
"--verbose",
"--dryrun",
]
Expand All @@ -79,14 +62,14 @@ def test_make_program_all() -> None:

@pytest.mark.dependency(name="mfpymake")
@pytest.mark.base
def test_mfpymake() -> None:
def test_mfpymake(module_tmpdir) -> None:
src = (
"program hello\n"
+ " ! This is a comment line; it is ignored by the compiler\n"
+ " print *, 'Hello, World!'\n"
+ "end program hello\n"
)
src_file = dstpth / "mfpymake_src/hello.f90"
src_file = module_tmpdir / "mfpymake_src" / "hello.f90"
src_file.parent.mkdir(parents=True, exist_ok=True)
with open(src_file, "w") as f:
f.write(src)
Expand All @@ -97,26 +80,13 @@ def test_mfpymake() -> None:
"-mc",
"--verbose",
"--appdir",
str(dstpth),
str(module_tmpdir),
"-fc",
]
if os.environ.get("FC") is None:
cmd.append("gfortran")
else:
cmd.append(os.environ.get("FC"))
run_cli_cmd(cmd)
cmd = [dstpth / "hello"]
cmd = [module_tmpdir / "hello"]
run_cli_cmd(cmd)


@pytest.mark.dependency(name="clean", depends=["make_program"])
@pytest.mark.base
def test_clean_up() -> None:
clean_up()
return


if __name__ == "__main__":
for target in targets:
test_make_program(target)
test_clean_up()
163 changes: 57 additions & 106 deletions autotest/test_gridgen.py
Original file line number Diff line number Diff line change
@@ -1,88 +1,47 @@
import os
import pathlib as pl
import shutil
import subprocess
import sys

import pytest

import pymake

# use the line below to set fortran compiler using environmental variables
# if sys.platform.lower() == "win32":
# os.environ["CC"] = "icl"
# else:
# os.environ["CC"] = "icc"

# define program data
target = "gridgen"
if sys.platform.lower() == "win32":
target += ".exe"

# get program dictionary
prog_dict = pymake.usgs_program_data.get_target(target)

# set up paths
dstpth = pl.Path(f"temp_{os.path.basename(__file__).replace('.py', '')}")
dstpth.mkdir(parents=True, exist_ok=True)

ver = prog_dict.version
pth = dstpth / prog_dict.dirname
expth = pth / "examples/biscayne"
exe_name = dstpth / target

pm = pymake.Pymake(verbose=True)
pm.target = target
pm.appdir = str(dstpth)
env_var = os.environ.get("CC")
if env_var is not None:
pm.cc = env_var
else:
pm.cc = "g++"
pm.fc = None
pm.inplace = True
pm.makeclean = True

biscayne_cmds = [
"buildqtg action01_buildqtg.dfn",
"grid02qtg-to-usgdata action02_writeusgdata.dfn",
"grid01mfg-to-polyshapefile action03_shapefile.dfn",
"grid02qtg-to-polyshapefile action03_shapefile.dfn",
"grid01mfg-to-pointshapefile action03_shapefile.dfn",
"grid02qtg-to-pointshapefile action03_shapefile.dfn",
"canal_grid02qtg_lay1_intersect action04_intersect.dfn",
"chd_grid02qtg_lay1_intersect action04_intersect.dfn",
"grid01mfg-to-vtkfile action05_vtkfile.dfn",
"grid02qtg-to-vtkfile action05_vtkfile.dfn",
"grid02qtg-to-vtkfilesv action05_vtkfile.dfn",
]


def clean_up():
print("Removing test files and directories")

# finalize pymake object
pm.finalize()

if os.path.isfile(exe_name):
print(f"Removing {target}")
os.remove(exe_name)
@pytest.fixture(scope="module")
def target(module_tmpdir) -> pl.Path:
target = "gridgen"
# if sys.platform.lower() == "win32":
# target += ".exe"
return module_tmpdir / target


print(f"Removing folder {pth}")
if pth.is_dir():
shutil.rmtree(pth)
@pytest.fixture(scope="module")
def prog_data(target) -> dict:
return pymake.usgs_program_data.get_target(target.name)

dirs_temp = [dstpth]
for d in dirs_temp:
if d.is_dir():
shutil.rmtree(d)

return
@pytest.fixture(scope="module")
def workspace(module_tmpdir, prog_data) -> pl.Path:
return module_tmpdir / prog_data.dirname


def run_command(cmdlist, cwd):
@pytest.fixture(scope="module")
def pm(module_tmpdir, target) -> pymake.Pymake:
pm = pymake.Pymake(verbose=True)
pm.target = str(target)
pm.appdir = str(module_tmpdir)
pm.cc = os.environ.get("CC", "g++")
pm.fc = None
pm.inplace = True
pm.makeclean = True
yield pm
pm.finalize()


def run_command(args, cwd):
p = subprocess.Popen(
cmdlist,
args,
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
Expand All @@ -94,51 +53,43 @@ def run_command(cmdlist, cwd):
return retval


def run_gridgen(cmd):
success = False
prog = os.path.abspath(exe_name)
if os.path.exists(prog):
testpth = os.path.abspath(expth)

cmdlist = [prog] + cmd.split()
print(f"running {' '.join(cmdlist)}")
retcode = run_command(cmdlist, testpth)
if retcode == 0:
success = True

return success
def run_gridgen(cmd, ws, exe):
args = [str(exe)] + cmd.split()
print(f"running {' '.join(args)}")
return run_command(args, ws) == 0


@pytest.mark.dependency(name="download")
@pytest.mark.base
def test_download():
# Remove the existing target download directory if it exists
if dstpth.is_dir():
shutil.rmtree(dstpth)

# download the target
pm.download_target(target, download_path=dstpth)
def test_download(pm, module_tmpdir, target):
pm.download_target(target, download_path=module_tmpdir)
assert pm.download, f"could not download {target} distribution"


@pytest.mark.dependency(name="build", depends=["download"])
@pytest.mark.base
def test_compile():
def test_compile(pm, target):
assert pm.build() == 0, f"could not compile {target}"
assert target.is_file()


@pytest.mark.dependency(name="test", depends=["build"])
@pytest.mark.regression
@pytest.mark.parametrize("cmd", biscayne_cmds)
def test_gridgen(cmd):
assert run_gridgen(cmd), f"could not run {cmd}"


@pytest.mark.base
def test_clean_up():
clean_up()


if __name__ == "__main__":
test_download()
test_compile()
# for cmd in biscayne_cmds:
# run_gridgen(cmd)
test_clean_up()
@pytest.mark.parametrize(
"cmd",
[
"buildqtg action01_buildqtg.dfn",
"grid02qtg-to-usgdata action02_writeusgdata.dfn",
"grid01mfg-to-polyshapefile action03_shapefile.dfn",
"grid02qtg-to-polyshapefile action03_shapefile.dfn",
"grid01mfg-to-pointshapefile action03_shapefile.dfn",
"grid02qtg-to-pointshapefile action03_shapefile.dfn",
"canal_grid02qtg_lay1_intersect action04_intersect.dfn",
"chd_grid02qtg_lay1_intersect action04_intersect.dfn",
"grid01mfg-to-vtkfile action05_vtkfile.dfn",
"grid02qtg-to-vtkfile action05_vtkfile.dfn",
"grid02qtg-to-vtkfilesv action05_vtkfile.dfn",
],
)
def test_gridgen(cmd, workspace, target):
assert run_gridgen(cmd, workspace / "examples" / "biscayne", target), f"could not run {cmd}"
Loading

0 comments on commit 540b659

Please sign in to comment.