Scope spec retries to transient failures, enable random ordering, tier timeouts (#382)#415
Conversation
New offline-capable specs (no CPLN_ORG, no cpln binary, no HTTP): - spec/core/shell_spec.rb for lib/core/shell.rb - spec/core/controlplane_api_spec.rb for lib/core/controlplane_api.rb - spec/command/update_github_actions_spec.rb for lib/command/update_github_actions.rb - spec/core/doctor_service_spec.rb for lib/core/doctor_service.rb - spec/core/helpers_spec.rb for lib/core/helpers.rb - spec/command/test_spec.rb for lib/command/test.rb - spec/command/staging_branch_validation_spec.rb for lib/command/staging_branch_validation.rb - spec/core/github_flow_readiness/checks_spec.rb for lib/core/github_flow_readiness/checks.rb Also adds the new specs to the documented offline smoke suite in spec/README.md. The ninth file listed in issue #379, lib/command/terraform/import.rb, already has an offline spec (spec/command/terraform/import_spec.rb); the issue's audit missed it, so no new spec is added for it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…r timeouts (#382) Behavior changes in spec/spec_helper.rb: - Retries are now scoped via rspec-retry's exceptions_to_retry (supported by the pinned rspec-retry 0.6.2; verified in the gem source). Only transient failures retry: socket-level errors (Errno::ECONNREFUSED, ECONNRESET, EHOSTUNREACH, ENETUNREACH, EPIPE, ETIMEDOUT, EOFError, SocketError, OpenSSL::SSL::SSLError), Timeout::Error (covers Net::OpenTimeout/ReadTimeout raised inside example code), and a TransientServerHTTPError matcher for the bare RuntimeError that ControlplaneApiDirect#call raises on 5xx/429 responses (all named Net::HTTP 5xx classes plus the Net::HTTPServerError fallback and TooManyRequests). Assertion failures and other deterministic errors now fail on the first attempt everywhere, including live runs. - Example-level hangs cut off by the per-example timeout are NOT retried: timeout >= 0.2 interrupts the example thread with Timeout::ExitException (an Exception, not a Timeout::Error), which rspec-core records as the example's exception, so a hung example fails fast on the first attempt instead of tripling the stall. - RSPEC_RETRY_COUNT is normalized with Integer(ENV.fetch(...)). rspec-retry already clamps .to_i values to a minimum of one attempt (0 and 1 both mean single attempt, before and after this change); the normalization makes empty or garbage values raise ArgumentError at load time instead of silently degrading to a single attempt. - Random ordering is now active config (config.order = :random plus Kernel.srand config.seed) instead of commented-out boilerplate. RSpec prints "Randomized with seed N" so CI logs carry the seed. - The per-example timeout is tiered: 600s when CPLN_ORG is configured (live runs, where untagged image-build/deploy specs can legitimately take minutes) or when the example is tagged :slow; 60s otherwise (offline/unit runs, which complete in under a second). Validation (offline suite from spec/README.md, 195 examples): - Seeds 101, 1, 7777, 31337, 999983, 24601, 86753: all green, 195 examples, 0 failures. - RSPEC_RETRY_COUNT=0 with seed 555: green, confirming normalization and no retry dependence. - Throwaway probe spec confirmed assertion failures and plain RuntimeErrors get exactly 1 attempt while Errno::ECONNRESET and the 5xx RuntimeError matcher retry ("RSpec::Retry: 2nd try"); probe deleted after the experiment. - Timeout::ExitException semantics verified empirically (inner rescue of Exception records ExitException; Timeout.timeout returns normally). - No ordering-dependent failures surfaced; no other spec files changed. - rubocop on spec/spec_helper.rb: no offenses. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR makes RSpec execution faster to diagnose and more selective about retries. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (1): Last reviewed commit: "Scope spec retries to transient failures..." | Re-trigger Greptile |
|
Review: Scope spec retries to transient failures, enable random ordering, tier timeouts (#382) Single-file change to Overview
Correctness
Minor / nit
Risks already called out by the author (agree, non-blocking)
Security Overall: solid, well-reasoned change with good test coverage of the retry-scoping behavior and thorough self-review already baked into the PR description. No blocking issues found. |
Closes #382.
Single-file change to
spec/spec_helper.rb(stacked on #414; retargets tomainwhen it merges):exceptions_to_retry: network/socket/SSL errors,Timeout::Error(coversNet::OpenTimeout/ReadTimeout), and a custom matcher for the bareRuntimeErrorthatControlplaneApiDirect#callraises on 5xx/429 (all 5xx classes 500–511 + theNet::HTTPServerErrorfallback for unregistered codes). Assertion/deterministic failures now fail on the first attempt everywhere — including live runs.RSPEC_RETRY_COUNTnormalized withInteger(ENV.fetch("RSPEC_RETRY_COUNT", "3"))— empty/garbage values fail at load instead of silently degrading.config.order = :random+Kernel.srand config.seed; RSpec printsRandomized with seed Nin every run (CI logs carry the repro seed natively).:slow; 60s for offline/unit runs. Live untagged specs keep their full original budget — this cannot tighten live CI.Codex Decision Log
:integrationtag exists (the Test suite cannot load without CPLN_ORG — even pure unit specs require live-org configuration #373 taxonomy is live-vs-offline +:slow), so metadata-scoped retries would need path lists.exception.is_a?(klass) || klass === exception) and empirically (assertion failure: 1 attempt;Errno::ECONNRESET/fake-5xx: retried and passed).run_cpflow_commandconverting API errors to exit status) no longer retry — watch live flake rates after merge.Timeout.timeouthook surface asTimeout::ExitException(notTimeout::Error) and are not retried — they fail fast on attempt 1.cpln_org_configured?(per-process, frozen at load) rather than per-example tags.MultipleExceptionError(transient error + after-hook failure) is not retried under exception scoping.Confidence
RSPEC_RETRY_COUNT=0(seed 555).srand), but watch the first live CI run; the printed seed reproduces any failure.Batch: CPFLOW B 07-16 15:43 (
cpf-b-20260716-1543), lane issue382, epic #387.🤖 Generated with Claude Code