From 0d17123a0938d9b67a77071f7498b28cf6832ddd Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Wed, 6 May 2026 21:12:05 +0900 Subject: [PATCH 1/6] Run specs in randomized order 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) --- CONTRIBUTING.md | 2 +- spec/spec.opts | 6 ------ spec/spec_helper.rb | 5 +++++ 3 files changed, 6 insertions(+), 7 deletions(-) delete mode 100644 spec/spec.opts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d9635e7e..eeb0d8c7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -81,7 +81,7 @@ Specs run in randomized order. The seed is printed at the start of the run, e.g.: ``` -==> Randomized with seed 12345 (reproduce: bundle exec rspec --seed 12345) +Randomized with seed 12345 ``` To reproduce that exact run: diff --git a/spec/spec.opts b/spec/spec.opts deleted file mode 100644 index d4254ee1..00000000 --- a/spec/spec.opts +++ /dev/null @@ -1,6 +0,0 @@ ---colour ---format -progress ---loadby -mtime ---reverse \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index bb3591d6..0eec81a9 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -120,3 +120,8 @@ def only(*whitelist) self.reject { |key, value| !whitelist.include?(key) } end unless method_defined?(:only) end + +RSpec.configure do |config| + config.order = :random + Kernel.srand config.seed +end From b8c81a58df364f2bf3b74191e8c5a6c3491c9c85 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Wed, 6 May 2026 21:12:50 +0900 Subject: [PATCH 2/6] Reset package state between Numeric variable examples 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) --- spec/plsql/variable_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/plsql/variable_spec.rb b/spec/plsql/variable_spec.rb index 45fa68cc..98ba2c82 100644 --- a/spec/plsql/variable_spec.rb +++ b/spec/plsql/variable_spec.rb @@ -112,6 +112,10 @@ SQL end + before(:each) do + plsql.execute "BEGIN DBMS_SESSION.RESET_PACKAGE; END;" + end + after(:all) do plsql.execute "DROP PACKAGE test_package" plsql.logoff From c66d0087c1cbfce9b62c4b36b9edc76462b9b61b Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Wed, 6 May 2026 21:27:12 +0900 Subject: [PATCH 3/6] Avoid mutating shared @employees in view spec 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) --- spec/plsql/view_spec.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/plsql/view_spec.rb b/spec/plsql/view_spec.rb index 6d6df830..93dbc60d 100644 --- a/spec/plsql/view_spec.rb +++ b/spec/plsql/view_spec.rb @@ -196,9 +196,10 @@ end it "should select record in view using :column => nil condition" do - employee = @employees.last - employee[:employee_id] = employee[:employee_id] + 1 - employee[:hire_date] = nil + employee = @employees.last.merge( + employee_id: @employees.last[:employee_id] + 1, + hire_date: nil + ) plsql.test_employees_v.insert employee expect(plsql.test_employees_v.first("WHERE hire_date IS NULL")).to eq(employee) expect(plsql.test_employees_v.first(hire_date: nil)).to eq(employee) From 9e311cfdd0b17bbe1103c5102993c9696d0bcfdc Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Wed, 6 May 2026 21:31:35 +0900 Subject: [PATCH 4/6] Reset plsql.activerecord_class after ActiveRecord connection examples 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) --- spec/plsql/schema_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/plsql/schema_spec.rb b/spec/plsql/schema_spec.rb index d540e3ea..b8c7e8d3 100644 --- a/spec/plsql/schema_spec.rb +++ b/spec/plsql/schema_spec.rb @@ -193,6 +193,10 @@ class TestModel < TestBaseModel end end + after(:all) do + plsql.activerecord_class = nil + end + before(:each) do plsql.activerecord_class = ActiveRecord::Base end From cf51357b5f540e454b8e9e3cf79f8bda8931841c Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Wed, 6 May 2026 21:48:01 +0900 Subject: [PATCH 5/6] Avoid orphaning the outer session in the Oracle 9.2 nested describe 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___* 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) --- spec/plsql/procedure_spec.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/plsql/procedure_spec.rb b/spec/plsql/procedure_spec.rb index 7e4efc50..4cee3b94 100644 --- a/spec/plsql/procedure_spec.rb +++ b/spec/plsql/procedure_spec.rb @@ -1506,8 +1506,9 @@ def new_candidate(status) describe "using Oracle 9.2" do before(:all) do - # get actual database_version - plsql.connect! CONNECTION_PARAMS + # get actual database_version using the outer describe's connection; + # calling plsql.connect! here would orphan the outer session, leaking + # ruby__* temporary tables when this skip fires. skip "Skip if the actual database version is 18c or higher" if (plsql.connection.database_version <=> [18, 0, 0, 0]) >= 0 end From 956cc17522c9b49e4c160403728e1511f978c223 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Wed, 6 May 2026 22:09:39 +0900 Subject: [PATCH 6/6] Fix Named Schema after(:all) to fully release plsql.connection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- spec/plsql/schema_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/plsql/schema_spec.rb b/spec/plsql/schema_spec.rb index b8c7e8d3..0c5760d4 100644 --- a/spec/plsql/schema_spec.rb +++ b/spec/plsql/schema_spec.rb @@ -120,7 +120,7 @@ end after(:all) do - plsql.connection.logoff + plsql.logoff end it "should find existing schema" do