diff --git a/README.md b/README.md index df406928..1c3eaa8a 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ require 'ldclient-rb' client = LaunchDarkly::LDClient.new("your_sdk_key") ``` +*NOTE: Please refer to [our documentation](https://docs.launchdarkly.com/docs/ruby-sdk-reference#section-initializing-ldclient-using-spring-unicorn-or-puma) for additional instructions on how to use LaunchDarkly with [Spring](https://github.com/rails/spring), [Unicorn](https://bogomips.org/unicorn/), or [Puma](https://github.com/puma/puma).* + ### Ruby on Rails 1. Add `gem 'ldclient-rb'` to your Gemfile and `bundle install` diff --git a/lib/ldclient-rb/evaluation.rb b/lib/ldclient-rb/evaluation.rb index f873a6e3..1b5bbdca 100644 --- a/lib/ldclient-rb/evaluation.rb +++ b/lib/ldclient-rb/evaluation.rb @@ -263,6 +263,7 @@ def check_prerequisites(flag, user, store, events, logger) event = { kind: "feature", key: prereq_key, + user: user, variation: prereq_res.variation_index, value: prereq_res.value, version: prereq_flag[:version], @@ -272,7 +273,7 @@ def check_prerequisites(flag, user, store, events, logger) } events.push(event) rescue => exn - Util.log_exception(logger, "Error evaluating prerequisite flag \"#{prereq_key}\" for flag \"{flag[:key]}\"", exn) + Util.log_exception(logger, "Error evaluating prerequisite flag \"#{prereq_key}\" for flag \"#{flag[:key]}\"", exn) prereq_ok = false end end diff --git a/lib/ldclient-rb/ldclient.rb b/lib/ldclient-rb/ldclient.rb index a5799700..28c21869 100644 --- a/lib/ldclient-rb/ldclient.rb +++ b/lib/ldclient-rb/ldclient.rb @@ -211,6 +211,10 @@ def variation_detail(key, user, default) # @return [void] # def identify(user) + if !user || user[:key].nil? + @config.logger.warn("Identify called with nil user or nil user key!") + return + end sanitize_user(user) @event_processor.add_event(kind: "identify", key: user[:key], user: user) end @@ -229,6 +233,10 @@ def identify(user) # @return [void] # def track(event_name, user, data) + if !user || user[:key].nil? + @config.logger.warn("Track called with nil user or nil user key!") + return + end sanitize_user(user) @event_processor.add_event(kind: "custom", key: event_name, user: user, data: data) end diff --git a/lib/ldclient-rb/util.rb b/lib/ldclient-rb/util.rb index 03849957..396a5171 100644 --- a/lib/ldclient-rb/util.rb +++ b/lib/ldclient-rb/util.rb @@ -1,3 +1,4 @@ +require "net/http" require "uri" module LaunchDarkly diff --git a/spec/evaluation_spec.rb b/spec/evaluation_spec.rb index 3af960c6..68824ebd 100644 --- a/spec/evaluation_spec.rb +++ b/spec/evaluation_spec.rb @@ -127,7 +127,7 @@ def boolean_flag_with_clauses(clauses) detail = LaunchDarkly::EvaluationDetail.new('b', 1, { kind: 'PREREQUISITE_FAILED', prerequisiteKey: 'feature1' }) events_should_be = [{ - kind: 'feature', key: 'feature1', variation: nil, value: nil, version: 2, prereqOf: 'feature0', + kind: 'feature', key: 'feature1', user: user, variation: nil, value: nil, version: 2, prereqOf: 'feature0', trackEvents: nil, debugEventsUntilDate: nil }] result = evaluate(flag, user, features, logger) @@ -159,7 +159,7 @@ def boolean_flag_with_clauses(clauses) detail = LaunchDarkly::EvaluationDetail.new('b', 1, { kind: 'PREREQUISITE_FAILED', prerequisiteKey: 'feature1' }) events_should_be = [{ - kind: 'feature', key: 'feature1', variation: 1, value: 'e', version: 2, prereqOf: 'feature0', + kind: 'feature', key: 'feature1', user: user, variation: 1, value: 'e', version: 2, prereqOf: 'feature0', trackEvents: nil, debugEventsUntilDate: nil }] result = evaluate(flag, user, features, logger) @@ -189,7 +189,7 @@ def boolean_flag_with_clauses(clauses) detail = LaunchDarkly::EvaluationDetail.new('b', 1, { kind: 'PREREQUISITE_FAILED', prerequisiteKey: 'feature1' }) events_should_be = [{ - kind: 'feature', key: 'feature1', variation: 0, value: 'd', version: 2, prereqOf: 'feature0', + kind: 'feature', key: 'feature1', user: user, variation: 0, value: 'd', version: 2, prereqOf: 'feature0', trackEvents: nil, debugEventsUntilDate: nil }] result = evaluate(flag, user, features, logger) @@ -218,7 +218,7 @@ def boolean_flag_with_clauses(clauses) user = { key: 'x' } detail = LaunchDarkly::EvaluationDetail.new('a', 0, { kind: 'FALLTHROUGH' }) events_should_be = [{ - kind: 'feature', key: 'feature1', variation: 1, value: 'e', version: 2, prereqOf: 'feature0', + kind: 'feature', key: 'feature1', user: user, variation: 1, value: 'e', version: 2, prereqOf: 'feature0', trackEvents: nil, debugEventsUntilDate: nil }] result = evaluate(flag, user, features, logger) diff --git a/spec/fixtures/numeric_key_user.json b/spec/fixtures/numeric_key_user.json deleted file mode 100644 index 2a7ec475..00000000 --- a/spec/fixtures/numeric_key_user.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "key": 33, - "custom":{ - "groups":[ - "microsoft", - "google" - ] - } -} diff --git a/spec/fixtures/sanitized_numeric_key_user.json b/spec/fixtures/sanitized_numeric_key_user.json deleted file mode 100644 index 874e0067..00000000 --- a/spec/fixtures/sanitized_numeric_key_user.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "key": "33", - "custom":{ - "groups":[ - "microsoft", - "google" - ] - } -} diff --git a/spec/ldclient_spec.rb b/spec/ldclient_spec.rb index fca81ab0..6f530610 100644 --- a/spec/ldclient_spec.rb +++ b/spec/ldclient_spec.rb @@ -8,7 +8,8 @@ subject.new("secret", offline_config) end let(:null_data) { LaunchDarkly::NullUpdateProcessor.new } - let(:config) { LaunchDarkly::Config.new({send_events: false, data_source: null_data}) } + let(:logger) { double().as_null_object } + let(:config) { LaunchDarkly::Config.new({ send_events: false, data_source: null_data, logger: logger }) } let(:client) do subject.new("secret", config) end @@ -17,16 +18,31 @@ JSON.parse(data, symbolize_names: true) end let(:user) do - data = File.read(File.join("spec", "fixtures", "user.json")) - JSON.parse(data, symbolize_names: true) + { + key: "user@test.com", + custom: { + groups: [ "microsoft", "google" ] + } + } end let(:numeric_key_user) do - data = File.read(File.join("spec", "fixtures", "numeric_key_user.json")) - JSON.parse(data, symbolize_names: true) + { + key: 33, + custom: { + groups: [ "microsoft", "google" ] + } + } end let(:sanitized_numeric_key_user) do - data = File.read(File.join("spec", "fixtures", "sanitized_numeric_key_user.json")) - JSON.parse(data, symbolize_names: true) + { + key: "33", + custom: { + groups: [ "microsoft", "google" ] + } + } + end + let(:user_without_key) do + { name: "Keyless Joe" } end def event_processor @@ -342,6 +358,18 @@ def event_processor expect(event_processor).to receive(:add_event).with(hash_including(user: sanitized_numeric_key_user)) client.track("custom_event_name", numeric_key_user, nil) end + + it "does not send an event, and logs a warning, if user is nil" do + expect(event_processor).not_to receive(:add_event) + expect(logger).to receive(:warn) + client.track("custom_event_name", nil, nil) + end + + it "does not send an event, and logs a warning, if user key is nil" do + expect(event_processor).not_to receive(:add_event) + expect(logger).to receive(:warn) + client.track("custom_event_name", user_without_key, nil) + end end describe '#identify' do @@ -354,6 +382,18 @@ def event_processor expect(event_processor).to receive(:add_event).with(hash_including(user: sanitized_numeric_key_user)) client.identify(numeric_key_user) end + + it "does not send an event, and logs a warning, if user is nil" do + expect(event_processor).not_to receive(:add_event) + expect(logger).to receive(:warn) + client.identify(nil) + end + + it "does not send an event, and logs a warning, if user key is nil" do + expect(event_processor).not_to receive(:add_event) + expect(logger).to receive(:warn) + client.identify(user_without_key) + end end describe 'with send_events: false' do