Skip to content
Merged
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: 8 additions & 5 deletions .github/workflows/integration_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ jobs:
juju-channel: 3.6/stable
provider: lxd
test-tox-env: integration
modules: '["test_multi_unit_same_machine", "test_charm_fork_path_change", "test_charm_no_runner", "test_charm_upgrade"]'
# INTEGRATION_TOKEN, INTEGRATION_TOKEN_ALT, OS_* are passed through INTEGRATION_TEST_SECRET_ENV_VALUE_<N>
# mapping. See CONTRIBUTING.md for more details.
modules: '["test_multi_unit_same_machine", "test_charm_no_runner", "test_charm_upgrade"]'
# Sensitive env vars are passed through INTEGRATION_TEST_SECRET_ENV_VALUE_<N>;
# see CONTRIBUTING.md for the slot-to-var mapping.
extra-arguments: |
-m=openstack \
--log-format="%(asctime)s %(levelname)s %(message)s" \
Expand All @@ -35,6 +35,7 @@ jobs:
--openstack-no-proxy="${{ vars.INTEGRATION_TEST_OPENSTACK_NO_PROXY }}" \
--openstack-flavor-name="${{ vars.INTEGRATION_TEST_OPENSTACK_FLAVOR_NAME }}" \
--openstack-image-id="${{ vars.INTEGRATION_TEST_IMAGE_ID }}" \
--github-app-client-id="${{ vars.INTEGRATION_TEST_GITHUB_APP_CLIENT_ID }}" \
--dockerhub-mirror="${{ vars.INTEGRATION_TEST_DOCKERHUB_MIRROR }}"
self-hosted-runner: true
self-hosted-runner-label: pfe-ci
Expand All @@ -49,8 +50,8 @@ jobs:
provider: lxd
test-tox-env: integration
modules: '["test_prometheus_metrics"]'
# INTEGRATION_TOKEN, INTEGRATION_TOKEN_ALT, OS_* are passed through INTEGRATION_TEST_SECRET_ENV_VALUE_<N>
# mapping. See CONTRIBUTING.md for more details.
# Sensitive env vars are passed through INTEGRATION_TEST_SECRET_ENV_VALUE_<N>;
# see CONTRIBUTING.md for the slot-to-var mapping.
extra-arguments: |
-m=openstack \
--log-format="%(asctime)s %(levelname)s %(message)s" \
Expand All @@ -63,6 +64,7 @@ jobs:
--openstack-no-proxy="${{ vars.INTEGRATION_TEST_OPENSTACK_NO_PROXY }}" \
--openstack-flavor-name="${{ vars.INTEGRATION_TEST_OPENSTACK_FLAVOR_NAME }}" \
--openstack-image-id="${{ vars.INTEGRATION_TEST_IMAGE_ID }}" \
--github-app-client-id="${{ vars.INTEGRATION_TEST_GITHUB_APP_CLIENT_ID }}" \
--dockerhub-mirror="${{ vars.INTEGRATION_TEST_DOCKERHUB_MIRROR }}"
self-hosted-runner: true
self-hosted-runner-label: pfe-ci
Expand Down Expand Up @@ -91,6 +93,7 @@ jobs:
--openstack-no-proxy="${{ vars.INTEGRATION_TEST_OPENSTACK_NO_PROXY }}" \
--openstack-flavor-name="${{ vars.INTEGRATION_TEST_OPENSTACK_FLAVOR_NAME }}" \
--openstack-image-id="${{ vars.INTEGRATION_TEST_IMAGE_ID }}" \
--github-app-client-id="${{ vars.INTEGRATION_TEST_GITHUB_APP_CLIENT_ID }}" \
--dockerhub-mirror="${{ vars.INTEGRATION_TEST_DOCKERHUB_MIRROR }}" \
--base="${{ matrix.base }}"
self-hosted-runner: true
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/test_github_runner_manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,11 @@ jobs:
- name: Run integration tests - ${{ matrix.test-module }}
working-directory: ./github-runner-manager/
env:
# GitHub configuration
# INTEGRATION_TOKEN, INTEGRATION_TOKEN_ALT
# Sensitive env vars are passed through INTEGRATION_TEST_SECRET_ENV_VALUE_<N>;
# see CONTRIBUTING.md for the slot-to-var mapping.
${{ vars.INTEGRATION_TEST_SECRET_ENV_NAME }}: ${{ secrets.INTEGRATION_TEST_SECRET_ENV_VALUE }}
${{ vars.INTEGRATION_TEST_SECRET_ENV_NAME_1 }}: ${{ secrets.INTEGRATION_TEST_SECRET_ENV_VALUE_1 }}
${{ vars.INTEGRATION_TEST_SECRET_ENV_NAME_2 }}: ${{ secrets.INTEGRATION_TEST_SECRET_ENV_VALUE_2 }}
# OpenStack configuration
# OS_AUTH_URL, OS_PROJECT_DOMAIN_NAME, OS_PROJECT_NAME, OS_USER_DOMAIN_NAME, OS_USERNAME, OS_PASSWORD, OS_NETWORK, OS_REGION_NAME
${{ vars.INTEGRATION_TEST_SECRET_ENV_NAME_3 }}: ${{ secrets.INTEGRATION_TEST_SECRET_ENV_VALUE_3 }}
${{ vars.INTEGRATION_TEST_SECRET_ENV_NAME_4 }}: ${{ secrets.INTEGRATION_TEST_SECRET_ENV_VALUE_4 }}
${{ vars.INTEGRATION_TEST_SECRET_ENV_NAME_5 }}: ${{ secrets.INTEGRATION_TEST_SECRET_ENV_VALUE_5 }}
Expand All @@ -50,6 +49,8 @@ jobs:
${{ vars.INTEGRATION_TEST_SECRET_ENV_NAME_8 }}: ${{ secrets.INTEGRATION_TEST_SECRET_ENV_VALUE_8 }}
${{ vars.INTEGRATION_TEST_SECRET_ENV_NAME_9 }}: ${{ secrets.INTEGRATION_TEST_SECRET_ENV_VALUE_9 }}
${{ vars.INTEGRATION_TEST_SECRET_ENV_NAME_10 }}: ${{ secrets.INTEGRATION_TEST_SECRET_ENV_VALUE_10 }}
${{ vars.INTEGRATION_TEST_SECRET_ENV_NAME_11 }}: ${{ secrets.INTEGRATION_TEST_SECRET_ENV_VALUE_11 }}
${{ vars.INTEGRATION_TEST_SECRET_ENV_NAME_12 }}: ${{ secrets.INTEGRATION_TEST_SECRET_ENV_VALUE_12 }}
Comment thread
cbartz marked this conversation as resolved.
run: |
tox -e integration -- -v --tb=native -s \
tests/integration/${{ matrix.test-module }}.py \
Expand Down
16 changes: 8 additions & 8 deletions github-runner-manager/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ def pytest_addoption(parser):
parser: Pytest parser.
"""
parser.addoption(
"--github-token",
Comment thread
cbartz marked this conversation as resolved.
"--github-repository",
action="store",
help="GitHub personal access token for integration tests.",
default=os.getenv("INTEGRATION_TOKEN"),
help="The GitHub repository in <owner>/<repo> format for integration tests.",
Comment thread
cbartz marked this conversation as resolved.
)
parser.addoption(
"--github-repository",
"--github-app-client-id",
action="store",
help="The GitHub repository in <owner>/<repo> format for integration tests.",
help="GitHub App Client ID for integration tests.",
default=os.getenv("GITHUB_APP_CLIENT_ID"),
)
parser.addoption(
"--github-token-alt",
"--github-app-installation-id",
action="store",
help="Alternate GitHub token from a different user for fork testing.",
default=os.getenv("INTEGRATION_TOKEN_ALT"),
help="GitHub App installation ID for integration tests.",
default=os.getenv("GITHUB_APP_INSTALLATION_ID"),
)
parser.addoption(
"--openstack-auth-url",
Expand Down
39 changes: 28 additions & 11 deletions github-runner-manager/tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
"""Fixtures for github-runner-manager integration tests."""

import logging
import os
import time
from pathlib import Path
from typing import Generator
from typing import Generator, cast

import openstack
import pytest
Expand Down Expand Up @@ -35,7 +36,12 @@ def test_config(pytestconfig: pytest.Config) -> TestConfig:

@pytest.fixture(scope="module")
def github_config(pytestconfig: pytest.Config) -> GitHubConfig:
"""Get GitHub configuration from pytest options or environment.
"""Get GitHub configuration.

The token and private key are read from the environment only
(``INTEGRATION_TOKEN`` and ``GITHUB_APP_PRIVATE_KEY``). The repository path
and GitHub App client/installation IDs come from pytest options; the app
ID options fall back to environment variables (see ``pytest_addoption``).

Args:
pytestconfig: Pytest configuration object.
Expand All @@ -44,21 +50,32 @@ def github_config(pytestconfig: pytest.Config) -> GitHubConfig:
GitHub configuration object.

Raises:
pytest.fail: If neither --github-token option nor INTEGRATION_TOKEN
environment variable is set.
pytest.fail: If INTEGRATION_TOKEN or the GitHub repository is not set.
"""
token = pytestconfig.getoption("--github-token")
alt_token = pytestconfig.getoption("--github-token-alt", None)
token = os.getenv("INTEGRATION_TOKEN")
path = pytestconfig.getoption("--github-repository")
app_client_id = pytestconfig.getoption("--github-app-client-id") or None
installation_id_raw = pytestconfig.getoption("--github-app-installation-id") or None
private_key = os.getenv("GITHUB_APP_PRIVATE_KEY") or None

