diff --git a/launchdarkly-openfeature-server-sdk.gemspec b/launchdarkly-openfeature-server-sdk.gemspec index e6f27f1..824f8ec 100644 --- a/launchdarkly-openfeature-server-sdk.gemspec +++ b/launchdarkly-openfeature-server-sdk.gemspec @@ -28,7 +28,7 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] - spec.add_runtime_dependency "launchdarkly-server-sdk", "~> 8.15" + spec.add_runtime_dependency "launchdarkly-server-sdk", "~> 8.19" spec.add_runtime_dependency "openfeature-sdk", ">= 0.6.1", "< 0.9" # For more information and examples about making a new gem, check out our diff --git a/spec/provider_recovery_spec.rb b/spec/provider_recovery_spec.rb new file mode 100644 index 0000000..36f50ac --- /dev/null +++ b/spec/provider_recovery_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# +# Since LaunchDarkly Ruby SDK 8.19 the data source retries every transport +# failure indefinitely instead of stopping permanently, so an initialization +# that fails within the wait time is routinely followed by a background +# recovery. The provider must report READY when that happens. +# +RSpec.describe LaunchDarkly::OpenFeature::Provider do + let(:td) { + td = LaunchDarkly::Integrations::TestData.data_source + td.update(td.flag("fallthrough-boolean").variation_for_all(true)) + td + } + let(:config) { LaunchDarkly::Config.new(data_source: td, send_events: false) } + let(:provider) { described_class.new("example-key", config) } + let(:api) { OpenFeature::SDK::API.instance } + + after do + api.configuration.shutdown + end + + it "reports READY after a failed initialization once the data source becomes valid" do + allow(provider.client).to receive(:initialized?).and_return(false) + + expect { api.set_provider_and_wait(provider) }.to raise_error(/unable to initialize/) + + client = api.build_client + expect(client.provider_status).to eq(OpenFeature::SDK::ProviderState::ERROR) + + # The data source recovering reaches the provider through its registered + # status listener; drive it the way the SDK broadcaster does on recovery. + listener = LaunchDarkly::OpenFeature::Impl::DataSourceStatusListener.new(provider) + listener.update( + LaunchDarkly::Interfaces::DataSource::Status.new( + LaunchDarkly::Interfaces::DataSource::Status::VALID, Time.now, nil + ) + ) + + expect(client.provider_status).to eq(OpenFeature::SDK::ProviderState::READY) + end +end