Skip to content

Commit

Permalink
chore: Add hook support to contract tests (#257)
Browse files Browse the repository at this point in the history
  • Loading branch information
keelerm84 committed Apr 5, 2024
1 parent 3cf16eb commit 05678b4
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 9 deletions.
7 changes: 7 additions & 0 deletions contract-tests/client_entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'net/http'
require 'launchdarkly-server-sdk'
require './big_segment_store_fixture'
require './hook'
require 'http'

class ClientEntity
Expand Down Expand Up @@ -62,6 +63,12 @@ def initialize(log, config)
}
end

if config[:hooks]
opts[:hooks] = config[:hooks][:hooks].map do |hook|
Hook.new(hook[:name], hook[:callbackUri], hook[:data] || {})
end
end

startWaitTimeMs = config[:startWaitTimeMs] || 5_000

@client = LaunchDarkly::LDClient.new(
Expand Down
68 changes: 68 additions & 0 deletions contract-tests/hook.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
require 'ldclient-rb'

class Hook
include LaunchDarkly::Interfaces::Hooks::Hook

#
# @param name [String]
# @param callback_uri [String]
# @param data [Hash]
#
def initialize(name, callback_uri, data)
@metadata = LaunchDarkly::Interfaces::Hooks::Metadata.new(name)
@callback_uri = callback_uri
@data = data
@context_filter = LaunchDarkly::Impl::ContextFilter.new(false, [])
end

def metadata
@metadata
end

#
# @param evaluation_series_context [LaunchDarkly::Interfaces::Hooks::EvaluationSeriesContext]
# @param data [Hash]
#
def before_evaluation(evaluation_series_context, data)
payload = {
evaluationSeriesContext: {
flagKey: evaluation_series_context.key,
context: @context_filter.filter(evaluation_series_context.context),
defaultValue: evaluation_series_context.default_value,
method: evaluation_series_context.method,
},
evaluationSeriesData: data,
stage: 'beforeEvaluation',
}
result = HTTP.post(@callback_uri, json: payload)

(data || {}).merge(@data[:beforeEvaluation] || {})
end


#
# @param evaluation_series_context [LaunchDarkly::Interfaces::Hooks::EvaluationSeriesContext]
# @param data [Hash]
# @param detail [LaunchDarkly::EvaluationDetail]
#
def after_evaluation(evaluation_series_context, data, detail)
payload = {
evaluationSeriesContext: {
flagKey: evaluation_series_context.key,
context: @context_filter.filter(evaluation_series_context.context),
defaultValue: evaluation_series_context.default_value,
method: evaluation_series_context.method,
},
evaluationSeriesData: data,
evaluationDetail: {
value: detail.value,
variationIndex: detail.variation_index,
reason: detail.reason,
},
stage: 'afterEvaluation',
}
HTTP.post(@callback_uri, json: payload)

(data || {}).merge(@data[:afterEvaluation] || {})
end
end
1 change: 1 addition & 0 deletions contract-tests/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
'polling-gzip',
'inline-context',
'anonymous-redaction',
'evaluation-hooks',
],
}.to_json
end
Expand Down
10 changes: 5 additions & 5 deletions lib/ldclient-rb/interfaces.rb
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ def metadata
# @return [Hash] Data to use when executing the next state of the hook in the evaluation series.
#
def before_evaluation(evaluation_series_context, data)
{}
data
end

#
Expand Down Expand Up @@ -953,19 +953,19 @@ def initialize(name)
class EvaluationSeriesContext
attr_reader :key
attr_reader :context
attr_reader :value
attr_reader :default_value
attr_reader :method

#
# @param key [String]
# @param context [LaunchDarkly::LDContext]
# @param value [any]
# @param default_value [any]
# @param method [Symbol]
#
def initialize(key, context, value, method)
def initialize(key, context, default_value, method)
@key = key
@context = context
@value = value
@default_value = default_value
@method = method
end
end
Expand Down
9 changes: 5 additions & 4 deletions lib/ldclient-rb/ldclient.rb
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ def variation(key, context, default)
# @return [EvaluationDetail] an object describing the result
#
def variation_detail(key, context, default)
context = Impl::Context::make_context(context)
detail, _, _ = evaluate_with_hooks(key, context, default, :variation_detail) do
evaluate_internal(key, context, default, true)
end
Expand All @@ -264,8 +265,8 @@ def variation_detail(key, context, default)
# ```
#
# @param key [String]
# @param context [String]
# @param default [String]
# @param context [LDContext]
# @param default [any]
# @param method [Symbol]
# @param &block [#call] Implicit passed block
#
Expand Down Expand Up @@ -633,14 +634,15 @@ def create_default_data_source(sdk_key, config, diagnostic_accumulator)
# @return [Array<EvaluationDetail, [LaunchDarkly::Impl::Model::FeatureFlag, nil], [String, nil]>]
#
def variation_with_flag(key, context, default)
context = Impl::Context::make_context(context)
evaluate_with_hooks(key, context, default, :variation_detail) do
evaluate_internal(key, context, default, false)
end
end

#
# @param key [String]
# @param context [Hash, LDContext]
# @param context [LDContext]
# @param default [Object]
# @param with_reasons [Boolean]
#
Expand All @@ -657,7 +659,6 @@ def evaluate_internal(key, context, default, with_reasons)
return detail, nil, "no context provided"
end

context = Impl::Context::make_context(context)
unless context.valid?
@config.logger.error { "[LDClient] Context was invalid for evaluation of flag '#{key}' (#{context.error}); returning default value" }
detail = Evaluator.error_result(EvaluationReason::ERROR_USER_NOT_SPECIFIED, default)
Expand Down

0 comments on commit 05678b4

Please sign in to comment.