Skip to content

Run specs in randomized order#284

Merged
yahonda merged 6 commits intorsim:masterfrom
yahonda:enable-random-spec-order
May 6, 2026
Merged

Run specs in randomized order#284
yahonda merged 6 commits intorsim:masterfrom
yahonda:enable-random-spec-order

Conversation

@yahonda
Copy link
Copy Markdown
Collaborator

@yahonda yahonda commented May 6, 2026

Summary

CONTRIBUTING.md already documents that specs run in randomized order with a reproducible seed, but the configuration to make that true was missing — RSpec ran in :defined order. This PR enables random ordering and fixes the four order-dependent specs that the change surfaces, so the suite is stable under randomization.

The five commits are intentionally split for review:

  1. Run specs in randomized order — set config.order = :random and Kernel.srand config.seed in spec/spec_helper.rb; remove the unused RSpec 1.x-era spec/spec.opts (its --loadby mtime --reverse directly contradicts random order); align the CONTRIBUTING.md banner example with RSpec's actual start-of-run output.

  2. Reset package state between Numeric variable examples — the "Numeric" shared examples in variable_spec.rb shared numeric_var across three examples; with random order the default-value check could observe a previously-assigned value. Added DBMS_SESSION.RESET_PACKAGE in before(:each) so every example re-initializes to defaults.

  3. Avoid mutating shared @Employees in view spec — the :column => nil condition example in view_spec.rb mutated @employees.last in place, leaving the array — built once in before(:all) — corrupted for any subsequent example. Switched to merge so the shared array stays intact.

  4. Reset plsql.activerecord_class after ActiveRecord connection examplesschema_spec.rb's ActiveRecord describe bound the global plsql singleton to AR via before(:each) but never reset it. Because oci_connection.ora_date_to_ruby_date consults plsql.default_timezone (a singleton) and that accessor returns ActiveRecord.default_timezone (:utc in modern Rails) when an AR class is bound, every later test reading DATE values back through any OCI connection saw UTC. Added after(:all) { plsql.activerecord_class = nil }.

  5. Avoid orphaning the outer session in the Oracle 9.2 nested describe — the nested "using Oracle 9.2" describe in procedure_spec.rb called plsql.connect! again in its before(:all) before the version-skip check. That replaced the outer describe's connection with a fresh session; when skip fired the nested after(:all) was suppressed, but the outer after(:all) still ran on the new session — its drop_session_ruby_temporary_tables filtered by the new session_id and never touched the outer session's ruby_<outer_sid>_<package_id>_* tables, while the outer session itself was leaked. Once that orphan held its temporary tables in use, any later drop_all_ruby_temporary_tables hit ORA-14452. Dropped the redundant plsql.connect!; the version check now uses the outer describe's existing connection.

Test plan

  • Verified each failing seed reproduces against current master and is fixed on this branch (variable_spec / view_spec / connection_spec timezone / connection_spec temp tables, seeds 35757 / 45895 / 47562 / 12899).
  • Ran the full suite 10 random seeds × 3 trials for each previously failing seed — 0 failures.
  • Ran 10 fresh random runs on the integrated branch — 10/10 clean (461 examples, 1 pending, 0 failures).
  • CI on this branch (Oracle Database Free 23c, Ruby 4.0).

yahonda and others added 6 commits May 6, 2026 21:55
Configure RSpec to randomize example order and seed Ruby's RNG from
config.seed so any non-RSpec randomness is reproducible from the
printed seed. Remove the unused RSpec 1.x-era spec/spec.opts (not
loaded by RSpec::Core::RakeTask, and its --loadby mtime --reverse
ordering would conflict with random order). Update the CONTRIBUTING.md
banner example to match RSpec's actual start-of-run output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The "Numeric" shared examples have three tests that share a single
package variable (numeric_var): one reads the default value, two
others assign a value via the setter. When examples run in defined
order the default-value test runs first and observes the initial
default, but in any other order it observes the previously-assigned
value because Oracle keeps package variable state at session scope
across tests.

CREATE OR REPLACE PACKAGE alone does not clear that session state
when the spec is unchanged, so call DBMS_SESSION.RESET_PACKAGE in
before(:each) to force re-initialization to defaults before every
example.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The :column => nil select example mutated the last entry of the
@Employees array, which is built once in before(:all) and shared
with every other example in the View describe. When the example ran
before any of the "should insert many records ..." examples, the
later tests compared their actual results against an @Employees
array whose last element had been overwritten with employee_id+1
and hire_date: nil, producing spurious failures.

Build the modified employee with merge so the underlying @Employees
array stays untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The ActiveRecord connection describe block bound the global plsql
schema to ActiveRecord via plsql.activerecord_class= in before(:each)
but never reset it. Because oci_connection.ora_date_to_ruby_date
consults plsql.default_timezone (a singleton on the global plsql
schema), and that accessor returns ActiveRecord.default_timezone
when an AR class is bound, every subsequent test that read DATE
values back through any OCI connection saw UTC values instead of
the local-time defaults. The connection-level
"should parse PL/SQL procedure call ... and get bind parameter
value" example then asserted equality between a local Time and the
UTC round-trip and failed.

Reset plsql.activerecord_class to nil in after(:all) so other
describe blocks observe a fresh, non-AR-bound plsql singleton.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The "using Oracle 9.2" nested describe inside "Function with table
indexed by binary integer parameter" called plsql.connect! in its
before(:all) before checking the database version and skipping on
18c or higher. That call replaced the outer describe's connection
with a fresh session; when skip fired the nested after(:all) was
suppressed, but the outer after(:all) still ran on the new session.
Its drop_session_ruby_temporary_tables therefore filtered by the
new session_id and never touched the outer session's
ruby_<outer_sid>_<package_id>_* tables, while the outer session
itself was now leaked. Once that orphan session held its temporary
tables in use, any later attempt to drop_all_ruby_temporary_tables
hit ORA-14452.

Drop the redundant plsql.connect! and check the version using the
outer describe's existing connection.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Named Schema describe ended its after(:all) with
plsql.connection.logoff, which closes the underlying connection but
leaves plsql.connection pointing at the now-closed wrapper. Any
later example that attempted plsql.logoff if plsql.connection (for
example the after(:each) in "Connection with connect!") then
followed the stale reference into rollback on a dead OCI8 handle
and raised "OCI8 was already closed". Surfaced under random order
when "Named Schema" ran before "Connection with connect!" — the
"should not connect with wrong port number" example never replaced
the stale connection (its connect! is meant to fail), so its
after(:each) was the one that hit the dead handle.

Use plsql.logoff so the schema's setter clears @connection to nil.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@yahonda yahonda merged commit 076bc16 into rsim:master May 6, 2026
20 checks passed
@yahonda yahonda deleted the enable-random-spec-order branch May 6, 2026 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant