Skip to content

Commit

Permalink
#10 add fixtures (#13)
Browse files Browse the repository at this point in the history
* #10: Added pytest fixtures for usage in integration tests of external projects
* Use pyyaml for reading project short tag from error_code_config.yml
* Added ip-whitelisting to fixture operational_saas_database_id
* Verified fixture in test_operational_database
* Replaced bash script in justfile by python
* Added developer instructions
* Updated README file
* moved developer instructions to Developer guide.

Co-authored-by: Torsten Kilias <[email protected]>
  • Loading branch information
ckunki and tkilias authored May 27, 2024
1 parent 6e60c3f commit e2a0157
Show file tree
Hide file tree
Showing 16 changed files with 418 additions and 69 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/ci-main.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Continues Integration (Master)
name: Continuous Integration (Main)

on:
workflow_dispatch:
Expand All @@ -13,3 +13,6 @@ jobs:

CI:
uses: ./.github/workflows/ci.yml
secrets: inherit
with:
slow-tests: true
5 changes: 4 additions & 1 deletion .github/workflows/ci-pr.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Continues Integration (PR)
name: Continuous Integration (PR)

on:
pull_request:
Expand All @@ -7,3 +7,6 @@ jobs:

CI:
uses: ./.github/workflows/ci.yml
secrets: inherit
with:
slow-tests: true
22 changes: 19 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ name: CI

on:
workflow_call:
inputs:
slow-tests:
type: boolean
required: false
default: false
secrets:
ALTERNATIVE_GITHUB_TOKEN:
required: false
Expand All @@ -13,6 +18,11 @@ jobs:
runs-on: ubuntu-20.04

steps:
- name: Set pytest markers
id: pytest-markers
if: ${{ ! inputs.slow-tests }}
run: echo slow-tests='-m "not slow"' >> "$GITHUB_OUTPUT"

- name: SCM Checkout
uses: actions/checkout@v4
with:
Expand All @@ -21,6 +31,12 @@ jobs:
- name: Setup Development Environment
uses: ./.github/actions/pytest-plugins-environment

- name: Run Tests of all plugins
run: just test

- name: Run Tests of All Plugins
run: |
echo "PYTEST_ADDOPTS = $PYTEST_ADDOPTS"
just test
env:
SAAS_HOST: ${{ secrets.INTEGRATION_TEAM_SAAS_STAGING_HOST }}
SAAS_ACCOUNT_ID: ${{ secrets.INTEGRATION_TEAM_SAAS_STAGING_ACCOUNT_ID }}
SAAS_PAT: ${{ secrets.INTEGRATION_TEAM_SAAS_STAGING_PAT }}
PYTEST_ADDOPTS: '-o log_cli=true -o log_cli_level=INFO ${{ steps.pytest-markers.outputs.slow-tests }}'
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Pytest-Plugins for Exasol

Welcome to the official repository for Exasol pytest-plugins!

This collection of plugins is designed to enhance and simplify the testing experience for projects related to Exasol.

By providing a centralized location for pytest plugins, we aim to foster collaboration, ensure consistency, and improve the quality of testing practices within the organization.

## Introduction

