19
19
import asyncio
20
20
from contextlib import asynccontextmanager
21
21
from pathlib import Path
22
+ from secrets import token_hex
22
23
from types import SimpleNamespace
23
- from uuid import uuid1
24
24
25
25
import pytest
26
26
27
- from cylc .flow .exceptions import (
28
- WorkflowFilesError ,
29
- )
30
- from cylc .flow .install import (
31
- reinstall_workflow ,
32
- )
27
+ from cylc .flow .exceptions import WorkflowFilesError
28
+ from cylc .flow .install import reinstall_workflow
33
29
from cylc .flow .option_parsers import Options
34
30
from cylc .flow .scripts .reinstall import (
35
31
get_option_parser as reinstall_gop ,
36
32
reinstall_cli ,
37
33
)
38
- from cylc .flow .workflow_files import (
39
- WorkflowFiles ,
40
- )
34
+ from cylc .flow .workflow_files import WorkflowFiles
41
35
42
36
from .utils .entry_points import EntryPointWrapper
43
37
38
+
44
39
ReInstallOptions = Options (reinstall_gop ())
45
40
46
41
# cli opts
@@ -66,17 +61,30 @@ def non_interactive(monkeypatch):
66
61
)
67
62
68
63
64
+ @pytest .fixture
65
+ def answer_prompt (monkeypatch : pytest .MonkeyPatch ):
66
+ """Answer reinstall prompt."""
67
+
68
+ def inner (answer : str ):
69
+ monkeypatch .setattr (
70
+ 'cylc.flow.scripts.reinstall._input' , lambda x : answer
71
+ )
72
+
73
+ return inner
74
+
75
+
69
76
@pytest .fixture
70
77
def one_src (tmp_path ):
71
- src_dir = tmp_path
78
+ src_dir = tmp_path / 'src'
79
+ src_dir .mkdir ()
72
80
(src_dir / 'flow.cylc' ).touch ()
73
81
(src_dir / 'rose-suite.conf' ).touch ()
74
82
return SimpleNamespace (path = src_dir )
75
83
76
84
77
85
@pytest .fixture
78
86
def one_run (one_src , test_dir , run_dir ):
79
- w_run_dir = test_dir / str ( uuid1 () )
87
+ w_run_dir = test_dir / token_hex ( 4 )
80
88
w_run_dir .mkdir ()
81
89
(w_run_dir / 'flow.cylc' ).touch ()
82
90
(w_run_dir / 'rose-suite.conf' ).touch ()
@@ -151,7 +159,7 @@ async def test_interactive(
151
159
capsys ,
152
160
capcall ,
153
161
interactive ,
154
- monkeypatch
162
+ answer_prompt
155
163
):
156
164
"""It should perform a dry-run and prompt in interactive mode."""
157
165
# capture reinstall calls
@@ -162,11 +170,7 @@ async def test_interactive(
162
170
# give it something to reinstall
163
171
(one_src .path / 'a' ).touch ()
164
172
165
- # reinstall answering "no" to any prompt
166
- monkeypatch .setattr (
167
- 'cylc.flow.scripts.reinstall._input' ,
168
- lambda x : 'n'
169
- )
173
+ answer_prompt ('n' )
170
174
assert (
171
175
await reinstall_cli (opts = ReInstallOptions (), workflow_id = one_run .id )
172
176
is False
@@ -177,11 +181,7 @@ async def test_interactive(
177
181
assert 'Reinstall canceled, no changes made.' in capsys .readouterr ().out
178
182
reinstall_calls .clear ()
179
183
180
- # reinstall answering "yes" to any prompt
181
- monkeypatch .setattr (
182
- 'cylc.flow.scripts.reinstall._input' ,
183
- lambda x : 'y'
184
- )
184
+ answer_prompt ('y' )
185
185
assert await reinstall_cli (opts = ReInstallOptions (), workflow_id = one_run .id )
186
186
187
187
# two rsync calls should have been made (i.e. the --dry-run and the real)
@@ -241,7 +241,7 @@ async def test_rsync_stuff(one_src, one_run, capsys, non_interactive):
241
241
242
242
243
243
async def test_rose_warning (
244
- one_src , one_run , capsys , interactive , monkeypatch
244
+ one_src , one_run , capsys , interactive , answer_prompt
245
245
):
246
246
"""It should warn that Rose installed files will be deleted.
247
247
@@ -252,11 +252,7 @@ async def test_rose_warning(
252
252
'Files created by Rose file installation will show as deleted'
253
253
)
254
254
255
- # reinstall answering "no" to any prompt
256
- monkeypatch .setattr (
257
- 'cylc.flow.scripts.reinstall._input' ,
258
- lambda x : 'n'
259
- )
255
+ answer_prompt ('n' )
260
256
(one_src .path / 'a' ).touch () # give it something to install
261
257
262
258
# reinstall (with rose-suite.conf file)
@@ -311,6 +307,35 @@ async def test_rsync_fail(one_src, one_run, mock_glbl_cfg, non_interactive):
311
307
assert 'An error occurred reinstalling' in str (exc_ctx .value )
312
308
313
309
310
+ async def test_permissions_change (
311
+ one_src ,
312
+ one_run ,
313
+ interactive ,
314
+ answer_prompt ,
315
+ monkeypatch : pytest .MonkeyPatch ,
316
+ capsys : pytest .CaptureFixture ,
317
+ ):
318
+ """It detects permissions changes."""
319
+ # Add script file:
320
+ script_path : Path = one_src .path / 'myscript'
321
+ script_path .touch ()
322
+ await reinstall_cli (
323
+ opts = ReInstallOptions (skip_interactive = True ), workflow_id = one_run .id
324
+ )
325
+ assert (one_run .path / 'myscript' ).is_file ()
326
+ capsys .readouterr () # clears capsys
327
+
328
+ # Change permissions (e.g. user forgot to make it executable before)
329
+ script_path .chmod (0o777 )
330
+ # Answer "no" to reinstall prompt (we just want to test dry run)
331
+ answer_prompt ('n' )
332
+ await reinstall_cli (
333
+ opts = ReInstallOptions (), workflow_id = one_run .id
334
+ )
335
+ out , _ = capsys .readouterr ()
336
+ assert "send myscript" in out
337
+
338
+
314
339
@pytest .fixture
315
340
def my_install_plugin (monkeypatch ):
316
341
"""This configures a single post_install plugin.
0 commit comments