Skip to content

Tests

Tests #256

Workflow file for this run

# This file is centrally managed as a template file in https://github.com/canonical/solutions-engineering-automation
# To update the file:
# - Edit it in the canonical/solutions-engineering-automation repository.
# - Open a PR with the changes.
# - When the PR merges, the soleng-terraform bot will open a PR to the target repositories with the changes.
name: Tests
on:
workflow_call:
workflow_dispatch:
pull_request:
types: [opened, synchronize, reopened]
branches: [main]
paths-ignore:
- "**.md"
- "**.rst"
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
lint:
name: Lint
strategy:
fail-fast: false
matrix:
python-version: ['3.10']
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# pin tox to the current major version to avoid
# workflows breaking all at once when a new major version is released.
python -m pip install 'tox<5'
- name: Run linters
run: tox -e lint
unit:
name: Unit
strategy:
fail-fast: false
matrix:
python-version: ['3.10']
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install 'tox<5'
- name: Run unit tests
run: tox -e unit
- name: Determine system architecture
run: echo "SYSTEM_ARCH=$(uname -m)" >> $GITHUB_ENV
- name: Create artifact name suffix
run: |
PYTHON_VERSION_SANITIZED=${{ matrix.python-version }}
PYTHON_VERSION_SANITIZED=${PYTHON_VERSION_SANITIZED//./-}
echo "ARTIFACT_SUFFIX=$PYTHON_VERSION_SANITIZED-${{ env.SYSTEM_ARCH }}" >> $GITHUB_ENV
- name: Rename Unit Test Coverage Artifact
run: |
if [ -e ".coverage-unit" ]; then
mv .coverage-unit .coverage-unit-${{ env.ARTIFACT_SUFFIX }}
else
echo "No coverage file found, skipping rename"
fi
- name: Upload Unit Test Coverage File
uses: actions/upload-artifact@v4
with:
include-hidden-files: true
if-no-files-found: ignore
name: coverage-unit-${{ env.ARTIFACT_SUFFIX }}
path: .coverage-unit-${{ env.ARTIFACT_SUFFIX }}
build:
needs:
- lint
- unit
name: build charms
runs-on: ${{ matrix.runs-on }}
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
runs-on: [['self-hosted', 'jammy', 'amd64', 'two-xlarge']]
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: canonical/craft-actions/charmcraft/setup@main
with:
channel: "3.x/stable"
- name: Pack the charms
id: build
run: |
charmcraft -v pack
echo "charms=$(ls -1 *.charm | tr '\n' ' ')" >> "$GITHUB_OUTPUT"
- name: List the names of the built charms
run: echo "::notice::Successfully built ${{ steps.build.outputs.charms}}"
- name: Determine system architecture
run: echo "SYSTEM_ARCH=$(uname -m)" >> $GITHUB_ENV
- name: Upload the tested charms
uses: actions/upload-artifact@v4
with:
name: built_charms_${{ env.SYSTEM_ARCH }}
path: ./*.charm
func:
needs:
- build
name: functional tests
runs-on: ${{ matrix.runs-on }}
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
runs-on: [['self-hosted', 'jammy', 'amd64', 'two-xlarge']]
test-command: ['TEST_MODEL_SETTINGS="update-status-hook-interval=30s" tox -e func']
juju-channel: ['3.6/stable']
steps:
- uses: actions/checkout@v4
with:
submodules: true
# arm64 runners don't have gcc installed by default
- name: Install dependencies
run: |
sudo apt update
sudo apt install -y gcc
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Setup Juju environment
uses: charmed-kubernetes/actions-operator@main
with:
provider: "lxd"
juju-channel: ${{ matrix.juju-channel }}
charmcraft-channel: "3.x/stable"
- name: Determine system architecture
run: echo "SYSTEM_ARCH=$(uname -m)" >> $GITHUB_ENV
# This is used by zaza in the functional tests for non-amd64 architectures (if applicable)
- name: Set zaza juju model constraints for architecture
run: |
if [ "${{ env.SYSTEM_ARCH }}" = "aarch64" ]; then
echo "TEST_MODEL_CONSTRAINTS=arch=arm64" >> "$GITHUB_ENV"
fi
- name: Download the built charms
uses: actions/download-artifact@v4
with:
name: built_charms_${{ env.SYSTEM_ARCH }}
- name: List the names of the downloaded charms
run: |
ls *.charm
- name: Run tests
run: |
# These variables are for a consistent method to find the charm file(s) across all projects.
# It is designed to work both with charms that output one file per base,
# and charms that output a single file to run on all bases.
# Not all charms will use them, and for some charms the variables will resolve to the same file.
export CHARM_PATH_NOBLE="$(pwd)/$(ls | grep '.*24.04.*\.charm$')"
echo "$CHARM_PATH_NOBLE"
export CHARM_PATH_JAMMY="$(pwd)/$(ls | grep '.*22.04.*\.charm$')"
echo "$CHARM_PATH_JAMMY"
export CHARM_PATH_FOCAL="$(pwd)/$(ls | grep '.*20.04.*\.charm$')"
echo "$CHARM_PATH_FOCAL"
${{ matrix.test-command }}
env:
TEST_JUJU_CHANNEL: ${{ matrix.juju-channel }}
- name: Generate Safe Test Command Identifier by removing spaces and special characters
run: |
TEST_CMD_ID=$(echo "${{ matrix.test-command }}" | sed 's/[^a-zA-Z0-9]/_/g')
echo "TEST_CMD_ID=$TEST_CMD_ID" >> $GITHUB_ENV
- name: Create artifact name suffix
run: |
echo "ARTIFACT_SUFFIX=${{ env.TEST_CMD_ID }}-${{ env.SYSTEM_ARCH }}" >> $GITHUB_ENV
- name: Rename Functional Test Coverage Artifact
run: |
if [ -e ".coverage-func" ]; then
mv .coverage-func .coverage-func-${{ env.ARTIFACT_SUFFIX }}
else
echo "No coverage file found, skipping rename"
fi
- name: Upload Functional Test Coverage Artifact
uses: actions/upload-artifact@v4
with:
include-hidden-files: true
if-no-files-found: ignore
name: coverage-functional-${{ env.ARTIFACT_SUFFIX }}
path: .coverage-func-${{ env.ARTIFACT_SUFFIX }}
# Save output for debugging
- name: Generate debugging information
if: always()
run: |
set -x
# install dependencies
sudo snap install --classic juju-crashdump
sudo apt install -y jq uuid
# Print juju controller information for debugging
# to check controller and client are compatible versions;
# we can have a mismatch if using an external controller.
juju version
juju controllers
models="$(juju models --format json | jq -r '.models[]."short-name"')"
dir="$(mktemp -d)"
# Use a different dir to avoid charmed-kubernetes/actions-operator from also trying to upload crashdumps.
# We don't want to rely on that action, because it doesn't use a descriptive enough name for the artefact,
# and we may stop using that action soon.
echo "CRASHDUMPS_DIR=$dir" | tee -a "$GITHUB_ENV"
echo "CRASHDUMPS_ARTEFACT_SUFFIX=$(uuid)-$(uname -m)" | tee -a "$GITHUB_ENV"
for model in $models; do
# show status here for quick debugging
juju status -m "$model"
juju-crashdump --as-root -m "$model" -u "$model-$(uname -m)" -o "$dir"
done
- name: Upload juju crashdumps
uses: actions/upload-artifact@v4
if: always()
with:
name: "juju-crashdumps-${{ env.CRASHDUMPS_ARTEFACT_SUFFIX }}"
path: "${{ env.CRASHDUMPS_DIR }}/juju-crashdump-*.tar.xz"
tics-analysis:
runs-on: [self-hosted, linux, amd64, tiobe, jammy]
if: >
(github.event_name == 'push' && github.ref == 'refs/heads/main') ||
(github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main')
needs: func
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install coverage tools
run: |
pip install coverage[toml]
# Install everything from all requirements.txt files otherwise TICS errors.
- name: Install all charm dependencies
run: |
for f in $(find -name '*requirements.txt'); do
echo "${f}"
pip3 install --requirement "${f}"
done
# For reactive charms
for f in $(find -name 'wheelhouse.txt'); do
echo "${f}"
pip3 install --requirement "${f}"
done
- name: Determine system architecture
run: echo "SYSTEM_ARCH=$(uname -m)" >> $GITHUB_ENV
- name: Download Coverage Files
uses: actions/download-artifact@v4
with:
pattern: coverage-*-${{ env.SYSTEM_ARCH }}
merge-multiple: true
path: artifacts/
continue-on-error: true
- name: Merge coverage reports
run: |
# Create the path that is expected to have a coverage.xml for tics
mkdir -p tests/report/
coverage_files=(./artifacts/.coverage*)
if [ -e "${coverage_files[0]}" ]; then
echo "Merging coverage files: ${coverage_files[*]}"
coverage combine "${coverage_files[@]}"
# Check if there is actual data to report before generating XML with merged reports
if coverage report > /dev/null 2>&1; then
coverage report --show-missing
coverage xml -o tests/report/coverage.xml
fi
fi
- name: Run TICS analysis
uses: tiobe/tics-github-action@v3
with:
mode: qserver
project: openstack-exporter-operator
viewerUrl: https://canonical.tiobe.com/tiobeweb/TICS/api/cfg?name=default
branchdir: ${{ github.workspace }}
ticsAuthToken: ${{ secrets.TICSAUTHTOKEN }}
installTics: true