[pytest](https://pytest.org) is a powerful testing framework for [python](https://www.python.org), and with the help of these plugins, developers can extend its functionality to better suit the testing requirements of Exasol-related projects.

Whether you're looking to use database interactions, enhance test reporting, or streamline your testing pipeline, our plugins are here to help.

## Plugins

| Plugin | Description | PYPI |
|----------------------|----------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|
| `pytest-exasol-itde` | Fixture to enable simple usage with Exasol's project [ITDE](https://github.com/exasol/integration-test-docker-environment) | [pytest-exasol-itde](https://pypi.org/project/pytest-exasol-itde/) |
| `pytest-exasol-saas` | Fixture to enable simple usage with Exasol's project [saas-api-python](https://github.com/exasol/saas-api-python/) | [pytest-exasol-saas](https://pypi.org/project/pytest-exasol-saas/) |


## Installation

To ensure you're using the latest features and bug fixes, we recommend installing the plugins directly from PyPI using your preferred package manager. This approach simplifies the process of keeping your testing environment up-to-date.

For example, to install the `pytest-exasol-itde` plugin, you could use the following command:


```shell
pip install pytest-exasol-itde
```

To install a specific version of a plugin, simply specify the version number:

```shell
pip install "pytest-exasol-itde==x.y.z"
```

Replace x.y.z with the desired version number.

## Development

See [Developer Guide](doc/developer-guide.md).
55 changes: 0 additions & 55 deletions README.rst

This file was deleted.

23 changes: 23 additions & 0 deletions doc/developer-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Developer Guide Exasol pytest-plugins

## Dependencies

Before you can start developing in this workspace, please ensure you have the following tools installed either globally or at a workspace level.

* [Python](https://www.python.org)
* [Just](https://github.com/casey/just)

## Run Tests

### Slow Tests

Some of the test cases verify connecting to a SaaS database instance and
execution will take about 20 minutes.

These test cases are only executed by the following GitHub workflows
* `ci-main.yml`
* `ci-slow.yml`

Both of these workflows can be run manually, workflow `ci-main.yml` is executed automatically at the 7th day of each month.

For merging a pull request to branch `main` workflow `ci-slow.yml` needs to be run and terminate successfully.
17 changes: 12 additions & 5 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@ default:

# Run tests for one or multiple projects within this respository
test +projects=PROJECTS:
#!/usr/bin/env bash
for p in {{projects}}; do
poetry -C ${p}/ install
poetry -C ${p}/ run nox -f ${p}/noxfile.py -s coverage
done
#!/usr/bin/env python3
import subprocess, sys
rc = 0
def run(command):
global rc
result = subprocess.run(command.split())
rc = result.returncode or rc
for p in "{{projects}}".split():
run(f"poetry -C {p}/ install")
run(f"poetry -C {p}/ run nox -f {p}/noxfile.py -s coverage")
sys.exit(rc)

# Create a release
release project version:
Expand Down
4 changes: 4 additions & 0 deletions pytest-itde/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ pyexasol = "^0.25"
[tool.poetry.plugins.pytest11]
itde = "exasol.pytest_itde"

[tool.pytest.ini_options]
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
]

[tool.poetry.group.dev.dependencies]
exasol-toolbox = "0.8.0"
Expand Down
40 changes: 40 additions & 0 deletions pytest-saas/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,43 @@ To install the pytest-exasol-saas plugin, you can use pip:
```shell
pip install pytest-exasol-saas
```

## Database Instances

### Using an Existing Database Instance

By default the fixtures in pytest-exasol-saas Plugin will create instances of Exasol SaaS database with scope `session`.

If you want to use an existing instance instead, then you can provide the instance's ID with the command line option `--saas-database-id <ID>` to pytest.

### Keeping Database Instances After the Test Session

By default the fixtures in pytest-exasol-saas Plugin will remove the created database instances after the session or in case of errors.

However, if you provide the command line option `--keep-saas-database` then the pytest-exasol-saas plugin will _keep_ these instances for subsequent inspection or reuse.

Please note hat long-running instances will cause significant costs.

### Naming Database Instances

pytest-exasol-saas Plugin will name the database instances using 3 components

* **Project Short Tag**: Abbreviation of the current project, see below for different [options for providing the project short tag](#options-for-providing-the-project-short-tag).
* **Timestamp**: Number of seconds since epoc, see [Unix Time](https://en.wikipedia.org/wiki/Unix_time).
* A dash character `-`
* **User Name**: Login name of the current user.

A database instances might for example have the name `1715155224SAPIPY-run` indicating it was
* created on Wednesday, May 8, 2024
* in the context of a project with short tag `SAPIPY`
* by a user with login name starting with `run`

Please note that Exasol SaaS limits the length of database names to 10 characters only. So pytest-exasol-saas plugin will shorten the constructed name to 10 characters max.

If running your tests on a server for Continuous Integration (CI) then the name of the user might be not very expressive.

### Options for providing the Project Short Tag

* In yaml file `error_code_config.yml` in the project's root directory
* CLI option `--project-short-tag <short tag>` to pytest
* Environment variable `PROJECT_SHORT_TAG`
1 change: 1 addition & 0 deletions pytest-saas/doc/changes/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ This version introduces the `pytest-exasol-saas` plugin providing pytest functio
## Features

* #9: Added sub-project for exasol-saas-api
* #10: Added pytest fixtures for usage in integration tests of external projects
101 changes: 101 additions & 0 deletions pytest-saas/exasol/pytest_saas/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import os
from pathlib import Path

import pytest
from exasol.saas.client import openapi
from exasol.saas.client.api_access import (
OpenApiAccess,
create_saas_client,
timestamp_name,
)

import exasol.pytest_saas.project_short_tag as pst


def pytest_addoption(parser):
parser.addoption(
f"--saas-database-id",
help="""ID of the instance of an existing SaaS database to be
used during the current pytest session instead of creating a
dedicated instance temporarily.""",
)
parser.addoption(
f"--keep-saas-database",
action="store_true",
default=False,
help="""Keep the SaaS database instance created for the current
pytest session for subsequent inspection or reuse.""",
)
parser.addoption(
f"--project-short-tag",
help="""Short tag aka. "abbreviation" for your current project.
See docstring in project_short_tag.py for more details.
pytest plugin for exasol-saas-api will include this short tag into
the names of created database instances.""",
)


def _env(var: str) -> str:
result = os.environ.get(var)
if result:
return result
raise RuntimeError(f"Environment variable {var} is empty.")


@pytest.fixture(scope="session")
def saas_host() -> str:
return _env("SAAS_HOST")


@pytest.fixture(scope="session")
def saas_pat() -> str:
return _env("SAAS_PAT")


@pytest.fixture(scope="session")
def saas_account_id() -> str:
return _env("SAAS_ACCOUNT_ID")


@pytest.fixture(scope="session")
def project_short_tag(request):
return (
request.config.getoption("--project-short-tag")
or os.environ.get("PROJECT_SHORT_TAG")
or pst.read_from_yaml(request.config.rootpath)
)


@pytest.fixture(scope="session")
def database_name(project_short_tag):
return timestamp_name(project_short_tag)


@pytest.fixture(scope="session")
def api_access(saas_host, saas_pat, saas_account_id) -> OpenApiAccess:
with create_saas_client(saas_host, saas_pat) as client:
yield OpenApiAccess(client, saas_account_id)


@pytest.fixture(scope="session")
def saas_database(
request, api_access, database_name
) -> openapi.models.database.Database:
"""
Note: The SaaS instance database returned by this fixture initially
will not be operational. The startup takes about 20 minutes.
"""
db_id = request.config.getoption("--saas-database-id")
if db_id:
yield api_access.get_database(db_id)
return
with api_access.database(database_name) as db:
yield db


@pytest.fixture(scope="session")
def operational_saas_database_id(api_access, saas_database) -> str:
db = saas_database
api_access.add_allowed_ip()
api_access.wait_until_running(db.id)
return db.id
Loading

0 comments on commit e2a0157

Please sign in to comment.