Browse Source
* [python] Add task type python http * Fix unittest error * Fix UT error3.0.0/version-upgrade
Jiajie Zhong
3 years ago
committed by
GitHub
10 changed files with 435 additions and 33 deletions
@ -0,0 +1,115 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one |
||||
# or more contributor license agreements. See the NOTICE file |
||||
# distributed with this work for additional information |
||||
# regarding copyright ownership. The ASF licenses this file |
||||
# to you under the Apache License, Version 2.0 (the |
||||
# "License"); you may not use this file except in compliance |
||||
# with the License. You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, |
||||
# software distributed under the License is distributed on an |
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
||||
# KIND, either express or implied. See the License for the |
||||
# specific language governing permissions and limitations |
||||
# under the License. |
||||
|
||||
"""Task shell.""" |
||||
|
||||
from typing import Optional |
||||
|
||||
from pydolphinscheduler.constants import TaskType |
||||
from pydolphinscheduler.core.task import Task, TaskParams |
||||
|
||||
|
||||
class HttpMethod: |
||||
"""Constant of HTTP method.""" |
||||
|
||||
GET = "GET" |
||||
POST = "POST" |
||||
HEAD = "HEAD" |
||||
PUT = "PUT" |
||||
DELETE = "DELETE" |
||||
|
||||
|
||||
class HttpCheckCondition: |
||||
"""Constant of HTTP check condition. |
||||
|
||||
For now it contain four value: |
||||
- STATUS_CODE_DEFAULT: when http response code equal to 200, mark as success. |
||||
- STATUS_CODE_CUSTOM: when http response code equal to the code user define, mark as success. |
||||
- BODY_CONTAINS: when http response body contain text user define, mark as success. |
||||
- BODY_NOT_CONTAINS: when http response body do not contain text user define, mark as success. |
||||
""" |
||||
|
||||
STATUS_CODE_DEFAULT = "STATUS_CODE_DEFAULT" |
||||
STATUS_CODE_CUSTOM = "STATUS_CODE_CUSTOM" |
||||
BODY_CONTAINS = "BODY_CONTAINS" |
||||
BODY_NOT_CONTAINS = "BODY_NOT_CONTAINS" |
||||
|
||||
|
||||
class HttpTaskParams(TaskParams): |
||||
"""Parameter only for Http task types.""" |
||||
|
||||
def __init__( |
||||
self, |
||||
url: str, |
||||
http_method: Optional[str] = HttpMethod.GET, |
||||
http_params: Optional[str] = None, |
||||
http_check_condition: Optional[str] = HttpCheckCondition.STATUS_CODE_DEFAULT, |
||||
condition: Optional[str] = None, |
||||
connect_timeout: Optional[int] = 60000, |
||||
socket_timeout: Optional[int] = 60000, |
||||
*args, |
||||
**kwargs |
||||
): |
||||
super().__init__(*args, **kwargs) |
||||
self.url = url |
||||
if not hasattr(HttpMethod, http_method): |
||||
raise ValueError("Parameter http_method %s not support.", http_method) |
||||
self.http_method = http_method |
||||
self.http_params = http_params or [] |
||||
if not hasattr(HttpCheckCondition, http_check_condition): |
||||
raise ValueError( |
||||
"Parameter http_check_condition %s not support.", http_check_condition |
||||
) |
||||
self.http_check_condition = http_check_condition |
||||
if ( |
||||
http_check_condition != HttpCheckCondition.STATUS_CODE_DEFAULT |
||||
and condition is None |
||||
): |
||||
raise ValueError( |
||||
"Parameter condition must provider if http_check_condition not equal to STATUS_CODE_DEFAULT" |
||||
) |
||||
self.condition = condition |
||||
self.connect_timeout = connect_timeout |
||||
self.socket_timeout = socket_timeout |
||||
|
||||
|
||||
class Http(Task): |
||||
"""Task HTTP object, declare behavior for HTTP task to dolphinscheduler.""" |
||||
|
||||
def __init__( |
||||
self, |
||||
name: str, |
||||
url: str, |
||||
http_method: Optional[str] = HttpMethod.GET, |
||||
http_params: Optional[str] = None, |
||||
http_check_condition: Optional[str] = HttpCheckCondition.STATUS_CODE_DEFAULT, |
||||
condition: Optional[str] = None, |
||||
connect_timeout: Optional[int] = 60000, |
||||
socket_timeout: Optional[int] = 60000, |
||||
*args, |
||||
**kwargs |
||||
): |
||||
task_params = HttpTaskParams( |
||||
url=url, |
||||
http_method=http_method, |
||||
http_params=http_params, |
||||
http_check_condition=http_check_condition, |
||||
condition=condition, |
||||
connect_timeout=connect_timeout, |
||||
socket_timeout=socket_timeout, |
||||
) |
||||
super().__init__(name, TaskType.HTTP, task_params, *args, **kwargs) |
@ -0,0 +1,47 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one |
||||
# or more contributor license agreements. See the NOTICE file |
||||
# distributed with this work for additional information |
||||
# regarding copyright ownership. The ASF licenses this file |
||||
# to you under the Apache License, Version 2.0 (the |
||||
# "License"); you may not use this file except in compliance |
||||
# with the License. You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, |
||||
# software distributed under the License is distributed on an |
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
||||
# KIND, either express or implied. See the License for the |
||||
# specific language governing permissions and limitations |
||||
# under the License. |
||||
|
||||
"""Task Python.""" |
||||
|
||||
import inspect |
||||
import types |
||||
from typing import Any |
||||
|
||||
from pydolphinscheduler.constants import TaskType |
||||
from pydolphinscheduler.core.task import Task, TaskParams |
||||
|
||||
|
||||
class PythonTaskParams(TaskParams): |
||||
"""Parameter only for Python task types.""" |
||||
|
||||
def __init__(self, raw_script: str, *args, **kwargs): |
||||
super().__init__(*args, **kwargs) |
||||
self.raw_script = raw_script |
||||
|
||||
|
||||
class Python(Task): |
||||
"""Task Python object, declare behavior for Python task to dolphinscheduler.""" |
||||
|
||||
def __init__(self, name: str, code: Any, *args, **kwargs): |
||||
if isinstance(code, str): |
||||
task_params = PythonTaskParams(raw_script=code) |
||||
elif isinstance(code, types.FunctionType): |
||||
py_function = inspect.getsource(code) |
||||
task_params = PythonTaskParams(raw_script=py_function) |
||||
else: |
||||
raise ValueError("Parameter code do not support % for now.", type(code)) |
||||
super().__init__(name, TaskType.PYTHON, task_params, *args, **kwargs) |
@ -0,0 +1,112 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one |
||||
# or more contributor license agreements. See the NOTICE file |
||||
# distributed with this work for additional information |
||||
# regarding copyright ownership. The ASF licenses this file |
||||
# to you under the Apache License, Version 2.0 (the |
||||
# "License"); you may not use this file except in compliance |
||||
# with the License. You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, |
||||
# software distributed under the License is distributed on an |
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
||||
# KIND, either express or implied. See the License for the |
||||
# specific language governing permissions and limitations |
||||
# under the License. |
||||
|
||||
"""Test Task HTTP.""" |
||||
|
||||
from unittest.mock import patch |
||||
|
||||
import pytest |
||||
|
||||
from pydolphinscheduler.tasks.http import ( |
||||
Http, |
||||
HttpCheckCondition, |
||||
HttpMethod, |
||||
HttpTaskParams, |
||||
) |
||||
|
||||
|
||||
@pytest.mark.parametrize( |
||||
"class_name, attrs", |
||||
[ |
||||
(HttpMethod, ("GET", "POST", "HEAD", "PUT", "DELETE")), |
||||
( |
||||
HttpCheckCondition, |
||||
( |
||||
"STATUS_CODE_DEFAULT", |
||||
"STATUS_CODE_CUSTOM", |
||||
"BODY_CONTAINS", |
||||
"BODY_NOT_CONTAINS", |
||||
), |
||||
), |
||||
], |
||||
) |
||||
def test_attr_exists(class_name, attrs): |
||||
"""Test weather class HttpMethod and HttpCheckCondition contain specific attribute.""" |
||||
assert all(hasattr(class_name, attr) for attr in attrs) |
||||
|
||||
|
||||
@pytest.mark.parametrize( |
||||
"param", |
||||
[ |
||||
{"http_method": "http_method"}, |
||||
{"http_check_condition": "http_check_condition"}, |
||||
{"http_check_condition": HttpCheckCondition.STATUS_CODE_CUSTOM}, |
||||
{ |
||||
"http_check_condition": HttpCheckCondition.STATUS_CODE_CUSTOM, |
||||
"condition": None, |
||||
}, |
||||
], |
||||
) |
||||
def test_http_task_param_not_support_param(param): |
||||
"""Test HttpTaskParams not support parameter.""" |
||||
url = "https://www.apache.org" |
||||
with pytest.raises(ValueError, match="Parameter .*?"): |
||||
HttpTaskParams(url, **param) |
||||
|
||||
|
||||
def test_http_to_dict(): |
||||
"""Test task HTTP function to_dict.""" |
||||
code = 123 |
||||
version = 1 |
||||
name = "test_http_to_dict" |
||||
url = "https://www.apache.org" |
||||
expect = { |
||||
"code": code, |
||||
"name": name, |
||||
"version": 1, |
||||
"description": None, |
||||
"delayTime": 0, |
||||
"taskType": "HTTP", |
||||
"taskParams": { |
||||
"localParams": [], |
||||
"httpParams": [], |
||||
"url": url, |
||||
"httpMethod": "GET", |
||||
"httpCheckCondition": "STATUS_CODE_DEFAULT", |
||||
"condition": None, |
||||
"connectTimeout": 60000, |
||||
"socketTimeout": 60000, |
||||
"dependence": {}, |
||||
"resourceList": [], |
||||
"conditionResult": {"successNode": [""], "failedNode": [""]}, |
||||
"waitStartTimeout": {}, |
||||
}, |
||||
"flag": "YES", |
||||
"taskPriority": "MEDIUM", |
||||
"workerGroup": "default", |
||||
"failRetryTimes": 0, |
||||
"failRetryInterval": 1, |
||||
"timeoutFlag": "CLOSE", |
||||
"timeoutNotifyStrategy": None, |
||||
"timeout": 0, |
||||
} |
||||
with patch( |
||||
"pydolphinscheduler.core.task.Task.gen_code_and_version", |
||||
return_value=(code, version), |
||||
): |
||||
http = Http(name, url) |
||||
assert http.to_dict() == expect |
@ -0,0 +1,115 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one |
||||
# or more contributor license agreements. See the NOTICE file |
||||
# distributed with this work for additional information |
||||
# regarding copyright ownership. The ASF licenses this file |
||||
# to you under the Apache License, Version 2.0 (the |
||||
# "License"); you may not use this file except in compliance |
||||
# with the License. You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, |
||||
# software distributed under the License is distributed on an |
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
||||
# KIND, either express or implied. See the License for the |
||||
# specific language governing permissions and limitations |
||||
# under the License. |
||||
|
||||
"""Test Task python.""" |
||||
|
||||
|
||||
from unittest.mock import patch |
||||
|
||||
import pytest |
||||
|
||||
from pydolphinscheduler.tasks.python import Python, PythonTaskParams |
||||
|
||||
|
||||
@pytest.mark.parametrize( |
||||
"name, value", |
||||
[ |
||||
("local_params", "local_params"), |
||||
("resource_list", "resource_list"), |
||||
("dependence", "dependence"), |
||||
("wait_start_timeout", "wait_start_timeout"), |
||||
("condition_result", "condition_result"), |
||||
], |
||||
) |
||||
def test_python_task_params_attr_setter(name, value): |
||||
"""Test python task parameters.""" |
||||
command = 'print("hello world.")' |
||||
python_task_params = PythonTaskParams(command) |
||||
assert command == python_task_params.raw_script |
||||
setattr(python_task_params, name, value) |
||||
assert value == getattr(python_task_params, name) |
||||
|
||||
|
||||
@pytest.mark.parametrize( |
||||
"script_code", |
||||
[ |
||||
123, |
||||
("print", "hello world"), |
||||
], |
||||
) |
||||
def test_python_task_not_support_code(script_code): |
||||
"""Test python task parameters.""" |
||||
name = "not_support_code_type" |
||||
code = 123 |
||||
version = 1 |
||||
with patch( |
||||
"pydolphinscheduler.core.task.Task.gen_code_and_version", |
||||
return_value=(code, version), |
||||
): |
||||
with pytest.raises(ValueError, match="Parameter code do not support .*?"): |
||||
Python(name, script_code) |
||||
|
||||
|
||||
def foo(): # noqa: D103 |
||||
print("hello world.") |
||||
|
||||
|
||||
@pytest.mark.parametrize( |
||||
"name, script_code, raw", |
||||
[ |
||||
("string_define", 'print("hello world.")', 'print("hello world.")'), |
||||
( |
||||
"function_define", |
||||
foo, |
||||
'def foo(): # noqa: D103\n print("hello world.")\n', |
||||
), |
||||
], |
||||
) |
||||
def test_python_to_dict(name, script_code, raw): |
||||
"""Test task python function to_dict.""" |
||||
code = 123 |
||||
version = 1 |
||||
expect = { |
||||
"code": code, |
||||
"name": name, |
||||
"version": 1, |
||||
"description": None, |
||||
"delayTime": 0, |
||||
"taskType": "PYTHON", |
||||
"taskParams": { |
||||
"resourceList": [], |
||||
"localParams": [], |
||||
"rawScript": raw, |
||||
"dependence": {}, |
||||
"conditionResult": {"successNode": [""], "failedNode": [""]}, |
||||
"waitStartTimeout": {}, |
||||
}, |
||||
"flag": "YES", |
||||
"taskPriority": "MEDIUM", |
||||
"workerGroup": "default", |
||||
"failRetryTimes": 0, |
||||
"failRetryInterval": 1, |
||||
"timeoutFlag": "CLOSE", |
||||
"timeoutNotifyStrategy": None, |
||||
"timeout": 0, |
||||
} |
||||
with patch( |
||||
"pydolphinscheduler.core.task.Task.gen_code_and_version", |
||||
return_value=(code, version), |
||||
): |
||||
shell = Python(name, script_code) |
||||
assert shell.to_dict() == expect |
Loading…
Reference in new issue