Skip to content

rptest: add skip_in_cdt opt-out for CDT runs#30975

Draft
oleiman wants to merge 1 commit into
devfrom
ci/noticket/opt-out-cdt
Draft

rptest: add skip_in_cdt opt-out for CDT runs#30975
oleiman wants to merge 1 commit into
devfrom
ci/noticket/opt-out-cdt

Conversation

@oleiman

@oleiman oleiman commented Jun 30, 2026

Copy link
Copy Markdown
Member

CDT runs every ducktape test on real cloud infrastructure, and a whole-run timeout fails the entire run. Some tests (e.g. exhaustive broker HTTP-API tests) add runtime there without adding cloud-infra coverage.

skip_in_cdt opts out a test method or a whole class; skip_file_in_cdt opts out every test class in a module. All are gated on CLOUD_PROVIDER != "docker", so they no-op locally and in dockerized CI and the default behavior is unchanged. In CDT they attach ducktape's ignore mark, so opted-out tests report as IGNORE rather than vanishing from the run.

reason is documentation only; it is never passed to ducktape's ignore, which would otherwise treat it as a parametrization matcher and silently un-skip the test.

Accounting

Backports Required

  • none - not a bug fix
  • none - this is a backport
  • none - issue does not exist in previous branches
  • none - papercut/not impactful enough to backport
  • v26.1.x
  • v25.3.x
  • v25.2.x

Release Notes

  • none

@oleiman oleiman self-assigned this Jun 30, 2026
@oleiman oleiman requested a review from Copilot June 30, 2026 22:23
@oleiman oleiman added the claude-review Adding this label to a PR will trigger a workflow to review the code using claude. label Jun 30, 2026

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

Adds an opt-out mechanism for ducktape tests to be skipped specifically in CDT (real cloud) runs, keeping local/docker CI behavior unchanged while still reporting skipped tests as IGNORE in CDT.

Changes:

  • Introduces in_cdt(), skip_in_cdt (method/class decorator), and skip_file_in_cdt (module-level helper) in mode_checks.py.
  • Adds unit tests validating method-, class-, and file-scope skipping behavior and ensuring reason is not forwarded to ducktape’s ignore.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
tests/rptest/utils/mode_checks.py Adds CDT detection and skip helpers that apply ducktape IGNORE marks only when running in real-cloud CDT.
tests/rptest/utils/skip_in_cdt_test.py Adds unit tests for method/class/file scope CDT skipping and verifies ignore mark semantics.

Comment on lines +192 to +194
if in_cdt():
# ignore(method) attaches IgnoreAll (ignores all parametrizations) in place.
ignore(method)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In-place mutation is ducktape's mark contract (Mark.mark writes to fun.__dict__, same as @cluster/@matrix), so the mark reliably lands on method itself. The method path returns target to keep the type-preserving @overload/TypeVar signature -- capturing ignore()'s loosely-typed return reintroduces strict-pyright errors. I did remove the asymmetry you flagged: both method- and class-scope now go through a shared _mark_own_cdt_tests helper, so neither relies on the return.

@oleiman oleiman added claude-review Adding this label to a PR will trigger a workflow to review the code using claude. and removed claude-review Adding this label to a PR will trigger a workflow to review the code using claude. labels Jun 30, 2026
@claude

claude Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review

Nice, focused utility — gating everything on CLOUD_PROVIDER != "docker" so it no-ops locally and in dockerized CI is the right call, and using ducktape's ignore (so opted-out tests report as IGNORE rather than vanishing) is a good design choice. The unit test coverage for method/class/file scope, plus the regression guard that reason is not forwarded to ignore, is solid.

Main concern: class/file scope misses inherited test methods

_skip_class_in_cdt iterates vars(cls), which only contains attributes defined directly on the class. A very common rptest pattern is a base class that defines the tests and thin subclasses that only parametrize (e.g. TLSVersionTestBaseTLSVersionTestRSA/TLSVersionTestECDSA in tls_version_test.py). Applying @skip_in_cdt to such a subclass marks nothing, so the test still runs in CDT — the exact failure this PR aims to prevent, and silent (no error). skip_file_in_cdt shares the gap when the base class is imported from another module. Details and a suggested fix (walk the MRO) are in the inline comment.

Minor notes

  • In-place-mutation reliance: _skip_method_in_cdt calls ignore(method) and discards the return value, relying on ignore mutating in place, while _skip_class_in_cdt uses setattr(..., ignore(member)). Both work given ducktape's ignore both mutates and returns the same object, but the two helpers are inconsistent — worth aligning for clarity.
  • reason is invisible at runtime: it's stored on the target but never logged, so a CDT IGNORE report won't show why a test was skipped. Not blocking, but a short vlog/print at decoration time (or surfacing it in the ignore output) would aid triage. The PR body already explains why it can't be passed to ignore directly — good.
  • Per CLAUDE.md, run tools/type-checking/type-check.sh check utils/mode_checks.py utils/skip_in_cdt_test.py on the changed files before merge.

