From 60a9dcc641318a9e100e84ac5734e7a0000bbcae Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Wed, 18 Dec 2024 23:23:07 -0800 Subject: [PATCH] Global namespacing that applies to all threads Namespacing is thread-local currently, so it's easy to lose, e.g. when running parallel tests, Capybara tests, or executor pools. Changing that is a major compatibility break, so we introduce a non-thread-local Kredis.global_namespace attribute that behaves as we'd expect. When Kredis.namespace is set, it's appended to the global namespace. --- lib/kredis/namespace.rb | 16 +++++++++++++--- lib/kredis/railtie.rb | 14 ++------------ test/attributes_test.rb | 18 +++++++++--------- test/connections_test.rb | 11 +++++++++-- test/migration_test.rb | 28 ++++++++++++++++------------ test/test_helper.rb | 2 ++ 6 files changed, 51 insertions(+), 38 deletions(-) diff --git a/lib/kredis/namespace.rb b/lib/kredis/namespace.rb index 5a8f871..0074da6 100644 --- a/lib/kredis/namespace.rb +++ b/lib/kredis/namespace.rb @@ -1,12 +1,22 @@ # frozen_string_literal: true module Kredis::Namespace - def namespace=(namespace) - Thread.current[:kredis_namespace] = namespace + attr_accessor :global_namespace + + def namespace=(value) + if global_namespace + if value + value = "#{global_namespace}:#{value}" + else + value = global_namespace + end + end + + Thread.current[:kredis_namespace] = value end def namespace - Thread.current[:kredis_namespace] + Thread.current[:kredis_namespace] ||= global_namespace end def namespaced_key(key) diff --git a/lib/kredis/railtie.rb b/lib/kredis/railtie.rb index 013cf8e..dc22231 100644 --- a/lib/kredis/railtie.rb +++ b/lib/kredis/railtie.rb @@ -5,18 +5,8 @@ class Kredis::Railtie < ::Rails::Railtie initializer "kredis.testing" do ActiveSupport.on_load(:active_support_test_case) do - $kredis_parallel_worker = nil - parallelize_setup { |worker| $kredis_parallel_worker = worker } - - setup do - @original_namespace = Kredis.namespace - Kredis.namespace = [ @original_namespace, :test, $kredis_parallel_worker ].compact.join("-") - end - - teardown do - Kredis.clear_all - Kredis.namespace = @original_namespace - end + parallelize_setup { |worker| Kredis.global_namespace = [ Kredis.global_namespace, :test, worker ].compact.join("-") } + teardown { Kredis.clear_all } end end diff --git a/test/attributes_test.rb b/test/attributes_test.rb index 6fa0b4e..c886dc4 100644 --- a/test/attributes_test.rb +++ b/test/attributes_test.rb @@ -120,12 +120,12 @@ class AttributesTest < ActiveSupport::TestCase test "proxy with custom string key" do @person.nothing.set "everything" - assert_equal "everything", Kredis.redis.get("something:else") + assert_equal "everything", Kredis.redis.get(Kredis.namespaced_key("something:else")) end test "proxy with custom proc key" do @person.something.set "everything" - assert_equal "everything", Kredis.redis.get("person:8:something") + assert_equal "everything", Kredis.redis.get(Kredis.namespaced_key("person:8:something")) end test "list" do @@ -135,17 +135,17 @@ class AttributesTest < ActiveSupport::TestCase test "list with custom proc key" do @person.names_with_custom_key_via_lambda.append(%w[ david kasper ]) - assert_equal %w[ david kasper ], Kredis.redis.lrange("person:8:names_customized", 0, -1) + assert_equal %w[ david kasper ], Kredis.redis.lrange(Kredis.namespaced_key("person:8:names_customized"), 0, -1) end test "list with custom method key" do @person.names_with_custom_key_via_method.append(%w[ david kasper ]) - assert_equal %w[ david kasper ], Kredis.redis.lrange("some-generated-key", 0, -1) + assert_equal %w[ david kasper ], Kredis.redis.lrange(Kredis.namespaced_key("some-generated-key"), 0, -1) end test "list with default proc value" do assert_equal %w[ Random Jason ], @person.names_with_default_via_lambda.elements - assert_equal %w[ Random Jason ], Kredis.redis.lrange("people:8:names_with_default_via_lambda", 0, -1) + assert_equal %w[ Random Jason ], Kredis.redis.lrange(Kredis.namespaced_key("people:8:names_with_default_via_lambda"), 0, -1) end test "unique list" do @@ -157,7 +157,7 @@ class AttributesTest < ActiveSupport::TestCase test "unique list with default proc value" do assert_equal %w[ Random Jason ], @person.skills_with_default_via_lambda.elements - assert_equal %w[ Random Jason ], Kredis.redis.lrange("people:8:skills_with_default_via_lambda", 0, -1) + assert_equal %w[ Random Jason ], Kredis.redis.lrange(Kredis.namespaced_key("people:8:skills_with_default_via_lambda"), 0, -1) end test "ordered set" do @@ -222,7 +222,7 @@ class AttributesTest < ActiveSupport::TestCase end test "float with default proc value" do - assert_not_equal 73.2, Kredis.redis.get("people:8:height_with_default_via_lambda") + assert_not_equal 73.2, Kredis.redis.get(Kredis.namespaced_key("people:8:height_with_default_via_lambda")) assert_equal 73.2, @person.height_with_default_via_lambda.value assert_equal "73.2", @person.height_with_default_via_lambda.to_s end @@ -321,7 +321,7 @@ class AttributesTest < ActiveSupport::TestCase test "set with default proc value" do assert_equal [ "Paris" ], @person.vacations_with_default_via_lambda.members - assert_equal [ "Paris" ], Kredis.redis.smembers("people:8:vacations_with_default_via_lambda") + assert_equal [ "Paris" ], Kredis.redis.smembers(Kredis.namespaced_key("people:8:vacations_with_default_via_lambda")) end test "json" do @@ -332,7 +332,7 @@ class AttributesTest < ActiveSupport::TestCase test "json with default proc value" do expect = { "height" => 73.2, "weight" => 182.4, "eye_color" => "ha" } assert_equal expect, @person.settings_with_default_via_lambda.value - assert_equal expect.to_json, Kredis.redis.get("people:8:settings_with_default_via_lambda") + assert_equal expect.to_json, Kredis.redis.get(Kredis.namespaced_key("people:8:settings_with_default_via_lambda")) end diff --git a/test/connections_test.rb b/test/connections_test.rb index a3bc5bd..6ad32eb 100644 --- a/test/connections_test.rb +++ b/test/connections_test.rb @@ -4,8 +4,15 @@ require "yaml" class ConnectionsTest < ActiveSupport::TestCase - setup { Kredis.connections = {} } - teardown { Kredis.namespace = nil } + setup do + Kredis.connections = {} + @original_global_namespace, Kredis.global_namespace = Kredis.global_namespace, nil + end + + teardown do + Kredis.global_namespace = @original_global_namespace + Kredis.namespace = nil + end test "clear all" do list = Kredis.list "mylist" diff --git a/test/migration_test.rb b/test/migration_test.rb index 3532e3c..0ec5d41 100644 --- a/test/migration_test.rb +++ b/test/migration_test.rb @@ -3,12 +3,10 @@ require "test_helper" class MigrationTest < ActiveSupport::TestCase - setup { @proxy = Kredis.string "new_proxy" } - test "migrate_all" do 3.times { |index| Kredis.proxy("mykey:#{index}").set "hello there #{index}" } - Kredis::Migration.migrate_all("mykey:*") { |key| key.gsub("mykey", "thykey") } + Kredis::Migration.migrate_all(Kredis.namespaced_key("mykey:*")) { |key| "thykey:#{key.split(":").last}" } 3.times do |index| assert_equal "hello there #{index}", Kredis.proxy("thykey:#{index}").get @@ -16,19 +14,25 @@ class MigrationTest < ActiveSupport::TestCase end test "migrate" do + @original_global_namespace, Kredis.global_namespace = Kredis.global_namespace, nil + old_proxy = Kredis.string "old_proxy" old_proxy.set "hello there" - assert_not @proxy.assigned? - Kredis::Migration.migrate from: "old_proxy", to: @proxy.key - assert_equal "hello there", @proxy.value + new_proxy = Kredis.string "new_proxy" + assert_not new_proxy.assigned? + + Kredis::Migration.migrate from: Kredis.namespaced_key("old_proxy"), to: "new_proxy" + assert_equal "hello there", new_proxy.value assert old_proxy.assigned?, "just copying the data" + ensure + Kredis.global_namespace = @original_global_namespace end test "migrate with blank keys" do assert_nothing_raised do - Kredis::Migration.migrate from: "old_key", to: nil - Kredis::Migration.migrate from: "old_key", to: "" + Kredis::Migration.migrate from: Kredis.namespaced_key("old_key"), to: nil + Kredis::Migration.migrate from: Kredis.namespaced_key("old_key"), to: "" end end @@ -37,7 +41,7 @@ class MigrationTest < ActiveSupport::TestCase Kredis.namespace = "migrate" - Kredis::Migration.migrate from: "key", to: "key" + Kredis::Migration.migrate from: "#{Kredis.global_namespace}:key", to: "key" assert_equal "x", Kredis.proxy("key").get ensure @@ -47,7 +51,7 @@ class MigrationTest < ActiveSupport::TestCase test "migrate with automatic id extraction" do Kredis.proxy("mykey:1").set "hey" - Kredis::Migration.migrate_all "mykey:*" do |key, id| + Kredis::Migration.migrate_all Kredis.namespaced_key("mykey:*") do |key, id| assert_equal 1, id key end @@ -56,7 +60,7 @@ class MigrationTest < ActiveSupport::TestCase test "delete_all with pattern" do 3.times { |index| Kredis.proxy("mykey:#{index}").set "hello there #{index}" } - Kredis::Migration.delete_all "mykey:*" + Kredis::Migration.delete_all Kredis.namespaced_key("mykey:*") 3.times { |index| assert_nil Kredis.proxy("mykey:#{index}").get } end @@ -64,7 +68,7 @@ class MigrationTest < ActiveSupport::TestCase test "delete_all with keys" do 3.times { |index| Kredis.proxy("mykey:#{index}").set "hello there #{index}" } - Kredis::Migration.delete_all(*3.times.map { |index| "mykey:#{index}" }) + Kredis::Migration.delete_all(*3.times.map { |index| Kredis.namespaced_key("mykey:#{index}") }) 3.times { |index| assert_nil Kredis.proxy("mykey:#{index}").get } end diff --git a/test/test_helper.rb b/test/test_helper.rb index e7a3cd9..9459ad1 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -9,6 +9,8 @@ require "kredis" +Kredis.global_namespace = "kredis-test" + Kredis.configurator = Class.new do def config_for(name) { db: "1" } end def root() Pathname.new(".") end