|
8 | 8 | - :mod:`tests.processes.wps_package`.
|
9 | 9 | """
|
10 | 10 | import contextlib
|
| 11 | +import json |
11 | 12 | import logging
|
12 | 13 | import os
|
| 14 | +from inspect import cleandoc |
13 | 15 |
|
14 | 16 | import colander
|
15 | 17 | import pytest
|
|
23 | 25 | mocked_aws_s3,
|
24 | 26 | mocked_aws_s3_bucket_test_file,
|
25 | 27 | mocked_execute_process,
|
| 28 | + mocked_http_file, |
| 29 | + mocked_reference_test_file, |
26 | 30 | mocked_sub_requests
|
27 | 31 | )
|
28 | 32 | from weaver.execute import EXECUTE_MODE_ASYNC, EXECUTE_RESPONSE_DOCUMENT, EXECUTE_TRANSMISSION_MODE_REFERENCE
|
|
37 | 41 | IANA_NAMESPACE,
|
38 | 42 | get_cwl_file_format
|
39 | 43 | )
|
40 |
| -from weaver.processes.constants import CWL_REQUIREMENT_APP_BUILTIN, CWL_REQUIREMENT_INIT_WORKDIR |
| 44 | +from weaver.processes.constants import ( |
| 45 | + CWL_REQUIREMENT_APP_BUILTIN, |
| 46 | + CWL_REQUIREMENT_APP_DOCKER, |
| 47 | + CWL_REQUIREMENT_INIT_WORKDIR |
| 48 | +) |
41 | 49 | from weaver.utils import get_any_value
|
42 | 50 |
|
43 | 51 | EDAM_PLAIN = EDAM_NAMESPACE + ":" + EDAM_MAPPING[CONTENT_TYPE_TEXT_PLAIN]
|
@@ -69,6 +77,7 @@ def setUpClass(cls):
|
69 | 77 | "weaver.wps": True,
|
70 | 78 | "weaver.wps_path": "/ows/wps",
|
71 | 79 | "weaver.wps_restapi_path": "/",
|
| 80 | + "weaver.wps_output_dir": "/tmp", # nosec: B108 # don't care hardcoded for test |
72 | 81 | }
|
73 | 82 | super(WpsPackageAppTest, cls).setUpClass()
|
74 | 83 |
|
@@ -925,6 +934,178 @@ def test_valid_io_min_max_occurs_as_str_or_int(self):
|
925 | 934 | "Field '{}' of input '{}'({}) is expected to be '{}' but was '{}'" \
|
926 | 935 | .format(field, process_input, i, proc_in_exp, proc_in_res)
|
927 | 936 |
|
| 937 | + @mocked_aws_credentials |
| 938 | + @mocked_aws_s3 |
| 939 | + @mocked_http_file |
| 940 | + def test_execute_job_with_array_input(self): |
| 941 | + """ |
| 942 | + The test validates job can receive an array as input and process it as expected. |
| 943 | + """ |
| 944 | + cwl = { |
| 945 | + "cwlVersion": "v1.0", |
| 946 | + "class": "CommandLineTool", |
| 947 | + "baseCommand": ["python3", "script.py"], |
| 948 | + "inputs": |
| 949 | + { |
| 950 | + "test_int_array": {"type": {"type": "array", "items": "int"}, "inputBinding": {"position": 1}}, |
| 951 | + "test_float_array": {"type": {"type": "array", "items": "float"}}, |
| 952 | + "test_string_array": {"type": {"type": "array", "items": "string"}}, |
| 953 | + "test_reference_array": {"type": {"type": "array", "items": "File"}}, |
| 954 | + "test_int_value": "int", |
| 955 | + "test_float_value": "float", |
| 956 | + "test_string_value": "string", |
| 957 | + "test_reference_http_value": "File", |
| 958 | + "test_reference_file_value": "File", |
| 959 | + "test_reference_s3_value": "File" |
| 960 | + }, |
| 961 | + "requirements": { |
| 962 | + CWL_REQUIREMENT_APP_DOCKER: { |
| 963 | + "dockerPull": "python:3.7-alpine" |
| 964 | + }, |
| 965 | + CWL_REQUIREMENT_INIT_WORKDIR: { |
| 966 | + "listing": [ |
| 967 | + { |
| 968 | + "entryname": "script.py", |
| 969 | + "entry": cleandoc(""" |
| 970 | + import json |
| 971 | + import os |
| 972 | + input = $(inputs) |
| 973 | + for key, value in input.items(): |
| 974 | + if isinstance(value, list): |
| 975 | + if all(isinstance(val, int) for val in value): |
| 976 | + value = map(lambda v: v+1, value) |
| 977 | + elif all(isinstance(val, float) for val in value): |
| 978 | + value = map(lambda v: v+0.5, value) |
| 979 | + elif all(isinstance(val, bool) for val in value): |
| 980 | + value = map(lambda v: not v, value) |
| 981 | + elif all(isinstance(val, str) for val in value): |
| 982 | + value = map(lambda v: v.upper(), value) |
| 983 | + elif all(isinstance(val, dict) for val in value): |
| 984 | + def tmp(value): |
| 985 | + path_ = value.get('path') |
| 986 | + if path_ and os.path.exists(path_): |
| 987 | + with open (path_, 'r') as file_: |
| 988 | + filedata = file_.read() |
| 989 | + return filedata.upper() |
| 990 | + value = map(tmp, value) |
| 991 | + input[key] = ";".join(map(str, value)) |
| 992 | + elif isinstance(value, dict): |
| 993 | + path_ = value.get('path') |
| 994 | + if path_ and os.path.exists(path_): |
| 995 | + with open (path_, 'r') as file_: |
| 996 | + filedata = file_.read() |
| 997 | + input[key] = filedata.upper() |
| 998 | + elif isinstance(value, str): |
| 999 | + input[key] = value.upper() |
| 1000 | + elif isinstance(value, bool): |
| 1001 | + input[key] = not value |
| 1002 | + elif isinstance(value, int): |
| 1003 | + input[key] = value+1 |
| 1004 | + elif isinstance(value, float): |
| 1005 | + input[key] = value+0.5 |
| 1006 | + json.dump(input, open("./tmp.txt","w")) |
| 1007 | + """) |
| 1008 | + } |
| 1009 | + ] |
| 1010 | + } |
| 1011 | + }, |
| 1012 | + "outputs": [{"id": "output_test", "type": "File", "outputBinding": {"glob": "tmp.txt"}}], |
| 1013 | + } |
| 1014 | + body = { |
| 1015 | + "processDescription": { |
| 1016 | + "process": { |
| 1017 | + "id": self._testMethodName, |
| 1018 | + "title": "some title", |
| 1019 | + "abstract": "this is a test", |
| 1020 | + }, |
| 1021 | + }, |
| 1022 | + "deploymentProfileName": "http://www.opengis.net/profiles/eoc/wpsApplication", |
| 1023 | + "executionUnit": [{"unit": cwl}], |
| 1024 | + } |
| 1025 | + try: |
| 1026 | + desc, _ = self.deploy_process(body) |
| 1027 | + except colander.Invalid: |
| 1028 | + self.fail("Test") |
| 1029 | + |
| 1030 | + assert desc["process"] is not None |
| 1031 | + |
| 1032 | + test_bucket_ref = mocked_aws_s3_bucket_test_file( |
| 1033 | + "wps-process-test-bucket", |
| 1034 | + "input_file_s3.txt", |
| 1035 | + "This is a generated file for s3 test" |
| 1036 | + ) |
| 1037 | + |
| 1038 | + test_http_ref = mocked_reference_test_file( |
| 1039 | + "input_file_http.txt", |
| 1040 | + "http", |
| 1041 | + "This is a generated file for http test" |
| 1042 | + ) |
| 1043 | + |
| 1044 | + test_file_ref = mocked_reference_test_file( |
| 1045 | + "input_file_ref.txt", |
| 1046 | + "file", |
| 1047 | + "This is a generated file for file test" |
| 1048 | + ) |
| 1049 | + |
| 1050 | + exec_body = { |
| 1051 | + "mode": EXECUTE_MODE_ASYNC, |
| 1052 | + "response": EXECUTE_RESPONSE_DOCUMENT, |
| 1053 | + "inputs": |
| 1054 | + [ |
| 1055 | + {"id": "test_int_array", "value": [10, 20, 30, 40, 50]}, |
| 1056 | + {"id": "test_float_array", "value": [10.03, 20.03, 30.03, 40.03, 50.03]}, |
| 1057 | + {"id": "test_string_array", "value": ["this", "is", "a", "test"]}, |
| 1058 | + {"id": "test_reference_array", |
| 1059 | + "value": [{"href": test_file_ref}, |
| 1060 | + {"href": test_http_ref}, |
| 1061 | + {"href": test_bucket_ref} |
| 1062 | + ] |
| 1063 | + }, |
| 1064 | + {"id": "test_int_value", "value": 2923}, |
| 1065 | + {"id": "test_float_value", "value": 389.73}, |
| 1066 | + {"id": "test_string_value", "value": "stringtest"}, |
| 1067 | + {"id": "test_reference_http_value", "href": test_http_ref}, |
| 1068 | + {"id": "test_reference_file_value", "href": test_file_ref}, |
| 1069 | + {"id": "test_reference_s3_value", "href": test_bucket_ref} |
| 1070 | + ], |
| 1071 | + "outputs": [ |
| 1072 | + {"id": "output_test", "type": "File"}, |
| 1073 | + ] |
| 1074 | + } |
| 1075 | + |
| 1076 | + with contextlib.ExitStack() as stack_exec: |
| 1077 | + for mock_exec in mocked_execute_process(): |
| 1078 | + stack_exec.enter_context(mock_exec) |
| 1079 | + proc_url = "/processes/{}/jobs".format(self._testMethodName) |
| 1080 | + resp = mocked_sub_requests(self.app, "post_json", proc_url, timeout=5, |
| 1081 | + data=exec_body, headers=self.json_headers, only_local=True) |
| 1082 | + assert resp.status_code in [200, 201], "Failed with: [{}]\nReason:\n{}".format(resp.status_code, resp.json) |
| 1083 | + status_url = resp.json.get("location") |
| 1084 | + |
| 1085 | + results = self.monitor_job(status_url) |
| 1086 | + |
| 1087 | + job_output_file = results.get("output_test")["href"].split("/", 3)[-1] |
| 1088 | + tmpfile = "{}/{}".format(self.settings["weaver.wps_output_dir"], job_output_file) |
| 1089 | + |
| 1090 | + try: |
| 1091 | + processed_values = json.load(open(tmpfile, "r")) |
| 1092 | + except FileNotFoundError: |
| 1093 | + self.fail("Output file [{}] was not found where it was expected to resume test".format(tmpfile)) |
| 1094 | + except Exception as exception: |
| 1095 | + self.fail("An error occured during the reading of the file: {}".format(exception)) |
| 1096 | + assert processed_values["test_int_array"] == "11;21;31;41;51" |
| 1097 | + assert processed_values["test_float_array"] == "10.53;20.53;30.53;40.53;50.53" |
| 1098 | + assert processed_values["test_string_array"] == "THIS;IS;A;TEST" |
| 1099 | + assert processed_values["test_reference_array"] == ("THIS IS A GENERATED FILE FOR FILE TEST;" |
| 1100 | + "THIS IS A GENERATED FILE FOR HTTP TEST;" |
| 1101 | + "THIS IS A GENERATED FILE FOR S3 TEST") |
| 1102 | + assert processed_values["test_int_value"] == 2924 |
| 1103 | + assert processed_values["test_float_value"] == 390.23 |
| 1104 | + assert processed_values["test_string_value"] == "STRINGTEST" |
| 1105 | + assert processed_values["test_reference_s3_value"] == "THIS IS A GENERATED FILE FOR S3 TEST" |
| 1106 | + assert processed_values["test_reference_http_value"] == "THIS IS A GENERATED FILE FOR HTTP TEST" |
| 1107 | + assert processed_values["test_reference_file_value"] == "THIS IS A GENERATED FILE FOR FILE TEST" |
| 1108 | + |
928 | 1109 | # FIXME: test not working
|
929 | 1110 | # same payloads sent directly to running weaver properly raise invalid schema -> bad request error
|
930 | 1111 | # somehow they don't work within this test (not raised)...
|
|
0 commit comments