From e4413ad6dc3688e6040536c0ea9ab210fe43acdd Mon Sep 17 00:00:00 2001 From: greg pereira Date: Thu, 2 May 2024 07:32:20 -0700 Subject: [PATCH] adding a object_detection_client workflow file Signed-off-by: greg pereira --- .github/workflows/model_servers.yaml | 36 ++++---- .github/workflows/object_detection.yaml | 89 +++++++++++++++++++ .../object_detection_python/tests/conftest.py | 1 + .../computer_vision/object_detection/Makefile | 15 ++++ .../object_detection/tests/conftest.py | 54 ----------- recipes/computer_vision/tests/conftest.py | 8 ++ .../tests => tests/functional}/__init__.py | 0 .../tests/functional/conftest.py | 58 ++++++++++++ .../functional/test_app.py} | 9 +- .../tests/integration/__init__.py | 0 .../tests/integration/conftest.py | 7 ++ .../tests/integration/test_app.py | 3 + .../tests/requirements.txt | 0 13 files changed, 206 insertions(+), 74 deletions(-) create mode 100644 .github/workflows/object_detection.yaml create mode 100644 recipes/computer_vision/object_detection/Makefile delete mode 100644 recipes/computer_vision/object_detection/tests/conftest.py create mode 100644 recipes/computer_vision/tests/conftest.py rename recipes/computer_vision/{object_detection/tests => tests/functional}/__init__.py (100%) create mode 100644 recipes/computer_vision/tests/functional/conftest.py rename recipes/computer_vision/{object_detection/tests/test_alive.py => tests/functional/test_app.py} (64%) create mode 100644 recipes/computer_vision/tests/integration/__init__.py create mode 100644 recipes/computer_vision/tests/integration/conftest.py create mode 100644 recipes/computer_vision/tests/integration/test_app.py rename recipes/computer_vision/{object_detection => }/tests/requirements.txt (100%) diff --git a/.github/workflows/model_servers.yaml b/.github/workflows/model_servers.yaml index 7655aad9a..3d63390aa 100644 --- a/.github/workflows/model_servers.yaml +++ b/.github/workflows/model_servers.yaml @@ -26,24 +26,24 @@ jobs: strategy: matrix: include: - # - image_name: llamacpp_python - # model: granite - # flavor: base - # directory: llamacpp_python - # platforms: linux/amd64,linux/arm64 - # no_gpu: 1 - # - image_name: llamacpp_python_cuda - # model: granite - # flavor: cuda - # directory: llamacpp_python - # platforms: linux/amd64 - # cuda: 1 - # - image_name: whispercpp - # model: whisper-small - # flavor: base - # directory: whispercpp - # platforms: linux/amd64,linux/arm64 - # no_gpu: 1 + - image_name: llamacpp_python + model: granite + flavor: base + directory: llamacpp_python + platforms: linux/amd64,linux/arm64 + no_gpu: 1 + - image_name: llamacpp_python_cuda + model: granite + flavor: cuda + directory: llamacpp_python + platforms: linux/amd64 + cuda: 1 + - image_name: whispercpp + model: whisper-small + flavor: base + directory: whispercpp + platforms: linux/amd64,linux/arm64 + no_gpu: 1 - image_name: object_detection_python model: facebook-detr-resnet-101 flavor: base diff --git a/.github/workflows/object_detection.yaml b/.github/workflows/object_detection.yaml new file mode 100644 index 000000000..74742e8ed --- /dev/null +++ b/.github/workflows/object_detection.yaml @@ -0,0 +1,89 @@ +name: Object Detection + +on: + pull_request: + branches: + - main + paths: + - ./recipes/computer_vision/object_detection/** + - .github/workflows/object_detection.yaml + push: + branches: + - main + paths: + - ./recipes/computer_vision/object_detection/** + - .github/workflows/object_detection.yaml + + workflow_dispatch: + +env: + REGISTRY: ghcr.io + REGISTRY_ORG: containers + RECIPE_NAME: object_detection + RECIPE_TYPE: computer_vision + IMAGE_NAME: object_detection_client + +jobs: + chatbot-build-and-push: + if: "!contains(github.event.pull_request.labels.*.name, 'hold-tests')" + runs-on: ubuntu-22.04 + permissions: + contents: read + packages: write + services: + registry: + image: registry:2.8.3 + ports: + - 5000:5000 + steps: + - uses: actions/checkout@v4.1.4 + + - name: Install qemu dependency + run: | + sudo apt-get update + sudo apt-get install -y qemu-user-static + + - name: Build Image + id: build_image + uses: redhat-actions/buildah-build@v2.13 + with: + image: ${{ env.REGISTRY }}/${{ env.REGISTRY_ORG }}/${{ env.IMAGE_NAME }} + tags: latest + platforms: linux/amd64,linux/arm64 + containerfiles: ./recipes/${{ env.RECIPE_TYPE }}/${{ env.RECIPE_NAME }}/app/Containerfile + context: recipes/${{ env.RECIPE_TYPE }}/${{ env.RECIPE_NAME }}/app + + - name: Set up Python + uses: actions/setup-python@v5.1.0 + with: + python-version: '3.11' + + - name: Install Dependencies + working-directory: ./recipes/${{ env.RECIPE_TYPE }}/${{ env.RECIPE_NAME }} + run: make install + + - name: Download model + working-directory: ./models + run: make download-model-facebook-detr-resnet-101 + + - name: Run Functional Tests + shell: bash + run: make functional-tests + working-directory: ./recipes/${{ env.RECIPE_TYPE }}/${{ env.RECIPE_NAME }} + + - name: Login to Registry + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: redhat-actions/podman-login@v1.7 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Push Image + id: push_image + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: redhat-actions/push-to-registry@v2.8 + with: + image: ${{ steps.build_image.outputs.image }} + tags: ${{ steps.build_image.outputs.tags }} + registry: ${{ env.REGISTRY }} diff --git a/model_servers/object_detection_python/tests/conftest.py b/model_servers/object_detection_python/tests/conftest.py index cb04988bc..ad019c9db 100644 --- a/model_servers/object_detection_python/tests/conftest.py +++ b/model_servers/object_detection_python/tests/conftest.py @@ -5,6 +5,7 @@ IMAGE_NAME = os.getenv("IMAGE_NAME", "containers/object_detection_python:latest") MODEL_NAME = os.getenv("MODEL_NAME", "facebook/detr-resnet-101") MODELS_DIR = os.getenv("MODELS_DIR", "/app/models") + MODEL_PATH = f"{MODELS_DIR}/{MODEL_NAME}" PORT = os.getenv("PORT", 8000) diff --git a/recipes/computer_vision/object_detection/Makefile b/recipes/computer_vision/object_detection/Makefile new file mode 100644 index 000000000..b18a45b36 --- /dev/null +++ b/recipes/computer_vision/object_detection/Makefile @@ -0,0 +1,15 @@ +SHELL := /bin/bash +APP ?= object_detection_client +PORT ?= 8501 +MODEL_NAME ?= facebook/detr-resnet-101 + +include ../../common/Makefile.common + +.PHONY: functional-tests +functional-tests: + IMAGE_NAME=${IMAGE_NAME} REGISTRY=${REGISTRY} MODEL_NAME=${MODEL_NAME} pytest -vvv --driver=Chrome --driver-path=$(RECIPE_BINARIES_PATH)/chromedriver ${RELATIVE_TESTS_PATH}/functional + +RECIPE_BINARIES_PATH := $(shell realpath ../../common/bin) +RELATIVE_MODELS_PATH := ../../../models +RELATIVE_TESTS_PATH := ../tests + diff --git a/recipes/computer_vision/object_detection/tests/conftest.py b/recipes/computer_vision/object_detection/tests/conftest.py deleted file mode 100644 index eebb15a97..000000000 --- a/recipes/computer_vision/object_detection/tests/conftest.py +++ /dev/null @@ -1,54 +0,0 @@ -import pytest_container -import pytest -import os -import logging -import platform - -if 'PORT' not in os.environ: - PORT = 8000 -else: - PORT = os.environ['PORT'] - try: - PORT = int(PORT) - except: - PORT = 8000 - -if 'IMAGE' not in os.environ: - IMAGE = 'ghcr.io/containers/model_servers/object_detection_python:latest' -else: - IMAGE = os.environ['IMAGE'] - -MODEL_NAME=os.environ['MODEL_NAME'] -MODEL_PATH=os.environ['MODEL_PATH'] - -BIND_MOUNT_OPTIONS = 'ro' - -MS = pytest_container.Container( - url=f"containers-storage:{IMAGE}", - volume_mounts=[ - pytest_container.container.BindMount( - container_path=f"{MODEL_PATH}", - host_path=f"./{MODEL_NAME}", - flags=[BIND_MOUNT_OPTIONS] - ) - ], - extra_environment_variables={ - "MODEL_NAME": f"{MODEL_NAME}", - "MODEL_PATH": f"{MODEL_PATH}", - "HOST": "0.0.0.0", - "PORT": f"{PORT}" - }, - forwarded_ports=[ - pytest_container.PortForwarding( - container_port=PORT, - host_port=PORT - ) - ], - ) - -def pytest_addoption(parser): - pytest_container.add_logging_level_options(parser) - - -def pytest_generate_tests(metafunc): - pytest_container.auto_container_parametrize(metafunc) diff --git a/recipes/computer_vision/tests/conftest.py b/recipes/computer_vision/tests/conftest.py new file mode 100644 index 000000000..7a2206fab --- /dev/null +++ b/recipes/computer_vision/tests/conftest.py @@ -0,0 +1,8 @@ +import pytest +import os + + +@pytest.fixture +def chrome_options(chrome_options): + chrome_options.add_argument("--headless") + return chrome_options diff --git a/recipes/computer_vision/object_detection/tests/__init__.py b/recipes/computer_vision/tests/functional/__init__.py similarity index 100% rename from recipes/computer_vision/object_detection/tests/__init__.py rename to recipes/computer_vision/tests/functional/__init__.py diff --git a/recipes/computer_vision/tests/functional/conftest.py b/recipes/computer_vision/tests/functional/conftest.py new file mode 100644 index 000000000..35f5137b3 --- /dev/null +++ b/recipes/computer_vision/tests/functional/conftest.py @@ -0,0 +1,58 @@ +import pytest_container +import os +import logging + +REGISTRY=os.environ['REGISTRY'] +IMAGE_NAME=os.environ['IMAGE_NAME'] +MODEL_NAME=os.environ['MODEL_NAME'] + +logging.info(""" +Starting pytest with the following ENV vars: + REGISTRY: {REGISTRY} + IMAGE_NAME: {IMAGE_NAME} + MODEL_NAME: {MODEL_NAME} +For: + model_server: whispercpp +""".format(REGISTRY=REGISTRY, IMAGE_NAME=IMAGE_NAME, MODEL_NAME=MODEL_NAME)) + + +MS = pytest_container.Container( + url=f"containers-storage:{REGISTRY}/{IMAGE_NAME}", + volume_mounts=[ + pytest_container.container.BindMount( + container_path=f"/locallm/models/${MODEL_NAME}", + host_path=f"./{MODEL_NAME}", + flags=["ro"] + ) + ], + extra_environment_variables={ + "MODEL_PATH": f"/locall/models/{MODEL_NAME}", + "HOST": "0.0.0.0", + "PORT": "8001" + }, + forwarded_ports=[ + pytest_container.PortForwarding( + container_port=8001, + host_port=8001 + ) + ], + ) + +CB = pytest_container.Container( + url=f"containers-storage:{os.environ['REGISTRY']}/containers/{os.environ['IMAGE_NAME']}", + extra_environment_variables={ + "MODEL_ENDPOINT": "http://10.88.0.1:8001" + }, + forwarded_ports=[ + pytest_container.PortForwarding( + container_port=8501, + host_port=8501 + ) + ], + ) + +def pytest_generate_tests(metafunc): + pytest_container.auto_container_parametrize(metafunc) + +def pytest_addoption(parser): + pytest_container.add_logging_level_options(parser) diff --git a/recipes/computer_vision/object_detection/tests/test_alive.py b/recipes/computer_vision/tests/functional/test_app.py similarity index 64% rename from recipes/computer_vision/object_detection/tests/test_alive.py rename to recipes/computer_vision/tests/functional/test_app.py index 226aac1c0..73cf26de7 100644 --- a/recipes/computer_vision/object_detection/tests/test_alive.py +++ b/recipes/computer_vision/tests/functional/test_app.py @@ -1,8 +1,8 @@ import pytest_container -from .conftest import MS +from .conftest import CB import tenacity -CONTAINER_IMAGES = [MS] +CONTAINER_IMAGES = [CB] def test_etc_os_release_present(auto_container: pytest_container.container.ContainerData): assert auto_container.connection.file("/etc/os-release").exists @@ -10,3 +10,8 @@ def test_etc_os_release_present(auto_container: pytest_container.container.Conta @tenacity.retry(stop=tenacity.stop_after_attempt(5), wait=tenacity.wait_exponential()) def test_alive(auto_container: pytest_container.container.ContainerData, host): host.run_expect([0],f"curl http://localhost:{auto_container.forwarded_ports[0].host_port}",).stdout.strip() + +def test_title(auto_container: pytest_container.container.ContainerData, selenium): + selenium.get(f"http://localhost:{auto_container.forwarded_ports[0].host_port}") + assert selenium.title == "Streamlit" + diff --git a/recipes/computer_vision/tests/integration/__init__.py b/recipes/computer_vision/tests/integration/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/recipes/computer_vision/tests/integration/conftest.py b/recipes/computer_vision/tests/integration/conftest.py new file mode 100644 index 000000000..3a67a71cb --- /dev/null +++ b/recipes/computer_vision/tests/integration/conftest.py @@ -0,0 +1,7 @@ +import os +import pytest + + +@pytest.fixture() +def url(): + return os.environ["URL"] diff --git a/recipes/computer_vision/tests/integration/test_app.py b/recipes/computer_vision/tests/integration/test_app.py new file mode 100644 index 000000000..e2825e60c --- /dev/null +++ b/recipes/computer_vision/tests/integration/test_app.py @@ -0,0 +1,3 @@ +def test_title(url,selenium): + selenium.get(f"http://{url}:8501") + assert selenium.title == "Streamlit" diff --git a/recipes/computer_vision/object_detection/tests/requirements.txt b/recipes/computer_vision/tests/requirements.txt similarity index 100% rename from recipes/computer_vision/object_detection/tests/requirements.txt rename to recipes/computer_vision/tests/requirements.txt