From 88a0747a2df4eee295d375e1ddff35816a932e63 Mon Sep 17 00:00:00 2001 From: Matthew Keeler Date: Tue, 10 Nov 2026 15:42:37 -0500 Subject: [PATCH] fix: Prevent TestDataV2 from restoring an old flag builder when the flag key is a Symbol TestDataV2 stored a flag builder under the key that the caller passed to flag. use_preconfigured_flag discards the builder under the String key from the flag data, so it missed a builder that flag(:key) created. A later flag(:key) then returned the old builder, and update replaced the preconfigured flag with it. flag and FlagBuilderV2 now convert the key to a String. A Symbol key and a String key get the same builder, and a built flag has a String key, as a flag from LaunchDarkly has. --- lib/ldclient-rb/integrations/test_data_v2.rb | 1 + .../test_data_v2/flag_builder_v2.rb | 2 +- spec/integrations/test_data_v2_spec.rb | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/ldclient-rb/integrations/test_data_v2.rb b/lib/ldclient-rb/integrations/test_data_v2.rb index e742d3d5..3fe331ac 100644 --- a/lib/ldclient-rb/integrations/test_data_v2.rb +++ b/lib/ldclient-rb/integrations/test_data_v2.rb @@ -83,6 +83,7 @@ def initialize # @return [FlagBuilderV2] a flag configuration builder # def flag(key) + key = key.to_s existing_builder = @lock.with_read_lock do if @flag_builders.key?(key) && !@flag_builders[key].nil? @flag_builders[key] diff --git a/lib/ldclient-rb/integrations/test_data_v2/flag_builder_v2.rb b/lib/ldclient-rb/integrations/test_data_v2/flag_builder_v2.rb index b279b5fe..91947dec 100644 --- a/lib/ldclient-rb/integrations/test_data_v2/flag_builder_v2.rb +++ b/lib/ldclient-rb/integrations/test_data_v2/flag_builder_v2.rb @@ -26,7 +26,7 @@ class FlagBuilderV2 # @api private def initialize(key) - @_key = key + @_key = key.to_s @_on = true @_variations = [] @_off_variation = nil diff --git a/spec/integrations/test_data_v2_spec.rb b/spec/integrations/test_data_v2_spec.rb index 0c519fa8..5cda80c2 100644 --- a/spec/integrations/test_data_v2_spec.rb +++ b/spec/integrations/test_data_v2_spec.rb @@ -91,6 +91,25 @@ module Integrations expect(td.flag('myflag').build(1)[:variations]).to eq([true, false]) end + it 'starts a new flag builder after a preconfigured flag replaces a flag built with a symbol key' do + td = TestDataV2.data_source + td.update(td.flag(:myflag).variations('x', 'y')) + td.use_preconfigured_flag({ key: 'myflag', variations: ['a'] }) + expect(td.flag(:myflag).build(1)[:variations]).to eq([true, false]) + end + + it 'gives a symbol key and a string key the same flag builder' do + td = TestDataV2.data_source + td.update(td.flag(:myflag).variations('x', 'y')) + expect(td.flag('myflag').build(1)[:variations]).to eq(['x', 'y']) + end + + it 'stores a flag built with a symbol key with a string key' do + td = TestDataV2.data_source + td.update(td.flag(:myflag).variation_for_all(true)) + expect(td.make_init_data[:flags][:myflag][:key]).to eq('myflag') + end + it 'sends a preconfigured flag to a running data source' do td = TestDataV2.data_source source = LaunchDarkly::Impl::Integrations::TestData::TestDataSourceV2.new(td)