Skip to content

Fix custom image integration test #1627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions tests/basic/06_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
39 changes: 32 additions & 7 deletions tests/docker/conftest.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -53,6 +65,7 @@ def set_up_serverless_client():
working_dir=resources_path,
)
serverless.upload(function)
print("ServerlessClient ready...")

return [compose, serverless]

Expand All @@ -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()
115 changes: 115 additions & 0 deletions tests/docker/docker-compose-test.yaml
Original file line number Diff line number Diff line change
@@ -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
- [email protected]
- 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:
16 changes: 16 additions & 0 deletions tests/docker/function/Sample-Docker
Original file line number Diff line number Diff line change
@@ -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



8 changes: 8 additions & 0 deletions tests/docker/function/runner.py
Original file line number Diff line number Diff line change
@@ -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)
22 changes: 12 additions & 10 deletions tests/docker/test_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -12,7 +12,6 @@
QiskitFunction,
BaseClient,
ServerlessClient,
QiskitServerlessException,
)


Expand Down Expand Up @@ -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 = """
Expand All @@ -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."""
Expand Down
2 changes: 1 addition & 1 deletion tests/tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading