Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
188 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# This file is part of REANA. | ||
# Copyright (C) 2020 CERN. | ||
# | ||
# REANA is free software; you can redistribute it and/or modify it | ||
# under the terms of the MIT License; see LICENSE file for more details. | ||
"""REANA Workflow Operational Options implementation utils.""" | ||
|
||
import copy | ||
import subprocess | ||
import sys | ||
|
||
import click | ||
|
||
from reana_commons.errors import REANAValidationError | ||
|
||
available_options = { | ||
'CACHE': {'serial': True}, | ||
'FROM': {'serial': True}, | ||
'TARGET': {'serial': True, 'cwl': lambda: '--target'}, | ||
'toplevel': {'yadage': True}, | ||
'initdir': {'yadage': True} | ||
} | ||
|
||
|
||
def _validate_cwl_operational_options(operational_options): | ||
"""Validate cwl operational options.""" | ||
cmd = 'cwltool --version {0}'.format( | ||
' '.join([f'{k} {v}' for k, v in operational_options.items()])) | ||
try: | ||
subprocess.check_call(cmd, shell=True) | ||
return operational_options | ||
except subprocess.CalledProcessError as err: | ||
raise REANAValidationError( | ||
'==> ERROR: CWL validation failed.Operational options "{0}" ' | ||
'are not valid. \n{1}'.format(operational_options, err)) | ||
|
||
|
||
engine_validation = { | ||
'cwl': _validate_cwl_operational_options | ||
} | ||
|
||
|
||
def validate_operational_options(workflow_type, parsed_options): | ||
"""Validate and return workflow operational options. | ||
:param workflow_type: A supported workflow specification type. | ||
:param parsed_options: A dict with the parsed operational parameters. | ||
:returns: A dictionary which represents the valid workflow specification. | ||
""" | ||
if not isinstance(parsed_options, dict): | ||
raise REANAValidationError( | ||
'==> ERROR: Operational options must be a dictionary.') | ||
|
||
validated_options = copy.deepcopy(parsed_options) | ||
for option in parsed_options.keys(): | ||
if option not in available_options: | ||
raise REANAValidationError( | ||
'==> ERROR: Operational option "{0}" not supported.' | ||
.format(option)) | ||
exists = available_options[option].get(workflow_type) | ||
if not exists: | ||
raise REANAValidationError( | ||
'==> ERROR: Operational option "{0}" not supported for' | ||
' {1} workflows.' | ||
.format(option, workflow_type)) | ||
# Override engine specific options | ||
if callable(exists): | ||
validated_options[exists()] = validated_options[option] | ||
del validated_options[option] | ||
|
||
func = engine_validation.get(workflow_type) | ||
if func: | ||
func(validated_options) | ||
|
||
return validated_options |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# This file is part of REANA. | ||
# Copyright (C) 2020 CERN. | ||
# | ||
# REANA is free software; you can redistribute it and/or modify it | ||
# under the terms of the MIT License; see LICENSE file for more details. | ||
|
||
"""REANA-Commons utilities testing.""" | ||
|
||
import mock | ||
import pytest | ||
|
||
from reana_commons.errors import REANAValidationError | ||
from reana_commons.operational_options import validate_operational_options | ||
|
||
|
||
def _mock_check_call(cmd, shell): | ||
from reana_commons.operational_options import available_options | ||
assert available_options['TARGET']['cwl']() in cmd | ||
|
||
|
||
def test_wrong_option_format(): | ||
"""Test passing option with wrong type.""" | ||
with pytest.raises(REANAValidationError) as e: | ||
workflow_type = 'serial' | ||
option_tuple = ('CACHE=on',) | ||
validate_operational_options(workflow_type, option_tuple) | ||
assert 'must be a dict' in e.value.message | ||
|
||
|
||
def test_unsupported_option(): | ||
"""Test passing unsupported option.""" | ||
with pytest.raises(REANAValidationError) as e: | ||
workflow_type = 'yadage' | ||
options = {'unsupported': 'yes'} | ||
validate_operational_options(workflow_type, options) | ||
assert 'not supported' in e.value.message | ||
|
||
|
||
def test_unsupported_workflow_engine(): | ||
"""Test passing unsupported workflow engine.""" | ||
with pytest.raises(REANAValidationError) as e: | ||
workflow_type = 'foo' | ||
options = {'TARGET': 'gendata'} | ||
validate_operational_options(workflow_type, options) | ||
assert f'not supported for {workflow_type} workflows' in e.value.message | ||
|
||
|
||
def test_unsupported_option_for_workflow_engine(): | ||
"""Test passing unsupported option for valid workflow engine.""" | ||
with pytest.raises(REANAValidationError) as e: | ||
workflow_type = 'serial' | ||
options = {'toplevel': 'github:reanahub/awesome-workflow'} | ||
validate_operational_options(workflow_type, options) | ||
assert f'not supported for {workflow_type} workflows' in e.value.message | ||
|
||
|
||
def test_successful_serial_validation(): | ||
"""Test passing valid options to serial workflow engine.""" | ||
workflow_type = 'serial' | ||
options = {'FROM': 'fitdata'} | ||
options = validate_operational_options(workflow_type, options) | ||
assert options['FROM'] | ||
|
||
|
||
def test_successful_yadage_validation(): | ||
"""Test passing valid options to yadage workflow engine.""" | ||
workflow_type = 'yadage' | ||
options = {'toplevel': 'github:reanahub/awesome-workflow'} | ||
options = validate_operational_options(workflow_type, options) | ||
assert options['toplevel'] | ||
|
||
|
||
@mock.patch('subprocess.check_call', _mock_check_call) | ||
def test_cwl_transformation(): | ||
"""Test cwl option `TARGET` => `--target` transformation.""" | ||
workflow_type = 'cwl' | ||
options = {'TARGET': 'gendata'} | ||
options = validate_operational_options(workflow_type, options) | ||
assert options['--target'] |