Skip to content

Commit

Permalink
Merge pull request #315 from cylc/1.3.x-sync
Browse files Browse the repository at this point in the history
🤖 Merge 1.3.x-sync into master
  • Loading branch information
MetRonnie authored May 9, 2024
2 parents 69f321c + f33490d commit 6bde9de
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 3 deletions.
10 changes: 10 additions & 0 deletions cylc/rose/entry_points.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Top level module providing entry point functions."""

import os
from pathlib import Path
from typing import TYPE_CHECKING

from cylc.rose.utilities import (
ROSE_SUITE_OPT_CONF_KEYS,
copy_config_file,
dump_rose_log,
export_environment,
Expand Down Expand Up @@ -71,6 +73,14 @@ def post_install(srcdir: Path, rundir: str, opts: 'Values') -> bool:
if config_node:
dump_rose_log(rundir=_rundir, node=config_node)

# Having dumped the config we clear rose options
# as they do not apply after this.
# see https://github.com/cylc/cylc-rose/pull/312
opts.rose_template_vars = []
opts.opt_conf_keys = []
opts.defines = []
os.unsetenv(ROSE_SUITE_OPT_CONF_KEYS)

return True


Expand Down
7 changes: 4 additions & 3 deletions cylc/rose/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
from cylc.flow.option_parsers import Values


ROSE_SUITE_OPT_CONF_KEYS = 'ROSE_SUITE_OPT_CONF_KEYS'
SECTIONS = {'jinja2:suite.rc', 'empy:suite.rc', 'template variables'}
SET_BY_CYLC = 'set by Cylc'
ROSE_ORIG_HOST_INSTALLED_OVERRIDE_STRING = (
Expand Down Expand Up @@ -275,7 +276,7 @@ def rose_config_tree_loader(
opt_conf_keys = []

# get optional config key set as environment variable:
opt_conf_keys_env = os.getenv("ROSE_SUITE_OPT_CONF_KEYS")
opt_conf_keys_env = os.getenv(ROSE_SUITE_OPT_CONF_KEYS)
if opt_conf_keys_env:
opt_conf_keys += shlex.split(opt_conf_keys_env)

Expand Down Expand Up @@ -615,8 +616,8 @@ def merge_opts(config, opt_conf_keys):
"""
all_opt_conf_keys = []
all_opt_conf_keys.append(config['opts'].value)
if "ROSE_SUITE_OPT_CONF_KEYS" in os.environ:
all_opt_conf_keys.append(os.environ["ROSE_SUITE_OPT_CONF_KEYS"])
if ROSE_SUITE_OPT_CONF_KEYS in os.environ:
all_opt_conf_keys.append(os.environ[ROSE_SUITE_OPT_CONF_KEYS])
if opt_conf_keys and isinstance(opt_conf_keys, str):
all_opt_conf_keys.append(opt_conf_keys)
if opt_conf_keys and isinstance(opt_conf_keys, list):
Expand Down
65 changes: 65 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import asyncio
from functools import partial
from io import StringIO
from pathlib import Path
from shlex import split
from shutil import rmtree
from subprocess import run
from time import sleep
from types import SimpleNamespace
from uuid import uuid4

Expand Down Expand Up @@ -392,3 +396,64 @@ def test_dir(request, mod_test_dir):
else:
# test failed -> remove the test dir if empty
_rm_if_empty(path)


@pytest.fixture
def file_poll():
"""Poll for the existance of a file.
"""
def _inner(
fpath: "Path", timeout: int = 5, inverse: bool = False
):
timeout_func(
lambda: fpath.exists() != inverse,
f"file {fpath} {'still' if inverse else 'not'} found after "
f"{timeout} seconds",
timeout
)
return _inner


@pytest.fixture
def purge_workflow(run_ok, file_poll):
"""Ensure workflow is stopped and cleaned"""
def _inner(id_, timeout=5):
stop = f'cylc stop {id_} --now --now'
clean = f'cylc clean {id_}'
timeout_func(
partial(run_ok, stop),
message=f'Not run after {timeout} seconds: {stop}',
timeout=timeout
)
file_poll(
Path.home() / 'cylc-run' / id_ / '.service/contact',
inverse=True,
)
timeout_func(
partial(run_ok, clean),
message=f'Not run after {timeout} seconds: {clean}',
timeout=timeout
)
return _inner


@pytest.fixture
def run_ok():
"""Run a bash script.
Fail if it fails and return its output.
"""
def _inner(script: str):
result = run(split(script), capture_output=True)
assert result.returncode == 0, f'{script} failed: {result.stderr}'
return result
return _inner


def timeout_func(func, message, timeout=5):
"""Wrap a function in a timeout"""
for _ in range(timeout):
if func():
break
sleep(1)
else:
raise TimeoutError(message)
77 changes: 77 additions & 0 deletions tests/functional/test_reinstall_overrides.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@

# THIS FILE IS PART OF THE ROSE-CYLC PLUGIN FOR THE CYLC WORKFLOW ENGINE.
# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Functional tests checking Cylc reinstall and reload behaviour is correct
WRT to deletion of Rose Options at the end of the post install plugin.
https://github.com/cylc/cylc-rose/pull/312
"""


from pathlib import Path
from textwrap import dedent


async def test_reinstall_overrides(
cylc_install_cli,
cylc_reinstall_cli,
workflow_name,
file_poll,
tmp_path,
purge_workflow,
run_ok
):
"""When reinstalling and reloading the new installation are picked up.
> cylc install this -S 'var=CLIinstall'
> cylc play this --pause
> cylc reinstall this -S 'var=CLIreinstall'
> cylc play this --pause
See https://github.com/cylc/cylc-flow/issues/5968
"""
(tmp_path / 'flow.cylc').write_text(dedent(""" #!jinja2
[scheduling]
[[graph]]
R1 = foo
[runtime]
[[foo]]
script = cylc message -- {{var}}
"""))
(tmp_path / 'rose-suite.conf').write_text(
'[template variables]\nvar="rose-suite.conf"')

# Install workflow.
wid, _ = await cylc_install_cli(
tmp_path,
workflow_name=workflow_name,
opts={'rose_template_vars': ['var="CLIinstall"']})

# Play workflow
run_ok(f'cylc play --pause {wid}')

# Reinstall the workflow:
await cylc_reinstall_cli(
wid,
{'rose_template_vars': ['var="CLIreinstall"']})

# Reload the workflow:
run_ok(f'cylc reload {wid}')

# The config being run has been modified:
run_dir = Path.home() / 'cylc-run' / wid
config_log = (run_dir / 'log/config/02-reload-01.cylc')
file_poll(config_log)
assert 'cylc message -- CLIreinstall' in config_log.read_text()

purge_workflow(wid)

0 comments on commit 6bde9de

Please sign in to comment.