Skip to content

CLOUD-929 - Initial pytest test migration#2058

Open
jvpasinatto wants to merge 28 commits into
mainfrom
pytest-complete
Open

CLOUD-929 - Initial pytest test migration#2058
jvpasinatto wants to merge 28 commits into
mainfrom
pytest-complete

Conversation

@jvpasinatto

@jvpasinatto jvpasinatto commented Sep 23, 2025

Copy link
Copy Markdown
Contributor

Due to the high volume of requests, we're unable to provide free service for this account. To continue using the service, please upgarde to a paid plan.

CHANGE DESCRIPTION

This PR sets up the initial groundwork for transitioning to pytest as our testing framework. It includes:

  • Conversion of init-deploy, finalizer and liveness tests to pytest
  • Addition of a GitHub Action to check Python code quality

Create virtual environment and install dependencies:
uv sync --locked

Run all tests:
uv run pytest

Run a specific test
uv run pytest e2e-tests/init-deploy

Enabling debug logging:
LOG_LEVEL=DEBUG uv run pytest

CHECKLIST

Jira

  • Is the Jira ticket created and referenced properly?
  • Does the Jira ticket have the proper statuses for documentation (Needs Doc) and QA (Needs QA)?
  • Does the Jira ticket link to the proper milestone (Fix Version field)?