if not token or not alt_token or not path:
if not token or not path:
pytest.fail(
"GitHub configuration not provided. Use --github-token, --github-token-alt, and "
"--github-repository options or set INTEGRATION_TOKEN, INTEGRATION_TOKEN_ALT, and "
"GITHUB_REPOSITORY environment variables."
"GitHub configuration not provided. Set INTEGRATION_TOKEN and use "
"--github-repository."
)

if all((app_client_id, installation_id_raw, private_key)):
logger.info("Using GitHub App authentication for integration tests")
return GitHubConfig(
token=token,
path=path,
app_client_id=app_client_id,
installation_id=int(cast(str, installation_id_raw)),
private_key=private_key,
)

return GitHubConfig(token=token, alt_token=alt_token, path=path)
logger.info("Using PAT authentication for integration tests")
return GitHubConfig(token=token, path=path)


@pytest.fixture(scope="module")
Expand Down
29 changes: 23 additions & 6 deletions github-runner-manager/tests/integration/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,23 @@ class GitHubConfig:

Attributes:
token: GitHub personal access token.
alt_token: Alternate GitHub personal access token for external contributor.
path: GitHub path in <owner>/<repo> or <org> format.
app_client_id: GitHub App Client ID.
installation_id: GitHub App installation ID.
private_key: GitHub App PEM-encoded private key.
has_app_auth: Whether GitHub App authentication credentials are configured.
"""

token: str
alt_token: str
token: str = field(repr=False)
path: str
app_client_id: str | None = None
installation_id: int | None = None
private_key: str | None = field(default=None, repr=False)

@property
def has_app_auth(self) -> bool:
"""Whether GitHub App authentication credentials are configured."""
return all((self.app_client_id, self.installation_id, self.private_key))


@dataclass
Expand All @@ -54,7 +64,7 @@ class OpenStackConfig:
auth_url: str
project: str
username: str
password: str
password: str = field(repr=False)
Comment thread
cbartz marked this conversation as resolved.
network: str
region_name: str = "RegionOne"
user_domain_name: str = "Default"
Expand Down Expand Up @@ -166,7 +176,6 @@ def create_default_config(
if github_config is None:
github_config = GitHubConfig(
token="ghp_test_token_1234567890abcdef",
alt_token="ghp_test_alt_token_1234567890abcdef",
path="test-org",
)

Expand Down Expand Up @@ -214,7 +223,15 @@ def create_default_config(
"allow_external_contributor": allow_external_contributor,
"extra_labels": test_config.labels,
"github_config": {
"auth": {"token": github_config.token},
"auth": (
{
"app_client_id": github_config.app_client_id,
"installation_id": github_config.installation_id,
"private_key": github_config.private_key,
}
if github_config.has_app_auth
else {"token": github_config.token}
),
"path": path_config,
},
"service_config": {
Expand Down
45 changes: 45 additions & 0 deletions github-runner-manager/tests/unit/test_integration_factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright 2026 Canonical Ltd.
# See LICENSE file for licensing details.

"""Unit tests for integration test factories."""

from tests.integration.factories import GitHubConfig, create_default_config


def test_create_default_config_uses_token_auth_by_default():
"""
arrange: A GitHub test config without GitHub App credentials.
act: Build the integration test application config.
assert: The GitHub auth block uses token auth.
"""
config = create_default_config(
github_config=GitHubConfig(
token="ghp_test_token_1234567890abcdef",
path="canonical/example",
)
)

assert config["github_config"]["auth"] == {"token": "ghp_test_token_1234567890abcdef"}


def test_create_default_config_uses_github_app_auth_when_available():
"""
arrange: A GitHub test config with complete GitHub App credentials.
act: Build the integration test application config.
assert: The GitHub auth block uses GitHub App auth.
"""
config = create_default_config(
github_config=GitHubConfig(
token="ghp_test_token_1234567890abcdef",
path="canonical/example",
app_client_id="Iv23liExample",
installation_id=456,
private_key="-----BEGIN PRIVATE KEY-----\nabc\n-----END PRIVATE KEY-----",
)
)

assert config["github_config"]["auth"] == {
"app_client_id": "Iv23liExample",
"installation_id": 456,
"private_key": "-----BEGIN PRIVATE KEY-----\nabc\n-----END PRIVATE KEY-----",
}
1 change: 0 additions & 1 deletion github-runner-manager/tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ passenv =
PYTHONPATH
GITHUB_REPOSITORY
INTEGRATION_TOKEN
INTEGRATION_TOKEN_ALT
OS_AUTH_URL
OS_PROJECT_DOMAIN_NAME
OS_PROJECT_NAME
Expand Down
6 changes: 0 additions & 6 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,6 @@ def pytest_addoption(parser: Parser):
help="The GitHub App installation ID for GitHub App authentication testing.",
default=os.environ.get("GITHUB_APP_INSTALLATION_ID"),
)
parser.addoption(
Comment thread
cbartz marked this conversation as resolved.
"--github-app-private-key",
action="store",
help="The GitHub App PEM-encoded private key for GitHub App authentication testing.",
default=os.environ.get("GITHUB_APP_PRIVATE_KEY"),
)
parser.addoption(
"--keep-models",
action="store_true",
Expand Down
Loading
Loading