Skip to content
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
5 changes: 4 additions & 1 deletion .github/workflows/test_docker_compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ jobs:
- name: Test Frontend
run: |
echo "Testing frontend HTTP response..."
curl -f -I http://localhost:30001 || (echo "Frontend test failed" && exit 1)
# Use a GET (not HEAD/-I): the Flutter dev web-server used by
# docker-compose responds 404 to HEAD but 200 to GET. -o /dev/null
# discards the body so this stays a lightweight smoke test.
curl -f -s -o /dev/null http://localhost:30001 || (echo "Frontend test failed" && exit 1)

- name: Test Database connectivity
run: |
Expand Down
20 changes: 19 additions & 1 deletion backend/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import json
from base64 import b64encode
from collections.abc import Callable
from collections.abc import Callable, Iterator
from contextlib import contextmanager
from os import environ

Expand All @@ -34,6 +34,7 @@
drop_database,
)

from test_observer.common import config
from test_observer.common.config import SESSIONS_SECRET
from test_observer.common.enums import Permission
from test_observer.controllers.applications.application_injection import (
Expand All @@ -46,6 +47,23 @@
from tests.data_generator import DataGenerator


@pytest.fixture(autouse=True)
def _clear_ignore_permissions() -> Iterator[None]:
"""
Ensure permission checks are enforced during tests.

The local development Docker environment sets IGNORE_PERMISSIONS to bypass
permission checks for convenience, but tests run inside that same container
and must exercise the real authorization logic. Clear the set in place (both
config and permissions modules reference the same object) and restore it
afterwards.
"""
original = set(config.IGNORE_PERMISSIONS)
config.IGNORE_PERMISSIONS.clear()
yield
config.IGNORE_PERMISSIONS.update(original)


def _check_postgres_connection(host: str, port: int, user: str, password: str) -> bool:
"""Check if we can connect to PostgreSQL at the given host."""
try:
Expand Down
23 changes: 22 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ services:
PYTHONDONTWRITEBYTECODE: "1" # Prevent .pyc files in development
SESSIONS_HTTPS_ONLY: "false"
REQUIRE_AUTHENTICATION: "${REQUIRE_AUTHENTICATION:-false}"
IGNORE_PERMISSIONS: "${IGNORE_PERMISSIONS:-view_user,change_user,view_team,change_team,add_application,change_application,view_application,view_permission,view_issue,change_issue,change_issue_attachment,change_issue_attachment_bulk,change_attachment_rule,change_auto_rerun,view_test,change_test,view_rerun,change_rerun,change_rerun_bulk,view_artefact,change_artefact,view_environment_review,change_environment_review,view_report,view_test_case_reported_issue,change_test_case_reported_issue,view_environment_reported_issue,change_environment_reported_issue,view_notification,change_notification}"
USE_LOCAL_LOGIN: "${USE_LOCAL_LOGIN:-true}"
Comment on lines 39 to 41

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the idea is to make local development easier, you can disable that if you want to test authorization

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can have different profiles in docker compose.

volumes:
# Mount source code from host for development
Expand All @@ -48,14 +49,34 @@ services:
image: test-observer-frontend
build:
context: ./frontend
dockerfile: Dockerfile
dockerfile: Dockerfile.dev
ports:
- "30001:80" # Adjust the port mapping as needed
depends_on:
test-observer-api:
condition: service_healthy
saml-idp:
condition: service_healthy
volumes:
# Mount source code from host for development (enables live code changes)
- ./frontend:/app
# Preserve container-managed build artifacts / package config so they
# don't clash with the host's (potentially different-platform) versions.
- /app/.dart_tool
- /app/build
# The dev container starts instantly but Flutter needs time to compile
# before it serves on :80. This healthcheck lets `docker compose up --wait`
# (used locally and in the test_docker_compose CI workflow) block until the
# app is actually being served, rather than merely "running".
healthcheck:
test: [ "CMD-SHELL", "curl -f http://localhost:80/ || exit 1" ]
interval: 10s
timeout: 5s
retries: 5
# Generous start_period: the very first `flutter run` compilation can take
# ~30-60s (longer on a cold pub cache). Failures during this window don't
# count against the retry budget.
start_period: 180s

test-observer-db:
image: docker.io/postgres:14
Expand Down
54 changes: 54 additions & 0 deletions frontend/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copyright 2025 Canonical Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3, as
# published by the Free Software Foundation.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-FileCopyrightText: Copyright 2025 Canonical Ltd.
# SPDX-License-Identifier: GPL-3.0-only

# Development image for the Test Observer frontend.
#
# Unlike the production Dockerfile, this image does NOT build a static release
# bundle. Instead the source is bind-mounted at runtime (see docker-compose.yml)
# and the container runs `flutter run` on a web server so that code changes are
# picked up without rebuilding the image.

FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y \
curl git wget unzip gdb libstdc++6 libglu1-mesa fonts-droid-fallback \
python3 inotify-tools && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

RUN git clone --depth 1 --branch '3.29.3' https://github.com/flutter/flutter.git /opt/flutter && \
/opt/flutter/bin/flutter doctor && \
/opt/flutter/bin/flutter config --enable-web

ENV PATH="$PATH:/opt/flutter/bin:/root/.pub-cache/bin"

WORKDIR /app

# Warm the pub cache so the first `flutter run` is fast. The source itself is
# bind-mounted at runtime, so only dependency manifests are copied here.
COPY pubspec.* /app/
RUN flutter pub get

# Copy the entrypoint into the image so it works even without the runtime
# bind-mount, and invoke it via `bash` so it doesn't depend on the executable
# bit being preserved. In docker-compose the bind-mount overrides this copy
# with the live host version.
COPY dev_entrypoint.sh /app/dev_entrypoint.sh

EXPOSE 80

CMD ["bash", "/app/dev_entrypoint.sh"]
55 changes: 55 additions & 0 deletions frontend/dev_entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/bin/bash

# Copyright 2025 Canonical Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3, as
# published by the Free Software Foundation.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-FileCopyrightText: Copyright 2025 Canonical Ltd.
# SPDX-License-Identifier: GPL-3.0-only

set -e

echo "Fetching Flutter dependencies..."
flutter pub get

echo "Generating code (blocking, so *.g.dart / *.freezed.dart are fresh before first compile)..."
dart run build_runner build --delete-conflicting-outputs

echo "Starting build_runner in watch mode (regenerates code on subsequent changes)..."
dart run build_runner watch --delete-conflicting-outputs &

# Feed the Flutter dev server's stdin through a FIFO so we can drive it
# non-interactively. A file watcher writes "R" (hot restart) to the FIFO
# whenever a source file changes, giving automatic reload on save without
# needing to attach a TTY to the container.
FIFO=/tmp/flutter-stdin
rm -f "$FIFO"
mkfifo "$FIFO"
# Hold the FIFO open for writing so it never receives EOF.
exec 3<>"$FIFO"

echo "Watching lib/ and web/ for changes to trigger automatic hot restart..."
(
while inotifywait -q -r -e modify,create,delete,move \
--include '\.(dart|yaml|json|html)$' lib web >/dev/null 2>&1; do
Comment thread
almeidaraul marked this conversation as resolved.
# Debounce bursts of file events (e.g. build_runner regenerating files).
sleep 1
echo "R" >&3
done
) &

echo "Starting Flutter web dev server (hot restart on save)..."
# --web-hostname 0.0.0.0 so the server is reachable from outside the container.
Comment thread
almeidaraul marked this conversation as resolved.
exec flutter run \
-d web-server \
--web-hostname 0.0.0.0 \
--web-port 80 \
<&3
Loading