Tests

  • Is an E2E test/test case added for the new feature/change?
  • Are unit tests added where appropriate?
  • Are OpenShift compare files changed for E2E tests (compare/*-oc.yml)?

Config/Logging/Testability

  • Are all needed new/changed options added to default YAML files?
  • Are all needed new/changed options added to the Helm Chart?
  • Did we add proper logging messages for operator actions?
  • Did we ensure compatibility with the previous version or cluster upgrade process?
  • Does the change support oldest and newest supported MongoDB version?
  • Does the change support oldest and newest supported Kubernetes version?

@pull-request-size pull-request-size Bot added the size/XXL 1000+ lines label Sep 23, 2025
Comment thread e2e-tests/init-deploy/test_init_deploy.py Outdated
Comment thread e2e-tests/init-deploy/test_init_deploy.py Outdated
Comment thread e2e-tests/tools.py Outdated
Comment thread e2e-tests/lib/tools.py Outdated
Comment thread e2e-tests/lib/tools.py Outdated

# TODO: consider using Python for filtering instead of yq
yq_filter = f"""
del(.metadata.ownerReferences[].apiVersion) |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This would be nice in a separated file perhaps

Comment thread e2e-tests/conftest.py
Comment thread e2e-tests/conftest.py Outdated


@pytest.fixture(scope="class")
def deploy_chaos_mesh(namespace):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we could have separate file for helm installed dependencies and use a generic function with parameters to install a helm chart since subprocess is going to be used fot it

@egegunes egegunes added this to the v1.22.0 milestone Dec 15, 2025
Comment thread e2e-tests/tools.py Outdated
Comment on lines +26 to +36
def kubectl_bin(*args, check: bool = True, input_data: str = "") -> str:
"""Execute kubectl command"""
cmd = ["kubectl"] + list(args)
logger.debug(" ".join(map(str, cmd)))
result = subprocess.run(cmd, check=check, capture_output=True, text=True, input=input_data)

if result.stderr:
logger.warning(f"kubectl error: {result.stderr}")
return result.stderr

return result.stdout

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it would be nice to add a -n <current-namespace> option and stop changing the kubectl context. This would match the approach used in kuttl tests and would let us run multiple tests in parallel on the same cluster. I don’t think it would cause any problems.

Comment thread e2e-tests/conftest.py Outdated
os.environ.setdefault("DELETE_CRD_ON_START", "1")
os.environ.setdefault("SKIP_DELETE", "0")
os.environ.setdefault("SKIP_BACKUPS_TO_AWS_GCP_AZURE", "1")
os.environ.setdefault("UPDATE_COMPARE_FILES", "0")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

UPDATE_COMPARE_FILES isn't implemented in this PR

Comment thread e2e-tests/lib/tools.py Outdated

if result.stderr:
logger.warning(f"kubectl error: {result.stderr}")
return result.stderr

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
return result.stderr

If we have stderr and result.returncode is 0, I think we should still return stdout

Comment thread e2e-tests/tools.py Outdated
Comment thread e2e-tests/functions
create_infra() {
local ns="$1"

echo "$ns" > /tmp/pytest_current_namespace

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[shfmt] reported by reviewdog 🐶

Suggested change
echo "$ns" > /tmp/pytest_current_namespace
echo "$ns" >/tmp/pytest_current_namespace

@egegunes egegunes modified the milestones: v1.22.0, v1.23.0 Mar 6, 2026
@jvpasinatto jvpasinatto marked this pull request as ready for review May 5, 2026 13:26
Comment thread .github/workflows/e2e-py-check.yml Fixed
Copilot AI review requested due to automatic review settings June 4, 2026 12:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR lays the initial foundation for migrating the existing e2e-tests suite to pytest by introducing a Python test harness (fixtures + helper library), converting several tests to pytest, and updating CI (Jenkins + GitHub Actions) to run checks and publish pytest-style reports.

Changes:

  • Add Python project + locked dependencies via uv (pyproject.toml, uv.lock) and Makefile targets to manage them.
  • Introduce pytest infrastructure (e2e-tests/conftest.py, e2e-tests/lib/*) and migrate init-deploy, finalizer, and liveness tests to pytest.
  • Update Jenkins to execute tests via pytest (including a wrapper for legacy bash tests) and generate/merge HTML + JUnit reports; add a GitHub Action for ruff/mypy.

Reviewed changes

Copilot reviewed 28 out of 30 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
uv.lock Adds a locked Python dependency set for the pytest migration.
pyproject.toml Defines the Python test project, deps, and tool configs (pytest/mypy/ruff).
Makefile Adds uv installation plus Python deps/format/check targets.
Jenkinsfile Runs tests via pytest, generates per-test reports, merges/publishes final report.
e2e-tests/test_pytest_wrapper.py Pytest wrapper entrypoint to run legacy bash tests under pytest.
e2e-tests/README.md Documents uv setup and pytest usage for e2e tests.
e2e-tests/liveness/test_liveness.py Migrates liveness test to pytest.
e2e-tests/lib/utils.py Adds shared utilities (retry, git helpers, rich logging theme/highlighter).
e2e-tests/lib/secrets.py Adds helpers for reading/applying secrets and cloud credential handling.
e2e-tests/lib/report_generator.py Adds pytest-html customizations and report extras generator.
e2e-tests/lib/operator.py Adds Python operator deploy / CRD finalizer handling helpers.
e2e-tests/lib/mongo.py Adds MongoDB helpers for mongosh execution and JSON comparisons.
e2e-tests/lib/kubectl.py Adds kubectl execution + common wait/detect helpers.
e2e-tests/lib/k8s_collector.py Adds K8s resource/log collection for failure diagnostics.
e2e-tests/lib/config.py Adds cluster apply + kubectl compare (via yq filtering) helpers.
e2e-tests/lib/bash_wrapper.py Runs legacy run bash scripts with live output under pytest.
e2e-tests/lib/__init__.py Marks lib as a Python package for imports/plugins.
e2e-tests/init-deploy/test_init_deploy.py Migrates init-deploy scenario to pytest.
e2e-tests/init-deploy/conf/another-name-rs0.yml Adjusts replset termination grace period used by migrated test.
e2e-tests/init-deploy/compare/statefulset_another-name-rs0.yml Updates expected manifest to match grace period change.
e2e-tests/init-deploy/compare/statefulset_another-name-rs0-oc.yml Same as above for OpenShift expected manifest.
e2e-tests/init-deploy/compare/statefulset_another-name-rs0-4-oc.yml Same as above for OpenShift expected manifest variant.
e2e-tests/init-deploy/compare/find-1.json Adds expected JSON output for migrated init-deploy checks.
e2e-tests/init-deploy/compare/find-2.json Adds expected JSON output for migrated init-deploy checks.
e2e-tests/init-deploy/compare/find-3.json Adds expected JSON output for migrated init-deploy checks.
e2e-tests/functions Adds namespace marker for pytest failure diagnostics (legacy bash tests).
e2e-tests/finalizer/test_finalizer.py Migrates finalizer test to pytest.
e2e-tests/conftest.py Adds pytest fixtures + env setup + failure report enrichment.
.gitignore Ignores pytest reports and Python __pycache__.
.github/workflows/e2e-py-check.yml Adds ruff + mypy checks for Python e2e code on PRs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +3 to +7
on:
pull_request:
paths:
- 'e2e-tests/**/*.py'

Comment thread Jenkinsfile
Comment on lines +291 to +295
export DEBUG_TESTS=1
export KUBECONFIG=/tmp/${CLUSTER_NAME}-${clusterSuffix}
export PATH="\$HOME/.local/bin:\$PATH"
mkdir -p e2e-tests/reports

Comment thread e2e-tests/functions
Comment on lines 1886 to +1889
local ns="$1"

echo "$ns" > /tmp/pytest_current_namespace

Comment thread e2e-tests/conftest.py
Comment on lines +83 to +88
"""Get namespace from global or temp file (for bash wrapper tests)."""
if _current_namespace:
return _current_namespace
try:
with open("/tmp/pytest_current_namespace") as f:
return f.read().strip() or None
Comment on lines +1 to +3
import os
import re
from typing import Any, List, MutableSequence
Comment on lines +93 to +98
def highlight_log_levels(logs: str) -> str:
"""Add basic color highlighting for common log levels"""
return LOG_LEVEL_PATTERN.sub(
lambda m: f'<span style="color: {LOG_LEVEL_COLORS[m.group(1)]};">{m.group(1)}</span>',
logs,
)
Comment on lines +136 to +139
create_collapsible_section("Operator Pod Logs", highlight_log_levels(summary["logs"]))
),
extras.html(create_collapsible_section("Kubernetes Resources", summary["resources"])),
extras.html(
Comment on lines +41 to +45
for i, var in enumerate(ENV_VARS_TO_REPORT):
value = os.environ.get(var, "")
escaped_value = value.replace("<", "&lt;").replace(">", "&gt;")
bg = "#f9f9f9" if i % 2 == 0 else "#ffffff"
rows += f'<tr style="background-color: {bg};"><td style="border: 1px solid #ddd; padding: 6px;"><code>{var}</code></td><td style="border: 1px solid #ddd; padding: 6px;"><code>{escaped_value}</code></td></tr>\n'
Comment thread e2e-tests/lib/mongo.py
Comment on lines +30 to +46
replica_set = "cfg" if "cfg" in uri else "rs0"
connection_string = f"{driver}://{uri}{suffix}/admin?ssl=false&replicaSet={replica_set}"
if mongo_flag:
connection_string += f" {mongo_flag}"

result = kubectl_bin(
"exec",
self.client,
"--",
"timeout",
str(timeout),
"mongosh",
f"{connection_string}",
"--eval",
command,
"--quiet",
check=False,
@egegunes egegunes removed this from the v1.23.0 milestone Jun 9, 2026
@JNKPercona

Copy link
Copy Markdown
Collaborator
Test Name Result Time
arbiter passed 00:10:16
balancer passed 00:17:24
cross-site-sharded passed 00:16:51
custom-replset-name passed 00:09:15
custom-tls passed 00:13:19
custom-users-roles passed 00:09:26
custom-users-roles-sharded passed 00:10:58
data-at-rest-encryption passed 00:11:47
data-sharded passed 00:22:29
demand-backup passed 00:15:48
demand-backup-eks-credentials-irsa passed 00:00:10
demand-backup-fs passed 00:22:01
demand-backup-if-unhealthy passed 00:06:56
demand-backup-incremental-aws passed 00:10:46
demand-backup-incremental-azure passed 00:10:47
demand-backup-incremental-gcp-native failure 00:07:08
demand-backup-incremental-gcp-s3 failure 00:06:29
demand-backup-incremental-minio passed 00:27:03
demand-backup-incremental-sharded-aws passed 00:18:41
demand-backup-incremental-sharded-azure failure 01:30:18
demand-backup-incremental-sharded-gcp-native passed 00:16:54
demand-backup-incremental-sharded-gcp-s3 passed 01:29:28
demand-backup-incremental-sharded-minio passed 00:26:51
demand-backup-logical-minio-native-tls passed 00:08:13
demand-backup-physical-parallel passed 00:07:42
demand-backup-physical-aws passed 00:11:32
demand-backup-physical-azure failure 01:25:56
demand-backup-physical-gcp-s3 passed 00:11:32
demand-backup-physical-gcp-native passed 00:11:32
demand-backup-physical-minio passed 01:21:44
demand-backup-physical-minio-native passed 01:20:12
demand-backup-physical-minio-native-tls passed 00:20:14
demand-backup-physical-sharded-parallel failure 01:18:07
demand-backup-physical-sharded-aws failure 01:17:52
demand-backup-physical-sharded-azure passed 01:14:55
demand-backup-physical-sharded-gcp-native passed 00:18:56
demand-backup-physical-sharded-minio passed 01:12:35
demand-backup-physical-sharded-minio-native passed 01:12:34
demand-backup-sharded failure 01:10:24
demand-backup-snapshot failure 01:04:47
demand-backup-snapshot-vault failure 01:02:30
disabled-auth failure 00:59:41
expose-sharded failure 00:53:32
finalizer passed 00:07:12
ignore-labels-annotations failure 01:30:17
init-deploy failure 01:30:17
ldap passed 00:08:12
ldap-tls passed 00:12:02
limits passed 00:06:40
liveness failure 01:30:11
mongod-major-upgrade passed 00:13:03
mongod-major-upgrade-sharded passed 00:20:43
monitoring-2-0 passed 00:24:45
monitoring-pmm3 passed 00:28:20
multi-cluster-service failure 01:30:08
multi-storage failure 01:30:14
non-voting-and-hidden failure 01:30:04
one-pod passed 00:07:58
operator-self-healing-chaos failure 01:23:09
pitr passed 00:32:42
pitr-physical failure 01:18:16
pitr-sharded passed 00:21:13
pitr-to-new-cluster passed 00:24:37
pitr-physical-backup-source passed 00:56:30
preinit-updates failure 01:05:29
pvc-auto-resize failure 01:01:53
pvc-resize passed 00:15:50
recover-no-primary failure 00:50:45
replset-overrides passed 00:20:14
replset-remapping passed 00:16:40
replset-remapping-sharded failure 00:28:59
rs-shard-migration failure 00:23:19
scaling passed 00:10:21
scheduled-backup failure 00:02:33
security-context failure 00:44:29
self-healing-chaos passed 00:15:07
service-per-pod passed 00:18:55
serviceless-external-nodes passed 00:44:32
smart-update failure 00:44:29
split-horizon passed 00:13:51
split-horizon-manual-tls passed 00:12:47
stable-resource-version failure 00:44:13
storage passed 00:07:26
tls-issue-cert-manager passed 00:29:10
unsafe-psa failure 00:36:51
upgrade passed 00:09:16
upgrade-consistency failure 00:30:26
upgrade-consistency-sharded-tls failure 00:29:10
upgrade-sharded passed 00:18:41
upgrade-partial-backup passed 00:15:09
users failure 00:15:06
users-vault failure 00:06:54
version-service failure 00:06:39
Summary Value
Tests Run 93/93
Job Duration 04:15:24
Total Test Time 53:22:07

Commit: fb8cc71
Image: perconalab/percona-server-mongodb-operator:PR-2058-fb8cc7187
Test report: report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants