From f1d2e58141351a1235bcdb9bf6620f9734a29839 Mon Sep 17 00:00:00 2001 From: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Date: Mon, 21 Oct 2024 14:11:35 -0700 Subject: [PATCH] feat: Add support for client-side prerequisite events. --- priv/flags-segments-put-data.json | 16 + src/ldclient_eval.erl | 43 ++- src/ldclient_flag.erl | 46 ++- .../src/ts_service_request_handler.erl | 4 +- test/ldclient_eval_SUITE.erl | 285 ++++++++---------- test/ldclient_parse_SUITE.erl | 122 +++++++- 6 files changed, 326 insertions(+), 190 deletions(-) diff --git a/priv/flags-segments-put-data.json b/priv/flags-segments-put-data.json index 6bba69b..8a11c8e 100644 --- a/priv/flags-segments-put-data.json +++ b/priv/flags-segments-put-data.json @@ -96,6 +96,10 @@ }, "prereqs-fail-off": { "clientSide": true, + "clientSideAvailability": { + "usingEnvironmentId": true, + "usingMobileKey": false + }, "debugEventsUntilDate": null, "deleted": false, "fallthrough": { @@ -124,6 +128,10 @@ }, "prereqs-fail-off-null": { "clientSide": true, + "clientSideAvailability": { + "usingEnvironmentId": true, + "usingMobileKey": false + }, "debugEventsUntilDate": null, "deleted": false, "fallthrough": { @@ -152,6 +160,10 @@ }, "prereqs-fail-variation": { "clientSide": true, + "clientSideAvailability": { + "usingEnvironmentId": true, + "usingMobileKey": false + }, "debugEventsUntilDate": null, "deleted": false, "fallthrough": { @@ -254,6 +266,10 @@ }, "prereqs-success": { "clientSide": true, + "clientSideAvailability": { + "usingEnvironmentId": true, + "usingMobileKey": false + }, "debugEventsUntilDate": null, "deleted": false, "fallthrough": { diff --git a/src/ldclient_eval.erl b/src/ldclient_eval.erl index 0e6f2af..05d8ac0 100644 --- a/src/ldclient_eval.erl +++ b/src/ldclient_eval.erl @@ -40,8 +40,8 @@ target_match }. -type all_flags_state_options() :: #{ - with_reasons => boolean() -%% client_side_only => boolean(), % TODO: Support. + with_reasons => boolean(), + client_side_only => boolean() %% details_only_for_tracked_flags => boolean() % TODO: Support. }. @@ -113,6 +113,26 @@ all_flags_state(Context, Options, Tag) -> is_not_deleted(#{deleted := true}) -> false; is_not_deleted(_) -> true. +-spec is_prereq_of(FlagKey :: ldclient_flag:key(), Event :: ldclient_event:event()) -> boolean(). +is_prereq_of(FlagKey, #{data := #{prereq_of := PrereqOf}} = _Event) -> + FlagKey =:= PrereqOf. + +-spec maybe_add_prerequisites(Prerequisites :: [ldclient_flag:key()], Map :: map()) -> map(). +maybe_add_prerequisites([] = _Prerequisites, Map) -> Map; +maybe_add_prerequisites(Prerequisites, Map) -> Map#{<<"prerequisites">> => Prerequisites}. + + +-spec is_visible(Item :: map(), Options :: all_flags_state_options()) -> boolean(). +is_visible( + #{clientSideAvailability := #{ + usingEnvironmentId := UsingEnvironmentId + }} = _Item, + #{client_side_only := true} = _Options +) -> UsingEnvironmentId; +%% All flags will have the availability set via parsing. So when client_side_only is not true +%% we want everything to be visible. +is_visible(_, _) -> true. + -spec all_flags_state( Context :: ldclient_context:context(), Options :: all_flags_state_options(), @@ -127,17 +147,26 @@ all_flags_state(_Context, _Options, _Tag, _, not_initialized) -> all_flags_state(Context, #{with_reasons := WithReason} = _Options, Tag, Offline, store_initialized) -> error_logger:warning_msg("Called allFlagsState before client initialization; using last known values from data store."), all_flags_state(Context, #{with_reasons := WithReason} = _Options, Tag, Offline, initialized); -all_flags_state(Context, #{with_reasons := WithReason} = _Options, Tag, _, initialized) -> +all_flags_state(Context, #{with_reasons := WithReason} = Options, Tag, _, initialized) -> FeatureStore = ldclient_config:get_value(Tag, feature_store), - AllFlags = [Flag || Flag = {_, FlagValue} <- FeatureStore:all(Tag, features), is_not_deleted(FlagValue)], + AllFlags = [Flag || Flag = {_, FlagValue} <- FeatureStore:all(Tag, features), is_not_deleted(FlagValue), is_visible(FlagValue, Options)], EvalFun = fun({FlagKey, #{version := Version} = Flag}, #{<<"$flagsState">> := FlagsState} = Acc) -> % Here the state is either initialized, or store_initialized, and we are online. Call directly to that version % of flag_key_for_context. This will prevent additional warnings for the client initialization not being % complete in the store_initialized state. - {{VariationIndex, V, Reason}, _Events} = flag_key_for_context(Tag, FlagKey, Context, null, online, initialized), - FlagState = maybe_add_track_events(Flag, + {{VariationIndex, V, Reason}, Events} = flag_key_for_context(Tag, FlagKey, Context, null, online, initialized), + DirectPrereqEvents = lists:filter(fun(Event) -> is_prereq_of(FlagKey, Event) end, Events), + Prereqs = lists:reverse(lists:map(fun(Event) -> + #{data := #{key := Key}} = Event, + Key + end, + DirectPrereqEvents + )), + FlagState = + maybe_add_prerequisites(Prereqs, + maybe_add_track_events(Flag, maybe_add_debug_events_until_date(Flag, #{ - <<"version">> => Version})), + <<"version">> => Version}))), UpdatedFlagState = case is_integer(VariationIndex) of true -> FlagState#{ <<"variation">> => VariationIndex diff --git a/src/ldclient_flag.erl b/src/ldclient_flag.erl index 0dc8d31..2075e52 100644 --- a/src/ldclient_flag.erl +++ b/src/ldclient_flag.erl @@ -13,21 +13,22 @@ %% Types -type flag() :: #{ - debugEventsUntilDate => pos_integer() | null, + debugEventsUntilDate => pos_integer() | null, deleted => boolean(), fallthrough => variation_or_rollout(), key => key(), - offVariation => variation(), + offVariation => variation(), on => boolean(), prerequisites => [prerequisite()], rules => [ldclient_rule:rule()], salt => binary(), targets => [target()], contextTargets => [target()], - trackEvents => boolean(), - trackEventsFallthrough => boolean(), + trackEvents => boolean(), + trackEventsFallthrough => boolean(), variations => [variation_value()], - version => version() + version => version(), + clientSideAvailability => client_side_availability() }. -type key() :: binary(). @@ -62,6 +63,12 @@ -type version() :: non_neg_integer(). +-type client_side_availability() :: #{ + usingEnvironmentId => boolean(), + usingMobileKey => boolean() +}. +%% Describes the availability of the flag to client-side SDKs. + -export_type([flag/0]). -export_type([key/0]). -export_type([prerequisite/0]). @@ -92,7 +99,11 @@ new(RawFlagMap) -> <<"trackEvents">> => false, <<"trackEventsFallthrough">> => false, <<"variations">> => [], - <<"version">> => 0 + <<"version">> => 0, + <<"clientSideAvailability">> => #{ + <<"usingEnvironmentId">> => false, + <<"usingMobileKey">> => false + } }, FlagMap = maps:merge(FlagTemplate, RawFlagMap), new_from_template(FlagMap). @@ -136,24 +147,35 @@ new_from_template(#{ <<"trackEvents">> := TrackEvents, <<"trackEventsFallthrough">> := TrackEventsFallthrough, <<"variations">> := Variations, - <<"version">> := Version + <<"version">> := Version, + <<"clientSideAvailability">> := ClientSideAvailability }) -> #{ - debugEventsUntilDate => DebugEventsUntilDate, + debugEventsUntilDate => DebugEventsUntilDate, deleted => Deleted, fallthrough => parse_variation_or_rollout(Fallthrough), key => Key, - offVariation => OffVariation, + offVariation => OffVariation, on => On, prerequisites => parse_prerequisites(Prerequisites), rules => parse_rules(Rules), salt => Salt, targets => parse_targets(Targets), contextTargets => parse_targets(ContextTargets), - trackEvents => TrackEvents, - trackEventsFallthrough => TrackEventsFallthrough, + trackEvents => TrackEvents, + trackEventsFallthrough => TrackEventsFallthrough, variations => Variations, - version => Version + version => Version, + clientSideAvailability => parse_client_side_availability(ClientSideAvailability) + }. + +-spec parse_client_side_availability(ClientSideAvailability :: map()) -> client_side_availability(). +parse_client_side_availability(ClientSideAvailability) -> + UsingEnvironmentId = maps:get(<<"usingEnvironmentId">>, ClientSideAvailability, false), + UsingMobileKey = maps:get(<<"usingMobileKey">>, ClientSideAvailability, false), + #{ + usingEnvironmentId => UsingEnvironmentId, + usingMobileKey => UsingMobileKey }. -spec parse_prerequisites([map()]) -> [prerequisite()]. diff --git a/test-service/src/ts_service_request_handler.erl b/test-service/src/ts_service_request_handler.erl index bd70d52..a517c69 100644 --- a/test-service/src/ts_service_request_handler.erl +++ b/test-service/src/ts_service_request_handler.erl @@ -78,7 +78,9 @@ get_service_detail(Req, State) -> <<"anonymous-redaction">>, <<"tls:custom-ca">>, <<"tls:skip-verify-peer">>, - <<"tls:verify-peer">> + <<"tls:verify-peer">>, + <<"client-prereq-events">>, + <<"all-flags-client-side-only">> ], <<"clientVersion">> => ldclient_config:get_version() }), diff --git a/test/ldclient_eval_SUITE.erl b/test/ldclient_eval_SUITE.erl index 5552f76..ea5c65a 100644 --- a/test/ldclient_eval_SUITE.erl +++ b/test/ldclient_eval_SUITE.erl @@ -67,6 +67,7 @@ all_flags_state/1, all_flags_state_with_reason/1, all_flags_state_offline/1, + all_flags_state_client_side_only/1, malformed_clause/1, malformed_rollout/1, malformed_segment_rollout/1, @@ -136,6 +137,7 @@ all() -> all_flags_state, all_flags_state_with_reason, all_flags_state_offline, + all_flags_state_client_side_only, malformed_clause, malformed_rollout, malformed_segment_rollout, @@ -750,7 +752,7 @@ missing_all_fields(_) -> ActualEvents = lists:sort(extract_events(Events)), ExpectedEvents = ActualEvents. -missing_rollout_for_rule(_) -> +missing_rollout_for_rule(_) -> {{2,<<"FallthroughValue">>,fallthrough}, Events} = ldclient_eval:flag_key_for_context(default, <<"missing-rollout-for-rule">>, #{key => <<"context123">>, kind => <<"user">>}, "DefaultValue"), ExpectedEvents = lists:sort([{<<"missing-rollout-for-rule">>, feature_request, 2, <<"FallthroughValue">>, "DefaultValue", fallthrough, null}]), ActualEvents = lists:sort(extract_events(Events)), @@ -810,6 +812,100 @@ rule_match_rollout_not_in_experiment(_) -> ExpectedEvents = ActualEvents. all_flags_state(_) -> + #{<<"$flagsState">> := + #{<<"bad-variation">> := + #{<<"trackEvents">> := true,<<"version">> := 5}, + <<"experiment-traffic-allocation-v2">> := + #{<<"reason">> := + #{kind := <<"FALLTHROUGH">>,inExperiment := true}, + <<"trackReason">> := true,<<"variation">> := 0, + <<"version">> := 5}, + <<"experiment-traffic-allocation-v2-rules">> := + #{<<"trackEvents">> := true,<<"variation">> := 0, + <<"version">> := 1}, + <<"extra-fields">> := + #{<<"trackEvents">> := true,<<"variation">> := 0, + <<"version">> := 5}, + <<"fallthrough-no-rollout-or-variation">> := + #{<<"trackEvents">> := true,<<"version">> := 7243}, + <<"keep-it-off">> := + #{<<"trackEvents">> := true,<<"variation">> := 1, + <<"version">> := 5}, + <<"keep-it-off-null-off-variation">> := + #{<<"trackEvents">> := true,<<"version">> := 5}, + <<"keep-it-on">> := + #{<<"prerequisites">> := [<<"keep-it-on-two">>], + <<"trackEvents">> := true,<<"variation">> := 0, + <<"version">> := 5}, + <<"keep-it-on-another">> := + #{<<"trackEvents">> := true,<<"variation">> := 0, + <<"version">> := 5}, + <<"keep-it-on-two">> := + #{<<"trackEvents">> := true,<<"variation">> := 0, + <<"version">> := 5}, + <<"missing-all-fields">> := #{<<"version">> := 0}, + <<"missing-rollout-for-rule">> := + #{<<"trackEvents">> := true,<<"variation">> := 2, + <<"version">> := 4243}, + <<"missing-some-fields">> := + #{<<"variation">> := 0,<<"version">> := 0}, + <<"prereqs-fail-off">> := + #{<<"trackEvents">> := true,<<"variation">> := 1, + <<"version">> := 245}, + <<"prereqs-fail-off-null">> := + #{<<"trackEvents">> := true,<<"version">> := 2}, + <<"prereqs-fail-variation">> := + #{<<"prerequisites">> := [<<"keep-it-on">>], + <<"trackEvents">> := true,<<"variation">> := 1, + <<"version">> := 245}, + <<"prereqs-success">> := + #{<<"prerequisites">> := + [<<"keep-it-on">>,<<"keep-it-on-another">>], + <<"trackEvents">> := true,<<"variation">> := 1, + <<"version">> := 24}, + <<"roll-me">> := + #{<<"trackEvents">> := true,<<"variation">> := 4, + <<"version">> := 5}, + <<"roll-me-custom">> := + #{<<"trackEvents">> := true,<<"variation">> := 0, + <<"version">> := 5}, + <<"roll-me-invalid">> := + #{<<"trackEvents">> := true,<<"variation">> := 1, + <<"version">> := 5}, + <<"rule-me">> := + #{<<"trackEvents">> := true,<<"variation">> := 0, + <<"version">> := 5}, + <<"segment-me">> := + #{<<"trackEvents">> := true,<<"variation">> := 1, + <<"version">> := 5}, + <<"target-me">> := + #{<<"trackEvents">> := true,<<"variation">> := 0, + <<"version">> := 5}}, + <<"$valid">> := true, + <<"bad-variation">> := null, + <<"experiment-traffic-allocation-v2">> := <<"a">>, + <<"experiment-traffic-allocation-v2-rules">> := <<"a">>, + <<"extra-fields">> := true, + <<"fallthrough-no-rollout-or-variation">> := null, + <<"keep-it-off">> := false, + <<"keep-it-off-null-off-variation">> := null, + <<"keep-it-on">> := true, + <<"keep-it-on-another">> := true, + <<"keep-it-on-two">> := true, + <<"missing-all-fields">> := null, + <<"missing-rollout-for-rule">> := <<"FallthroughValue">>, + <<"missing-some-fields">> := true, + <<"prereqs-fail-off">> := false, + <<"prereqs-fail-off-null">> := null, + <<"prereqs-fail-variation">> := false, + <<"prereqs-success">> := false, + <<"roll-me">> := <<"e">>, + <<"roll-me-custom">> := <<"a">>, + <<"roll-me-invalid">> := <<"b">>, + <<"rule-me">> := <<"a">>,<<"segment-me">> := false, + <<"target-me">> := true} = ldclient_eval:all_flags_state(#{key => <<"userKeyA">>, kind => <<"user">>}, #{with_reasons => false}, default). + +all_flags_state_with_reason(_) -> #{<<"$flagsState">> := #{<<"bad-variation">> := #{<<"reason">> := @@ -967,170 +1063,41 @@ all_flags_state(_) -> <<"target-me">> := true } = ldclient_eval:all_flags_state(#{key => <<"userKeyA">>, kind => <<"user">>}, #{with_reasons => true}, default). -all_flags_state_with_reason(_) -> - #{<<"$flagsState">> := - #{<<"bad-variation">> := - #{<<"reason">> := - #{errorKind := <<"MALFORMED_FLAG">>, - kind := <<"ERROR">>}, - <<"trackEvents">> := true, - <<"version">> := 5}, - <<"experiment-traffic-allocation-v2">> := - #{<<"reason">> := - #{inExperiment := true, - kind := <<"FALLTHROUGH">>}, - <<"variation">> := 0, - <<"version">> := 5}, - <<"experiment-traffic-allocation-v2-rules">> := - #{<<"reason">> := - #{inExperiment := true, - kind := <<"RULE_MATCH">>, - ruleId := - <<"ab4a9fb3-7e85-429f-8078-23aa70094540">>, - ruleIndex := 0}, - <<"trackEvents">> := true, - <<"variation">> := 0, - <<"version">> := 1}, - <<"extra-fields">> := - #{<<"reason">> := #{kind := <<"FALLTHROUGH">>}, - <<"trackEvents">> := true,<<"variation">> := 0, - <<"version">> := 5}, - <<"fallthrough-no-rollout-or-variation">> := - #{<<"reason">> := - #{errorKind := <<"MALFORMED_FLAG">>, - kind := <<"ERROR">>}, - <<"trackEvents">> := true, - <<"version">> := 7243}, - <<"keep-it-off">> := - #{<<"reason">> := #{kind := <<"OFF">>}, - <<"trackEvents">> := true, - <<"variation">> := 1, - <<"version">> := 5}, - <<"keep-it-off-null-off-variation">> := - #{<<"reason">> := #{kind := <<"OFF">>}, - <<"trackEvents">> := true, - <<"version">> := 5}, - <<"keep-it-on">> := - #{<<"reason">> := #{kind := <<"FALLTHROUGH">>}, - <<"trackEvents">> := true, - <<"variation">> := 0, - <<"version">> := 5}, - <<"keep-it-on-another">> := - #{<<"reason">> := #{kind := <<"FALLTHROUGH">>}, - <<"trackEvents">> := true, - <<"variation">> := 0, - <<"version">> := 5}, - <<"keep-it-on-two">> := - #{<<"reason">> := #{kind := <<"FALLTHROUGH">>}, - <<"trackEvents">> := true, - <<"variation">> := 0, - <<"version">> := 5}, - <<"missing-all-fields">> := - #{<<"reason">> := - #{errorKind := <<"MALFORMED_FLAG">>, - kind := <<"ERROR">>}, - <<"version">> := 0}, - <<"missing-rollout-for-rule">> := - #{<<"reason">> := #{kind := <<"FALLTHROUGH">>}, - <<"trackEvents">> := true, - <<"variation">> := 2, - <<"version">> := 4243}, - <<"missing-some-fields">> := - #{<<"reason">> := #{kind := <<"FALLTHROUGH">>}, - <<"variation">> := 0, - <<"version">> := 0}, - <<"prereqs-fail-off">> := - #{<<"reason">> := - #{kind := <<"PREREQUISITE_FAILED">>, - prerequisiteKey := <<"keep-it-off">>}, - <<"trackEvents">> := true, - <<"variation">> := 1, - <<"version">> := 245}, - <<"prereqs-fail-off-null">> := - #{<<"reason">> := - #{kind := <<"PREREQUISITE_FAILED">>, - prerequisiteKey := <<"keep-it-off">>}, - <<"trackEvents">> := true, - <<"version">> := 2}, - <<"prereqs-fail-variation">> := - #{<<"reason">> := - #{kind := <<"PREREQUISITE_FAILED">>, - prerequisiteKey := <<"keep-it-on">>}, - <<"trackEvents">> := true, - <<"variation">> := 1, - <<"version">> := 245}, - <<"prereqs-success">> := - #{<<"reason">> := #{kind := <<"FALLTHROUGH">>}, - <<"trackEvents">> := true, - <<"variation">> := 1, - <<"version">> := 24}, - <<"roll-me">> := - #{<<"reason">> := #{kind := <<"FALLTHROUGH">>}, - <<"trackEvents">> := true, - <<"variation">> := 4, - <<"version">> := 5}, - <<"roll-me-custom">> := - #{<<"reason">> := #{kind := <<"FALLTHROUGH">>}, - <<"trackEvents">> := true, - <<"variation">> := 0, - <<"version">> := 5}, - <<"roll-me-invalid">> := - #{<<"reason">> := #{kind := <<"FALLTHROUGH">>}, - <<"trackEvents">> := true, - <<"variation">> := 1, - <<"version">> := 5}, - <<"rule-me">> := - #{<<"reason">> := #{kind := <<"FALLTHROUGH">>}, - <<"trackEvents">> := true, - <<"variation">> := 0, - <<"version">> := 5}, - <<"segment-me">> := - #{<<"reason">> := - #{kind := <<"RULE_MATCH">>, - ruleId := - <<"489a185d-caaf-4db9-b192-e09e927d070c">>, - ruleIndex := 1}, - <<"trackEvents">> := true, - <<"variation">> := 1, - <<"version">> := 5}, - <<"target-me">> := - #{<<"reason">> := #{kind := <<"FALLTHROUGH">>}, - <<"trackEvents">> := true, - <<"variation">> := 0, - <<"version">> := 5} - }, - <<"$valid">> := true, - <<"bad-variation">> := null, - <<"experiment-traffic-allocation-v2">> := <<"a">>, - <<"experiment-traffic-allocation-v2-rules">> := <<"a">>, - <<"extra-fields">> := true, - <<"fallthrough-no-rollout-or-variation">> := null, - <<"keep-it-off">> := false, - <<"keep-it-off-null-off-variation">> := null, - <<"keep-it-on">> := true, - <<"keep-it-on-another">> := true, - <<"keep-it-on-two">> := true, - <<"missing-all-fields">> := null, - <<"missing-rollout-for-rule">> := <<"FallthroughValue">>, - <<"missing-some-fields">> := true, - <<"prereqs-fail-off">> := false, - <<"prereqs-fail-off-null">> := null, - <<"prereqs-fail-variation">> := false, - <<"prereqs-success">> := false, - <<"roll-me">> := <<"e">>, - <<"roll-me-custom">> := <<"a">>, - <<"roll-me-invalid">> := <<"b">>, - <<"rule-me">> := <<"a">>, - <<"segment-me">> := false, - <<"target-me">> := true - } = ldclient_eval:all_flags_state(#{key => <<"userKeyA">>, kind => <<"user">>}, #{with_reasons => true}, default). - all_flags_state_offline(_) -> #{ <<"$flagsState">> := #{}, <<"$valid">> := false } = ldclient_eval:all_flags_state(#{key => <<"userKeyA">>, kind => <<"user">>}, #{with_reasons => true}, offline). + all_flags_state_client_side_only(_) -> + #{<<"$flagsState">> := + #{<<"fallthrough-no-rollout-or-variation">> := + #{<<"trackEvents">> := true,<<"version">> := 7243}, + <<"missing-rollout-for-rule">> := + #{<<"trackEvents">> := true,<<"variation">> := 2, + <<"version">> := 4243}, + <<"prereqs-fail-off">> := + #{<<"trackEvents">> := true,<<"variation">> := 1, + <<"version">> := 245}, + <<"prereqs-fail-off-null">> := + #{<<"trackEvents">> := true,<<"version">> := 2}, + <<"prereqs-fail-variation">> := + #{<<"prerequisites">> := [<<"keep-it-on">>], + <<"trackEvents">> := true,<<"variation">> := 1, + <<"version">> := 245}, + <<"prereqs-success">> := + #{<<"prerequisites">> := + [<<"keep-it-on">>,<<"keep-it-on-another">>], + <<"trackEvents">> := true,<<"variation">> := 1, + <<"version">> := 24}}, + <<"$valid">> := true, + <<"fallthrough-no-rollout-or-variation">> := null, + <<"missing-rollout-for-rule">> := <<"FallthroughValue">>, + <<"prereqs-fail-off">> := false, + <<"prereqs-fail-off-null">> := null, + <<"prereqs-fail-variation">> := false, + <<"prereqs-success">> := false} = ldclient_eval:all_flags_state(#{key => <<"userKeyA">>, kind => <<"user">>}, #{with_reasons => false, client_side_only => true}, default). + malformed_clause(_) -> ok = ldclient_update_stream_server:process_event(#{event => <<"put">>, data => <<" { diff --git a/test/ldclient_parse_SUITE.erl b/test/ldclient_parse_SUITE.erl index 73ba2c9..af39ac6 100644 --- a/test/ldclient_parse_SUITE.erl +++ b/test/ldclient_parse_SUITE.erl @@ -22,7 +22,11 @@ parse_segment_full/1, parse_flag_rollout_kind/1, parse_flag_invalid_kind/1, - parse_flag_experiment_kind/1 + parse_flag_experiment_kind/1, + parse_client_side_availability_both_false/1, + parse_client_side_availability_using_environment_id/1, + parse_client_side_availability_using_mobile_key/1, + parse_client_side_availability_both_true/1 ]). %%==================================================================== @@ -42,7 +46,11 @@ all() -> parse_segment_full, parse_flag_rollout_kind, parse_flag_invalid_kind, - parse_flag_experiment_kind + parse_flag_experiment_kind, + parse_client_side_availability_both_false, + parse_client_side_availability_using_environment_id, + parse_client_side_availability_using_mobile_key, + parse_client_side_availability_both_true ]. init_per_suite(Config) -> @@ -92,7 +100,11 @@ parse_flag_empty(_) -> trackEvents => false, trackEventsFallthrough => false, variations => [], - version => 0 + version => 0, + clientSideAvailability => #{ + usingEnvironmentId => false, + usingMobileKey => false + } }, FlagExpected = ldclient_flag:new(FlagRaw). @@ -125,7 +137,11 @@ parse_flag_key_only(_) -> trackEvents => false, trackEventsFallthrough => false, variations => [], - version => 0 + version => 0, + clientSideAvailability => #{ + usingEnvironmentId => false, + usingMobileKey => false + } }, FlagExpected = ldclient_flag:new(FlagRaw). @@ -161,7 +177,11 @@ parse_flag_bare(_) -> trackEvents => true, trackEventsFallthrough => true, variations => [true, false], - version => 10 + version => 10, + clientSideAvailability => #{ + usingEnvironmentId => false, + usingMobileKey => false + } }, FlagExpected = ldclient_flag:new(FlagRaw). @@ -278,7 +298,11 @@ parse_flag_full(_) -> trackEvents => true, trackEventsFallthrough => true, variations => [<<"A">>, <<"B">>, <<"C">>], - version => 9 + version => 9, + clientSideAvailability => #{ + usingEnvironmentId => false, + usingMobileKey => false + } }, FlagExpected = ldclient_flag:new(FlagRaw). @@ -336,7 +360,11 @@ parse_flag_ignore_invalid(_) -> trackEvents => false, trackEventsFallthrough => false, variations => [<<"A">>, <<"B">>, <<"C">>], - version => 0 + version => 0, + clientSideAvailability => #{ + usingEnvironmentId => false, + usingMobileKey => false + } }, FlagExpected = ldclient_flag:new(FlagRaw). @@ -370,7 +398,11 @@ parse_flag_invalid_fallthrough(_) -> trackEvents => false, trackEventsFallthrough => false, variations => [], - version => 0 + version => 0, + clientSideAvailability => #{ + usingEnvironmentId => false, + usingMobileKey => false + } }, FlagExpected = ldclient_flag:new(FlagRaw). @@ -539,7 +571,11 @@ parse_flag_invalid_kind(_) -> trackEvents => false, trackEventsFallthrough => false, variations => [], - version => 9 + version => 9, + clientSideAvailability => #{ + usingEnvironmentId => false, + usingMobileKey => false + } }, FlagExpected = ldclient_flag:new(FlagRaw). @@ -584,7 +620,11 @@ parse_flag_rollout_kind(_) -> trackEvents => false, trackEventsFallthrough => false, variations => [], - version => 9 + version => 9, + clientSideAvailability => #{ + usingEnvironmentId => false, + usingMobileKey => false + } }, FlagExpected = ldclient_flag:new(FlagRaw). @@ -629,6 +669,66 @@ parse_flag_experiment_kind(_) -> trackEvents => false, trackEventsFallthrough => false, variations => [], - version => 9 + version => 9, + clientSideAvailability => #{ + usingEnvironmentId => false, + usingMobileKey => false + } }, FlagExpected = ldclient_flag:new(FlagRaw). + +parse_client_side_availability_both_false(_) -> + BothFalse = #{ + <<"clientSideAvailability">> => #{ + <<"usingEnvironmentId">> => false, + <<"usingMobileKey">> => false + } + }, + #{ + clientSideAvailability := #{ + usingEnvironmentId := false, + usingMobileKey := false + } + } = ldclient_flag:new(BothFalse). + +parse_client_side_availability_using_environment_id(_) -> + UsingEnvironment = #{ + <<"clientSideAvailability">> => #{ + <<"usingEnvironmentId">> => true, + <<"usingMobileKey">> => false + } + }, + #{ + clientSideAvailability := #{ + usingEnvironmentId := true, + usingMobileKey := false + } + } = ldclient_flag:new(UsingEnvironment). + +parse_client_side_availability_using_mobile_key(_) -> + UsingMobileKey = #{ + <<"clientSideAvailability">> => #{ + <<"usingEnvironmentId">> => false, + <<"usingMobileKey">> => true + } + }, + #{ + clientSideAvailability := #{ + usingEnvironmentId := false, + usingMobileKey := true + } + } = ldclient_flag:new(UsingMobileKey). + +parse_client_side_availability_both_true(_) -> + BothTrue = #{ + <<"clientSideAvailability">> => #{ + <<"usingEnvironmentId">> => true, + <<"usingMobileKey">> => true + } + }, + #{ + clientSideAvailability := #{ + usingEnvironmentId := true, + usingMobileKey := true + } + } = ldclient_flag:new(BothTrue).