Browse Source
* [python] Add integrated test to python gateway server * Build java code and create standalone server image in GA * Add component start docker in python * Run example to make sure it work to it close: #8035 * Fix build docker image working directory * Fix working directory3.0.0/version-upgrade
Jiajie Zhong
3 years ago
committed by
GitHub
12 changed files with 288 additions and 11 deletions
@ -0,0 +1,18 @@
|
||||
# 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 integration between Python API and PythonGatewayServer.""" |
@ -0,0 +1,58 @@
|
||||
# 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 whether success submit examples DAG to PythonGatewayServer.""" |
||||
|
||||
from pathlib import Path |
||||
|
||||
import pytest |
||||
|
||||
from tests.testing.constants import ignore_exec_examples |
||||
from tests.testing.docker_wrapper import DockerWrapper |
||||
from tests.testing.path import path_example |
||||
|
||||
|
||||
@pytest.fixture(scope="module") |
||||
def setup_docker(): |
||||
"""Set up and teardown docker env for fixture.""" |
||||
docker_wrapper = DockerWrapper( |
||||
image="apache/dolphinscheduler-standalone-server:ci", |
||||
container_name="ci-dolphinscheduler-standalone-server", |
||||
) |
||||
ports = {"25333/tcp": 25333} |
||||
container = docker_wrapper.run_until_log( |
||||
log="Started StandaloneServer in", tty=True, ports=ports |
||||
) |
||||
assert container is not None |
||||
yield |
||||
docker_wrapper.remove_container() |
||||
|
||||
|
||||
@pytest.mark.parametrize( |
||||
"example_path", |
||||
[ |
||||
path |
||||
for path in path_example.iterdir() |
||||
if path.is_file() and path.stem not in ignore_exec_examples |
||||
], |
||||
) |
||||
def test_exec_white_list_example(setup_docker, example_path: Path): |
||||
"""Test execute examples and submit DAG to PythonGatewayServer.""" |
||||
try: |
||||
exec(example_path.read_text()) |
||||
except Exception: |
||||
raise Exception("Run example %s failed.", example_path.stem) |
@ -0,0 +1,98 @@
|
||||
# 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. |
||||
|
||||
"""Wrap docker commands for easier create docker container.""" |
||||
|
||||
import time |
||||
from typing import Optional |
||||
|
||||
import docker |
||||
from docker.errors import ImageNotFound |
||||
from docker.models.containers import Container |
||||
|
||||
|
||||
class DockerWrapper: |
||||
"""Wrap docker commands for easier create docker container. |
||||
|
||||
:param image: The image to create docker container. |
||||
""" |
||||
|
||||
def __init__(self, image: str, container_name: str): |
||||
self._client = docker.from_env() |
||||
self.image = image |
||||
self.container_name = container_name |
||||
|
||||
def run(self, *args, **kwargs) -> Container: |
||||
"""Create and run a new container. |
||||
|
||||
This method would return immediately after the container started, if you wish it return container |
||||
object when specific service start, you could see :func:`run_until_log` which return container |
||||
object when specific output log appear in docker. |
||||
""" |
||||
if not self.images_exists: |
||||
raise ValueError("Docker image named %s do not exists.", self.image) |
||||
return self._client.containers.run( |
||||
image=self.image, name=self.container_name, detach=True, *args, **kwargs |
||||
) |
||||
|
||||
def run_until_log( |
||||
self, log: str, remove_exists: Optional[bool] = True, *args, **kwargs |
||||
) -> Container: |
||||
"""Create and run a new container, return when specific log appear. |
||||
|
||||
It will call :func:`run` inside this method. And after container started, it would not |
||||
return it immediately but run command `docker logs` to see whether specific log appear. |
||||
It will raise `RuntimeError` when 10 minutes after but specific log do not appear. |
||||
""" |
||||
if remove_exists: |
||||
self.remove_container() |
||||
|
||||
log_byte = str.encode(log) |
||||
container = self.run(*args, **kwargs) |
||||
|
||||
timeout_threshold = 10 * 60 |
||||
start_time = time.time() |
||||
while time.time() <= start_time + timeout_threshold: |
||||
if log_byte in container.logs(tail=1000): |
||||
break |
||||
time.sleep(2) |
||||
# Stop container and raise error when reach timeout threshold but do not appear specific log output |
||||
else: |
||||
container.remove(force=True) |
||||
raise RuntimeError( |
||||
"Can not capture specific log `%s` in %d seconds, remove container.", |
||||
(log, timeout_threshold), |
||||
) |
||||
return container |
||||
|
||||
def remove_container(self): |
||||
"""Remove container which already running.""" |
||||
containers = self._client.containers.list( |
||||
all=True, filters={"name": self.container_name} |
||||
) |
||||
if containers: |
||||
for container in containers: |
||||
container.remove(force=True) |
||||
|
||||
@property |
||||
def images_exists(self) -> bool: |
||||
"""Check whether the image exists in local docker repository or not.""" |
||||
try: |
||||
self._client.images.get(self.image) |
||||
return True |
||||
except ImageNotFound: |
||||
return False |
Loading…
Reference in new issue