Skip to content

Commit f03bbad

Browse files
author
Alan Christie
committed
Fixes test with multi-line commands
Inputs now require an explicit prefix (enforced) Introduces a '--wipe' --dry-run and --keep-results can now be used together
1 parent 707bd01 commit f03bbad

File tree

2 files changed

+67
-17
lines changed

2 files changed

+67
-17
lines changed

jote/compose.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ def _get_docker_compose_version() -> str:
4545
return result.stdout.decode("utf-8").split('\n')[0][23:]
4646

4747

48+
def get_test_root() -> str:
49+
"""Returns the root of the testing directory.
50+
"""
51+
cwd: str = os.getcwd()
52+
return f'{cwd}/data-manager/jote'
53+
54+
4855
class Compose:
4956

5057
# The docker-compose version (for the first test)
@@ -69,8 +76,8 @@ def __init__(self, collection: str,
6976
def get_test_path(self) -> str:
7077
"""Returns the path to the root directory for a given test.
7178
"""
72-
cwd: str = os.getcwd()
73-
return f'{cwd}/data-manager/jote/{self._collection}.{self._job}.{self._test}'
79+
root: str = get_test_root()
80+
return f'{root}/{self._collection}.{self._job}.{self._test}'
7481

7582
def get_test_project_path(self) -> str:
7683
"""Returns the path to the root directory for a given test.
@@ -147,7 +154,7 @@ def run(self) -> Tuple[int, str, str]:
147154
finally:
148155
os.chdir(cwd)
149156

150-
print(f'# Executed ({test.returncode})')
157+
print(f'# Executed (exit code {test.returncode})')
151158

152159
return test.returncode,\
153160
test.stdout.decode("utf-8"),\

jote/jote.py

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@
1515

1616
from decoder import decoder
1717

18+
from .compose import get_test_root
1819
from .compose import Compose
1920

2021
# Where can we expect to find Job definitions?
2122
_DEFINITION_DIRECTORY: str = 'data-manager'
23+
# Data directory
24+
_DATA_DIRECTORY: str = 'data'
2225

2326
# The yamllint configuration file of the repository under test.
2427
# Expected to be in the repo we're running from.
@@ -70,7 +73,8 @@ def _check_cwd() -> bool:
7073
' but it is not here')
7174
return False
7275

73-
expected_directories: List[str] = [_DEFINITION_DIRECTORY]
76+
expected_directories: List[str] = [_DEFINITION_DIRECTORY,
77+
_DATA_DIRECTORY]
7478
for expected_directory in expected_directories:
7579
if not os.path.isdir(expected_directory):
7680
print(f'! Expected directory "{expected_directory}"'
@@ -113,19 +117,29 @@ def _load(skip_lint: bool = False) -> Tuple[List[DefaultMunch], int]:
113117
def _copy_inputs(test_inputs: DefaultMunch,
114118
project_path: str) -> bool:
115119
"""Copies all the test files into the test project directory.
116-
Files are expected to reside in the repo's 'data' directory.
120+
Files are expected to reside in the repo's 'data' directory
121+
and must begin 'data/'
117122
"""
118123

119124
# The files are assumed to reside in the repo's 'data' directory.
120-
print('# Copying inputs...')
125+
print(f'# Copying inputs (from "${{PWD}}/{_DATA_DIRECTORY}")...')
121126

127+
expected_prefix: str = f'{_DATA_DIRECTORY}/'
122128
for test_input in test_inputs:
123-
test_file: str = os.path.join('data', test_inputs[test_input])
129+
130+
test_file: str = test_inputs[test_input]
124131
print(f'# + {test_file} ({test_input})')
132+
133+
if not test_file.startswith(expected_prefix):
134+
print('! FAILURE')
135+
print(f'! Input file {test_file} must start with "{expected_prefix}"')
136+
return False
125137
if not os.path.isfile(test_file):
126138
print('! FAILURE')
127-
print(f'! missing input file {test_file} ({test_input})')
139+
print(f'! Missing input file {test_file} ({test_input})')
128140
return False
141+
142+
# Looks OK, copy it
129143
shutil.copy(test_file, project_path)
130144

131145
print('# Copied')
@@ -236,26 +250,35 @@ def _test(args: argparse.Namespace,
236250
_print_test_banner(collection, job, job_test_name)
237251

238252
# Render the command for this test.
239-
# First extract the variables and values form options and inputs...
253+
# First extract the variables and values from 'options'
254+
# and then 'inputs'...
240255
job_variables: Dict[str, Any] = {}
241256
for variable in job_definition.tests[job_test_name].options:
242257
job_variables[variable] =\
243258
job_definition.tests[job_test_name].options[variable]
259+
# We only pass the basename of the input to the command decoding
260+
# i.e. strip the source directory.
244261
for variable in job_definition.tests[job_test_name].inputs:
245262
job_variables[variable] =\
246-
job_definition.tests[job_test_name].inputs[variable]
247-
# Get the raw (encoded) command
263+
os.path.basename(job_definition.tests[job_test_name]
264+
.inputs[variable])
265+
266+
# Get the raw (encoded) command from the job definition...
248267
raw_command: str = job_definition.command
249-
# Apply the rendering...
250-
job_command, test_status =\
268+
# Decode it using our variables...
269+
decoded_command, test_status =\
251270
decoder.decode(raw_command,
252271
job_variables,
253272
'command',
254273
decoder.TextEncoding.JINJA2_3_0)
255274
if not test_status:
256275
print('! FAILURE')
257276
print('! Failed to render command')
258-
print('! error={job_command}')
277+
print(f'! error={decoded_command}')
278+
279+
# The command must not contain new-lines.
280+
# So split then join the command.
281+
job_command: str = ''.join(decoded_command.splitlines())
259282

260283
# Create the test directories, docker-compose file
261284
# and copy inputs...
@@ -317,7 +340,7 @@ def _test(args: argparse.Namespace,
317340
job_definition.tests[job_test_name].checks.outputs)
318341

319342
# Clean-up
320-
if test_status:
343+
if test_status and not args.keep_results:
321344
t_compose.delete()
322345

323346
# Told to stop on first failure?
@@ -327,6 +350,12 @@ def _test(args: argparse.Namespace,
327350
return test_status
328351

329352

353+
def _wipe() -> None:
354+
"""Wipes the results of all tests.
355+
"""
356+
shutil.rmtree(get_test_root())
357+
358+
330359
# -----------------------------------------------------------------------------
331360
# main
332361
# -----------------------------------------------------------------------------
@@ -383,14 +412,21 @@ def main() -> None:
383412
' configuration of the repository under test.'
384413
' Using this flag skips that step')
385414

415+
arg_parser.add_argument('-w', '--wipe', action='store_true',
416+
help='Wipe does nto run any tests, it simply'
417+
' wipes the repository clean of jote'
418+
' test material. It would be wise'
419+
' to run this once you have finished testing.'
420+
' Using this negates the effect of any other'
421+
' option.')
422+
386423
args: argparse.Namespace = arg_parser.parse_args()
387424

388425
if args.test and args.job is None:
389426
arg_parser.error('--test requires --job')
390427
if args.job and args.collection is None:
391428
arg_parser.error('--job requires --collection')
392-
if args.keep_results and args.dry_run:
393-
arg_parser.error('Cannot use --dry-run and --keep-results')
429+
394430
# Args are OK if we get here.
395431
test_fail_count: int = 0
396432

@@ -400,6 +436,13 @@ def main() -> None:
400436
print('! The directory does not look correct')
401437
arg_parser.error('Done (FAILURE)')
402438

439+
# Told to wipe?
440+
# If so wipe, and leave.
441+
if args.wipe:
442+
_wipe()
443+
print(f'Done [Wiped]')
444+
return
445+
403446
# Load all the files we can and then run the tests.
404447
job_definitions, num_tests = _load(args.skip_lint)
405448
if num_tests < 0:

0 commit comments

Comments
 (0)