Repository navigation
feat(standard-tests): fail on an empty test-scenario set unless acceptance-test-config.yml declares a bypass_reason - #1228
Conversation
…tance-test-config.yml declares a bypass_reason An acceptance-test-config.yml that yielded no runnable config made pytest skip every scenario test as an empty parameter set, and the run passed. A connector whose configs were never collected, whose file was missing, or whose layout the reader did not understand looked the same as a tested one. Collection now fails when no scenario can run and no bypass_reason says why. A bypass is accepted at the top level of the file (the whole connector, and the opt-out for a connector without test configs), on a section, or on an entry without config_path. Bypasses are reported as skipped tests carrying the declared reason, grouped by reason, plus one line after collection. The reader also: - parses legacy list-format sections as the section's tests list; - fails with a migration message on a legacy top-level `tests:` key; - treats a missing file as an error for Python and manifest-only connectors, and as a bypass for Java connectors; - wraps invalid entries in an error that names the entry and field but never prints the offending values. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
👋 Greetings, Airbyte Team Member!Here are some helpful tips and reminders for your convenience. 💡 Show Tips and TricksTesting This CDK VersionYou can test this version of the CDK using the following: # Run the CLI from this branch:
uvx 'git+https://github.com/airbytehq/airbyte-python-cdk.git@tolik0/cdk/empty-scenarios-fail#egg=airbyte-python-cdk[dev]' --help
# Update a connector to use the CDK from this branch ref:
cd airbyte-integrations/connectors/source-example
poe use-cdk-branch tolik0/cdk/empty-scenarios-failPR Slash CommandsAirbyte Maintainers can execute the following slash commands on your PR:
|
PyTest Results (Fast)5 948 tests +110 5 917 ✅ +110 6m 25s ⏱️ - 1m 44s Results for commit 2e8cc3b. ± Comparison against base commit 8b721cd. This pull request removes 2 and adds 112 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
PyTest Results (Full)5 951 tests +110 5 920 ✅ +110 11m 27s ⏱️ - 5m 14s Results for commit 2e8cc3b. ± Comparison against base commit 8b721cd. This pull request removes 2 and adds 112 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
Resolve the conflicts with #1226, which checks every acceptance-test-config.yml entry for keys the standard tests do not read: - Move that check from `get_scenarios()` into `collect_scenarios()`, so the entries of legacy list sections are checked too. Invalid values are collected the same way, and both raise one `AcceptanceTestConfigError` listing every problem in #1226's format, which pytest reports without a traceback. - Drop `bypass_reason` from `AWAITING_READER`: this change reads it. - cdk-migrations.md: #1226's section ships as 7.39.0 and is renamed; this change's section drops the invalid-entry row, which 7.39.0 already covers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Daryna Ishchenko (darynaishchenko)
left a comment
There was a problem hiding this comment.
Requesting changes for the release ordering only. The code itself looks sound to me.
Done well:
- the bypass model (top-level, per section, per entry) and the "top-level bypass next to runnable configs" guard;
- failure messages that name keys and sections, never values;
- the
cdk-migrations.mdsection; - strong tests: 18 of 24 deliberate mutations are caught.
Rollout: this is breaking for connector test suites (not syncs) and ships as a minor, which is fine only if airbytehq/airbyte#88931 and #88932 merge first (inline comment on pytest_hooks.py). I independently verified that the files in both fleet PRs load and collect correctly under this branch and under the released CLI.
Not inline (low, for later): YAML parse errors echo the offending source line; a bypass_reason on a runnable entry is silently dropped; AcceptanceTestConfigError and ScenarioBypass are importable only from a private module; the PR body's fleet counts are stale.
…_scenarios; tighten tests
…e-test-config.yml Since #1228, get_scenarios() raises MissingAcceptanceTestConfigError when a connector has no acceptance-test-config.yml, so the tmp connector of the test_fail_read_with_invalid_config tests needs one. The suite helper now writes a file with one basic_read config unless the test wrote its own.
What
Implements P0.3 of the CAT → FAST coverage epic (airbytehq/airbyte-internal-issues#17131, under airbytehq/airbyte-internal-issues#17129): an empty test-scenario set must fail, not silently skip.
Until now,
pytest_generate_testsparametrizedscenariowith whateverget_scenarios()returned. An empty list made pytest skip every scenario test asgot empty parameter setand the run passed. A connector whose configs were never collected, whose file was missing, or whose layout the reader did not understand looked the same as a tested one.How
Zero scenarios is an error. When no scenario can run and no
bypass_reasonexplains why, collection fails with one message that names the file and says why each section and entry produced nothing (e.g.`acceptance_tests.spec.tests[0]`: no `config_path` and no `bypass_reason` (keys: `spec_path`)), followed by the fix. The error is raised withpytrace=Falseoutside theexceptblock, so it prints once, without a traceback.Explicit, machine-readable bypass. A
bypass_reasoncounts in three places:connection: {bypass_reason: ...}), the layout CAT used and that ~285 connectors have today. It is ignored when the section lists a runnable config, as before.config_path. An entry with aconfig_pathalways runs.Only the collected sections count (
spec,connection,discovery,basic_read,full_refresh). Anincrementalbypass or an IAM-role config does not make a connector "bypassed".Bypasses are visible. Each scenario test gets one extra skipped param per distinct reason (
[bypassed-connection-discovery-basic_read-full_refresh],[bypassed-connector]) whose skip message isacceptance-test-config.yml bypasses <scope>: <reason>, and collection prints one line per connector, e.g.source-hibob: acceptance-test-config.yml declares 1 bypass(es), reported as skipped tests: the connector: No test config in GSM for this connector. The reasons land in the JUnit XML.Legacy list-format sections (
connection: [...]) are read as the section'stestslist, throughsection_entries(), which the spec backward-compatibility waiver reader from feat(standard-tests): check spec backward compatibility against the published version #1220 now shares.Legacy top-level
tests:fails with one message naming the file and the migration (rename toacceptance_tests:, nest entries undertests). Converting those 34 connectors is airbytehq/airbyte-internal-issues#16264.A missing file is an error for Python and manifest-only connectors. Java connectors (
language:javainmetadata.yaml) are reported as bypassed, since their Gradle suites test them.Suites with their own scenarios. A suite that overrides
get_scenarios()supplies its scenarios in code, so itsacceptance-test-config.ymlis not read for bypasses: a missing file, a legacy layout or a top-levelbypass_reasonchanges nothing. If the override returns no scenario, collection fails with<Suite>.get_scenarios() returned no test scenarios.No values in failure messages. An entry the scenario model rejects (e.g.
empty_streamsas plain strings) is reported by location, field and rule; pydantic's input values are not printed.Changes
airbyte_cdk/test/standard_tests/_acceptance_test_config.py(new, private): loading, layout errors, scenario and bypass collection, and the empty-set message.docker_base.py:acceptance_test_configandget_scenarios()use it. Newget_scenario_bypasses()anddescribe_empty_scenarios(), which skip the file when a subclass overridesget_scenarios().get_scenarios()raisesMissingAcceptanceTestConfigError(aFileNotFoundError) orAcceptanceTestConfigError(aValueError) instead of warning, so existingexcept FileNotFoundError/except ValueErrorcallers keep working.pytest_hooks.py: the failure, the bypass params and the collection line (pytest_report_collectionfinish).scenario.py: one field,ConnectorTestScenario.bypass_reason, holding the reason on the placeholder scenario of a skipped bypass test. Kept minimal on purpose (see Rollout)._spec_compatibility.py: reads thespecsection through the sharedsection_entries().cdk-migrations.md: new## Upgrading to the next minor release (unreleased)section with a before/now table, the three bypass forms and the migration steps.Fleet impact
Classifier over the 594 non-archived Python and manifest-only connectors on airbyte master (
fd347841abe, re-run 2026-10-27; first run on1e22e3c), and over master plus both fleet PRs:acceptance-test-config.ymlUserWarning, silently skippedtests:The first run also found one invalid entry (
expect_recordswithoutpath); the P1.5 cleanup removed it from master.Certified connectors newly declaring a bypass: destination-pinecone (GSM holds a config no entry lists) and source-granola (no GSM config).
The connectors kept in the private enterprise repository, whose CI runs the same standard tests, are not affected: the same classifier finds every Python and manifest-only connector there runnable.
Rollout
Release gate. This PR stays in draft until all of these are done:
bypass_reasonnow fail collection, linking thecdk-migrations.mdsectionIf the fleet PRs cannot land before the next release, split this PR: ship the bypass reading and reporting first, and make the empty set a failure one release later.
specfailures, a revoked GSM credential, a broken build), so it needs those fixed first or a merge with the failures noted. All are safe on the released CDK: the 37 connectors touched at the time collected with exit 0 underairbyte-cdk[dev]7.36.0, and on 2026-10-27 the 35 connectors of #88931 and the follow-up collect with exit 0 under 7.39.1, the release CI installs today. PR A's new files carryacceptance_tests: {}next to thebypass_reasonbecause 7.36.0 rejects a file withoutacceptance_tests. Neither PR bumps a version (CheckVersionIncrementskips: onlyacceptance-test-config.ymlchanged).feat, no!), with the migration note under the shared "next minor release (unreleased)" heading.mainthe same day:scenario.py,docker_base.pyandcdk-migrations.mdare resolved (feat(standard-tests): remove the ignored scenario fields and reject acceptance-test-config keys that are not read #1226's notes now sit under## Upgrading to 7.39.0), andbypass_reasonis dropped fromAWAITING_READERintest_scenario_keys.py, since this PR reads it. The branch still merges cleanly withmain.acceptance-test-config.ymlto feat(standard-tests): check primary keys, state messages and error traces in read tests, and report stream statuses #1230's tmp fixture, because a missing file is now an error.honor acceptance-test bypass_reason for basic_read) overlaps the bypass handling and can be closed in favor of this one.Follow-ups
Left for later, from review:
Test plan
unit_tests/test/test_empty_scenarios.py(45 tests,pytesterruns of the real hooks): every bypass form and its scope; the empty-set message; section bypass ignored next to runnable entries; blank and non-string reasons; top-level bypass with and without runnable entries; legacy list sections; legacy top-leveltests:; unusable layouts; missing file for Python, manifest-only and Java; collection failures print once, without a traceback or chained exception; skipped bypass params, ids and grouping; validation errors without values; a suite overridingget_scenarios()runs its own scenarios with no file, a legacy file or a top-level bypass, and fails when it returns none; the suitecreate_connector_test_suite(connector_directory=...)builds forairbyte-cdk connector testskips a bypass-only file and fails collection on a zero-scenario file. The no-traceback checks assert that nopytest_hooks.py:frame is printed; switching eitherpytrace=FalsetoTrue, or dropping the override check, fails tests.poetry run pytest unit_tests/test: 870 passed, 9 skipped (2026-10-28, head2e8cc3bf). Earlier, withunit_tests/resources: 834 passed, 20 skipped. The skip count depends on the registry: pokeapi's spec backward-compatibility test skips while the registry publishes a newer version than its fixture.poe lintandruff format --checkclean;poe type-checkreports no error in the changed files (the 51 existing errors are unchanged against main); Prettier clean on the new migration section.CLI proofs with this branch's
airbyte-cdk, on copies of monorepo connectors with GSM secrets fetched byairbyte-cdk secrets fetch:connector testexit 0, 9 passed, 3 skippedtests:connector testexit 0 (5 passed, 16 skipped);image testexit 0image testexit 0, 4 passed (discover kept)image testexit 0, 3 passedClassifier: master has 10 + 25 connectors to fix; master plus #88931, #88932 and the follow-up has 0 and 0; without the follow-up, 0 and 10 (re-run 2026-10-27 on
fd347841abe; the 10th no-bypass connector is source-github-g2, added to master on 2026-10-20 and now covered by PR A).🤖 Generated with Claude Code