Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/cwltool/tests/test_examples.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
| author | shellac |
|---|---|
| date | Mon, 01 Jun 2020 08:59:25 -0400 |
| parents | 79f47841a781 |
| children |
comparison
equal
deleted
inserted
replaced
| 4:79f47841a781 | 5:9b1c78e6ba9c |
|---|---|
| 1 import json | |
| 2 import logging | |
| 3 import os | |
| 4 import stat | |
| 5 import sys | |
| 6 from io import BytesIO, StringIO | |
| 7 import pytest | |
| 8 from typing_extensions import Text | |
| 9 | |
| 10 import schema_salad.validate | |
| 11 | |
| 12 import cwltool.checker | |
| 13 import cwltool.expression as expr | |
| 14 import cwltool.factory | |
| 15 import cwltool.pathmapper | |
| 16 import cwltool.process | |
| 17 import cwltool.workflow | |
| 18 from cwltool.context import RuntimeContext | |
| 19 from cwltool.errors import WorkflowException | |
| 20 from cwltool.main import main | |
| 21 from cwltool.utils import onWindows | |
| 22 from cwltool.resolver import Path | |
| 23 from cwltool.process import CWL_IANA | |
| 24 from cwltool.sandboxjs import JavascriptException | |
| 25 from .util import (get_data, get_main_output, get_windows_safe_factory, subprocess, | |
| 26 needs_docker, working_directory, needs_singularity, temp_dir, windows_needs_docker) | |
| 27 | |
| 28 import six | |
| 29 | |
| 30 try: | |
| 31 reload | |
| 32 except: # pylint: disable=bare-except | |
| 33 try: | |
| 34 from imp import reload | |
| 35 except: | |
| 36 from importlib import reload | |
| 37 | |
| 38 sys.argv = [''] | |
| 39 | |
| 40 expression_match = [ | |
| 41 ("(foo)", True), | |
| 42 ("(foo.bar)", True), | |
| 43 ("(foo['bar'])", True), | |
| 44 ("(foo[\"bar\"])", True), | |
| 45 ("(foo.bar.baz)", True), | |
| 46 ("(foo['bar'].baz)", True), | |
| 47 ("(foo['bar']['baz'])", True), | |
| 48 ("(foo['b\\'ar']['baz'])", True), | |
| 49 ("(foo['b ar']['baz'])", True), | |
| 50 ("(foo_bar)", True), | |
| 51 | |
| 52 ("(foo.[\"bar\"])", False), | |
| 53 ("(.foo[\"bar\"])", False), | |
| 54 ("(foo [\"bar\"])", False), | |
| 55 ("( foo[\"bar\"])", False), | |
| 56 ("(foo[bar].baz)", False), | |
| 57 ("(foo['bar\"].baz)", False), | |
| 58 ("(foo['bar].baz)", False), | |
| 59 ("{foo}", False), | |
| 60 ("(foo.bar", False), | |
| 61 ("foo.bar)", False), | |
| 62 ("foo.b ar)", False), | |
| 63 ("foo.b\'ar)", False), | |
| 64 ("(foo+bar", False), | |
| 65 ("(foo bar", False) | |
| 66 ] | |
| 67 | |
| 68 | |
| 69 @pytest.mark.parametrize('expression,expected', expression_match) | |
| 70 def test_expression_match(expression, expected): | |
| 71 match = expr.param_re.match(expression) | |
| 72 assert (match is not None) == expected | |
| 73 | |
| 74 | |
| 75 interpolate_input = { | |
| 76 "foo": { | |
| 77 "bar": { | |
| 78 "baz": "zab1" | |
| 79 }, | |
| 80 "b ar": { | |
| 81 "baz": 2 | |
| 82 }, | |
| 83 "b'ar": { | |
| 84 "baz": True | |
| 85 }, | |
| 86 'b"ar': { | |
| 87 "baz": None | |
| 88 } | |
| 89 }, | |
| 90 "lst": ["A", "B"] | |
| 91 } | |
| 92 | |
| 93 interpolate_parameters = [ | |
| 94 ("$(foo)", interpolate_input["foo"]), | |
| 95 | |
| 96 ("$(foo.bar)", interpolate_input["foo"]["bar"]), | |
| 97 ("$(foo['bar'])", interpolate_input["foo"]["bar"]), | |
| 98 ("$(foo[\"bar\"])", interpolate_input["foo"]["bar"]), | |
| 99 | |
| 100 ("$(foo.bar.baz)", interpolate_input['foo']['bar']['baz']), | |
| 101 ("$(foo['bar'].baz)", interpolate_input['foo']['bar']['baz']), | |
| 102 ("$(foo['bar'][\"baz\"])", interpolate_input['foo']['bar']['baz']), | |
| 103 ("$(foo.bar['baz'])", interpolate_input['foo']['bar']['baz']), | |
| 104 | |
| 105 ("$(foo['b\\'ar'].baz)", True), | |
| 106 ("$(foo[\"b'ar\"].baz)", True), | |
| 107 ("$(foo['b\\\"ar'].baz)", None), | |
| 108 | |
| 109 ("$(lst[0])", "A"), | |
| 110 ("$(lst[1])", "B"), | |
| 111 ("$(lst.length)", 2), | |
| 112 ("$(lst['length'])", 2), | |
| 113 | |
| 114 ("-$(foo.bar)", """-{"baz": "zab1"}"""), | |
| 115 ("-$(foo['bar'])", """-{"baz": "zab1"}"""), | |
| 116 ("-$(foo[\"bar\"])", """-{"baz": "zab1"}"""), | |
| 117 | |
| 118 ("-$(foo.bar.baz)", "-zab1"), | |
| 119 ("-$(foo['bar'].baz)", "-zab1"), | |
| 120 ("-$(foo['bar'][\"baz\"])", "-zab1"), | |
| 121 ("-$(foo.bar['baz'])", "-zab1"), | |
| 122 | |
| 123 ("-$(foo['b ar'].baz)", "-2"), | |
| 124 ("-$(foo['b\\'ar'].baz)", "-true"), | |
| 125 ("-$(foo[\"b\\'ar\"].baz)", "-true"), | |
| 126 ("-$(foo['b\\\"ar'].baz)", "-null"), | |
| 127 | |
| 128 ("$(foo.bar) $(foo.bar)", """{"baz": "zab1"} {"baz": "zab1"}"""), | |
| 129 ("$(foo['bar']) $(foo['bar'])", """{"baz": "zab1"} {"baz": "zab1"}"""), | |
| 130 ("$(foo[\"bar\"]) $(foo[\"bar\"])", """{"baz": "zab1"} {"baz": "zab1"}"""), | |
| 131 | |
| 132 ("$(foo.bar.baz) $(foo.bar.baz)", "zab1 zab1"), | |
| 133 ("$(foo['bar'].baz) $(foo['bar'].baz)", "zab1 zab1"), | |
| 134 ("$(foo['bar'][\"baz\"]) $(foo['bar'][\"baz\"])", "zab1 zab1"), | |
| 135 ("$(foo.bar['baz']) $(foo.bar['baz'])", "zab1 zab1"), | |
| 136 | |
| 137 ("$(foo['b ar'].baz) $(foo['b ar'].baz)", "2 2"), | |
| 138 ("$(foo['b\\'ar'].baz) $(foo['b\\'ar'].baz)", "true true"), | |
| 139 ("$(foo[\"b\\'ar\"].baz) $(foo[\"b\\'ar\"].baz)", "true true"), | |
| 140 ("$(foo['b\\\"ar'].baz) $(foo['b\\\"ar'].baz)", "null null") | |
| 141 ] | |
| 142 | |
| 143 | |
| 144 @pytest.mark.parametrize('pattern,expected', interpolate_parameters) | |
| 145 def test_expression_interpolate(pattern, expected): | |
| 146 assert expr.interpolate(pattern, interpolate_input) == expected | |
| 147 | |
| 148 interpolate_bad_parameters = [ | |
| 149 ("$(fooz)"), | |
| 150 ("$(foo.barz)"), | |
| 151 ("$(foo['barz'])"), | |
| 152 ("$(foo[\"barz\"])"), | |
| 153 | |
| 154 ("$(foo.bar.bazz)"), | |
| 155 ("$(foo['bar'].bazz)"), | |
| 156 ("$(foo['bar'][\"bazz\"])"), | |
| 157 ("$(foo.bar['bazz'])"), | |
| 158 | |
| 159 ("$(foo['b\\'ar'].bazz)"), | |
| 160 ("$(foo[\"b'ar\"].bazz)"), | |
| 161 ("$(foo['b\\\"ar'].bazz)"), | |
| 162 | |
| 163 ("$(lst[O])"), # not "0" the number, but the letter O | |
| 164 ("$(lst[2])"), | |
| 165 ("$(lst.lengthz)"), | |
| 166 ("$(lst['lengthz'])"), | |
| 167 | |
| 168 ("-$(foo.barz)"), | |
| 169 ("-$(foo['barz'])"), | |
| 170 ("-$(foo[\"barz\"])"), | |
| 171 | |
| 172 ("-$(foo.bar.bazz)"), | |
| 173 ("-$(foo['bar'].bazz)"), | |
| 174 ("-$(foo['bar'][\"bazz\"])"), | |
| 175 ("-$(foo.bar['bazz'])"), | |
| 176 | |
| 177 ("-$(foo['b ar'].bazz)"), | |
| 178 ("-$(foo['b\\'ar'].bazz)"), | |
| 179 ("-$(foo[\"b\\'ar\"].bazz)"), | |
| 180 ("-$(foo['b\\\"ar'].bazz)"), | |
| 181 ] | |
| 182 | |
| 183 @pytest.mark.parametrize('pattern', interpolate_bad_parameters) | |
| 184 def test_expression_interpolate_failures(pattern): | |
| 185 result = None | |
| 186 try: | |
| 187 result = expr.interpolate(pattern, interpolate_input) | |
| 188 except JavascriptException: | |
| 189 return | |
| 190 assert false, 'Should have produced a JavascriptException, got "{}".'.format(result) | |
| 191 | |
| 192 | |
| 193 @windows_needs_docker | |
| 194 def test_factory(): | |
| 195 factory = get_windows_safe_factory() | |
| 196 echo = factory.make(get_data("tests/echo.cwl")) | |
| 197 | |
| 198 assert echo(inp="foo") == {"out": "foo\n"} | |
| 199 | |
| 200 | |
| 201 def test_factory_bad_outputs(): | |
| 202 factory = cwltool.factory.Factory() | |
| 203 | |
| 204 with pytest.raises(schema_salad.validate.ValidationException): | |
| 205 factory.make(get_data("tests/echo_broken_outputs.cwl")) | |
| 206 | |
| 207 | |
| 208 def test_factory_default_args(): | |
| 209 factory = cwltool.factory.Factory() | |
| 210 | |
| 211 assert factory.runtime_context.use_container is True | |
| 212 assert factory.runtime_context.on_error == "stop" | |
| 213 | |
| 214 | |
| 215 def test_factory_redefined_args(): | |
| 216 runtime_context = RuntimeContext() | |
| 217 runtime_context.use_container = False | |
| 218 runtime_context.on_error = "continue" | |
| 219 factory = cwltool.factory.Factory(runtime_context=runtime_context) | |
| 220 | |
| 221 assert factory.runtime_context.use_container is False | |
| 222 assert factory.runtime_context.on_error == "continue" | |
| 223 | |
| 224 | |
| 225 def test_factory_partial_scatter(): | |
| 226 runtime_context = RuntimeContext() | |
| 227 runtime_context.on_error = "continue" | |
| 228 factory = cwltool.factory.Factory(runtime_context=runtime_context) | |
| 229 | |
| 230 with pytest.raises(cwltool.factory.WorkflowStatus) as err_info: | |
| 231 factory.make(get_data("tests/wf/scatterfail.cwl"))() | |
| 232 | |
| 233 err = err_info.value | |
| 234 assert err.out["out"][0]["checksum"] == 'sha1$e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e' | |
| 235 assert err.out["out"][1] is None | |
| 236 assert err.out["out"][2]["checksum"] == 'sha1$a3db5c13ff90a36963278c6a39e4ee3c22e2a436' | |
| 237 | |
| 238 | |
| 239 def test_factory_partial_output(): | |
| 240 runtime_context = RuntimeContext() | |
| 241 runtime_context.on_error = "continue" | |
| 242 factory = cwltool.factory.Factory(runtime_context=runtime_context) | |
| 243 | |
| 244 with pytest.raises(cwltool.factory.WorkflowStatus) as err_info: | |
| 245 factory.make(get_data("tests/wf/wffail.cwl"))() | |
| 246 | |
| 247 err = err_info.value | |
| 248 assert err.out["out1"]["checksum"] == 'sha1$e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e' | |
| 249 assert err.out["out2"] is None | |
| 250 | |
| 251 | |
| 252 def test_scandeps(): | |
| 253 obj = { | |
| 254 "id": "file:///example/foo.cwl", | |
| 255 "steps": [ | |
| 256 { | |
| 257 "id": "file:///example/foo.cwl#step1", | |
| 258 "inputs": [{ | |
| 259 "id": "file:///example/foo.cwl#input1", | |
| 260 "default": { | |
| 261 "class": "File", | |
| 262 "location": "file:///example/data.txt" | |
| 263 } | |
| 264 }], | |
| 265 "run": { | |
| 266 "id": "file:///example/bar.cwl", | |
| 267 "inputs": [{ | |
| 268 "id": "file:///example/bar.cwl#input2", | |
| 269 "default": { | |
| 270 "class": "Directory", | |
| 271 "location": "file:///example/data2", | |
| 272 "listing": [{ | |
| 273 "class": "File", | |
| 274 "location": "file:///example/data3.txt", | |
| 275 "secondaryFiles": [{ | |
| 276 "class": "File", | |
| 277 "location": "file:///example/data5.txt" | |
| 278 }] | |
| 279 }] | |
| 280 }, | |
| 281 }, { | |
| 282 "id": "file:///example/bar.cwl#input3", | |
| 283 "default": { | |
| 284 "class": "Directory", | |
| 285 "listing": [{ | |
| 286 "class": "File", | |
| 287 "location": "file:///example/data4.txt" | |
| 288 }] | |
| 289 } | |
| 290 }, { | |
| 291 "id": "file:///example/bar.cwl#input4", | |
| 292 "default": { | |
| 293 "class": "File", | |
| 294 "contents": "file literal" | |
| 295 } | |
| 296 }] | |
| 297 } | |
| 298 } | |
| 299 ] | |
| 300 } | |
| 301 | |
| 302 def loadref(base, p): | |
| 303 if isinstance(p, dict): | |
| 304 return p | |
| 305 raise Exception("test case can't load things") | |
| 306 | |
| 307 scanned_deps = cwltool.process.scandeps( | |
| 308 obj["id"], obj, | |
| 309 {"$import", "run"}, | |
| 310 {"$include", "$schemas", "location"}, | |
| 311 loadref) | |
| 312 | |
| 313 scanned_deps.sort(key=lambda k: k["basename"]) | |
| 314 | |
| 315 expected_deps = [ | |
| 316 {"basename": "bar.cwl", | |
| 317 "nameroot": "bar", | |
| 318 "class": "File", | |
| 319 "format": CWL_IANA, | |
| 320 "nameext": ".cwl", | |
| 321 "location": "file:///example/bar.cwl"}, | |
| 322 {"basename": "data.txt", | |
| 323 "nameroot": "data", | |
| 324 "class": "File", | |
| 325 "nameext": ".txt", | |
| 326 "location": "file:///example/data.txt"}, | |
| 327 {"basename": "data2", | |
| 328 "class": "Directory", | |
| 329 "location": "file:///example/data2", | |
| 330 "listing": [ | |
| 331 {"basename": "data3.txt", | |
| 332 "nameroot": "data3", | |
| 333 "class": "File", | |
| 334 "nameext": ".txt", | |
| 335 "location": "file:///example/data3.txt", | |
| 336 "secondaryFiles": [ | |
| 337 {"class": "File", | |
| 338 "basename": "data5.txt", | |
| 339 "location": "file:///example/data5.txt", | |
| 340 "nameext": ".txt", | |
| 341 "nameroot": "data5" | |
| 342 }] | |
| 343 }] | |
| 344 }, { | |
| 345 "basename": "data4.txt", | |
| 346 "nameroot": "data4", | |
| 347 "class": "File", | |
| 348 "nameext": ".txt", | |
| 349 "location": "file:///example/data4.txt" | |
| 350 }] | |
| 351 | |
| 352 assert scanned_deps == expected_deps | |
| 353 | |
| 354 scanned_deps = cwltool.process.scandeps( | |
| 355 obj["id"], obj, | |
| 356 set(("run"), ), | |
| 357 set(), loadref) | |
| 358 | |
| 359 scanned_deps.sort(key=lambda k: k["basename"]) | |
| 360 | |
| 361 expected_deps = [{ | |
| 362 "basename": "bar.cwl", | |
| 363 "nameroot": "bar", | |
| 364 "format": CWL_IANA, | |
| 365 "class": "File", | |
| 366 "nameext": ".cwl", | |
| 367 "location": "file:///example/bar.cwl" | |
| 368 }] | |
| 369 | |
| 370 assert scanned_deps == expected_deps | |
| 371 | |
| 372 def test_trick_scandeps(): | |
| 373 if sys.version_info[0] < 3: | |
| 374 stream = BytesIO() | |
| 375 else: | |
| 376 stream = StringIO() | |
| 377 | |
| 378 main(["--print-deps", "--debug", get_data("tests/wf/trick_defaults.cwl")], stdout=stream) | |
| 379 assert json.loads(stream.getvalue())["secondaryFiles"][0]["location"][:2] != "_:" | |
| 380 | |
| 381 | |
| 382 def test_input_deps(): | |
| 383 if sys.version_info[0] < 3: | |
| 384 stream = BytesIO() | |
| 385 else: | |
| 386 stream = StringIO() | |
| 387 | |
| 388 main(["--print-input-deps", get_data("tests/wf/count-lines1-wf.cwl"), | |
| 389 get_data("tests/wf/wc-job.json")], stdout=stream) | |
| 390 | |
| 391 expected = {"class": "File", | |
| 392 "location": "wc-job.json", | |
| 393 "format": CWL_IANA, | |
| 394 "secondaryFiles": [{"class": "File", | |
| 395 "location": "whale.txt", | |
| 396 "basename": "whale.txt", | |
| 397 "nameroot": "whale", | |
| 398 "nameext": ".txt"}]} | |
| 399 assert json.loads(stream.getvalue()) == expected | |
| 400 | |
| 401 | |
| 402 def test_input_deps_cmdline_opts(): | |
| 403 if sys.version_info[0] < 3: | |
| 404 stream = BytesIO() | |
| 405 else: | |
| 406 stream = StringIO() | |
| 407 | |
| 408 main(["--print-input-deps", | |
| 409 get_data("tests/wf/count-lines1-wf.cwl"), | |
| 410 "--file1", get_data("tests/wf/whale.txt")], stdout=stream) | |
| 411 expected = {"class": "File", | |
| 412 "location": "", | |
| 413 "format": CWL_IANA, | |
| 414 "secondaryFiles": [{"class": "File", | |
| 415 "location": "whale.txt", | |
| 416 "basename": "whale.txt", | |
| 417 "nameroot": "whale", | |
| 418 "nameext": ".txt"}]} | |
| 419 assert json.loads(stream.getvalue()) == expected | |
| 420 | |
| 421 | |
| 422 def test_input_deps_cmdline_opts_relative_deps_cwd(): | |
| 423 if sys.version_info[0] < 3: | |
| 424 stream = BytesIO() | |
| 425 else: | |
| 426 stream = StringIO() | |
| 427 | |
| 428 data_path = get_data("tests/wf/whale.txt") | |
| 429 main(["--print-input-deps", "--relative-deps", "cwd", | |
| 430 get_data("tests/wf/count-lines1-wf.cwl"), | |
| 431 "--file1", data_path], stdout=stream) | |
| 432 | |
| 433 goal = {"class": "File", | |
| 434 "location": "", | |
| 435 "format": CWL_IANA, | |
| 436 "secondaryFiles": [{"class": "File", | |
| 437 "location": str( | |
| 438 Path(os.path.relpath( | |
| 439 data_path, os.path.curdir))), | |
| 440 "basename": "whale.txt", | |
| 441 "nameroot": "whale", | |
| 442 "nameext": ".txt"}]} | |
| 443 assert json.loads(stream.getvalue()) == goal | |
| 444 | |
| 445 | |
| 446 def test_dedupe(): | |
| 447 not_deduped = [ | |
| 448 {"class": "File", | |
| 449 "location": "file:///example/a"}, | |
| 450 {"class": "File", | |
| 451 "location": "file:///example/a"}, | |
| 452 {"class": "File", | |
| 453 "location": "file:///example/d"}, | |
| 454 {"class": "Directory", | |
| 455 "location": "file:///example/c", | |
| 456 "listing": [ | |
| 457 {"class": "File", | |
| 458 "location": "file:///example/d"} | |
| 459 ]} | |
| 460 ] | |
| 461 | |
| 462 expected = [ | |
| 463 {"class": "File", | |
| 464 "location": "file:///example/a"}, | |
| 465 {"class": "Directory", | |
| 466 "location": "file:///example/c", | |
| 467 "listing": [ | |
| 468 {"class": "File", | |
| 469 "location": "file:///example/d"} | |
| 470 ]} | |
| 471 ] | |
| 472 | |
| 473 assert cwltool.pathmapper.dedup(not_deduped) == expected | |
| 474 | |
| 475 | |
| 476 record = { | |
| 477 'fields': [ | |
| 478 {'type': {'items': 'string', 'type': 'array'}, | |
| 479 'name': u'file:///home/chapmanb/drive/work/cwl/test_bcbio_cwl/run_info-cwl-workflow/wf-variantcall.cwl#vc_rec/vc_rec/description' | |
| 480 }, | |
| 481 {'type': {'items': 'File', 'type': 'array'}, | |
| 482 'name': u'file:///home/chapmanb/drive/work/cwl/test_bcbio_cwl/run_info-cwl-workflow/wf-variantcall.cwl#vc_rec/vc_rec/vrn_file' | |
| 483 }], | |
| 484 'type': 'record', | |
| 485 'name': u'file:///home/chapmanb/drive/work/cwl/test_bcbio_cwl/run_info-cwl-workflow/wf-variantcall.cwl#vc_rec/vc_rec' | |
| 486 } | |
| 487 | |
| 488 source_to_sink = [ | |
| 489 ('0', | |
| 490 {'items': ['string', 'null'], 'type': 'array'}, | |
| 491 {'items': ['string', 'null'], 'type': 'array'}, | |
| 492 True | |
| 493 ), | |
| 494 ('1', | |
| 495 {'items': ['string'], 'type': 'array'}, | |
| 496 {'items': ['string', 'null'], 'type': 'array'}, | |
| 497 True | |
| 498 ), | |
| 499 ('2', | |
| 500 {'items': ['string', 'null'], 'type': 'array'}, | |
| 501 {'items': ['string'], 'type': 'array'}, | |
| 502 True | |
| 503 ), | |
| 504 ('3', | |
| 505 {'items': ['string'], 'type': 'array'}, | |
| 506 {'items': ['int'], 'type': 'array'}, | |
| 507 False | |
| 508 ), | |
| 509 ('record 0', | |
| 510 record, record, | |
| 511 True | |
| 512 ), | |
| 513 ('record 1', | |
| 514 record, {'items': 'string', 'type': 'array'}, | |
| 515 False | |
| 516 ) | |
| 517 ] | |
| 518 | |
| 519 | |
| 520 @pytest.mark.parametrize('name, source, sink, expected', source_to_sink) | |
| 521 def test_compare_types(name, source, sink, expected): | |
| 522 assert cwltool.workflow.can_assign_src_to_sink(source, sink) == expected, name | |
| 523 | |
| 524 | |
| 525 source_to_sink_strict = [ | |
| 526 ('0', | |
| 527 ['string', 'null'], ['string', 'null'], | |
| 528 True | |
| 529 ), | |
| 530 ('1', | |
| 531 ['string'], ['string', 'null'], | |
| 532 True | |
| 533 ), | |
| 534 ('2', | |
| 535 ['string', 'int'], ['string', 'null'], | |
| 536 False | |
| 537 ), | |
| 538 ('3', | |
| 539 {'items': ['string'], 'type': 'array'}, | |
| 540 {'items': ['string', 'null'], 'type': 'array'}, | |
| 541 True | |
| 542 ), | |
| 543 ('4', | |
| 544 {'items': ['string', 'int'], 'type': 'array'}, | |
| 545 {'items': ['string', 'null'], 'type': 'array'}, | |
| 546 False | |
| 547 ) | |
| 548 ] | |
| 549 | |
| 550 | |
| 551 @pytest.mark.parametrize('name, source, sink, expected', source_to_sink_strict) | |
| 552 def test_compare_types_strict(name, source, sink, expected): | |
| 553 assert cwltool.workflow.can_assign_src_to_sink(source, sink, strict=True) == expected, name | |
| 554 | |
| 555 | |
| 556 typechecks = [ | |
| 557 (['string', 'int'], ['string', 'int', 'null'], | |
| 558 None, None, | |
| 559 "pass" | |
| 560 ), | |
| 561 (['string', 'int'], ['string', 'null'], | |
| 562 None, None, | |
| 563 "warning" | |
| 564 ), | |
| 565 (['File', 'int'], ['string', 'null'], | |
| 566 None, None, | |
| 567 "exception" | |
| 568 ), | |
| 569 ({'items': ['string', 'int'], 'type': 'array'}, | |
| 570 {'items': ['string', 'int', 'null'], 'type': 'array'}, | |
| 571 None, None, | |
| 572 "pass" | |
| 573 ), | |
| 574 ({'items': ['string', 'int'], 'type': 'array'}, | |
| 575 {'items': ['string', 'null'], 'type': 'array'}, | |
| 576 None, None, | |
| 577 "warning" | |
| 578 ), | |
| 579 ({'items': ['File', 'int'], 'type': 'array'}, | |
| 580 {'items': ['string', 'null'], 'type': 'array'}, | |
| 581 None, None, | |
| 582 "exception" | |
| 583 ), | |
| 584 # check linkMerge when sinktype is not an array | |
| 585 (['string', 'int'], ['string', 'int', 'null'], | |
| 586 "merge_nested", None, | |
| 587 "exception" | |
| 588 ), | |
| 589 # check linkMerge: merge_nested | |
| 590 (['string', 'int'], | |
| 591 {'items': ['string', 'int', 'null'], 'type': 'array'}, | |
| 592 "merge_nested", None, | |
| 593 "pass" | |
| 594 ), | |
| 595 (['string', 'int'], | |
| 596 {'items': ['string', 'null'], 'type': 'array'}, | |
| 597 "merge_nested", None, | |
| 598 "warning" | |
| 599 ), | |
| 600 (['File', 'int'], | |
| 601 {'items': ['string', 'null'], 'type': 'array'}, | |
| 602 "merge_nested", None, | |
| 603 "exception" | |
| 604 ), | |
| 605 # check linkMerge: merge_nested and sinktype is "Any" | |
| 606 (['string', 'int'], "Any", | |
| 607 "merge_nested", None, | |
| 608 "pass" | |
| 609 ), | |
| 610 # check linkMerge: merge_flattened | |
| 611 (['string', 'int'], | |
| 612 {'items': ['string', 'int', 'null'], 'type': 'array'}, | |
| 613 "merge_flattened", None, | |
| 614 "pass" | |
| 615 ), | |
| 616 (['string', 'int'], | |
| 617 {'items': ['string', 'null'], 'type': 'array'}, | |
| 618 "merge_flattened", None, | |
| 619 "warning" | |
| 620 ), | |
| 621 (['File', 'int'], | |
| 622 {'items': ['string', 'null'], 'type': 'array'}, | |
| 623 "merge_flattened", None, | |
| 624 "exception" | |
| 625 ), | |
| 626 ({'items': ['string', 'int'], 'type': 'array'}, | |
| 627 {'items': ['string', 'int', 'null'], 'type': 'array'}, | |
| 628 "merge_flattened", None, | |
| 629 "pass" | |
| 630 ), | |
| 631 ({'items': ['string', 'int'], 'type': 'array'}, | |
| 632 {'items': ['string', 'null'], 'type': 'array'}, | |
| 633 "merge_flattened", None, | |
| 634 "warning" | |
| 635 ), | |
| 636 ({'items': ['File', 'int'], 'type': 'array'}, | |
| 637 {'items': ['string', 'null'], 'type': 'array'}, | |
| 638 "merge_flattened", None, | |
| 639 "exception"), | |
| 640 # check linkMerge: merge_flattened and sinktype is "Any" | |
| 641 (['string', 'int'], "Any", | |
| 642 "merge_flattened", None, | |
| 643 "pass" | |
| 644 ), | |
| 645 ({'items': ['string', 'int'], 'type': 'array'}, "Any", | |
| 646 "merge_flattened", None, | |
| 647 "pass" | |
| 648 ), | |
| 649 # check linkMerge: merge_flattened when srctype is a list | |
| 650 ([{'items': 'string', 'type': 'array'}], | |
| 651 {'items': 'string', 'type': 'array'}, | |
| 652 "merge_flattened", None, | |
| 653 "pass" | |
| 654 ), | |
| 655 # check valueFrom | |
| 656 ({'items': ['File', 'int'], 'type': 'array'}, | |
| 657 {'items': ['string', 'null'], 'type': 'array'}, | |
| 658 "merge_flattened", "special value", | |
| 659 "pass" | |
| 660 ) | |
| 661 ] | |
| 662 | |
| 663 | |
| 664 @pytest.mark.parametrize('src_type,sink_type,link_merge,value_from,expected_type', typechecks) | |
| 665 def test_typechecking(src_type, sink_type, link_merge, value_from, expected_type): | |
| 666 assert cwltool.checker.check_types( | |
| 667 src_type, sink_type, linkMerge=link_merge, valueFrom=value_from | |
| 668 ) == expected_type | |
| 669 | |
| 670 | |
| 671 def test_lifting(): | |
| 672 # check that lifting the types of the process outputs to the workflow step | |
| 673 # fails if the step 'out' doesn't match. | |
| 674 factory = cwltool.factory.Factory() | |
| 675 with pytest.raises(schema_salad.validate.ValidationException): | |
| 676 echo = factory.make(get_data("tests/test_bad_outputs_wf.cwl")) | |
| 677 assert echo(inp="foo") == {"out": "foo\n"} | |
| 678 | |
| 679 | |
| 680 def test_malformed_outputs(): | |
| 681 # check that tool validation fails if one of the outputs is not a valid CWL type | |
| 682 factory = cwltool.factory.Factory() | |
| 683 with pytest.raises(schema_salad.validate.ValidationException): | |
| 684 factory.make(get_data("tests/wf/malformed_outputs.cwl"))() | |
| 685 | |
| 686 | |
| 687 def test_separate_without_prefix(): | |
| 688 # check that setting 'separate = false' on an inputBinding without prefix fails the workflow | |
| 689 factory = cwltool.factory.Factory() | |
| 690 with pytest.raises(WorkflowException): | |
| 691 factory.make(get_data("tests/wf/separate_without_prefix.cwl"))() | |
| 692 | |
| 693 | |
| 694 def test_static_checker(): | |
| 695 # check that the static checker raises exception when a source type | |
| 696 # mismatches its sink type. | |
| 697 factory = cwltool.factory.Factory() | |
| 698 | |
| 699 with pytest.raises(schema_salad.validate.ValidationException): | |
| 700 factory.make(get_data("tests/checker_wf/broken-wf.cwl")) | |
| 701 | |
| 702 with pytest.raises(schema_salad.validate.ValidationException): | |
| 703 factory.make(get_data("tests/checker_wf/broken-wf2.cwl")) | |
| 704 | |
| 705 with pytest.raises(schema_salad.validate.ValidationException): | |
| 706 factory.make(get_data("tests/checker_wf/broken-wf3.cwl")) | |
| 707 | |
| 708 | |
| 709 def test_var_spool_cwl_checker1(): | |
| 710 """Confirm that references to /var/spool/cwl are caught.""" | |
| 711 stream = StringIO() | |
| 712 streamhandler = logging.StreamHandler(stream) | |
| 713 _logger = logging.getLogger("cwltool") | |
| 714 _logger.addHandler(streamhandler) | |
| 715 | |
| 716 factory = cwltool.factory.Factory() | |
| 717 try: | |
| 718 factory.make(get_data("tests/non_portable.cwl")) | |
| 719 assert "non_portable.cwl:18:4: Non-portable reference to /var/spool/cwl detected" in stream.getvalue() | |
| 720 finally: | |
| 721 _logger.removeHandler(streamhandler) | |
| 722 | |
| 723 | |
| 724 def test_var_spool_cwl_checker2(): | |
| 725 """Confirm that references to /var/spool/cwl are caught.""" | |
| 726 stream = StringIO() | |
| 727 streamhandler = logging.StreamHandler(stream) | |
| 728 _logger = logging.getLogger("cwltool") | |
| 729 _logger.addHandler(streamhandler) | |
| 730 | |
| 731 factory = cwltool.factory.Factory() | |
| 732 try: | |
| 733 factory.make(get_data("tests/non_portable2.cwl")) | |
| 734 assert "non_portable2.cwl:19:4: Non-portable reference to /var/spool/cwl detected" in stream.getvalue() | |
| 735 finally: | |
| 736 _logger.removeHandler(streamhandler) | |
| 737 | |
| 738 | |
| 739 def test_var_spool_cwl_checker3(): | |
| 740 """Confirm that references to /var/spool/cwl are caught.""" | |
| 741 stream = StringIO() | |
| 742 streamhandler = logging.StreamHandler(stream) | |
| 743 _logger = logging.getLogger("cwltool") | |
| 744 _logger.addHandler(streamhandler) | |
| 745 | |
| 746 factory = cwltool.factory.Factory() | |
| 747 try: | |
| 748 factory.make(get_data("tests/portable.cwl")) | |
| 749 assert "Non-portable reference to /var/spool/cwl detected" not in stream.getvalue() | |
| 750 finally: | |
| 751 _logger.removeHandler(streamhandler) | |
| 752 | |
| 753 | |
| 754 def test_print_dot(): | |
| 755 assert main(["--print-dot", get_data('tests/wf/revsort.cwl')]) == 0 | |
| 756 | |
| 757 test_factors = [(""), ("--parallel"), ("--debug"), ("--parallel --debug")] | |
| 758 | |
| 759 @pytest.mark.parametrize("factor", test_factors) | |
| 760 def test_js_console_cmd_line_tool(factor): | |
| 761 for test_file in ("js_output.cwl", "js_output_workflow.cwl"): | |
| 762 commands = factor.split() | |
| 763 commands.extend(["--js-console", "--no-container", get_data("tests/wf/" + test_file)]) | |
| 764 error_code, _, stderr = get_main_output(commands) | |
| 765 | |
| 766 assert "[log] Log message" in stderr | |
| 767 assert "[err] Error message" in stderr | |
| 768 | |
| 769 assert error_code == 0, stderr | |
| 770 | |
| 771 @pytest.mark.parametrize("factor", test_factors) | |
| 772 def test_no_js_console(factor): | |
| 773 for test_file in ("js_output.cwl", "js_output_workflow.cwl"): | |
| 774 commands = factor.split() | |
| 775 commands.extend(["--no-container", get_data("tests/wf/" + test_file)]) | |
| 776 _, _, stderr = get_main_output(commands) | |
| 777 | |
| 778 assert "[log] Log message" not in stderr | |
| 779 assert "[err] Error message" not in stderr | |
| 780 | |
| 781 | |
| 782 @needs_docker | |
| 783 @pytest.mark.parametrize("factor", test_factors) | |
| 784 def test_cid_file_dir(tmpdir, factor): | |
| 785 test_file = "cache_test_workflow.cwl" | |
| 786 cwd = tmpdir.chdir() | |
| 787 commands = factor.split() | |
| 788 commands.extend(["--cidfile-dir", str(tmpdir), get_data("tests/wf/" + test_file)]) | |
| 789 error_code, stdout, stderr = get_main_output(commands) | |
| 790 assert "completed success" in stderr | |
| 791 assert error_code == 0 | |
| 792 cidfiles_count = sum(1 for _ in tmpdir.visit(fil="*")) | |
| 793 assert cidfiles_count == 2 | |
| 794 cwd.chdir() | |
| 795 tmpdir.remove(ignore_errors=True) | |
| 796 | |
| 797 | |
| 798 @needs_docker | |
| 799 @pytest.mark.parametrize("factor", test_factors) | |
| 800 def test_cid_file_dir_arg_is_file_instead_of_dir(tmpdir, factor): | |
| 801 test_file = "cache_test_workflow.cwl" | |
| 802 bad_cidfile_dir = Text(tmpdir.ensure("cidfile-dir-actually-a-file")) | |
| 803 commands = factor.split() | |
| 804 commands.extend(["--cidfile-dir", bad_cidfile_dir, | |
| 805 get_data("tests/wf/" + test_file)]) | |
| 806 error_code, _, stderr = get_main_output(commands) | |
| 807 assert "is not a directory, please check it first" in stderr, stderr | |
| 808 assert error_code == 2 or error_code == 1, stderr | |
| 809 tmpdir.remove(ignore_errors=True) | |
| 810 | |
| 811 | |
| 812 @needs_docker | |
| 813 @pytest.mark.parametrize("factor", test_factors) | |
| 814 def test_cid_file_non_existing_dir(tmpdir, factor): | |
| 815 test_file = "cache_test_workflow.cwl" | |
| 816 bad_cidfile_dir = Text(tmpdir.join("cidfile-dir-badpath")) | |
| 817 commands = factor.split() | |
| 818 commands.extend(['--record-container-id',"--cidfile-dir", bad_cidfile_dir, | |
| 819 get_data("tests/wf/" + test_file)]) | |
| 820 error_code, _, stderr = get_main_output(commands) | |
| 821 assert "directory doesn't exist, please create it first" in stderr, stderr | |
| 822 assert error_code == 2 or error_code == 1, stderr | |
| 823 tmpdir.remove(ignore_errors=True) | |
| 824 | |
| 825 | |
| 826 @needs_docker | |
| 827 @pytest.mark.parametrize("factor", test_factors) | |
| 828 def test_cid_file_w_prefix(tmpdir, factor): | |
| 829 test_file = "cache_test_workflow.cwl" | |
| 830 cwd = tmpdir.chdir() | |
| 831 try: | |
| 832 commands = factor.split() | |
| 833 commands.extend(['--record-container-id', '--cidfile-prefix=pytestcid', | |
| 834 get_data("tests/wf/" + test_file)]) | |
| 835 error_code, stdout, stderr = get_main_output(commands) | |
| 836 finally: | |
| 837 listing = tmpdir.listdir() | |
| 838 cwd.chdir() | |
| 839 cidfiles_count = sum(1 for _ in tmpdir.visit(fil="pytestcid*")) | |
| 840 tmpdir.remove(ignore_errors=True) | |
| 841 assert "completed success" in stderr | |
| 842 assert error_code == 0 | |
| 843 assert cidfiles_count == 2, '{}/n{}'.format(listing, stderr) | |
| 844 | |
| 845 | |
| 846 @needs_docker | |
| 847 @pytest.mark.parametrize("factor", test_factors) | |
| 848 def test_secondary_files_v1_1(factor): | |
| 849 test_file = "secondary-files.cwl" | |
| 850 test_job_file = "secondary-files-job.yml" | |
| 851 try: | |
| 852 old_umask = os.umask(stat.S_IWOTH) # test run with umask 002 | |
| 853 commands = factor.split() | |
| 854 commands.extend(["--enable-dev", | |
| 855 get_data(os.path.join("tests", test_file)), | |
| 856 get_data(os.path.join("tests", test_job_file))]) | |
| 857 error_code, _, stderr = get_main_output(commands) | |
| 858 finally: | |
| 859 assert stat.S_IMODE(os.stat('lsout').st_mode) == 436 # 664 in octal, '-rw-rw-r--' | |
| 860 os.umask(old_umask) # revert back to original umask | |
| 861 assert "completed success" in stderr | |
| 862 assert error_code == 0 | |
| 863 | |
| 864 @needs_docker | |
| 865 @pytest.mark.parametrize("factor", test_factors) | |
| 866 def test_secondary_files_v1_0(factor): | |
| 867 test_file = "secondary-files-string-v1.cwl" | |
| 868 test_job_file = "secondary-files-job.yml" | |
| 869 try: | |
| 870 old_umask = os.umask(stat.S_IWOTH) # test run with umask 002 | |
| 871 commands = factor.split() | |
| 872 commands.extend([ | |
| 873 get_data(os.path.join("tests", test_file)), | |
| 874 get_data(os.path.join("tests", test_job_file)) | |
| 875 ]) | |
| 876 error_code, _, stderr = get_main_output(commands) | |
| 877 finally: | |
| 878 assert stat.S_IMODE(os.stat('lsout').st_mode) == 436 # 664 in octal, '-rw-rw-r--' | |
| 879 os.umask(old_umask) # revert back to original umask | |
| 880 assert "completed success" in stderr | |
| 881 assert error_code == 0 | |
| 882 | |
| 883 | |
| 884 @needs_docker | |
| 885 @pytest.mark.parametrize("factor", test_factors) | |
| 886 def test_wf_without_container(tmpdir, factor): | |
| 887 test_file = "hello-workflow.cwl" | |
| 888 with temp_dir("cwltool_cache") as cache_dir: | |
| 889 commands = factor.split() | |
| 890 commands.extend(["--cachedir", cache_dir, "--outdir", str(tmpdir), | |
| 891 get_data("tests/wf/" + test_file), | |
| 892 "--usermessage", | |
| 893 "hello"]) | |
| 894 error_code, _, stderr = get_main_output(commands) | |
| 895 | |
| 896 assert "completed success" in stderr | |
| 897 assert error_code == 0 | |
| 898 | |
| 899 | |
| 900 @needs_docker | |
| 901 @pytest.mark.parametrize("factor", test_factors) | |
| 902 def test_issue_740_fixed(factor): | |
| 903 test_file = "cache_test_workflow.cwl" | |
| 904 with temp_dir("cwltool_cache") as cache_dir: | |
| 905 commands = factor.split() | |
| 906 commands.extend(["--cachedir", cache_dir, get_data("tests/wf/" + test_file)]) | |
| 907 error_code, _, stderr = get_main_output(commands) | |
| 908 | |
| 909 assert "completed success" in stderr | |
| 910 assert error_code == 0 | |
| 911 | |
| 912 commands = factor.split() | |
| 913 commands.extend(["--cachedir", cache_dir, get_data("tests/wf/" + test_file)]) | |
| 914 error_code, _, stderr = get_main_output(commands) | |
| 915 | |
| 916 assert "Output of job will be cached in" not in stderr | |
| 917 assert error_code == 0, stderr | |
| 918 | |
| 919 | |
| 920 @needs_docker | |
| 921 def test_compute_checksum(): | |
| 922 runtime_context = RuntimeContext() | |
| 923 runtime_context.compute_checksum = True | |
| 924 runtime_context.use_container = onWindows() | |
| 925 factory = cwltool.factory.Factory(runtime_context=runtime_context) | |
| 926 echo = factory.make(get_data("tests/wf/cat-tool.cwl")) | |
| 927 output = echo( | |
| 928 file1={"class": "File", | |
| 929 "location": get_data("tests/wf/whale.txt")}, | |
| 930 reverse=False) | |
| 931 assert output['output']["checksum"] == "sha1$327fc7aedf4f6b69a42a7c8b808dc5a7aff61376" | |
| 932 | |
| 933 | |
| 934 @needs_docker | |
| 935 @pytest.mark.parametrize("factor", test_factors) | |
| 936 def test_no_compute_chcksum(tmpdir, factor): | |
| 937 test_file = "tests/wf/wc-tool.cwl" | |
| 938 job_file = "tests/wf/wc-job.json" | |
| 939 commands = factor.split() | |
| 940 commands.extend(["--no-compute-checksum", "--outdir", str(tmpdir), | |
| 941 get_data(test_file), get_data(job_file)]) | |
| 942 error_code, stdout, stderr = get_main_output(commands) | |
| 943 assert "completed success" in stderr | |
| 944 assert error_code == 0 | |
| 945 assert "checksum" not in stdout | |
| 946 | |
| 947 | |
| 948 @pytest.mark.parametrize("factor", test_factors) | |
| 949 def test_bad_userspace_runtime(factor): | |
| 950 test_file = "tests/wf/wc-tool.cwl" | |
| 951 job_file = "tests/wf/wc-job.json" | |
| 952 commands = factor.split() | |
| 953 commands.extend([ | |
| 954 "--user-space-docker-cmd=quaquioN", "--default-container=debian", | |
| 955 get_data(test_file), get_data(job_file)]) | |
| 956 error_code, stdout, stderr = get_main_output(commands) | |
| 957 assert "or quaquioN is missing or broken" in stderr, stderr | |
| 958 assert error_code == 1 | |
| 959 | |
| 960 @windows_needs_docker | |
| 961 @pytest.mark.parametrize("factor", test_factors) | |
| 962 def test_bad_basecommand(factor): | |
| 963 test_file = "tests/wf/missing-tool.cwl" | |
| 964 commands = factor.split() | |
| 965 commands.extend([get_data(test_file)]) | |
| 966 error_code, stdout, stderr = get_main_output(commands) | |
| 967 assert "'neenooGo' not found" in stderr, stderr | |
| 968 assert error_code == 1 | |
| 969 | |
| 970 | |
| 971 @needs_docker | |
| 972 @pytest.mark.parametrize("factor", test_factors) | |
| 973 def test_bad_basecommand_docker(factor): | |
| 974 test_file = "tests/wf/missing-tool.cwl" | |
| 975 commands = factor.split() | |
| 976 commands.extend( | |
| 977 ["--debug", "--default-container", "debian", get_data(test_file)]) | |
| 978 error_code, stdout, stderr = get_main_output(commands) | |
| 979 assert "permanentFail" in stderr, stderr | |
| 980 assert error_code == 1 | |
| 981 | |
| 982 @pytest.mark.parametrize("factor", test_factors) | |
| 983 def test_v1_0_position_expression(factor): | |
| 984 test_file = "tests/echo-position-expr.cwl" | |
| 985 test_job = "tests/echo-position-expr-job.yml" | |
| 986 commands = factor.split() | |
| 987 commands.extend( | |
| 988 ['--debug', get_data(test_file), get_data(test_job)]) | |
| 989 error_code, stdout, stderr = get_main_output(commands) | |
| 990 assert "is not int" in stderr, stderr | |
| 991 assert error_code == 1 | |
| 992 | |
| 993 | |
| 994 @windows_needs_docker | |
| 995 @pytest.mark.parametrize("factor", test_factors) | |
| 996 def test_optional_numeric_output_0(factor): | |
| 997 test_file = "tests/wf/optional-numerical-output-0.cwl" | |
| 998 commands = factor.split() | |
| 999 commands.extend([get_data(test_file)]) | |
| 1000 error_code, stdout, stderr = get_main_output(commands) | |
| 1001 | |
| 1002 assert "completed success" in stderr | |
| 1003 assert error_code == 0 | |
| 1004 assert json.loads(stdout)['out'] == 0 | |
| 1005 | |
| 1006 @pytest.mark.parametrize("factor", test_factors) | |
| 1007 @windows_needs_docker | |
| 1008 def test_env_filtering(factor): | |
| 1009 test_file = "tests/env.cwl" | |
| 1010 commands = factor.split() | |
| 1011 commands.extend([get_data(test_file)]) | |
| 1012 error_code, stdout, stderr = get_main_output(commands) | |
| 1013 | |
| 1014 process = subprocess.Popen(["sh", "-c", r"""getTrueShellExeName() { | |
| 1015 local trueExe nextTarget 2>/dev/null | |
| 1016 trueExe=$(ps -o comm= $$) || return 1 | |
| 1017 [ "${trueExe#-}" = "$trueExe" ] || trueExe=${trueExe#-} | |
| 1018 [ "${trueExe#/}" != "$trueExe" ] || trueExe=$([ -n "$ZSH_VERSION" ] && which -p "$trueExe" || which "$trueExe") | |
| 1019 while nextTarget=$(readlink "$trueExe"); do trueExe=$nextTarget; done | |
| 1020 printf '%s\n' "$(basename "$trueExe")" | |
| 1021 } ; getTrueShellExeName"""], stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=None) | |
| 1022 sh_name, sh_name_err = process.communicate() | |
| 1023 sh_name = sh_name.decode('utf-8').strip() | |
| 1024 | |
| 1025 assert "completed success" in stderr, (error_code, stdout, stderr) | |
| 1026 assert error_code == 0, (error_code, stdout, stderr) | |
| 1027 if onWindows(): | |
| 1028 target = 5 | |
| 1029 elif sh_name == "dash": | |
| 1030 target = 4 | |
| 1031 else: # bash adds "SHLVL" and "_" environment variables | |
| 1032 target = 6 | |
| 1033 result = json.loads(stdout)['env_count'] | |
| 1034 details = '' | |
| 1035 if result != target: | |
| 1036 _, details, _ = get_main_output(["--quiet", get_data("tests/env2.cwl")]) | |
| 1037 print(sh_name) | |
| 1038 print(sh_name_err) | |
| 1039 print(details) | |
| 1040 assert result == target, (error_code, sh_name, sh_name_err, details, stdout, stderr) | |
| 1041 | |
| 1042 @windows_needs_docker | |
| 1043 def test_v1_0_arg_empty_prefix_separate_false(): | |
| 1044 test_file = "tests/arg-empty-prefix-separate-false.cwl" | |
| 1045 error_code, stdout, stderr = get_main_output( | |
| 1046 ['--debug', get_data(test_file), "--echo"]) | |
| 1047 assert "completed success" in stderr | |
| 1048 assert error_code == 0 |
