diff --git a/tests/basic/06_function.py b/tests/basic/06_function.py index 1481f2d07..283c28c54 100644 --- a/tests/basic/06_function.py +++ b/tests/basic/06_function.py @@ -21,19 +21,12 @@ provider=os.environ.get("PROVIDER_ID", "mockprovider"), description=help, ) -serverless.upload(function_with_custom_image) +runnable_function = serverless.upload(function_with_custom_image) -my_functions = serverless.list() -for function in my_functions: - print("Name: " + function.title) - print(function.description) - print() - -my_function = serverless.get("custom-image-function") -job = my_function.run(message="Argument for the custum function") +job = runnable_function.run(message="Argument for the custum function") print(job.result()) print(job.logs()) -jobs = my_function.jobs() +jobs = runnable_function.jobs() print(jobs) diff --git a/tests/docker/conftest.py b/tests/docker/conftest.py index fda2e3492..92a45ae55 100644 --- a/tests/docker/conftest.py +++ b/tests/docker/conftest.py @@ -1,6 +1,7 @@ # pylint: disable=import-error, invalid-name """ Fixtures for tests """ import os +from subprocess import CalledProcessError from pytest import fixture from testcontainers.compose import DockerCompose @@ -29,22 +30,33 @@ def local_client(): return LocalClient() -def set_up_serverless_client(): +def set_up_serverless_client( + compose_file_name="../../../docker-compose-dev.yaml", backoffice_port=8000 +): """Auxiliar fixture function to create a serverless client""" compose = DockerCompose( - resources_path, - compose_file_name="../../../docker-compose-dev.yaml", - pull=True, + resources_path, compose_file_name=compose_file_name, pull=False ) - compose.start() - - connection_url = "http://localhost:8000" + try: + compose.start() + except CalledProcessError as error: + print("COMPOSE START ERROR") + print("STDOUT:") + print(error.stdout) + print("STDERR:") + print(error.stderr) + raise error + + print(f"Docker started... (compose file: ${compose_file_name})") + connection_url = f"http://localhost:{backoffice_port}" compose.wait_for(f"{connection_url}/backoffice") + print(f"backoffice ready... (port: ${backoffice_port})") serverless = ServerlessClient( token=os.environ.get("GATEWAY_TOKEN", "awesome_token"), host=os.environ.get("GATEWAY_HOST", connection_url), ) + print("ServerlessClient verified...") # Initialize serverless folder for current user function = QiskitFunction( @@ -53,6 +65,7 @@ def set_up_serverless_client(): working_dir=resources_path, ) serverless.upload(function) + print("ServerlessClient ready...") return [compose, serverless] @@ -65,3 +78,15 @@ def serverless_client(): yield serverless compose.stop() + + +@fixture(scope="module") +def serverless_custom_image_yaml_client(): + """Fixture for testing files with serverless client.""" + [compose, serverless] = set_up_serverless_client( + compose_file_name="../docker-compose-test.yaml", backoffice_port=8001 + ) + + yield serverless + + compose.stop() diff --git a/tests/docker/docker-compose-test.yaml b/tests/docker/docker-compose-test.yaml new file mode 100644 index 000000000..4e2c2bebf --- /dev/null +++ b/tests/docker/docker-compose-test.yaml @@ -0,0 +1,115 @@ +# compose config for running images based on local files +services: + ray-head: + user: "0" + container_name: ray-head-test + image: test_function + build: + context: ./ + dockerfile: function/Sample-Docker + entrypoint: [ + "env", "RAY_LOG_TO_STDERR=1", "ray", "start", "--head", "--port=6379", + "--dashboard-host=0.0.0.0", "--block" + ] + ports: + - 8266:8266 + volumes: + - host-shm:/dev/shm + networks: + - safe-tier + postgres: + image: postgres + environment: + POSTGRES_DB: serverlessdb + POSTGRES_USER: serverlessuser + POSTGRES_PASSWORD: serverlesspassword + networks: + - safe-tier + ports: + - 5433:5433 + restart: + always + gateway: + container_name: gateway-test + build: + context: ../../ + dockerfile: gateway/Dockerfile + command: gunicorn main.wsgi:application --bind 0.0.0.0:8001 --workers=1 --threads=1 --max-requests=1200 --max-requests-jitter=50 --timeout=25 + ports: + - 8001:8001 + user: "root" # we use the root user here so the docker-compose watch can sync files into the container + environment: + - DEBUG=1 + - RAY_HOST=http://ray-head:8265 + - DJANGO_SUPERUSER_USERNAME=admin + - DJANGO_SUPERUSER_PASSWORD=123 + - DJANGO_SUPERUSER_EMAIL=admin@noemail.com + - SITE_HOST=http://gateway:8001 + - SETTINGS_AUTH_MECHANISM=mock_token + - DATABASE_HOST=postgres + - DATABASE_PORT=5432 + - DATABASE_NAME=serverlessdb + - DATABASE_USER=serverlessuser + - DATABASE_PASSWORD=serverlesspassword + networks: + - safe-tier + volumes: + - program-artifacts:/usr/src/app/media/ + depends_on: + - postgres + scheduler: + container_name: scheduler-test + build: + context: ../../ + dockerfile: gateway/Dockerfile + entrypoint: "./scripts/scheduler.sh" + environment: + - DEBUG=1 + - DATABASE_HOST=postgres + - DATABASE_PORT=5433 + - DATABASE_NAME=serverlessdb + - DATABASE_USER=serverlessuser + - DATABASE_PASSWORD=serverlesspassword + - RAY_CLUSTER_MODE_LOCAL_HOST=http://ray-head:8265 + - RAY_CLUSTER_MODE_LOCAL=1 + - SETTINGS_AUTH_MECHANISM=mock_token + networks: + - safe-tier + volumes: + - program-artifacts:/usr/src/app/media/ + depends_on: + - postgres + prometheus: + image: prom/prometheus:v2.44.0 + profiles: [ "full" ] + ports: + - 9000:9090 + loki: + image: grafana/loki:2.8.4 + profiles: [ "full" ] + ports: + - 3100:3100 + command: -config.file=/etc/loki/local-config.yaml + networks: + - safe-tier + promtail: + image: grafana/promtail:2.8.4 + profiles: [ "full" ] + volumes: + - host-log:/var/log + command: -config.file=/etc/promtail/config.yml + networks: + - safe-tier + grafana: + image: grafana/grafana:latest + profiles: [ "full" ] + ports: + - 3000:3000 + networks: + - safe-tier +networks: + safe-tier: +volumes: + program-artifacts: + host-shm: + host-log: diff --git a/tests/docker/function/Sample-Docker b/tests/docker/function/Sample-Docker new file mode 100644 index 000000000..5472aca01 --- /dev/null +++ b/tests/docker/function/Sample-Docker @@ -0,0 +1,16 @@ +FROM icr.io/quantum-public/qiskit-serverless/ray-node:latest + +# install all necessary dependencies for your custom image + +# copy our function implementation in `/runner.py` of the docker image +USER 0 +RUN pip install pendulum +RUN mkdir /runner +WORKDIR /runner +COPY function/runner.py . +WORKDIR / + +USER 1000 + + + diff --git a/tests/docker/function/runner.py b/tests/docker/function/runner.py new file mode 100755 index 000000000..2aa7e4c4c --- /dev/null +++ b/tests/docker/function/runner.py @@ -0,0 +1,8 @@ +import pendulum # type: ignore + +dt_toronto = pendulum.datetime(2012, 1, 1, tz="America/Toronto") +dt_vancouver = pendulum.datetime(2012, 1, 1, tz="America/Vancouver") + +diff = dt_vancouver.diff(dt_toronto).in_hours() + +print(diff) diff --git a/tests/docker/test_docker.py b/tests/docker/test_docker.py index 2e9e2dec1..2af1d1238 100644 --- a/tests/docker/test_docker.py +++ b/tests/docker/test_docker.py @@ -3,7 +3,7 @@ import os from time import sleep -from pytest import raises, mark +from pytest import mark from qiskit import QuantumCircuit from qiskit.circuit.random import random_circuit @@ -12,7 +12,6 @@ QiskitFunction, BaseClient, ServerlessClient, - QiskitServerlessException, ) @@ -143,11 +142,7 @@ def test_multiple_runs(self, base_client: BaseClient): assert isinstance(retrieved_job1.logs(), str) assert isinstance(retrieved_job2.logs(), str) - @mark.skip( - reason="Images are not working in tests jet and " - + "LocalClient does not manage image instead of working_dir+entrypoint" - ) - def test_error(self, base_client: BaseClient): + def test_custom_image(self, serverless_custom_image_yaml_client: BaseClient): """Integration test to force an error.""" description = """ @@ -166,12 +161,19 @@ def test_error(self, base_client: BaseClient): description=description, ) - runnable_function = base_client.upload(function_with_custom_image) + print("Uploading function...") + runnable_function = serverless_custom_image_yaml_client.upload( + function_with_custom_image + ) + print("Running...") job = runnable_function.run(message="Argument for the custum function") - with raises(QiskitServerlessException): - job.result() + print("Job:") + print(job) + + print("Result:") + print(job.result()) def test_update_sub_status(self, serverless_client: ServerlessClient): """Integration test for run functions multiple times.""" diff --git a/tests/tox.ini b/tests/tox.ini index 956032a29..3a1183beb 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -20,7 +20,7 @@ deps = -rrequirements-dev.txt commands = pip install ../client pip check - python -m pytest -v --order-dependencies + python -m pytest -v --order-dependencies --capture=no [testenv:lint] skip_install = true