Overall the approach is sound; the inherited-test-method gap is the one item I'd want addressed (or at least loudly documented) before this lands, since it can silently fail to skip.

Comment thread tests/rptest/utils/mode_checks.py Outdated
setattr(cls, "_skip_in_cdt_reason", reason)
if not in_cdt():
return
for name, member in list(vars(cls).items()):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

vars(cls) only returns attributes defined directly on cls; inherited test methods are not included. This silently breaks a common rptest pattern where a base class defines the tests and thin subclasses only parametrize:

class TLSVersionTestBase(RedpandaTest):
    @cluster(num_nodes=3)
    def test_ciphersuite_support(self): ...

@skip_in_cdt(reason="...")
class TLSVersionTestRSA(TLSVersionTestBase):  # no own test methods
    ...

Here vars(TLSVersionTestRSA) contains no test methods, so the decorator marks nothing and the test still runs in CDT — exactly the failure mode this PR is trying to prevent, with no error to signal it.

skip_file_in_cdt has the same gap whenever the base class lives in a different module (the __module__ filter excludes it, and the subclass's vars() is empty). It happens to work only when the base is defined in the same file, because the mark lands on the shared function object.

Consider walking the MRO (e.g. iterate over dir(cls) / inspect.getmembers, or cls.__mro__) so inherited test methods are also covered. Note the symmetric over-skip risk if you mark a shared base function: it would ignore that test for all subclasses. At minimum, document this limitation prominently in the docstring.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch -- the silent no-op was the real hazard. Since ducktape marks are function-scoped, walking the MRO to mark inherited methods would trade under-skip for over-skip (it would skip the shared base test for every subclass). So class-scope now raises when a class's tests are inherited, pointing to method- or base-scope. skip_file_in_cdt stays lenient: it marks tests defined in the module, so a same-module base still covers its subclasses via the shared function object; the cross-module case is documented. Added tests for both the raise and the same-module coverage.

CDT runs every ducktape test on real cloud infrastructure, and a
whole-run timeout fails the entire run. Some tests (e.g. exhaustive
broker HTTP-API tests) add runtime there without adding cloud-infra
coverage.

skip_in_cdt opts out a test method or a whole class; skip_file_in_cdt
opts out every test class in a module. All are gated on
CLOUD_PROVIDER != "docker", so they no-op locally and in dockerized CI
and the default behavior is unchanged. In CDT they attach ducktape's
ignore mark, so opted-out tests report as IGNORE rather than vanishing
from the run.

reason is documentation only; it is never passed to ducktape's ignore,
which would otherwise treat it as a parametrization matcher and
silently un-skip the test.
@oleiman oleiman force-pushed the ci/noticket/opt-out-cdt branch from c2a250c to d99bbc5 Compare July 1, 2026 06:35
@oleiman

oleiman commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

/cdt
rp_version=build
tests/rptest/tests/schema_registry_test.py

@oleiman

oleiman commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

/cdt
tests/rptest/tests/audit_log_test.py
tests/rptest/tests/acls_test.py
tests/rptest/tests/scram_test.py
tests/rptest/tests/enterprise_features_license_test.py
tests/rptest/tests/redpanda_oauth_test.py
tests/rptest/tests/pandaproxy_test.py
tests/rptest/tests/data_transforms_test.py
tests/rptest/tests/gbac_claim_test.py
tests/rptest/tests/cluster_features_test.py
tests/rptest/tests/rbac_test.py
tests/rptest/tests/log_compaction_test.py
tests/rptest/tests/security_report_test.py
tests/rptest/tests/maintenance_test.py
tests/rptest/tests/leadership_transfer_test.py

@oleiman

oleiman commented Jul 1, 2026

Copy link
Copy Markdown
Member Author

/cdt
tests/rptest/tests/schema_registry_test.py

@oleiman oleiman force-pushed the ci/noticket/opt-out-cdt branch from 2379a47 to d99bbc5 Compare July 2, 2026 02:24
@oleiman

oleiman commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

/cdt
tests/rptest/tests/acls_test.py
tests/rptest/tests/audit_log_test.py
tests/rptest/tests/cluster_features_test.py
tests/rptest/tests/enterprise_features_license_test.py
tests/rptest/tests/gbac_claim_test.py
tests/rptest/tests/leadership_transfer_test.py
tests/rptest/tests/maintenance_test.py
tests/rptest/tests/pandaproxy_test.py
tests/rptest/tests/rbac_test.py
tests/rptest/tests/redpanda_oauth_test.py
tests/rptest/tests/schema_registry_test.py
tests/rptest/tests/scram_test.py
tests/rptest/tests/security_report_test.py

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

Labels

claude-review Adding this label to a PR will trigger a workflow to review the code using claude.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants