diff --git a/.editorconfig b/.editorconfig index d6dfc0902..f7323810c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,239 +1,129 @@ -# Remove the line below if you want to inherit .editorconfig settings from higher directories root = true -# C# files -[*.cs] - -#### Core EditorConfig Options #### +############################### +# Core EditorConfig Options # +############################### +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options -# Indentation and spacing +# All files +[*] indent_style = space -# New line preferences -insert_final_newline = true +# XML project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 -#### .NET Coding Conventions #### +# XML config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 +# Code files +[*.{cs,csx,vb,vbx}] +indent_size = 4 +insert_final_newline = true +charset = utf-8-bom +############################### +# .NET Coding Conventions # +############################### +[*.{cs,vb}] # Organize usings -dotnet_separate_import_directive_groups = false -dotnet_sort_system_directives_first = false -file_header_template = unset - -# this. and Me. preferences -dotnet_style_qualification_for_event = false -dotnet_style_qualification_for_field = false -dotnet_style_qualification_for_method = false -dotnet_style_qualification_for_property = false - +dotnet_sort_system_directives_first = true +# this. preferences +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent # Language keywords vs BCL types preferences -dotnet_style_predefined_type_for_locals_parameters_members = true -dotnet_style_predefined_type_for_member_access = true - +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent # Parentheses preferences -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity -dotnet_style_parentheses_in_other_operators = never_if_unnecessary -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity - +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent # Modifier preferences -dotnet_style_require_accessibility_modifiers = for_non_interface_members - +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_readonly_field = true:suggestion # Expression-level preferences -dotnet_style_coalesce_expression = true -dotnet_style_collection_initializer = true -dotnet_style_explicit_tuple_names = true -dotnet_style_namespace_match_folder = true -dotnet_style_null_propagation = true -dotnet_style_object_initializer = true -dotnet_style_operator_placement_when_wrapping = beginning_of_line -dotnet_style_prefer_auto_properties = true -dotnet_style_prefer_compound_assignment = true -dotnet_style_prefer_conditional_expression_over_assignment = true -dotnet_style_prefer_conditional_expression_over_return = true -dotnet_style_prefer_inferred_anonymous_type_member_names = true -dotnet_style_prefer_inferred_tuple_names = true -dotnet_style_prefer_is_null_check_over_reference_equality_method = true -dotnet_style_prefer_simplified_boolean_expressions = true -dotnet_style_prefer_simplified_interpolation = true - -# Field preferences -dotnet_style_readonly_field = true - -# Parameter preferences -dotnet_code_quality_unused_parameters = all - -# Suppression preferences -dotnet_remove_unnecessary_suppression_exclusions = none - -# New line preferences -dotnet_style_allow_multiple_blank_lines_experimental = true -dotnet_style_allow_statement_immediately_after_block_experimental = true - -#### C# Coding Conventions #### - +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +############################### +# Naming Conventions # +############################### +# Style Definitions +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const +############################### +# C# Coding Conventions # +############################### +[*.cs] # var preferences -csharp_style_var_elsewhere = false -csharp_style_var_for_built_in_types = false -csharp_style_var_when_type_is_apparent = false - +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent +csharp_style_var_elsewhere = true:silent # Expression-bodied members -csharp_style_expression_bodied_accessors = true:silent -csharp_style_expression_bodied_constructors = false:silent -csharp_style_expression_bodied_indexers = true:silent -csharp_style_expression_bodied_lambdas = true:silent -csharp_style_expression_bodied_local_functions = false:silent csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent csharp_style_expression_bodied_operators = false:silent csharp_style_expression_bodied_properties = true:silent - +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent # Pattern matching preferences -csharp_style_pattern_matching_over_as_with_null_check = true -csharp_style_pattern_matching_over_is_with_cast_check = true -csharp_style_prefer_extended_property_pattern = true -csharp_style_prefer_not_pattern = true -csharp_style_prefer_pattern_matching = true -csharp_style_prefer_switch_expression = true - +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion # Null-checking preferences -csharp_style_conditional_delegate_call = true - +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion # Modifier preferences -csharp_prefer_static_local_function = true -csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async - -# Code-block preferences -csharp_prefer_braces = true:silent -csharp_prefer_simple_using_statement = true:suggestion -csharp_style_namespace_declarations = block_scoped:silent - +csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async:suggestion # Expression-level preferences +csharp_prefer_braces = true:silent +csharp_style_deconstructed_variable_declaration = true:suggestion csharp_prefer_simple_default_expression = true:suggestion -csharp_style_deconstructed_variable_declaration = true -csharp_style_implicit_object_creation_when_type_is_apparent = true -csharp_style_inlined_variable_declaration = true -csharp_style_prefer_index_operator = true csharp_style_prefer_local_over_anonymous_function = true:suggestion -csharp_style_prefer_null_check_over_type_check = true:suggestion -csharp_style_prefer_range_operator = true -csharp_style_prefer_tuple_swap = true -csharp_style_throw_expression = true:suggestion -csharp_style_unused_value_assignment_preference = discard_variable -csharp_style_unused_value_expression_statement_preference = discard_variable - -# 'using' directive preferences -csharp_using_directive_placement = outside_namespace:silent - +csharp_style_inlined_variable_declaration = true:suggestion +############################### +# C# Formatting Rules # +############################### # New line preferences -csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true -csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true -csharp_style_allow_embedded_statements_on_same_line_experimental = true - -#### C# Formatting Rules #### - -# New line preferences -csharp_new_line_before_catch = true +csharp_new_line_before_open_brace = all csharp_new_line_before_else = true +csharp_new_line_before_catch = true csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = false csharp_new_line_before_members_in_anonymous_types = true -csharp_new_line_before_members_in_object_initializers = true -csharp_new_line_before_open_brace = all csharp_new_line_between_query_expression_clauses = true - # Indentation preferences -csharp_indent_block_contents = true -csharp_indent_braces = false csharp_indent_case_contents = true -csharp_indent_case_contents_when_block = true -csharp_indent_labels = one_less_than_current csharp_indent_switch_labels = true - +csharp_indent_labels = flush_left # Space preferences csharp_space_after_cast = false -csharp_space_after_colon_in_inheritance_clause = true -csharp_space_after_comma = true -csharp_space_after_dot = false csharp_space_after_keywords_in_control_flow_statements = true -csharp_space_after_semicolon_in_for_statement = true -csharp_space_around_binary_operators = before_and_after -csharp_space_around_declaration_statements = false -csharp_space_before_colon_in_inheritance_clause = true -csharp_space_before_comma = false -csharp_space_before_dot = false -csharp_space_before_open_square_brackets = false -csharp_space_before_semicolon_in_for_statement = false -csharp_space_between_empty_square_brackets = false -csharp_space_between_method_call_empty_parameter_list_parentheses = false -csharp_space_between_method_call_name_and_opening_parenthesis = false csharp_space_between_method_call_parameter_list_parentheses = false -csharp_space_between_method_declaration_empty_parameter_list_parentheses = false -csharp_space_between_method_declaration_name_and_open_parenthesis = false csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_parentheses = false -csharp_space_between_square_brackets = false - +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false # Wrapping preferences -csharp_preserve_single_line_blocks = true csharp_preserve_single_line_statements = true - -#### Naming styles #### - -# Naming rules - -dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion -dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface -dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i - -dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.types_should_be_pascal_case.symbols = types -dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case - -dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members -dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case - -# Symbol specifications - -dotnet_naming_symbols.interface.applicable_kinds = interface -dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.interface.required_modifiers = - -dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum -dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.types.required_modifiers = - -dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method -dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.non_field_members.required_modifiers = - -# Naming styles - -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = -dotnet_naming_style.pascal_case.capitalization = pascal_case - -dotnet_naming_style.begins_with_i.required_prefix = I -dotnet_naming_style.begins_with_i.required_suffix = -dotnet_naming_style.begins_with_i.word_separator = -dotnet_naming_style.begins_with_i.capitalization = pascal_case - -[*.{cs,vb}] -dotnet_style_operator_placement_when_wrapping = beginning_of_line -tab_width = 4 -indent_size = 4 -end_of_line = lf -dotnet_style_coalesce_expression = true:suggestion -dotnet_style_null_propagation = true:suggestion -dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion -dotnet_style_prefer_auto_properties = true:silent -dotnet_style_object_initializer = true:suggestion -dotnet_style_collection_initializer = true:suggestion -dotnet_style_prefer_simplified_boolean_expressions = true:suggestion -dotnet_style_prefer_conditional_expression_over_assignment = true:silent -dotnet_style_prefer_conditional_expression_over_return = true:silent -dotnet_style_explicit_tuple_names = true:suggestion -dotnet_style_prefer_inferred_tuple_names = true:suggestion -dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion -dotnet_style_prefer_compound_assignment = true:suggestion -dotnet_style_prefer_simplified_interpolation = true:suggestion -dotnet_style_namespace_match_folder = true:suggestion +csharp_preserve_single_line_blocks = true diff --git a/OptimizelySDK.Tests/App.config b/OptimizelySDK.Tests/App.config index 3c9414802..14d4908f4 100644 --- a/OptimizelySDK.Tests/App.config +++ b/OptimizelySDK.Tests/App.config @@ -5,44 +5,47 @@ --> - -
- - - - - - + +
+ + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/OptimizelySDK.Tests/Assertions.cs b/OptimizelySDK.Tests/Assertions.cs index 3f95e42b2..9dfe2f7ba 100644 --- a/OptimizelySDK.Tests/Assertions.cs +++ b/OptimizelySDK.Tests/Assertions.cs @@ -14,16 +14,16 @@ * limitations under the License. */ -using NUnit.Framework; -using OptimizelySDK.Entity; -using OptimizelySDK.OptimizelyDecisions; -using OptimizelySDK.OptlyConfig; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading.Tasks; +using NUnit.Framework; +using OptimizelySDK.Entity; +using OptimizelySDK.OptimizelyDecisions; +using OptimizelySDK.OptlyConfig; namespace OptimizelySDK.Tests { @@ -36,10 +36,14 @@ public class Assertions { #region Basic asserts - public static bool HasItems(IEnumerable expected, IEnumerable actual, bool allowNull = true) + public static bool HasItems(IEnumerable expected, IEnumerable actual, + bool allowNull = true + ) { if (allowNull && expected == null && actual == null) + { return false; + } Assert.AreEqual(expected.Count(), actual.Count()); @@ -51,40 +55,50 @@ public static void AreEquivalent(IEnumerable expected, IEnumerable - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { Assert.AreEqual(z.Expected, z.Actual); - }; + } + + ; } } - public static void AreEquivalent(Dictionary expected, Dictionary actual) + public static void AreEquivalent(Dictionary expected, + Dictionary actual + ) { Assert.AreEqual(expected.Count, actual.Count); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEqual(z.Expected, z.Actual); - }; + } + + ; } - public static void AreEqual(KeyValuePair expected, KeyValuePair actual) + public static void AreEqual(KeyValuePair expected, + KeyValuePair actual + ) { Assert.AreEqual(expected.Key, actual.Key); Assert.AreEqual(expected.Value, actual.Value); @@ -95,7 +109,9 @@ public static void AreEqual(OptimizelyJSON expected, OptimizelyJSON actual) Assert.AreEqual(expected.ToString(), actual.ToString()); } - private static void AreEquivalent(KeyValuePair expected, KeyValuePair actual) + private static void AreEquivalent(KeyValuePair expected, + KeyValuePair actual + ) { Assert.AreEqual(expected.Key, actual.Key); Assert.AreEqual(expected.Value, actual.Value); @@ -105,7 +121,9 @@ private static void AreEquivalent(KeyValuePair expected, KeyValu #region - public static void AreEqual(OptimizelyForcedDecision expected, OptimizelyForcedDecision actual) + public static void AreEqual(OptimizelyForcedDecision expected, + OptimizelyForcedDecision actual + ) { Assert.AreEqual(expected.VariationKey, actual.VariationKey); } @@ -114,22 +132,27 @@ public static void AreEqual(OptimizelyForcedDecision expected, OptimizelyForcedD #region OptimizelyAttribute - public static void AreEquivalent(OptimizelyAttribute[] expected, OptimizelyAttribute[] actual) + public static void AreEquivalent(OptimizelyAttribute[] expected, + OptimizelyAttribute[] actual + ) { Assert.AreEqual(expected.Count(), actual.Count()); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEqual(z.Expected, z.Actual); - }; + } + + ; } public static void AreEqual(OptimizelyAttribute expected, OptimizelyAttribute actual) @@ -142,22 +165,26 @@ public static void AreEqual(OptimizelyAttribute expected, OptimizelyAttribute ac #region OptimizelyAudience - private static void AreEquivalent(OptimizelyAudience[] expected, OptimizelyAudience[] actual) + private static void AreEquivalent(OptimizelyAudience[] expected, OptimizelyAudience[] actual + ) { Assert.AreEqual(expected.Count(), actual.Count()); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEqual(z.Expected, z.Actual); - }; + } + + ; } private static void AreEqual(OptimizelyAudience expected, OptimizelyAudience actual) @@ -197,18 +224,21 @@ private static void AreEquivalent(UserAttributes expected, UserAttributes actual { Assert.AreEqual(expected.Count, actual.Count); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEquivalent(z.Expected, z.Actual); - }; + } + + ; } #endregion @@ -219,18 +249,21 @@ public static void AreEquivalent(OptimizelyEvent[] expected, OptimizelyEvent[] a { Assert.AreEqual(expected.Count(), actual.Count()); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEqual(z.Expected, z.Actual); - }; + } + + ; } private static void AreEqual(OptimizelyEvent expected, OptimizelyEvent actual) @@ -254,25 +287,32 @@ public static void AreEqual(OptimizelyDecision expected, OptimizelyDecision actu Assert.AreEqual(expected.VariationKey, actual.VariationKey); } - public static void AreEquivalent(IDictionary expected, IDictionary actual) + public static void AreEquivalent(IDictionary expected, + IDictionary actual + ) { Assert.AreEqual(expected.Count, actual.Count); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEquivalent(z.Expected, z.Actual); - }; + } + + ; } - public static void AreEquivalent(KeyValuePair expected, KeyValuePair actual) + public static void AreEquivalent(KeyValuePair expected, + KeyValuePair actual + ) { Assert.AreEqual(expected.Key, actual.Key); AreEqual(expected.Value, actual.Value); @@ -282,22 +322,27 @@ public static void AreEquivalent(KeyValuePair expect #region OptimizelyExperiement - public static void AreEquivalent(List expected, List actual) + public static void AreEquivalent(List expected, + List actual + ) { Assert.AreEqual(expected.Count, actual.Count); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEqual(z.Expected, z.Actual); - }; + } + + ; } public static void AreEqual(OptimizelyExperiment expected, OptimizelyExperiment actual) @@ -307,25 +352,32 @@ public static void AreEqual(OptimizelyExperiment expected, OptimizelyExperiment Assert.AreEqual(expected.Audiences, actual.Audiences); } - public static void AreEquivalent(IDictionary expected, IDictionary actual) + public static void AreEquivalent(IDictionary expected, + IDictionary actual + ) { Assert.AreEqual(expected.Count, actual.Count); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEquivalent(z.Expected, z.Actual); - }; + } + + ; } - public static void AreEquivalent(KeyValuePair expected, KeyValuePair actual) + public static void AreEquivalent(KeyValuePair expected, + KeyValuePair actual + ) { Assert.AreEqual(expected.Key, actual.Key); AreEqual(expected.Value, actual.Value); @@ -335,30 +387,38 @@ public static void AreEquivalent(KeyValuePair expe #region OptimizelyFeature - public static void AreEquivalent(IDictionary expected, IDictionary actual) + public static void AreEquivalent(IDictionary expected, + IDictionary actual + ) { Assert.AreEqual(expected.Count, actual.Count); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEquivalent(z.Expected, z.Actual); - }; + } + + ; } - public static void AreEquivalent(KeyValuePair expected, KeyValuePair actual) + public static void AreEquivalent(KeyValuePair expected, + KeyValuePair actual + ) { Assert.AreEqual(expected.Key, actual.Key); AreEqual(expected.Value, actual.Value); } + [Obsolete] public static void AreEqual(OptimizelyFeature expected, OptimizelyFeature actual) { AreEquivalent(expected.DeliveryRules, actual.DeliveryRules); @@ -373,25 +433,32 @@ public static void AreEqual(OptimizelyFeature expected, OptimizelyFeature actual #region OptimizelyVariable - public static void AreEquivalent(IDictionary expected, IDictionary actual) + public static void AreEquivalent(IDictionary expected, + IDictionary actual + ) { Assert.AreEqual(expected.Count, actual.Count); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEquivalent(z.Expected, z.Actual); - }; + } + + ; } - public static void AreEquivalent(KeyValuePair expected, KeyValuePair actual) + public static void AreEquivalent(KeyValuePair expected, + KeyValuePair actual + ) { Assert.AreEqual(expected.Key, actual.Key); AreEqual(expected.Value, actual.Value); @@ -446,17 +513,20 @@ public static void AreEqual(FeatureDecision expected, FeatureDecision actual) #region FeatureFlags - public static void AreEquivalent(Dictionary expected, Dictionary actual) + public static void AreEquivalent(Dictionary expected, + Dictionary actual + ) { Assert.AreEqual(expected.Count, actual.Count); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { @@ -464,7 +534,9 @@ public static void AreEquivalent(Dictionary expected, Dicti } } - public static void AreEqual(KeyValuePair expected, KeyValuePair actual) + public static void AreEqual(KeyValuePair expected, + KeyValuePair actual + ) { Assert.AreEqual(expected.Key, actual.Key); AreEqual(expected.Value, actual.Value); @@ -475,7 +547,8 @@ public static void AreEqual(FeatureFlag expected, FeatureFlag actual) Assert.AreEqual(expected.Id, actual.Id); Assert.AreEqual(expected.Key, actual.Key); Assert.AreEqual(expected.RolloutId, actual.RolloutId); - AreEquivalent(expected.VariableKeyToFeatureVariableMap, actual.VariableKeyToFeatureVariableMap); + AreEquivalent(expected.VariableKeyToFeatureVariableMap, + actual.VariableKeyToFeatureVariableMap); } #endregion FeatureFlags @@ -492,17 +565,20 @@ public static void AreEqual(FeatureVariable expected, FeatureVariable actual) Assert.AreEqual(expected.Type, actual.Type); } - public static void AreEquivalent(Dictionary expected, Dictionary actual) + public static void AreEquivalent(Dictionary expected, + Dictionary actual + ) { Assert.AreEqual(expected.Count, actual.Count); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { @@ -510,7 +586,9 @@ public static void AreEquivalent(Dictionary expected, D } } - public static void AreEquivalent(KeyValuePair expected, KeyValuePair actual) + public static void AreEquivalent(KeyValuePair expected, + KeyValuePair actual + ) { Assert.AreEqual(expected.Key, actual.Key); AreEqual(expected.Value, actual.Value); @@ -526,121 +604,154 @@ public static void AreEqual(Variation expected, Variation actual) Assert.AreEqual(expected.Key, actual.Key); Assert.AreEqual(expected.FeatureEnabled, actual.FeatureEnabled); - AreEquivalent(expected.FeatureVariableUsageInstances, actual.FeatureVariableUsageInstances); - AreEquivalent(expected.VariableIdToVariableUsageInstanceMap, actual.VariableIdToVariableUsageInstanceMap); + AreEquivalent(expected.FeatureVariableUsageInstances, + actual.FeatureVariableUsageInstances); + AreEquivalent(expected.VariableIdToVariableUsageInstanceMap, + actual.VariableIdToVariableUsageInstanceMap); } - public static void AreEquivalent(Dictionary expected, Dictionary actual) + public static void AreEquivalent(Dictionary expected, + Dictionary actual + ) { Assert.AreEqual(expected.Count, actual.Count); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEqual(z.Expected, z.Actual); - }; + } + + ; } - public static void AreEquivalent(List>> expected, List>> actual) + public static void AreEquivalent(List>> expected, + List>> actual + ) { Assert.AreEqual(expected.Count, actual.Count); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEquivalent(z.Expected, z.Actual); - }; + } + + ; } - public static void AreEquivalent(IDictionary> expected, IDictionary> actual) + public static void AreEquivalent(IDictionary> expected, + IDictionary> actual + ) { Assert.AreEqual(expected.Count, actual.Count); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { AreEqual(z.Expected, z.Actual); - }; + } + + ; } - public static void AreEqual(KeyValuePair expected, KeyValuePair actual) + public static void AreEqual(KeyValuePair expected, + KeyValuePair actual + ) { Assert.AreEqual(expected.Key, actual.Key); AreEqual(expected.Value, actual.Value); } - public static void AreEqual(KeyValuePair> expected, KeyValuePair> actual) + public static void AreEqual(KeyValuePair> expected, + KeyValuePair> actual + ) { Assert.AreEqual(expected.Key, actual.Key); AreEquivalent(expected.Value, actual.Value); } - public static void AreEquivalent(KeyValuePair> expected, KeyValuePair> actual) + public static void AreEquivalent(KeyValuePair> expected, + KeyValuePair> actual + ) { Assert.AreEqual(expected.Key, actual.Key); AreEquivalent(expected.Value, actual.Value); } - public static void AreEquivalent(IEnumerable expected, IEnumerable actual) + public static void AreEquivalent(IEnumerable expected, + IEnumerable actual + ) { Assert.AreEqual(expected.Count(), actual.Count()); expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList().ForEach((item) => - { - AreEqual(item.Expected, item.Actual); - }); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(). + ForEach((item) => + { + AreEqual(item.Expected, item.Actual); + }); } #endregion Variations #region FeatureVariableUsage - public static void AreEquivalent(IEnumerable expected, IEnumerable actual) + public static void AreEquivalent(IEnumerable expected, + IEnumerable actual + ) { if (HasItems(expected, actual)) { expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList().ForEach((item) => - { - AreEqual(item.Expected, item.Actual); - }); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(). + ForEach((item) => + { + AreEqual(item.Expected, item.Actual); + }); } } - public static void AreEquivalent(Dictionary expected, Dictionary actual) + public static void AreEquivalent(Dictionary expected, + Dictionary actual + ) { if (expected == null && actual == null) { @@ -649,19 +760,23 @@ public static void AreEquivalent(Dictionary expect Assert.AreEqual(expected.Count(), actual.Count()); expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList().ForEach((item) => - { - AreEquivalent(item.Expected, item.Actual); - }); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(). + ForEach((item) => + { + AreEquivalent(item.Expected, item.Actual); + }); } - public static void AreEquivalent(KeyValuePair expected, KeyValuePair actual) + public static void AreEquivalent(KeyValuePair expected, + KeyValuePair actual + ) { Assert.AreEqual(expected.Key, actual.Key); AreEqual(expected.Value, actual.Value); @@ -677,22 +792,27 @@ public static void AreEqual(FeatureVariableUsage expected, FeatureVariableUsage #region TrafficAllocation - public static void AreEquivalent(IEnumerable expected, IEnumerable actual) + public static void AreEquivalent(IEnumerable expected, + IEnumerable actual + ) { Assert.AreEqual(expected.Count(), actual.Count()); var zipped = expected.Zip(actual, (e, a) => - { - return new { - Expected = e, - Actual = a - }; - }).ToList(); + return new + { + Expected = e, + Actual = a, + }; + }). + ToList(); foreach (var z in zipped) { Assert.AreEqual(z.Expected, z.Actual); - }; + } + + ; } public static void AreEqual(TrafficAllocation expected, TrafficAllocation actual) diff --git a/OptimizelySDK.Tests/AudienceConditionsTests/ConditionEvaluationTest.cs b/OptimizelySDK.Tests/AudienceConditionsTests/ConditionEvaluationTest.cs index 9d84e4b42..3b7d92426 100644 --- a/OptimizelySDK.Tests/AudienceConditionsTests/ConditionEvaluationTest.cs +++ b/OptimizelySDK.Tests/AudienceConditionsTests/ConditionEvaluationTest.cs @@ -14,37 +14,87 @@ * limitations under the License. */ +using System; +using System.Collections.Generic; using Moq; using NUnit.Framework; using OptimizelySDK.AudienceConditions; using OptimizelySDK.Entity; using OptimizelySDK.Logger; using OptimizelySDK.Tests.Utils; -using System; -using System.Collections.Generic; namespace OptimizelySDK.Tests.AudienceConditionsTests { [TestFixture] public class ConditionEvaluationTest { - private BaseCondition LegacyCondition = new BaseCondition { Name = "device_type", Value = "iPhone", Type = "custom_attribute" }; - private BaseCondition ExistsCondition = new BaseCondition { Name = "input_value", Match = "exists", Type = "custom_attribute" }; - private BaseCondition SubstrCondition = new BaseCondition { Name = "location", Value = "USA", Match = "substring", Type = "custom_attribute" }; - private BaseCondition GTCondition = new BaseCondition { Name = "distance_gt", Value = 10, Match = "gt", Type = "custom_attribute" }; - private BaseCondition GECondition = new BaseCondition { Name = "distance_ge", Value = 10, Match = "ge", Type = "custom_attribute" }; - private BaseCondition LTCondition = new BaseCondition { Name = "distance_lt", Value = 10, Match = "lt", Type = "custom_attribute" }; - private BaseCondition LECondition = new BaseCondition { Name = "distance_le", Value = 10, Match = "le", Type = "custom_attribute" }; - private BaseCondition ExactStrCondition = new BaseCondition { Name = "browser_type", Value = "firefox", Match = "exact", Type = "custom_attribute" }; - private BaseCondition ExactBoolCondition = new BaseCondition { Name = "is_registered_user", Value = false, Match = "exact", Type = "custom_attribute" }; - private BaseCondition ExactDecimalCondition = new BaseCondition { Name = "pi_value", Value = 3.14, Match = "exact", Type = "custom_attribute" }; - private BaseCondition ExactIntCondition = new BaseCondition { Name = "lasers_count", Value = 9000, Match = "exact", Type = "custom_attribute" }; - private BaseCondition InfinityIntCondition = new BaseCondition { Name = "max_num_value", Value = 9223372036854775807, Match = "exact", Type = "custom_attribute" }; - private BaseCondition SemVerLTCondition = new BaseCondition { Name = "semversion_lt", Value = "3.7.1", Match = "semver_lt", Type = "custom_attribute" }; - private BaseCondition SemVerGTCondition = new BaseCondition { Name = "semversion_gt", Value = "3.7.1", Match = "semver_gt", Type = "custom_attribute" }; - private BaseCondition SemVerEQCondition = new BaseCondition { Name = "semversion_eq", Value = "3.7.1", Match = "semver_eq", Type = "custom_attribute" }; - private BaseCondition SemVerGECondition = new BaseCondition { Name = "semversion_ge", Value = "3.7.1", Match = "semver_ge", Type = "custom_attribute" }; - private BaseCondition SemVerLECondition = new BaseCondition { Name = "semversion_le", Value = "3.7.1", Match = "semver_le", Type = "custom_attribute" }; + private BaseCondition LegacyCondition = new BaseCondition + { Name = "device_type", Value = "iPhone", Type = "custom_attribute" }; + + private BaseCondition ExistsCondition = new BaseCondition + { Name = "input_value", Match = "exists", Type = "custom_attribute" }; + + private BaseCondition SubstrCondition = new BaseCondition + { Name = "location", Value = "USA", Match = "substring", Type = "custom_attribute" }; + + private BaseCondition GTCondition = new BaseCondition + { Name = "distance_gt", Value = 10, Match = "gt", Type = "custom_attribute" }; + + private BaseCondition GECondition = new BaseCondition + { Name = "distance_ge", Value = 10, Match = "ge", Type = "custom_attribute" }; + + private BaseCondition LTCondition = new BaseCondition + { Name = "distance_lt", Value = 10, Match = "lt", Type = "custom_attribute" }; + + private BaseCondition LECondition = new BaseCondition + { Name = "distance_le", Value = 10, Match = "le", Type = "custom_attribute" }; + + private BaseCondition ExactStrCondition = new BaseCondition + { + Name = "browser_type", Value = "firefox", Match = "exact", Type = "custom_attribute", + }; + + private BaseCondition ExactBoolCondition = new BaseCondition + { + Name = "is_registered_user", Value = false, Match = "exact", Type = "custom_attribute", + }; + + private BaseCondition ExactDecimalCondition = new BaseCondition + { Name = "pi_value", Value = 3.14, Match = "exact", Type = "custom_attribute" }; + + private BaseCondition ExactIntCondition = new BaseCondition + { Name = "lasers_count", Value = 9000, Match = "exact", Type = "custom_attribute" }; + + private BaseCondition InfinityIntCondition = new BaseCondition + { + Name = "max_num_value", Value = 9223372036854775807, Match = "exact", + Type = "custom_attribute", + }; + + private BaseCondition SemVerLTCondition = new BaseCondition + { + Name = "semversion_lt", Value = "3.7.1", Match = "semver_lt", Type = "custom_attribute", + }; + + private BaseCondition SemVerGTCondition = new BaseCondition + { + Name = "semversion_gt", Value = "3.7.1", Match = "semver_gt", Type = "custom_attribute", + }; + + private BaseCondition SemVerEQCondition = new BaseCondition + { + Name = "semversion_eq", Value = "3.7.1", Match = "semver_eq", Type = "custom_attribute", + }; + + private BaseCondition SemVerGECondition = new BaseCondition + { + Name = "semversion_ge", Value = "3.7.1", Match = "semver_ge", Type = "custom_attribute", + }; + + private BaseCondition SemVerLECondition = new BaseCondition + { + Name = "semversion_le", Value = "3.7.1", Match = "semver_le", Type = "custom_attribute", + }; private ILogger Logger; private Mock LoggerMock; @@ -64,121 +114,263 @@ public void TestEvaluateWithDifferentTypedAttributes() { var userAttributes = new UserAttributes { - {"browser_type", "firefox" }, - {"is_registered_user", false }, - {"distance_gt", 15 }, - {"pi_value", 3.14 }, + { "browser_type", "firefox" }, + { "is_registered_user", false }, + { "distance_gt", 15 }, + { "pi_value", 3.14 }, }; - Assert.That(ExactStrCondition.Evaluate(null, userAttributes.ToUserContext(), Logger), Is.True); - Assert.That(ExactBoolCondition.Evaluate(null, userAttributes.ToUserContext(), Logger), Is.True); - Assert.That(GTCondition.Evaluate(null, userAttributes.ToUserContext(), Logger), Is.True); - Assert.That(ExactDecimalCondition.Evaluate(null, userAttributes.ToUserContext(), Logger), Is.True); + Assert.That(ExactStrCondition.Evaluate(null, userAttributes.ToUserContext(), Logger), + Is.True); + Assert.That(ExactBoolCondition.Evaluate(null, userAttributes.ToUserContext(), Logger), + Is.True); + Assert.That(GTCondition.Evaluate(null, userAttributes.ToUserContext(), Logger), + Is.True); + Assert.That( + ExactDecimalCondition.Evaluate(null, userAttributes.ToUserContext(), Logger), + Is.True); } [Test] public void TestEvaluateWithNoMatchType() { - Assert.That(LegacyCondition.Evaluate(null, new UserAttributes { { "device_type", "iPhone" } }.ToUserContext(), Logger), Is.True); + Assert.That( + LegacyCondition.Evaluate(null, + new UserAttributes { { "device_type", "iPhone" } }.ToUserContext(), Logger), + Is.True); // Assumes exact evaluator if no match type is provided. - Assert.That(LegacyCondition.Evaluate(null, new UserAttributes { { "device_type", "IPhone" } }.ToUserContext(), Logger), Is.False); + Assert.That( + LegacyCondition.Evaluate(null, + new UserAttributes { { "device_type", "IPhone" } }.ToUserContext(), Logger), + Is.False); } [Test] public void TestEvaluateWithInvalidTypeProperty() { - BaseCondition condition = new BaseCondition { Name = "input_value", Value = "Android", Match = "exists", Type = "invalid_type" }; - Assert.That(condition.Evaluate(null, new UserAttributes { { "device_type", "iPhone" } }.ToUserContext(), Logger), Is.Null); + var condition = new BaseCondition + { + Name = "input_value", Value = "Android", Match = "exists", Type = "invalid_type", + }; + Assert.That( + condition.Evaluate(null, + new UserAttributes { { "device_type", "iPhone" } }.ToUserContext(), Logger), + Is.Null); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, $@"Audience condition ""{condition}"" uses an unknown condition type. You may need to upgrade to a newer release of the Optimizely SDK."), Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + $@"Audience condition ""{condition + }"" uses an unknown condition type. You may need to upgrade to a newer release of the Optimizely SDK."), + Times.Once); } [Test] public void TestEvaluateWithMissingTypeProperty() { - var condition = new BaseCondition { Name = "input_value", Value = "Android", Match = "exists" }; - Assert.That(condition.Evaluate(null, new UserAttributes { { "device_type", "iPhone" } }.ToUserContext(), Logger), Is.Null); + var condition = new BaseCondition + { Name = "input_value", Value = "Android", Match = "exists" }; + Assert.That( + condition.Evaluate(null, + new UserAttributes { { "device_type", "iPhone" } }.ToUserContext(), Logger), + Is.Null); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, $@"Audience condition ""{condition}"" uses an unknown condition type. You may need to upgrade to a newer release of the Optimizely SDK."), Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + $@"Audience condition ""{condition + }"" uses an unknown condition type. You may need to upgrade to a newer release of the Optimizely SDK."), + Times.Once); } [Test] public void TestEvaluateWithInvalidMatchProperty() { - BaseCondition condition = new BaseCondition { Name = "device_type", Value = "Android", Match = "invalid_match", Type = "custom_attribute" }; - Assert.That(condition.Evaluate(null, new UserAttributes { { "device_type", "Android" } }.ToUserContext(), Logger), Is.Null); - - LoggerMock.Verify(l => l.Log(LogLevel.WARN, $@"Audience condition ""{condition}"" uses an unknown match type. You may need to upgrade to a newer release of the Optimizely SDK."), Times.Once); - } - - [Test] - public void TestEvaluateLogsWarningAndReturnNullWhenAttributeIsNotProvidedAndConditionTypeIsNotExists() - { - Assert.That(ExactBoolCondition.Evaluate(null, new UserAttributes { }.ToUserContext(), Logger), Is.Null); - Assert.That(SubstrCondition.Evaluate(null, new UserAttributes { }.ToUserContext(), Logger), Is.Null); - Assert.That(LTCondition.Evaluate(null, new UserAttributes { }.ToUserContext(), Logger), Is.Null); - Assert.That(GTCondition.Evaluate(null, new UserAttributes { }.ToUserContext(), Logger), Is.Null); - - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""is_registered_user"",""value"":false} evaluated to UNKNOWN because no value was passed for user attribute ""is_registered_user""."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, @"Audience condition {""type"":""custom_attribute"",""match"":""substring"",""name"":""location"",""value"":""USA""} evaluated to UNKNOWN because no value was passed for user attribute ""location""."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, @"Audience condition {""type"":""custom_attribute"",""match"":""lt"",""name"":""distance_lt"",""value"":10} evaluated to UNKNOWN because no value was passed for user attribute ""distance_lt""."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, @"Audience condition {""type"":""custom_attribute"",""match"":""gt"",""name"":""distance_gt"",""value"":10} evaluated to UNKNOWN because no value was passed for user attribute ""distance_gt""."), Times.Once); - } - - [Test] - public void TestEvaluateLogsAndReturnNullWhenAttributeValueIsNullAndConditionTypeIsNotExists() - { - Assert.That(ExactBoolCondition.Evaluate(null, new UserAttributes { { "is_registered_user", null } }.ToUserContext(), Logger), Is.Null); - Assert.That(SubstrCondition.Evaluate(null, new UserAttributes { { "location", null } }.ToUserContext(), Logger), Is.Null); - Assert.That(LTCondition.Evaluate(null, new UserAttributes { { "distance_lt", null } }.ToUserContext(), Logger), Is.Null); - Assert.That(GTCondition.Evaluate(null, new UserAttributes { { "distance_gt", null } }.ToUserContext(), Logger), Is.Null); - - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""is_registered_user"",""value"":false} evaluated to UNKNOWN because a null value was passed for user attribute ""is_registered_user""."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, @"Audience condition {""type"":""custom_attribute"",""match"":""substring"",""name"":""location"",""value"":""USA""} evaluated to UNKNOWN because a null value was passed for user attribute ""location""."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, @"Audience condition {""type"":""custom_attribute"",""match"":""lt"",""name"":""distance_lt"",""value"":10} evaluated to UNKNOWN because a null value was passed for user attribute ""distance_lt""."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, @"Audience condition {""type"":""custom_attribute"",""match"":""gt"",""name"":""distance_gt"",""value"":10} evaluated to UNKNOWN because a null value was passed for user attribute ""distance_gt""."), Times.Once); - } - - [Test] - public void TestEvaluateReturnsFalseAndDoesNotLogForExistsConditionWhenAttributeIsNotProvided() - { - Assert.That(ExistsCondition.Evaluate(null, new UserAttributes().ToUserContext(), Logger), Is.False); + var condition = new BaseCondition + { + Name = "device_type", Value = "Android", Match = "invalid_match", + Type = "custom_attribute", + }; + Assert.That( + condition.Evaluate(null, + new UserAttributes { { "device_type", "Android" } }.ToUserContext(), Logger), + Is.Null); + + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + $@"Audience condition ""{condition + }"" uses an unknown match type. You may need to upgrade to a newer release of the Optimizely SDK."), + Times.Once); + } + + [Test] + public void + TestEvaluateLogsWarningAndReturnNullWhenAttributeIsNotProvidedAndConditionTypeIsNotExists() + { + Assert.That( + ExactBoolCondition.Evaluate(null, new UserAttributes { }.ToUserContext(), Logger), + Is.Null); + Assert.That( + SubstrCondition.Evaluate(null, new UserAttributes { }.ToUserContext(), Logger), + Is.Null); + Assert.That(LTCondition.Evaluate(null, new UserAttributes { }.ToUserContext(), Logger), + Is.Null); + Assert.That(GTCondition.Evaluate(null, new UserAttributes { }.ToUserContext(), Logger), + Is.Null); + + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""is_registered_user"",""value"":false} evaluated to UNKNOWN because no value was passed for user attribute ""is_registered_user""."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + @"Audience condition {""type"":""custom_attribute"",""match"":""substring"",""name"":""location"",""value"":""USA""} evaluated to UNKNOWN because no value was passed for user attribute ""location""."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + @"Audience condition {""type"":""custom_attribute"",""match"":""lt"",""name"":""distance_lt"",""value"":10} evaluated to UNKNOWN because no value was passed for user attribute ""distance_lt""."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + @"Audience condition {""type"":""custom_attribute"",""match"":""gt"",""name"":""distance_gt"",""value"":10} evaluated to UNKNOWN because no value was passed for user attribute ""distance_gt""."), + Times.Once); + } + + [Test] + public void + TestEvaluateLogsAndReturnNullWhenAttributeValueIsNullAndConditionTypeIsNotExists() + { + Assert.That( + ExactBoolCondition.Evaluate(null, + new UserAttributes { { "is_registered_user", null } }.ToUserContext(), Logger), + Is.Null); + Assert.That( + SubstrCondition.Evaluate(null, + new UserAttributes { { "location", null } }.ToUserContext(), Logger), Is.Null); + Assert.That( + LTCondition.Evaluate(null, + new UserAttributes { { "distance_lt", null } }.ToUserContext(), Logger), + Is.Null); + Assert.That( + GTCondition.Evaluate(null, + new UserAttributes { { "distance_gt", null } }.ToUserContext(), Logger), + Is.Null); + + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""is_registered_user"",""value"":false} evaluated to UNKNOWN because a null value was passed for user attribute ""is_registered_user""."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + @"Audience condition {""type"":""custom_attribute"",""match"":""substring"",""name"":""location"",""value"":""USA""} evaluated to UNKNOWN because a null value was passed for user attribute ""location""."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + @"Audience condition {""type"":""custom_attribute"",""match"":""lt"",""name"":""distance_lt"",""value"":10} evaluated to UNKNOWN because a null value was passed for user attribute ""distance_lt""."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + @"Audience condition {""type"":""custom_attribute"",""match"":""gt"",""name"":""distance_gt"",""value"":10} evaluated to UNKNOWN because a null value was passed for user attribute ""distance_gt""."), + Times.Once); + } + + [Test] + public void + TestEvaluateReturnsFalseAndDoesNotLogForExistsConditionWhenAttributeIsNotProvided() + { + Assert.That( + ExistsCondition.Evaluate(null, new UserAttributes().ToUserContext(), Logger), + Is.False); LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), Times.Never); } [Test] public void TestEvaluateLogsWarningAndReturnNullWhenAttributeTypeIsInvalid() { - Assert.That(ExactBoolCondition.Evaluate(null, new UserAttributes { { "is_registered_user", 5 } }.ToUserContext(), Logger), Is.Null); - Assert.That(SubstrCondition.Evaluate(null, new UserAttributes { { "location", false } }.ToUserContext(), Logger), Is.Null); - Assert.That(LTCondition.Evaluate(null, new UserAttributes { { "distance_lt", "invalid" } }.ToUserContext(), Logger), Is.Null); - Assert.That(GTCondition.Evaluate(null, new UserAttributes { { "distance_gt", true } }.ToUserContext(), Logger), Is.Null); - - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""is_registered_user"",""value"":false} evaluated to UNKNOWN because a value of type ""Int32"" was passed for user attribute ""is_registered_user""."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""substring"",""name"":""location"",""value"":""USA""} evaluated to UNKNOWN because a value of type ""Boolean"" was passed for user attribute ""location""."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""lt"",""name"":""distance_lt"",""value"":10} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""distance_lt""."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""gt"",""name"":""distance_gt"",""value"":10} evaluated to UNKNOWN because a value of type ""Boolean"" was passed for user attribute ""distance_gt""."), Times.Once); + Assert.That( + ExactBoolCondition.Evaluate(null, + new UserAttributes { { "is_registered_user", 5 } }.ToUserContext(), Logger), + Is.Null); + Assert.That( + SubstrCondition.Evaluate(null, + new UserAttributes { { "location", false } }.ToUserContext(), Logger), Is.Null); + Assert.That( + LTCondition.Evaluate(null, + new UserAttributes { { "distance_lt", "invalid" } }.ToUserContext(), Logger), + Is.Null); + Assert.That( + GTCondition.Evaluate(null, + new UserAttributes { { "distance_gt", true } }.ToUserContext(), Logger), + Is.Null); + + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""is_registered_user"",""value"":false} evaluated to UNKNOWN because a value of type ""Int32"" was passed for user attribute ""is_registered_user""."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""substring"",""name"":""location"",""value"":""USA""} evaluated to UNKNOWN because a value of type ""Boolean"" was passed for user attribute ""location""."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""lt"",""name"":""distance_lt"",""value"":10} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""distance_lt""."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""gt"",""name"":""distance_gt"",""value"":10} evaluated to UNKNOWN because a value of type ""Boolean"" was passed for user attribute ""distance_gt""."), + Times.Once); } [Test] public void TestEvaluateLogsWarningAndReturnNullWhenConditionTypeIsInvalid() { - var invalidCondition = new BaseCondition { Name = "is_registered_user", Value = new string[] { }, Match = "exact", Type = "custom_attribute" }; - Assert.That(invalidCondition.Evaluate(null, new UserAttributes { { "is_registered_user", true } }.ToUserContext(), Logger), Is.Null); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""is_registered_user"",""value"":[]} has an unsupported condition value. You may need to upgrade to a newer release of the Optimizely SDK."), Times.Once); - - invalidCondition = new BaseCondition { Name = "location", Value = 25, Match = "substring", Type = "custom_attribute" }; - Assert.That(invalidCondition.Evaluate(null, new UserAttributes { { "location", "USA" } }.ToUserContext(), Logger), Is.Null); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""substring"",""name"":""location"",""value"":25} has an unsupported condition value. You may need to upgrade to a newer release of the Optimizely SDK."), Times.Once); - - invalidCondition = new BaseCondition { Name = "distance_lt", Value = "invalid", Match = "lt", Type = "custom_attribute" }; - Assert.That(invalidCondition.Evaluate(null, new UserAttributes { { "distance_lt", 5 } }.ToUserContext(), Logger), Is.Null); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""lt"",""name"":""distance_lt"",""value"":""invalid""} has an unsupported condition value. You may need to upgrade to a newer release of the Optimizely SDK."), Times.Once); - - invalidCondition = new BaseCondition { Name = "distance_gt", Value = "invalid", Match = "gt", Type = "custom_attribute" }; - Assert.That(invalidCondition.Evaluate(null, new UserAttributes { { "distance_gt", "invalid" } }.ToUserContext(), Logger), Is.Null); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""gt"",""name"":""distance_gt"",""value"":""invalid""} has an unsupported condition value. You may need to upgrade to a newer release of the Optimizely SDK."), Times.Once); + var invalidCondition = new BaseCondition + { + Name = "is_registered_user", Value = new string[] { }, Match = "exact", + Type = "custom_attribute", + }; + Assert.That( + invalidCondition.Evaluate(null, + new UserAttributes { { "is_registered_user", true } }.ToUserContext(), Logger), + Is.Null); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""is_registered_user"",""value"":[]} has an unsupported condition value. You may need to upgrade to a newer release of the Optimizely SDK."), + Times.Once); + + invalidCondition = new BaseCondition + { Name = "location", Value = 25, Match = "substring", Type = "custom_attribute" }; + Assert.That( + invalidCondition.Evaluate(null, + new UserAttributes { { "location", "USA" } }.ToUserContext(), Logger), Is.Null); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""substring"",""name"":""location"",""value"":25} has an unsupported condition value. You may need to upgrade to a newer release of the Optimizely SDK."), + Times.Once); + + invalidCondition = new BaseCondition + { + Name = "distance_lt", Value = "invalid", Match = "lt", Type = "custom_attribute", + }; + Assert.That( + invalidCondition.Evaluate(null, + new UserAttributes { { "distance_lt", 5 } }.ToUserContext(), Logger), Is.Null); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""lt"",""name"":""distance_lt"",""value"":""invalid""} has an unsupported condition value. You may need to upgrade to a newer release of the Optimizely SDK."), + Times.Once); + + invalidCondition = new BaseCondition + { + Name = "distance_gt", Value = "invalid", Match = "gt", Type = "custom_attribute", + }; + Assert.That( + invalidCondition.Evaluate(null, + new UserAttributes { { "distance_gt", "invalid" } }.ToUserContext(), Logger), + Is.Null); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""gt"",""name"":""distance_gt"",""value"":""invalid""} has an unsupported condition value. You may need to upgrade to a newer release of the Optimizely SDK."), + Times.Once); } #endregion // Evaluate Tests @@ -188,45 +380,109 @@ public void TestEvaluateLogsWarningAndReturnNullWhenConditionTypeIsInvalid() [Test] public void TestExactMatcherReturnsFalseWhenAttributeValueDoesNotMatch() { - Assert.That(ExactStrCondition.Evaluate(null, new UserAttributes { { "browser_type", "chrome" } }.ToUserContext(), Logger), Is.False); - Assert.That(ExactBoolCondition.Evaluate(null, new UserAttributes { { "is_registered_user", true } }.ToUserContext(), Logger), Is.False); - Assert.That(ExactDecimalCondition.Evaluate(null, new UserAttributes { { "pi_value", 2.5 } }.ToUserContext(), Logger), Is.False); - Assert.That(ExactIntCondition.Evaluate(null, new UserAttributes { { "lasers_count", 55 } }.ToUserContext(), Logger), Is.False); + Assert.That( + ExactStrCondition.Evaluate(null, + new UserAttributes { { "browser_type", "chrome" } }.ToUserContext(), Logger), + Is.False); + Assert.That( + ExactBoolCondition.Evaluate(null, + new UserAttributes { { "is_registered_user", true } }.ToUserContext(), Logger), + Is.False); + Assert.That( + ExactDecimalCondition.Evaluate(null, + new UserAttributes { { "pi_value", 2.5 } }.ToUserContext(), Logger), Is.False); + Assert.That( + ExactIntCondition.Evaluate(null, + new UserAttributes { { "lasers_count", 55 } }.ToUserContext(), Logger), + Is.False); } [Test] public void TestExactMatcherReturnsNullWhenTypeMismatch() { - Assert.That(ExactStrCondition.Evaluate(null, new UserAttributes { { "browser_type", true } }.ToUserContext(), Logger), Is.Null); - Assert.That(ExactBoolCondition.Evaluate(null, new UserAttributes { { "is_registered_user", "abcd" } }.ToUserContext(), Logger), Is.Null); - Assert.That(ExactDecimalCondition.Evaluate(null, new UserAttributes { { "pi_value", false } }.ToUserContext(), Logger), Is.Null); - Assert.That(ExactIntCondition.Evaluate(null, new UserAttributes { { "lasers_count", "infinity" } }.ToUserContext(), Logger), Is.Null); - - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""browser_type"",""value"":""firefox""} evaluated to UNKNOWN because a value of type ""Boolean"" was passed for user attribute ""browser_type""."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""is_registered_user"",""value"":false} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""is_registered_user""."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""pi_value"",""value"":3.14} evaluated to UNKNOWN because a value of type ""Boolean"" was passed for user attribute ""pi_value""."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""lasers_count"",""value"":9000} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""lasers_count""."), Times.Once); + Assert.That( + ExactStrCondition.Evaluate(null, + new UserAttributes { { "browser_type", true } }.ToUserContext(), Logger), + Is.Null); + Assert.That( + ExactBoolCondition.Evaluate(null, + new UserAttributes { { "is_registered_user", "abcd" } }.ToUserContext(), + Logger), Is.Null); + Assert.That( + ExactDecimalCondition.Evaluate(null, + new UserAttributes { { "pi_value", false } }.ToUserContext(), Logger), Is.Null); + Assert.That( + ExactIntCondition.Evaluate(null, + new UserAttributes { { "lasers_count", "infinity" } }.ToUserContext(), Logger), + Is.Null); + + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""browser_type"",""value"":""firefox""} evaluated to UNKNOWN because a value of type ""Boolean"" was passed for user attribute ""browser_type""."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""is_registered_user"",""value"":false} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""is_registered_user""."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""pi_value"",""value"":3.14} evaluated to UNKNOWN because a value of type ""Boolean"" was passed for user attribute ""pi_value""."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""lasers_count"",""value"":9000} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""lasers_count""."), + Times.Once); } [Test] public void TestExactMatcherReturnsNullForOutOfBoundNumericValues() { - Assert.That(ExactIntCondition.Evaluate(null, new UserAttributes { { "lasers_count", double.NegativeInfinity } }.ToUserContext(), Logger), Is.Null); - Assert.That(ExactDecimalCondition.Evaluate(null, new UserAttributes { { "pi_value", Math.Pow(2, 53) + 2 } }.ToUserContext(), Logger), Is.Null); - Assert.That(InfinityIntCondition.Evaluate(null, new UserAttributes { { "max_num_value", 15 } }.ToUserContext(), Logger), Is.Null); - - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""lasers_count"",""value"":9000} evaluated to UNKNOWN because the number value for user attribute ""lasers_count"" is not in the range [-2^53, +2^53]."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""pi_value"",""value"":3.14} evaluated to UNKNOWN because the number value for user attribute ""pi_value"" is not in the range [-2^53, +2^53]."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""max_num_value"",""value"":9223372036854775807} has an unsupported condition value. You may need to upgrade to a newer release of the Optimizely SDK."), Times.Once); + Assert.That( + ExactIntCondition.Evaluate(null, + new UserAttributes + { { "lasers_count", double.NegativeInfinity } }.ToUserContext(), Logger), + Is.Null); + Assert.That( + ExactDecimalCondition.Evaluate(null, + new UserAttributes { { "pi_value", Math.Pow(2, 53) + 2 } }.ToUserContext(), + Logger), Is.Null); + Assert.That( + InfinityIntCondition.Evaluate(null, + new UserAttributes { { "max_num_value", 15 } }.ToUserContext(), Logger), + Is.Null); + + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""lasers_count"",""value"":9000} evaluated to UNKNOWN because the number value for user attribute ""lasers_count"" is not in the range [-2^53, +2^53]."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""pi_value"",""value"":3.14} evaluated to UNKNOWN because the number value for user attribute ""pi_value"" is not in the range [-2^53, +2^53]."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""exact"",""name"":""max_num_value"",""value"":9223372036854775807} has an unsupported condition value. You may need to upgrade to a newer release of the Optimizely SDK."), + Times.Once); } [Test] public void TestExactMatcherReturnsTrueWhenAttributeValueMatches() { - Assert.That(ExactStrCondition.Evaluate(null, new UserAttributes { { "browser_type", "firefox" } }.ToUserContext(), Logger), Is.True); - Assert.That(ExactBoolCondition.Evaluate(null, new UserAttributes { { "is_registered_user", false } }.ToUserContext(), Logger), Is.True); - Assert.That(ExactDecimalCondition.Evaluate(null, new UserAttributes { { "pi_value", 3.14 } }.ToUserContext(), Logger), Is.True); - Assert.That(ExactIntCondition.Evaluate(null, new UserAttributes { { "lasers_count", 9000 } }.ToUserContext(), Logger), Is.True); + Assert.That( + ExactStrCondition.Evaluate(null, + new UserAttributes { { "browser_type", "firefox" } }.ToUserContext(), Logger), + Is.True); + Assert.That( + ExactBoolCondition.Evaluate(null, + new UserAttributes { { "is_registered_user", false } }.ToUserContext(), Logger), + Is.True); + Assert.That( + ExactDecimalCondition.Evaluate(null, + new UserAttributes { { "pi_value", 3.14 } }.ToUserContext(), Logger), Is.True); + Assert.That( + ExactIntCondition.Evaluate(null, + new UserAttributes { { "lasers_count", 9000 } }.ToUserContext(), Logger), + Is.True); } #endregion // ExactMatcher Tests @@ -236,22 +492,37 @@ public void TestExactMatcherReturnsTrueWhenAttributeValueMatches() [Test] public void TestExistsMatcherReturnsFalseWhenAttributeIsNotProvided() { - Assert.That(ExistsCondition.Evaluate(null, new UserAttributes { }.ToUserContext(), Logger), Is.False); + Assert.That( + ExistsCondition.Evaluate(null, new UserAttributes { }.ToUserContext(), Logger), + Is.False); } [Test] public void TestExistsMatcherReturnsFalseWhenAttributeIsNull() { - Assert.That(ExistsCondition.Evaluate(null, new UserAttributes { { "input_value", null } }.ToUserContext(), Logger), Is.False); + Assert.That( + ExistsCondition.Evaluate(null, + new UserAttributes { { "input_value", null } }.ToUserContext(), Logger), + Is.False); } [Test] public void TestExistsMatcherReturnsTrueWhenAttributeValueIsProvided() { - Assert.That(ExistsCondition.Evaluate(null, new UserAttributes { { "input_value", "" } }.ToUserContext(), Logger), Is.True); - Assert.That(ExistsCondition.Evaluate(null, new UserAttributes { { "input_value", "iPhone" } }.ToUserContext(), Logger), Is.True); - Assert.That(ExistsCondition.Evaluate(null, new UserAttributes { { "input_value", 10 } }.ToUserContext(), Logger), Is.True); - Assert.That(ExistsCondition.Evaluate(null, new UserAttributes { { "input_value", false } }.ToUserContext(), Logger), Is.True); + Assert.That( + ExistsCondition.Evaluate(null, + new UserAttributes { { "input_value", "" } }.ToUserContext(), Logger), Is.True); + Assert.That( + ExistsCondition.Evaluate(null, + new UserAttributes { { "input_value", "iPhone" } }.ToUserContext(), Logger), + Is.True); + Assert.That( + ExistsCondition.Evaluate(null, + new UserAttributes { { "input_value", 10 } }.ToUserContext(), Logger), Is.True); + Assert.That( + ExistsCondition.Evaluate(null, + new UserAttributes { { "input_value", false } }.ToUserContext(), Logger), + Is.True); } #endregion // ExistsMatcher Tests @@ -261,21 +532,34 @@ public void TestExistsMatcherReturnsTrueWhenAttributeValueIsProvided() [Test] public void TestSubstringMatcherReturnsFalseWhenAttributeValueIsNotASubstring() { - Assert.That(SubstrCondition.Evaluate(null, new UserAttributes { { "location", "Los Angeles" } }.ToUserContext(), Logger), Is.False); + Assert.That( + SubstrCondition.Evaluate(null, + new UserAttributes { { "location", "Los Angeles" } }.ToUserContext(), Logger), + Is.False); } [Test] public void TestSubstringMatcherReturnsNullWhenAttributeValueIsNotAString() { - Assert.That(SubstrCondition.Evaluate(null, new UserAttributes { { "location", 10.5 } }.ToUserContext(), Logger), Is.Null); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""substring"",""name"":""location"",""value"":""USA""} evaluated to UNKNOWN because a value of type ""Double"" was passed for user attribute ""location""."), Times.Once); + Assert.That( + SubstrCondition.Evaluate(null, + new UserAttributes { { "location", 10.5 } }.ToUserContext(), Logger), Is.Null); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""substring"",""name"":""location"",""value"":""USA""} evaluated to UNKNOWN because a value of type ""Double"" was passed for user attribute ""location""."), + Times.Once); } [Test] public void TestSubstringMatcherReturnsTrueWhenAttributeValueIsASubstring() { - Assert.That(SubstrCondition.Evaluate(null, new UserAttributes { { "location", "USA" } }.ToUserContext(), Logger), Is.True); - Assert.That(SubstrCondition.Evaluate(null, new UserAttributes { { "location", "San Francisco, USA" } }.ToUserContext(), Logger), Is.True); + Assert.That( + SubstrCondition.Evaluate(null, + new UserAttributes { { "location", "USA" } }.ToUserContext(), Logger), Is.True); + Assert.That( + SubstrCondition.Evaluate(null, + new UserAttributes { { "location", "San Francisco, USA" } }.ToUserContext(), + Logger), Is.True); } #endregion // SubstringMatcher Tests @@ -285,81 +569,138 @@ public void TestSubstringMatcherReturnsTrueWhenAttributeValueIsASubstring() [Test] public void TestGTMatcherReturnsFalseWhenAttributeValueIsLessThanOrEqualToConditionValue() { - Assert.That(GTCondition.Evaluate(null, new UserAttributes { { "distance_gt", 5 } }.ToUserContext(), Logger), Is.False); - Assert.That(GTCondition.Evaluate(null, new UserAttributes { { "distance_gt", 10 } }.ToUserContext(), Logger), Is.False); + Assert.That( + GTCondition.Evaluate(null, + new UserAttributes { { "distance_gt", 5 } }.ToUserContext(), Logger), Is.False); + Assert.That( + GTCondition.Evaluate(null, + new UserAttributes { { "distance_gt", 10 } }.ToUserContext(), Logger), + Is.False); } [Test] public void TestGTMatcherReturnsNullWhenAttributeValueIsNotANumericValue() { - Assert.That(GTCondition.Evaluate(null, new UserAttributes { { "distance_gt", "invalid_type" } }.ToUserContext(), Logger), Is.Null); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""gt"",""name"":""distance_gt"",""value"":10} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""distance_gt""."), Times.Once); + Assert.That( + GTCondition.Evaluate(null, + new UserAttributes { { "distance_gt", "invalid_type" } }.ToUserContext(), + Logger), Is.Null); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""gt"",""name"":""distance_gt"",""value"":10} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""distance_gt""."), + Times.Once); } [Test] public void TestGTMatcherReturnsNullWhenAttributeValueIsOutOfBounds() { - Assert.That(GTCondition.Evaluate(null, new UserAttributes { { "distance_gt", double.PositiveInfinity } }.ToUserContext(), Logger), Is.Null); - Assert.That(GTCondition.Evaluate(null, new UserAttributes { { "distance_gt", Math.Pow(2, 53) + 2 } }.ToUserContext(), Logger), Is.Null); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""gt"",""name"":""distance_gt"",""value"":10} evaluated to UNKNOWN because the number value for user attribute ""distance_gt"" is not in the range [-2^53, +2^53]."), Times.Exactly(2)); + Assert.That( + GTCondition.Evaluate(null, + new UserAttributes + { { "distance_gt", double.PositiveInfinity } }.ToUserContext(), Logger), + Is.Null); + Assert.That( + GTCondition.Evaluate(null, + new UserAttributes { { "distance_gt", Math.Pow(2, 53) + 2 } }.ToUserContext(), + Logger), Is.Null); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""gt"",""name"":""distance_gt"",""value"":10} evaluated to UNKNOWN because the number value for user attribute ""distance_gt"" is not in the range [-2^53, +2^53]."), + Times.Exactly(2)); } [Test] public void TestGTMatcherReturnsTrueWhenAttributeValueIsGreaterThanConditionValue() { - Assert.That(GTCondition.Evaluate(null, new UserAttributes { { "distance_gt", 15 } }.ToUserContext(), Logger), Is.True); + Assert.That( + GTCondition.Evaluate(null, + new UserAttributes { { "distance_gt", 15 } }.ToUserContext(), Logger), Is.True); } [Test] public void TestSemVerGTTargetBetaComplex() { - var semverGTCondition = new BaseCondition { Name = "semversion_gt", Value = "2.1.3-beta+1", Match = "semver_gt", Type = "custom_attribute" }; - Assert.IsTrue(semverGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "2.1.3-beta+1.2.3" } }.ToUserContext(), Logger) ?? false); + var semverGTCondition = new BaseCondition + { + Name = "semversion_gt", Value = "2.1.3-beta+1", Match = "semver_gt", + Type = "custom_attribute", + }; + Assert.IsTrue(semverGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "2.1.3-beta+1.2.3" } }.ToUserContext(), + Logger) ?? false); } [Test] public void TestSemVerGTCompareAgainstPreReleaseToPreRelease() { - var semverGTCondition = new BaseCondition { Name = "semversion_gt", Value = "3.7.1-prerelease+build", Match = "semver_gt", Type = "custom_attribute" }; - Assert.IsTrue(semverGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "3.7.1-prerelease+rc" } }.ToUserContext(), Logger) ?? false); + var semverGTCondition = new BaseCondition + { + Name = "semversion_gt", Value = "3.7.1-prerelease+build", Match = "semver_gt", + Type = "custom_attribute", + }; + Assert.IsTrue(semverGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "3.7.1-prerelease+rc" } }.ToUserContext(), + Logger) ?? false); } [Test] public void TestSemVerGTComparePrereleaseSmallerThanBuild() { - var semverGTCondition = new BaseCondition { Name = "semversion_gt", Value = "3.7.1-prerelease", Match = "semver_gt", Type = "custom_attribute" }; - Assert.IsTrue(semverGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "3.7.1+build" } }.ToUserContext(), Logger) ?? false); + var semverGTCondition = new BaseCondition + { + Name = "semversion_gt", Value = "3.7.1-prerelease", Match = "semver_gt", + Type = "custom_attribute", + }; + Assert.IsTrue(semverGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "3.7.1+build" } }.ToUserContext(), + Logger) ?? false); } + #endregion // GTMatcher Tests #region GEMatcher Tests [Test] - public void TestGEMatcherReturnsFalseWhenAttributeValueIsLessButTrueForEqualToConditionValue() + public void + TestGEMatcherReturnsFalseWhenAttributeValueIsLessButTrueForEqualToConditionValue() { - Assert.IsFalse(GECondition.Evaluate(null, new UserAttributes { { "distance_ge", 5 } }.ToUserContext(), Logger)?? true); - Assert.IsTrue(GECondition.Evaluate(null, new UserAttributes { { "distance_ge", 10 } }.ToUserContext(), Logger)?? false); + Assert.IsFalse(GECondition.Evaluate(null, + new UserAttributes { { "distance_ge", 5 } }.ToUserContext(), Logger) ?? true); + Assert.IsTrue(GECondition.Evaluate(null, + new UserAttributes { { "distance_ge", 10 } }.ToUserContext(), Logger) ?? false); } [Test] public void TestGEMatcherReturnsNullWhenAttributeValueIsNotANumericValue() { - Assert.IsNull(GECondition.Evaluate(null, new UserAttributes { { "distance_ge", "invalid_type" } }.ToUserContext(), Logger)); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""ge"",""name"":""distance_ge"",""value"":10} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""distance_ge""."), Times.Once); + Assert.IsNull(GECondition.Evaluate(null, + new UserAttributes { { "distance_ge", "invalid_type" } }.ToUserContext(), Logger)); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""ge"",""name"":""distance_ge"",""value"":10} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""distance_ge""."), + Times.Once); } [Test] public void TestGEMatcherReturnsNullWhenAttributeValueIsOutOfBounds() { - Assert.IsNull(GECondition.Evaluate(null, new UserAttributes { { "distance_ge", double.PositiveInfinity } }.ToUserContext(), Logger)); - Assert.IsNull(GECondition.Evaluate(null, new UserAttributes { { "distance_ge", Math.Pow(2, 53) + 2 } }.ToUserContext(), Logger)); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""ge"",""name"":""distance_ge"",""value"":10} evaluated to UNKNOWN because the number value for user attribute ""distance_ge"" is not in the range [-2^53, +2^53]."), Times.Exactly(2)); + Assert.IsNull(GECondition.Evaluate(null, + new UserAttributes { { "distance_ge", double.PositiveInfinity } }.ToUserContext(), + Logger)); + Assert.IsNull(GECondition.Evaluate(null, + new UserAttributes { { "distance_ge", Math.Pow(2, 53) + 2 } }.ToUserContext(), + Logger)); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""ge"",""name"":""distance_ge"",""value"":10} evaluated to UNKNOWN because the number value for user attribute ""distance_ge"" is not in the range [-2^53, +2^53]."), + Times.Exactly(2)); } [Test] public void TestGEMatcherReturnsTrueWhenAttributeValueIsGreaterThanConditionValue() { - Assert.IsTrue(GECondition.Evaluate(null, new UserAttributes { { "distance_ge", 15 } }.ToUserContext(), Logger)?? false); + Assert.IsTrue(GECondition.Evaluate(null, + new UserAttributes { { "distance_ge", 15 } }.ToUserContext(), Logger) ?? false); } #endregion // GEMatcher Tests @@ -367,279 +708,555 @@ public void TestGEMatcherReturnsTrueWhenAttributeValueIsGreaterThanConditionValu #region LTMatcher Tests [Test] - public void TestLTMatcherReturnsFalseWhenAttributeValueIsGreaterThanOrEqualToConditionValue() + public void + TestLTMatcherReturnsFalseWhenAttributeValueIsGreaterThanOrEqualToConditionValue() { - Assert.That(LTCondition.Evaluate(null, new UserAttributes { { "distance_lt", 15 } }.ToUserContext(), Logger), Is.False); - Assert.That(LTCondition.Evaluate(null, new UserAttributes { { "distance_lt", 10 } }.ToUserContext(), Logger), Is.False); + Assert.That( + LTCondition.Evaluate(null, + new UserAttributes { { "distance_lt", 15 } }.ToUserContext(), Logger), + Is.False); + Assert.That( + LTCondition.Evaluate(null, + new UserAttributes { { "distance_lt", 10 } }.ToUserContext(), Logger), + Is.False); } [Test] public void TestLTMatcherReturnsNullWhenAttributeValueIsNotANumericValue() { - Assert.That(LTCondition.Evaluate(null, new UserAttributes { { "distance_lt", "invalid_type" } }.ToUserContext(), Logger), Is.Null); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""lt"",""name"":""distance_lt"",""value"":10} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""distance_lt""."), Times.Once); + Assert.That( + LTCondition.Evaluate(null, + new UserAttributes { { "distance_lt", "invalid_type" } }.ToUserContext(), + Logger), Is.Null); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""lt"",""name"":""distance_lt"",""value"":10} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""distance_lt""."), + Times.Once); } [Test] public void TestLTMatcherReturnsNullWhenAttributeValueIsOutOfBounds() { - Assert.That(LTCondition.Evaluate(null, new UserAttributes { { "distance_lt", double.NegativeInfinity } }.ToUserContext(), Logger), Is.Null); - Assert.That(LTCondition.Evaluate(null, new UserAttributes { { "distance_lt", -Math.Pow(2, 53) - 2 } }.ToUserContext(), Logger), Is.Null); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""lt"",""name"":""distance_lt"",""value"":10} evaluated to UNKNOWN because the number value for user attribute ""distance_lt"" is not in the range [-2^53, +2^53]."), Times.Exactly(2)); + Assert.That( + LTCondition.Evaluate(null, + new UserAttributes + { { "distance_lt", double.NegativeInfinity } }.ToUserContext(), Logger), + Is.Null); + Assert.That( + LTCondition.Evaluate(null, + new UserAttributes { { "distance_lt", -Math.Pow(2, 53) - 2 } }.ToUserContext(), + Logger), Is.Null); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""lt"",""name"":""distance_lt"",""value"":10} evaluated to UNKNOWN because the number value for user attribute ""distance_lt"" is not in the range [-2^53, +2^53]."), + Times.Exactly(2)); } [Test] public void TestLTMatcherReturnsTrueWhenAttributeValueIsLessThanConditionValue() { - Assert.That(LTCondition.Evaluate(null, new UserAttributes { { "distance_lt", 5 } }.ToUserContext(), Logger), Is.True); + Assert.That( + LTCondition.Evaluate(null, + new UserAttributes { { "distance_lt", 5 } }.ToUserContext(), Logger), Is.True); } [Test] public void TestSemVerLTTargetBuildComplex() { - var semverLTCondition = new BaseCondition { Name = "semversion_lt", Value = "2.1.3-beta+1.2.3", Match = "semver_lt", Type = "custom_attribute" }; - Assert.IsTrue(semverLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "2.1.3-beta+1" } }.ToUserContext(), Logger) ?? false); + var semverLTCondition = new BaseCondition + { + Name = "semversion_lt", Value = "2.1.3-beta+1.2.3", Match = "semver_lt", + Type = "custom_attribute", + }; + Assert.IsTrue(semverLTCondition.Evaluate(null, + new UserAttributes { { "semversion_lt", "2.1.3-beta+1" } }.ToUserContext(), + Logger) ?? false); } [Test] public void TestSemVerLTCompareMultipleDash() { - var semverLTCondition = new BaseCondition { Name = "semversion_lt", Value = "2.1.3-beta-1.2.3", Match = "semver_lt", Type = "custom_attribute" }; - Assert.IsTrue(semverLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "2.1.3-beta-1" } }.ToUserContext(), Logger) ?? false); + var semverLTCondition = new BaseCondition + { + Name = "semversion_lt", Value = "2.1.3-beta-1.2.3", Match = "semver_lt", + Type = "custom_attribute", + }; + Assert.IsTrue(semverLTCondition.Evaluate(null, + new UserAttributes { { "semversion_lt", "2.1.3-beta-1" } }.ToUserContext(), + Logger) ?? false); } #endregion // LTMatcher Tests #region LEMatcher Tests + [Test] - public void TestLEMatcherReturnsFalseWhenAttributeValueIsGreaterAndTrueIfEqualToConditionValue() + public void + TestLEMatcherReturnsFalseWhenAttributeValueIsGreaterAndTrueIfEqualToConditionValue() { - Assert.IsFalse(LECondition.Evaluate(null, new UserAttributes { { "distance_le", 15 } }.ToUserContext(), Logger) ?? true); - Assert.IsTrue(LECondition.Evaluate(null, new UserAttributes { { "distance_le", 10 } }.ToUserContext(), Logger) ?? false); + Assert.IsFalse(LECondition.Evaluate(null, + new UserAttributes { { "distance_le", 15 } }.ToUserContext(), Logger) ?? true); + Assert.IsTrue(LECondition.Evaluate(null, + new UserAttributes { { "distance_le", 10 } }.ToUserContext(), Logger) ?? false); } [Test] public void TestLEMatcherReturnsNullWhenAttributeValueIsNotANumericValue() { - Assert.IsNull(LECondition.Evaluate(null, new UserAttributes { { "distance_le", "invalid_type" } }.ToUserContext(), Logger)); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""le"",""name"":""distance_le"",""value"":10} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""distance_le""."), Times.Once); + Assert.IsNull(LECondition.Evaluate(null, + new UserAttributes { { "distance_le", "invalid_type" } }.ToUserContext(), Logger)); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""le"",""name"":""distance_le"",""value"":10} evaluated to UNKNOWN because a value of type ""String"" was passed for user attribute ""distance_le""."), + Times.Once); } [Test] public void TestLEMatcherReturnsNullWhenAttributeValueIsOutOfBounds() { - Assert.IsNull(LECondition.Evaluate(null, new UserAttributes { { "distance_le", double.NegativeInfinity } }.ToUserContext(), Logger)); - Assert.IsNull(LECondition.Evaluate(null, new UserAttributes { { "distance_le", -Math.Pow(2, 53) - 2 } }.ToUserContext(), Logger)); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, @"Audience condition {""type"":""custom_attribute"",""match"":""le"",""name"":""distance_le"",""value"":10} evaluated to UNKNOWN because the number value for user attribute ""distance_le"" is not in the range [-2^53, +2^53]."), Times.Exactly(2)); + Assert.IsNull(LECondition.Evaluate(null, + new UserAttributes { { "distance_le", double.NegativeInfinity } }.ToUserContext(), + Logger)); + Assert.IsNull(LECondition.Evaluate(null, + new UserAttributes { { "distance_le", -Math.Pow(2, 53) - 2 } }.ToUserContext(), + Logger)); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + @"Audience condition {""type"":""custom_attribute"",""match"":""le"",""name"":""distance_le"",""value"":10} evaluated to UNKNOWN because the number value for user attribute ""distance_le"" is not in the range [-2^53, +2^53]."), + Times.Exactly(2)); } [Test] public void TestLEMatcherReturnsTrueWhenAttributeValueIsLessThanConditionValue() { - Assert.IsTrue(LECondition.Evaluate(null, new UserAttributes { { "distance_le", 5 } }.ToUserContext(), Logger) ?? false); + Assert.IsTrue(LECondition.Evaluate(null, + new UserAttributes { { "distance_le", 5 } }.ToUserContext(), Logger) ?? false); } #endregion // LEMatcher Tests #region SemVerLTMatcher Tests + [Test] - public void TestSemVerLTMatcherReturnsFalseWhenAttributeValueIsGreaterThanOrEqualToConditionValue() + public void + TestSemVerLTMatcherReturnsFalseWhenAttributeValueIsGreaterThanOrEqualToConditionValue() { - Assert.IsFalse(SemVerLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "3.7.2" } }.ToUserContext(), Logger) ?? true); - Assert.IsFalse(SemVerLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "3.7.1" } }.ToUserContext(), Logger) ?? true); - Assert.IsFalse(SemVerLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "3.8" } }.ToUserContext(), Logger) ?? true); - Assert.IsFalse(SemVerLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "4" } }.ToUserContext(), Logger) ?? true); + Assert.IsFalse(SemVerLTCondition.Evaluate(null, + new UserAttributes { { "semversion_lt", "3.7.2" } }.ToUserContext(), + Logger) ?? + true); + Assert.IsFalse(SemVerLTCondition.Evaluate(null, + new UserAttributes { { "semversion_lt", "3.7.1" } }.ToUserContext(), + Logger) ?? + true); + Assert.IsFalse(SemVerLTCondition.Evaluate(null, + new UserAttributes { { "semversion_lt", "3.8" } }.ToUserContext(), Logger) ?? true); + Assert.IsFalse(SemVerLTCondition.Evaluate(null, + new UserAttributes { { "semversion_lt", "4" } }.ToUserContext(), Logger) ?? true); } [Test] public void TestSemVerLTMatcherReturnsTrueWhenAttributeValueIsLessThanConditionValue() { - Assert.IsTrue(SemVerLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "3.7.0" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(SemVerLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "3.7.1-beta" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(SemVerLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "2.7.1" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(SemVerLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "3.7" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(SemVerLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "3" } }.ToUserContext(), Logger) ?? false); + Assert.IsTrue(SemVerLTCondition.Evaluate(null, + new UserAttributes { { "semversion_lt", "3.7.0" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(SemVerLTCondition.Evaluate(null, + new UserAttributes + { { "semversion_lt", "3.7.1-beta" } }.ToUserContext(), Logger) ?? + false); + Assert.IsTrue(SemVerLTCondition.Evaluate(null, + new UserAttributes { { "semversion_lt", "2.7.1" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(SemVerLTCondition.Evaluate(null, + new UserAttributes { { "semversion_lt", "3.7" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(SemVerLTCondition.Evaluate(null, + new UserAttributes { { "semversion_lt", "3" } }.ToUserContext(), Logger) ?? false); } [Test] public void TestSemVerLTMatcherReturnsTrueWhenAttributeValueIsLessThanConditionValueBeta() { - var semverLTCondition = new BaseCondition { Name = "semversion_lt", Value = "3.7.0-beta.2.3", Match = "semver_lt", Type = "custom_attribute" }; - Assert.IsTrue(semverLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "3.7.0-beta.2.1" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverLTCondition.Evaluate(null, new UserAttributes { { "semversion_lt", "3.7.0-beta" } }.ToUserContext(), Logger) ?? false); + var semverLTCondition = new BaseCondition + { + Name = "semversion_lt", Value = "3.7.0-beta.2.3", Match = "semver_lt", + Type = "custom_attribute", + }; + Assert.IsTrue(semverLTCondition.Evaluate(null, + new UserAttributes { { "semversion_lt", "3.7.0-beta.2.1" } }.ToUserContext(), + Logger) ?? false); + Assert.IsTrue(semverLTCondition.Evaluate(null, + new UserAttributes + { { "semversion_lt", "3.7.0-beta" } }.ToUserContext(), Logger) ?? + false); } + #endregion // SemVerLTMatcher Tests #region SemVerGTMatcher Tests + [Test] - public void TestSemVerGTMatcherReturnsFalseWhenAttributeValueIsLessThanOrEqualToConditionValue() + public void + TestSemVerGTMatcherReturnsFalseWhenAttributeValueIsLessThanOrEqualToConditionValue() { - Assert.IsFalse(SemVerGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "3.7.0" } }.ToUserContext(), Logger)?? true); - Assert.IsFalse(SemVerGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "3.7.1" } }.ToUserContext(), Logger)?? true); - Assert.IsFalse(SemVerGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "3.6" } }.ToUserContext(), Logger)?? true); - Assert.IsFalse(SemVerGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "2" } }.ToUserContext(), Logger)?? true); + Assert.IsFalse(SemVerGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "3.7.0" } }.ToUserContext(), + Logger) ?? + true); + Assert.IsFalse(SemVerGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "3.7.1" } }.ToUserContext(), + Logger) ?? + true); + Assert.IsFalse(SemVerGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "3.6" } }.ToUserContext(), Logger) ?? true); + Assert.IsFalse(SemVerGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "2" } }.ToUserContext(), Logger) ?? true); } [Test] public void TestSemVerGTMatcherReturnsTrueWhenAttributeValueIsGreaterThanConditionValue() { - Assert.IsTrue(SemVerGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "3.7.2" } }.ToUserContext(), Logger)?? false); - Assert.IsTrue(SemVerGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "3.7.2-beta" } }.ToUserContext(), Logger)?? false); - Assert.IsTrue(SemVerGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "4.7.1" } }.ToUserContext(), Logger)?? false); - Assert.IsTrue(SemVerGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "3.8" } }.ToUserContext(), Logger)?? false); - Assert.IsTrue(SemVerGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "4" } }.ToUserContext(), Logger)?? false); + Assert.IsTrue(SemVerGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "3.7.2" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(SemVerGTCondition.Evaluate(null, + new UserAttributes + { { "semversion_gt", "3.7.2-beta" } }.ToUserContext(), Logger) ?? + false); + Assert.IsTrue(SemVerGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "4.7.1" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(SemVerGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "3.8" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(SemVerGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "4" } }.ToUserContext(), Logger) ?? false); + } + + [Test] + public void + TestSemVerGTMatcherReturnsTrueWhenAttributeValueIsGreaterThanConditionValueBeta() + { + var semverGTCondition = new BaseCondition + { + Name = "semversion_gt", Value = "3.7.0-beta.2.3", Match = "semver_gt", + Type = "custom_attribute", + }; + Assert.IsTrue(semverGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "3.7.0-beta.2.4" } }.ToUserContext(), + Logger) ?? false); + Assert.IsTrue(semverGTCondition.Evaluate(null, + new UserAttributes { { "semversion_gt", "3.7.0" } }.ToUserContext(), + Logger) ?? + false); } - [Test] - public void TestSemVerGTMatcherReturnsTrueWhenAttributeValueIsGreaterThanConditionValueBeta() - { - var semverGTCondition = new BaseCondition { Name = "semversion_gt", Value = "3.7.0-beta.2.3", Match = "semver_gt", Type = "custom_attribute" }; - Assert.IsTrue(semverGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "3.7.0-beta.2.4" } }.ToUserContext(), Logger)?? false); - Assert.IsTrue(semverGTCondition.Evaluate(null, new UserAttributes { { "semversion_gt", "3.7.0" } }.ToUserContext(), Logger)?? false); - } #endregion // SemVerGTMatcher Tests #region SemVerEQMatcher Tests + [Test] public void TestSemVerEQMatcherReturnsFalseWhenAttributeValueIsNotEqualToConditionValue() { - Assert.IsFalse(SemVerEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "3.7.0" } }.ToUserContext(), Logger) ?? true); - Assert.IsFalse(SemVerEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "3.7.2" } }.ToUserContext(), Logger) ?? true); - Assert.IsFalse(SemVerEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "3.6" } }.ToUserContext(), Logger)?? true); - Assert.IsFalse(SemVerEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "2" } }.ToUserContext(), Logger)?? true); - Assert.IsFalse(SemVerEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "4" } }.ToUserContext(), Logger)?? true); - Assert.IsFalse(SemVerEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "3" } }.ToUserContext(), Logger)?? true); + Assert.IsFalse(SemVerEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "3.7.0" } }.ToUserContext(), + Logger) ?? + true); + Assert.IsFalse(SemVerEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "3.7.2" } }.ToUserContext(), + Logger) ?? + true); + Assert.IsFalse(SemVerEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "3.6" } }.ToUserContext(), Logger) ?? true); + Assert.IsFalse(SemVerEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "2" } }.ToUserContext(), Logger) ?? true); + Assert.IsFalse(SemVerEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "4" } }.ToUserContext(), Logger) ?? true); + Assert.IsFalse(SemVerEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "3" } }.ToUserContext(), Logger) ?? true); } [Test] public void TestSemVerEQMatcherReturnsTrueWhenAttributeValueIsEqualToConditionValue() { - Assert.IsTrue(SemVerEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "3.7.1" } }.ToUserContext(), Logger) ?? false); + Assert.IsTrue(SemVerEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "3.7.1" } }.ToUserContext(), + Logger) ?? + false); } [Test] - public void TestSemVerEQMatcherReturnsTrueWhenAttributeValueIsEqualToConditionValueMajorOnly() + public void + TestSemVerEQMatcherReturnsTrueWhenAttributeValueIsEqualToConditionValueMajorOnly() { - var semverEQCondition = new BaseCondition { Name = "semversion_eq", Value = "3", Match = "semver_eq", Type = "custom_attribute" }; - Assert.IsTrue(semverEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "3.0.0" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "3.1" } }.ToUserContext(), Logger) ?? false); + var semverEQCondition = new BaseCondition + { + Name = "semversion_eq", Value = "3", Match = "semver_eq", Type = "custom_attribute", + }; + Assert.IsTrue(semverEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "3.0.0" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(semverEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "3.1" } }.ToUserContext(), + Logger) ?? + false); } [Test] - public void TestSemVerEQMatcherReturnsFalseOrFalseWhenAttributeValueIsNotEqualToConditionValueMajorOnly() + public void + TestSemVerEQMatcherReturnsFalseOrFalseWhenAttributeValueIsNotEqualToConditionValueMajorOnly() { - var semverEQCondition = new BaseCondition { Name = "semversion_eq", Value = "3", Match = "semver_eq", Type = "custom_attribute" }; - Assert.IsFalse(semverEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "4.0" } }.ToUserContext(), Logger) ?? true); - Assert.IsFalse(semverEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "2" } }.ToUserContext(), Logger) ?? true); + var semverEQCondition = new BaseCondition + { + Name = "semversion_eq", Value = "3", Match = "semver_eq", Type = "custom_attribute", + }; + Assert.IsFalse(semverEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "4.0" } }.ToUserContext(), Logger) ?? true); + Assert.IsFalse(semverEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "2" } }.ToUserContext(), Logger) ?? true); } [Test] public void TestSemVerEQMatcherReturnsTrueWhenAttributeValueIsEqualToConditionValueBeta() { - var semverEQCondition = new BaseCondition { Name = "semversion_eq", Value = "3.7.0-beta.2.3", Match = "semver_eq", Type = "custom_attribute" }; - Assert.IsTrue(semverEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "3.7.0-beta.2.3" } }.ToUserContext(), Logger) ?? false); + var semverEQCondition = new BaseCondition + { + Name = "semversion_eq", Value = "3.7.0-beta.2.3", Match = "semver_eq", + Type = "custom_attribute", + }; + Assert.IsTrue(semverEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "3.7.0-beta.2.3" } }.ToUserContext(), + Logger) ?? false); } [Test] public void TestSemVerEQTargetBuildIgnores() { - var semverEQCondition = new BaseCondition { Name = "semversion_eq", Value = "2.1.3", Match = "semver_eq", Type = "custom_attribute" }; - Assert.IsTrue(semverEQCondition.Evaluate(null, new UserAttributes { { "semversion_eq", "2.1.3+build" } }.ToUserContext(), Logger) ?? false); + var semverEQCondition = new BaseCondition + { + Name = "semversion_eq", Value = "2.1.3", Match = "semver_eq", + Type = "custom_attribute", + }; + Assert.IsTrue(semverEQCondition.Evaluate(null, + new UserAttributes { { "semversion_eq", "2.1.3+build" } }.ToUserContext(), + Logger) ?? false); } + #endregion // SemVerEQMatcher Tests #region SemVerGEMatcher Tests - [Test] - public void TestSemVerGEMatcherReturnsFalseWhenAttributeValueIsNotGreaterOrEqualToConditionValue() - { - Assert.IsFalse(SemVerGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3.7.0" } }.ToUserContext(), Logger) ?? true); - Assert.IsFalse(SemVerGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3.7.1-beta" } }.ToUserContext(), Logger) ?? true); - Assert.IsFalse(SemVerGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3.6" } }.ToUserContext(), Logger) ?? true); - Assert.IsFalse(SemVerGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "2" } }.ToUserContext(), Logger) ?? true); - Assert.IsFalse(SemVerGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3" } }.ToUserContext(), Logger) ?? true); - } [Test] - public void TestSemVerGEMatcherReturnsTrueWhenAttributeValueIsGreaterOrEqualToConditionValue() - { - Assert.IsTrue(SemVerGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3.7.1" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(SemVerGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3.7.2" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(SemVerGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3.8.1" } }.ToUserContext(), Logger) ?? false); ; - Assert.IsTrue(SemVerGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "4.7.1" } }.ToUserContext(), Logger) ?? false); + public void + TestSemVerGEMatcherReturnsFalseWhenAttributeValueIsNotGreaterOrEqualToConditionValue() + { + Assert.IsFalse(SemVerGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3.7.0" } }.ToUserContext(), + Logger) ?? + true); + Assert.IsFalse(SemVerGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3.7.1-beta" } }. + ToUserContext(), Logger) ?? + true); + Assert.IsFalse(SemVerGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3.6" } }.ToUserContext(), Logger) ?? true); + Assert.IsFalse(SemVerGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "2" } }.ToUserContext(), Logger) ?? true); + Assert.IsFalse(SemVerGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3" } }.ToUserContext(), Logger) ?? true); + } + + [Test] + public void + TestSemVerGEMatcherReturnsTrueWhenAttributeValueIsGreaterOrEqualToConditionValue() + { + Assert.IsTrue(SemVerGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3.7.1" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(SemVerGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3.7.2" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(SemVerGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3.8.1" } }.ToUserContext(), + Logger) ?? + false); + ; + Assert.IsTrue(SemVerGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "4.7.1" } }.ToUserContext(), + Logger) ?? + false); + } + + [Test] + public void + TestSemVerGEMatcherReturnsTrueWhenAttributeValueIsGreaterOrEqualToConditionValueMajorOnly() + { + var semverGECondition = new BaseCondition + { + Name = "semversion_ge", Value = "3", Match = "semver_ge", Type = "custom_attribute", + }; + Assert.IsTrue(semverGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3.7.0" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(semverGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3.0.0" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(semverGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "4.0" } }.ToUserContext(), + Logger) ?? + false); } [Test] - public void TestSemVerGEMatcherReturnsTrueWhenAttributeValueIsGreaterOrEqualToConditionValueMajorOnly() + public void + TestSemVerGEMatcherReturnsFalseWhenAttributeValueIsNotGreaterOrEqualToConditionValueMajorOnly() { - var semverGECondition = new BaseCondition { Name = "semversion_ge", Value = "3", Match = "semver_ge", Type = "custom_attribute" }; - Assert.IsTrue(semverGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3.7.0" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3.0.0" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "4.0" } }.ToUserContext(), Logger) ?? false); + var semverGECondition = new BaseCondition + { + Name = "semversion_ge", Value = "3", Match = "semver_ge", Type = "custom_attribute", + }; + Assert.IsFalse(semverGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "2" } }.ToUserContext(), Logger) ?? true); } [Test] - public void TestSemVerGEMatcherReturnsFalseWhenAttributeValueIsNotGreaterOrEqualToConditionValueMajorOnly() + public void + TestSemVerGEMatcherReturnsTrueWhenAttributeValueIsGreaterOrEqualToConditionValueBeta() { - var semverGECondition = new BaseCondition { Name = "semversion_ge", Value = "3", Match = "semver_ge", Type = "custom_attribute" }; - Assert.IsFalse(semverGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "2" } }.ToUserContext(), Logger) ?? true); + var semverGECondition = new BaseCondition + { + Name = "semversion_ge", Value = "3.7.0-beta.2.3", Match = "semver_ge", + Type = "custom_attribute", + }; + Assert.IsTrue(semverGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3.7.0-beta.2.3" } }.ToUserContext(), + Logger) ?? false); + Assert.IsTrue(semverGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3.7.0-beta.2.4" } }.ToUserContext(), + Logger) ?? false); + Assert.IsTrue(semverGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3.7.0-beta.2.3+1.2.3" } }.ToUserContext(), + Logger) ?? false); + Assert.IsTrue(semverGECondition.Evaluate(null, + new UserAttributes { { "semversion_ge", "3.7.1-beta.2.3" } }.ToUserContext(), + Logger) ?? false); } - [Test] - public void TestSemVerGEMatcherReturnsTrueWhenAttributeValueIsGreaterOrEqualToConditionValueBeta() - { - var semverGECondition = new BaseCondition { Name = "semversion_ge", Value = "3.7.0-beta.2.3", Match = "semver_ge", Type = "custom_attribute" }; - Assert.IsTrue(semverGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3.7.0-beta.2.3" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3.7.0-beta.2.4" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3.7.0-beta.2.3+1.2.3" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverGECondition.Evaluate(null, new UserAttributes { { "semversion_ge", "3.7.1-beta.2.3" } }.ToUserContext(), Logger) ?? false); - } #endregion // SemVerGEMatcher Tests #region SemVerLEMatcher Tests - [Test] - public void TestSemVerLEMatcherReturnsFalseWhenAttributeValueIsNotLessOrEqualToConditionValue() - { - Assert.IsFalse(SemVerLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.7.2" } }.ToUserContext(), Logger) ?? true); - Assert.IsFalse(SemVerLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.8" } }.ToUserContext(), Logger) ?? true); - Assert.IsFalse(SemVerLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "4" } }.ToUserContext(), Logger) ?? true); - } [Test] - public void TestSemVerLEMatcherReturnsTrueWhenAttributeValueIsLessOrEqualToConditionValue() + public void + TestSemVerLEMatcherReturnsFalseWhenAttributeValueIsNotLessOrEqualToConditionValue() { - Assert.IsTrue(SemVerLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.7.1" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(SemVerLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.7.0" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(SemVerLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.6.1" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(SemVerLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "2.7.1" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(SemVerLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.7.1-beta" } }.ToUserContext(), Logger) ?? false); + Assert.IsFalse(SemVerLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "3.7.2" } }.ToUserContext(), + Logger) ?? + true); + Assert.IsFalse(SemVerLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "3.8" } }.ToUserContext(), Logger) ?? true); + Assert.IsFalse(SemVerLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "4" } }.ToUserContext(), Logger) ?? true); } [Test] - public void TestSemVerLEMatcherReturnsTrueWhenAttributeValueIsLessOrEqualToConditionValueMajorOnly() + public void TestSemVerLEMatcherReturnsTrueWhenAttributeValueIsLessOrEqualToConditionValue() { - var semverLECondition = new BaseCondition { Name = "semversion_le", Value = "3", Match = "semver_le", Type = "custom_attribute" }; - Assert.IsTrue(semverLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.7.0-beta.2.4" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.7.1-beta" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.0.0" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "2.0" } }.ToUserContext(), Logger) ?? false); + Assert.IsTrue(SemVerLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "3.7.1" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(SemVerLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "3.7.0" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(SemVerLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "3.6.1" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(SemVerLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "2.7.1" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(SemVerLECondition.Evaluate(null, + new UserAttributes + { { "semversion_le", "3.7.1-beta" } }.ToUserContext(), Logger) ?? + false); + } + + [Test] + public void + TestSemVerLEMatcherReturnsTrueWhenAttributeValueIsLessOrEqualToConditionValueMajorOnly() + { + var semverLECondition = new BaseCondition + { + Name = "semversion_le", Value = "3", Match = "semver_le", Type = "custom_attribute", + }; + Assert.IsTrue(semverLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "3.7.0-beta.2.4" } }.ToUserContext(), + Logger) ?? false); + Assert.IsTrue(semverLECondition.Evaluate(null, + new UserAttributes + { { "semversion_le", "3.7.1-beta" } }.ToUserContext(), Logger) ?? + false); + Assert.IsTrue(semverLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "3.0.0" } }.ToUserContext(), + Logger) ?? + false); + Assert.IsTrue(semverLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "2.0" } }.ToUserContext(), + Logger) ?? + false); + } + + [Test] + public void + TestSemVerLEMatcherReturnsFalseWhenAttributeValueIsNotLessOrEqualToConditionValueMajorOnly() + { + var semverLECondition = new BaseCondition + { + Name = "semversion_le", Value = "3", Match = "semver_le", Type = "custom_attribute", + }; + Assert.IsFalse(semverLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "4" } }.ToUserContext(), Logger) ?? true); } [Test] - public void TestSemVerLEMatcherReturnsFalseWhenAttributeValueIsNotLessOrEqualToConditionValueMajorOnly() + public void + TestSemVerLEMatcherReturnsTrueWhenAttributeValueIsLessOrEqualToConditionValueBeta() { - var semverLECondition = new BaseCondition { Name = "semversion_le", Value = "3", Match = "semver_le", Type = "custom_attribute" }; - Assert.IsFalse(semverLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "4" } }.ToUserContext(), Logger) ?? true); + var semverLECondition = new BaseCondition + { + Name = "semversion_le", Value = "3.7.0-beta.2.3", Match = "semver_le", + Type = "custom_attribute", + }; + Assert.IsTrue(semverLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "3.7.0-beta.2.2" } }.ToUserContext(), + Logger) ?? false); + Assert.IsTrue(semverLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "3.7.0-beta.2.3" } }.ToUserContext(), + Logger) ?? false); + Assert.IsTrue(semverLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "3.7.0-beta.2.2+1.2.3" } }.ToUserContext(), + Logger) ?? false); + Assert.IsTrue(semverLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", "3.6.1-beta.2.3+1.2" } }.ToUserContext(), + Logger) ?? false); } - [Test] - public void TestSemVerLEMatcherReturnsTrueWhenAttributeValueIsLessOrEqualToConditionValueBeta() - { - var semverLECondition = new BaseCondition { Name = "semversion_le", Value = "3.7.0-beta.2.3", Match = "semver_le", Type = "custom_attribute" }; - Assert.IsTrue(semverLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.7.0-beta.2.2" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.7.0-beta.2.3" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.7.0-beta.2.2+1.2.3" } }.ToUserContext(), Logger) ?? false); - Assert.IsTrue(semverLECondition.Evaluate(null, new UserAttributes { { "semversion_le", "3.6.1-beta.2.3+1.2" } }.ToUserContext(), Logger) ?? false); - } #endregion // SemVerLEMatcher Tests #region SemVer Invalid Scenarios @@ -647,16 +1264,26 @@ public void TestSemVerLEMatcherReturnsTrueWhenAttributeValueIsLessOrEqualToCondi [Test] public void TestInvalidSemVersions() { - var invalidValues = new string[] {"-", ".", "..", "+", "+test", " ", "2 .3. 0", "2.", - ".2.2", "3.7.2.2", "3.x", ",", "+build-prerelese"}; - var semverLECondition = new BaseCondition { Name = "semversion_le", Value = "3", Match = "semver_le", Type = "custom_attribute" }; - foreach(var invalidValue in invalidValues) { - Assert.IsNull(semverLECondition.Evaluate(null, new UserAttributes { { "semversion_le", invalidValue } }.ToUserContext(), Logger), $"returned for {invalidValue}"); + var invalidValues = new string[] + { + "-", ".", "..", "+", "+test", " ", "2 .3. 0", "2.", + ".2.2", "3.7.2.2", "3.x", ",", "+build-prerelese", + }; + var semverLECondition = new BaseCondition + { + Name = "semversion_le", Value = "3", Match = "semver_le", Type = "custom_attribute", + }; + foreach (var invalidValue in invalidValues) + { + Assert.IsNull( + semverLECondition.Evaluate(null, + new UserAttributes { { "semversion_le", invalidValue } }.ToUserContext(), + Logger), $"returned for {invalidValue}"); } } #endregion - + #region Qualified Tests [Test] @@ -670,13 +1297,17 @@ public void QualifiedConditionWithNonStringValueShouldFail() }; var result = condition.Evaluate(null, null, Logger); - + Assert.That(result, Is.Null); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, $@"Audience condition ""{condition}"" has a qualified match but invalid value."), Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.WARN, + $@"Audience condition ""{condition + }"" has a qualified match but invalid value."), Times.Once); } - - + + private const string QUALIFIED_VALUE = "part-of-the-rebellion"; + private readonly List _qualifiedSegments = new List() { QUALIFIED_VALUE, @@ -693,7 +1324,7 @@ public void QualifiedConditionWithMatchingValueShouldBeTrue() }; var result = condition.Evaluate(null, _qualifiedSegments.ToUserContext(), Logger); - + Assert.True(result.HasValue && result.Value); LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), Times.Never); } @@ -709,11 +1340,11 @@ public void QualifiedConditionWithNonMatchingValueShouldBeFalse() }; var result = condition.Evaluate(null, _qualifiedSegments.ToUserContext(), Logger); - + Assert.True(result.HasValue && result.Value == false); - LoggerMock.Verify(l => l.Log( It.IsAny(), It.IsAny()), Times.Never); + LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), Times.Never); } - + #endregion } } diff --git a/OptimizelySDK.Tests/AudienceConditionsTests/ConditionsTest.cs b/OptimizelySDK.Tests/AudienceConditionsTests/ConditionsTest.cs index af311b8ea..ee77568c2 100644 --- a/OptimizelySDK.Tests/AudienceConditionsTests/ConditionsTest.cs +++ b/OptimizelySDK.Tests/AudienceConditionsTests/ConditionsTest.cs @@ -41,11 +41,17 @@ public class ConditionsTest public void Initialize() { TrueConditionMock = new Mock(); - TrueConditionMock.Setup(condition => condition.Evaluate(It.IsAny(), It.IsAny(), It.IsAny())).Returns(true); + TrueConditionMock.Setup(condition => condition.Evaluate(It.IsAny(), + It.IsAny(), It.IsAny())). + Returns(true); FalseConditionMock = new Mock(); - FalseConditionMock.Setup(condition => condition.Evaluate(It.IsAny(), It.IsAny(), It.IsAny())).Returns(false); + FalseConditionMock.Setup(condition => condition.Evaluate(It.IsAny(), + It.IsAny(), It.IsAny())). + Returns(false); NullConditionMock = new Mock(); - NullConditionMock.Setup(condition => condition.Evaluate(It.IsAny(), It.IsAny(), It.IsAny())).Returns((bool?)null); + NullConditionMock.Setup(condition => condition.Evaluate(It.IsAny(), + It.IsAny(), It.IsAny())). + Returns((bool?)null); TrueCondition = TrueConditionMock.Object; FalseCondition = FalseConditionMock.Object; @@ -61,7 +67,7 @@ public void Initialize() [Test] public void TestAndEvaluatorReturnsTrueWhenAllOperandsEvaluateToTrue() { - ICondition[] conditions = new ICondition[] { TrueCondition, TrueCondition }; + var conditions = new ICondition[] { TrueCondition, TrueCondition }; var andCondition = new AndCondition { Conditions = conditions }; Assert.That(andCondition.Evaluate(null, null, Logger), Is.True); @@ -70,19 +76,21 @@ public void TestAndEvaluatorReturnsTrueWhenAllOperandsEvaluateToTrue() [Test] public void TestAndEvaluatorReturnsFalseWhenAnyOperandEvaluatesToFalse() { - ICondition[] conditions = new ICondition[] { FalseCondition, TrueCondition }; + var conditions = new ICondition[] { FalseCondition, TrueCondition }; var andCondition = new AndCondition { Conditions = conditions }; Assert.That(andCondition.Evaluate(null, null, Logger), Is.False); // Should not be called due to short circuiting. - TrueConditionMock.Verify(condition => condition.Evaluate(It.IsAny(), It.IsAny(), Logger), Times.Never); + TrueConditionMock.Verify( + condition => condition.Evaluate(It.IsAny(), + It.IsAny(), Logger), Times.Never); } [Test] public void TestAndEvaluatorReturnsNullWhenAllOperandsEvaluateToNull() { - ICondition[] conditions = new ICondition[] { NullCondition, NullCondition }; + var conditions = new ICondition[] { NullCondition, NullCondition }; var andCondition = new AndCondition { Conditions = conditions }; Assert.That(andCondition.Evaluate(null, null, Logger), Is.Null); @@ -91,7 +99,7 @@ public void TestAndEvaluatorReturnsNullWhenAllOperandsEvaluateToNull() [Test] public void TestAndEvaluatorReturnsNullWhenOperandsEvaluateToTrueAndNull() { - ICondition[] conditions = new ICondition[] { TrueCondition, NullCondition, TrueCondition }; + var conditions = new ICondition[] { TrueCondition, NullCondition, TrueCondition }; var andCondition = new AndCondition { Conditions = conditions }; Assert.That(andCondition.Evaluate(null, null, Logger), Is.Null); @@ -100,7 +108,7 @@ public void TestAndEvaluatorReturnsNullWhenOperandsEvaluateToTrueAndNull() [Test] public void TestAndEvaluatorReturnsFalseWhenOperandsEvaluateToFalseAndNull() { - ICondition[] conditions = new ICondition[] { NullCondition, FalseCondition, NullCondition }; + var conditions = new ICondition[] { NullCondition, FalseCondition, NullCondition }; var andCondition = new AndCondition { Conditions = conditions }; Assert.That(andCondition.Evaluate(null, null, Logger), Is.False); @@ -109,7 +117,7 @@ public void TestAndEvaluatorReturnsFalseWhenOperandsEvaluateToFalseAndNull() [Test] public void TestAndEvaluatorReturnsFalseWhenOperandsEvaluateToTrueFalseAndNull() { - ICondition[] conditions = new ICondition[] { TrueCondition, FalseCondition, NullCondition }; + var conditions = new ICondition[] { TrueCondition, FalseCondition, NullCondition }; var andCondition = new AndCondition { Conditions = conditions }; Assert.That(andCondition.Evaluate(null, null, Logger), Is.False); @@ -122,7 +130,7 @@ public void TestAndEvaluatorReturnsFalseWhenOperandsEvaluateToTrueFalseAndNull() [Test] public void TestOrEvaluatorReturnsTrueWhenAnyOperandEvaluatesToTrue() { - ICondition[] conditions = new ICondition[] { TrueCondition, FalseCondition, NullCondition }; + var conditions = new ICondition[] { TrueCondition, FalseCondition, NullCondition }; var orCondition = new OrCondition { Conditions = conditions }; Assert.That(orCondition.Evaluate(null, null, Logger), Is.True); @@ -131,7 +139,7 @@ public void TestOrEvaluatorReturnsTrueWhenAnyOperandEvaluatesToTrue() [Test] public void TestOrEvaluatorReturnsFalseWhenAllOperandsEvaluatesToFalse() { - ICondition[] conditions = new ICondition[] { FalseCondition, FalseCondition }; + var conditions = new ICondition[] { FalseCondition, FalseCondition }; var orCondition = new OrCondition { Conditions = conditions }; Assert.That(orCondition.Evaluate(null, null, Logger), Is.False); @@ -140,7 +148,7 @@ public void TestOrEvaluatorReturnsFalseWhenAllOperandsEvaluatesToFalse() [Test] public void TestOrEvaluatorReturnsNullWhenOperandsEvaluateToFalseAndNull() { - ICondition[] conditions = new ICondition[] { FalseCondition, NullCondition, FalseCondition }; + var conditions = new ICondition[] { FalseCondition, NullCondition, FalseCondition }; var orCondition = new OrCondition { Conditions = conditions }; Assert.That(orCondition.Evaluate(null, null, Logger), Is.Null); @@ -149,7 +157,7 @@ public void TestOrEvaluatorReturnsNullWhenOperandsEvaluateToFalseAndNull() [Test] public void TestOrEvaluatorReturnsTrueWhenOperandsEvaluateToTrueAndNull() { - ICondition[] conditions = new ICondition[] { TrueCondition, NullCondition, TrueCondition }; + var conditions = new ICondition[] { TrueCondition, NullCondition, TrueCondition }; var orCondition = new OrCondition { Conditions = conditions }; Assert.That(orCondition.Evaluate(null, null, Logger), Is.True); @@ -158,7 +166,7 @@ public void TestOrEvaluatorReturnsTrueWhenOperandsEvaluateToTrueAndNull() [Test] public void TestOrEvaluatorReturnsTrueWhenOperandsEvaluateToFalseTrueAndNull() { - ICondition[] conditions = new ICondition[] { FalseCondition, NullCondition, TrueCondition }; + var conditions = new ICondition[] { FalseCondition, NullCondition, TrueCondition }; var orCondition = new OrCondition { Conditions = conditions }; Assert.That(orCondition.Evaluate(null, null, Logger), Is.True); diff --git a/OptimizelySDK.Tests/AudienceConditionsTests/SegmentsTests.cs b/OptimizelySDK.Tests/AudienceConditionsTests/SegmentsTests.cs index 42eccab23..b4b0b3bbd 100644 --- a/OptimizelySDK.Tests/AudienceConditionsTests/SegmentsTests.cs +++ b/OptimizelySDK.Tests/AudienceConditionsTests/SegmentsTests.cs @@ -14,13 +14,13 @@ * limitations under the License. */ +using System.Collections.Generic; +using System.Linq; using Moq; using NUnit.Framework; using OptimizelySDK.AudienceConditions; using OptimizelySDK.Entity; using OptimizelySDK.Logger; -using System.Collections.Generic; -using System.Linq; namespace OptimizelySDK.Tests.AudienceConditionsTests { @@ -128,7 +128,8 @@ public void ShouldNotFindOdpSegmentsFromConditions() { Conditions = new[] { - _customExactMatchCondition, _customExactMatchCondition, _customExactMatchCondition, + _customExactMatchCondition, _customExactMatchCondition, + _customExactMatchCondition, }, }; @@ -151,7 +152,8 @@ public void ShouldFindAndDedupeNestedOdpSegments() { Conditions = new ICondition[] { - _secondThirdPartyOdpQualifiedMatchCondition, _firstThirdPartyOdpQualifiedMatchCondition, + _secondThirdPartyOdpQualifiedMatchCondition, + _firstThirdPartyOdpQualifiedMatchCondition, }, }; var orConditions = new OrCondition diff --git a/OptimizelySDK.Tests/BucketerTest.cs b/OptimizelySDK.Tests/BucketerTest.cs index 46ca90c5f..c8c61864f 100644 --- a/OptimizelySDK.Tests/BucketerTest.cs +++ b/OptimizelySDK.Tests/BucketerTest.cs @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using Moq; using NUnit.Framework; using OptimizelySDK.Bucketing; @@ -30,8 +31,13 @@ public class BucketerTest private ProjectConfig Config; private DecisionReasons DecisionReasonsObj; private const string TestUserId = "testUserId"; - public string TestBucketingIdControl { get; } = "testBucketingIdControl!"; // generates bucketing number 3741 - public string TestBucketingIdVariation { get; } = "123456789'"; // generates bucketing number 4567 + + public string TestBucketingIdControl { get; } = + "testBucketingIdControl!"; // generates bucketing number 3741 + + public string TestBucketingIdVariation { get; } = + "123456789'"; // generates bucketing number 4567 + public string TestBucketingIdGroupExp2Var2 { get; } = "123456789"; // group_exp_2_var_2 public string TestUserIdBucketsToVariation { get; } = "bucketsToVariation!"; public string TestUserIdBucketsToNoGroup { get; } = "testUserId"; @@ -44,15 +50,13 @@ private class BucketerTestItem public string UserId { get; set; } public string ExperimentId { get; set; } public int ExpectedBucketValue { get; set; } - - public string BucketingId - { - get { return UserId + ExperimentId; } - } + + public string BucketingId => UserId + ExperimentId; public override string ToString() { - return string.Format("UserId: {0}, ExperimentId: {1}, BucketId: {2}, ExpectedBucketValue {3}", + return string.Format( + "UserId: {0}, ExperimentId: {1}, BucketId: {2}, ExpectedBucketValue {3}", UserId, ExperimentId, BucketingId, ExpectedBucketValue); } } @@ -62,7 +66,8 @@ public void Initialize() { LoggerMock = new Mock(); DecisionReasonsObj = new DecisionReasons(); - Config = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, new ErrorHandler.NoOpErrorHandler()); + Config = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, + new ErrorHandler.NoOpErrorHandler()); } [TestFixtureSetUp] @@ -78,17 +83,37 @@ public void TestGenerateBucketValue() var bucketer = new Bucketer(LoggerMock.Object); foreach (var item in new[] + { + new BucketerTestItem + { + UserId = "ppid1", ExperimentId = "1886780721", + ExpectedBucketValue = 5254, + }, + new BucketerTestItem + { + UserId = "ppid2", ExperimentId = "1886780721", + ExpectedBucketValue = 4299, + }, + new BucketerTestItem + { + UserId = "ppid2", ExperimentId = "1886780722", + ExpectedBucketValue = 2434, + }, + new BucketerTestItem + { + UserId = "ppid3", ExperimentId = "1886780721", + ExpectedBucketValue = 5439, + }, + new BucketerTestItem + { + UserId = + "a very very very very very very very very very very very very very very very long ppd string", + ExperimentId = "1886780721", ExpectedBucketValue = 6128, + }, + }) { - new BucketerTestItem { UserId = "ppid1", ExperimentId = "1886780721", ExpectedBucketValue = 5254 }, - new BucketerTestItem { UserId = "ppid2", ExperimentId = "1886780721", ExpectedBucketValue = 4299 }, - new BucketerTestItem { UserId = "ppid2", ExperimentId = "1886780722", ExpectedBucketValue = 2434 }, - new BucketerTestItem { UserId = "ppid3", ExperimentId = "1886780721", ExpectedBucketValue = 5439 }, - new BucketerTestItem { UserId = "a very very very very very very very very very very very very very very very long ppd string", - ExperimentId = "1886780721", ExpectedBucketValue = 6128 }, - }) - { - int result = bucketer.GenerateBucketValue(item.BucketingId); - Assert.AreEqual(item.ExpectedBucketValue, result, + var result = bucketer.GenerateBucketValue(item.BucketingId); + Assert.AreEqual(item.ExpectedBucketValue, result, string.Format("Unexpected Bucket Value: [{0}] for [{1}]", result, item)); } } @@ -96,90 +121,126 @@ public void TestGenerateBucketValue() [Test] public void TestBucketValidExperimentNotInGroup() { - TestBucketer bucketer = new TestBucketer(LoggerMock.Object); + var bucketer = new TestBucketer(LoggerMock.Object); bucketer.SetBucketValues(new[] { 3000, 7000, 9000 }); - var variation = bucketer.Bucket(Config, Config.GetExperimentFromKey("test_experiment"), TestBucketingIdControl, TestUserId); + var variation = bucketer.Bucket(Config, Config.GetExperimentFromKey("test_experiment"), + TestBucketingIdControl, TestUserId); // control Assert.AreEqual(new Variation { Id = "7722370027", Key = "control" }, variation.ResultObject); - LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), Times.Exactly(2)); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "Assigned bucket [3000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "User [testUserId] is in variation [control] of experiment [test_experiment].")); - Assert.AreEqual(variation.DecisionReasons.ToReport(true)[0], "User [testUserId] is in variation [control] of experiment [test_experiment]."); + LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), + Times.Exactly(2)); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + "Assigned bucket [3000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "User [testUserId] is in variation [control] of experiment [test_experiment].")); + Assert.AreEqual(variation.DecisionReasons.ToReport(true)[0], + "User [testUserId] is in variation [control] of experiment [test_experiment]."); // variation - variation = bucketer.Bucket(Config, Config.GetExperimentFromKey("test_experiment"), TestBucketingIdControl, TestUserId); + variation = bucketer.Bucket(Config, Config.GetExperimentFromKey("test_experiment"), + TestBucketingIdControl, TestUserId); Assert.AreEqual(new Variation { Id = "7721010009", Key = "variation" }, variation.ResultObject); - LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), Times.Exactly(4)); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "Assigned bucket [7000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "User [testUserId] is in variation [variation] of experiment [test_experiment].")); - Assert.AreEqual(variation.DecisionReasons.ToReport(true)[0], "User [testUserId] is in variation [variation] of experiment [test_experiment]."); + LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), + Times.Exactly(4)); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + "Assigned bucket [7000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "User [testUserId] is in variation [variation] of experiment [test_experiment].")); + Assert.AreEqual(variation.DecisionReasons.ToReport(true)[0], + "User [testUserId] is in variation [variation] of experiment [test_experiment]."); // no variation - variation = bucketer.Bucket(Config, Config.GetExperimentFromKey("test_experiment"), TestBucketingIdControl, TestUserId); + variation = bucketer.Bucket(Config, Config.GetExperimentFromKey("test_experiment"), + TestBucketingIdControl, TestUserId); Assert.AreEqual(new Variation { }, - variation.ResultObject); + variation.ResultObject); - LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), Times.Exactly(6)); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "Assigned bucket [9000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); + LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), + Times.Exactly(6)); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + "Assigned bucket [9000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); LoggerMock.Verify(l => l.Log(LogLevel.INFO, "User [testUserId] is in no variation.")); Assert.AreEqual(variation.DecisionReasons.ToReport(true).Count, 1); - Assert.AreEqual(variation.DecisionReasons.ToReport(true)[0], "User [testUserId] is in no variation."); + Assert.AreEqual(variation.DecisionReasons.ToReport(true)[0], + "User [testUserId] is in no variation."); } [Test] public void TestBucketValidExperimentInGroup() { - TestBucketer bucketer = new TestBucketer(LoggerMock.Object); - + var bucketer = new TestBucketer(LoggerMock.Object); + // group_experiment_1 (20% experiment) // variation 1 bucketer.SetBucketValues(new[] { 1000, 4000 }); - var variation = bucketer.Bucket(Config, Config.GetExperimentFromKey("group_experiment_1"), TestBucketingIdControl, TestUserId); + var variation = bucketer.Bucket(Config, + Config.GetExperimentFromKey("group_experiment_1"), TestBucketingIdControl, + TestUserId); Assert.AreEqual(new Variation { Id = "7722260071", Key = "group_exp_1_var_1" }, variation.ResultObject); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "Assigned bucket [1000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "User [testUserId] is in experiment [group_experiment_1] of group [7722400015].")); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "Assigned bucket [4000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "User [testUserId] is in variation [group_exp_1_var_1] of experiment [group_experiment_1].")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + "Assigned bucket [1000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "User [testUserId] is in experiment [group_experiment_1] of group [7722400015].")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + "Assigned bucket [4000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "User [testUserId] is in variation [group_exp_1_var_1] of experiment [group_experiment_1].")); Assert.AreEqual(variation.DecisionReasons.ToReport(true).Count, 2); - Assert.AreEqual(variation.DecisionReasons.ToReport(true)[0], "User [testUserId] is in experiment [group_experiment_1] of group [7722400015]."); - Assert.AreEqual(variation.DecisionReasons.ToReport(true)[1], "User [testUserId] is in variation [group_exp_1_var_1] of experiment [group_experiment_1]."); + Assert.AreEqual(variation.DecisionReasons.ToReport(true)[0], + "User [testUserId] is in experiment [group_experiment_1] of group [7722400015]."); + Assert.AreEqual(variation.DecisionReasons.ToReport(true)[1], + "User [testUserId] is in variation [group_exp_1_var_1] of experiment [group_experiment_1]."); // variation 2 bucketer.SetBucketValues(new[] { 1500, 7000 }); - var variation1 = bucketer.Bucket(Config, Config.GetExperimentFromKey("group_experiment_1"), TestBucketingIdControl, TestUserId); + var variation1 = bucketer.Bucket(Config, + Config.GetExperimentFromKey("group_experiment_1"), TestBucketingIdControl, + TestUserId); Assert.AreEqual(new Variation { Id = "7722360022", Key = "group_exp_1_var_2" }, variation1.ResultObject); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "Assigned bucket [1500] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "User [testUserId] is in experiment [group_experiment_1] of group [7722400015].")); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "Assigned bucket [7000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "User [testUserId] is in variation [group_exp_1_var_1] of experiment [group_experiment_1].")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + "Assigned bucket [1500] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "User [testUserId] is in experiment [group_experiment_1] of group [7722400015].")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + "Assigned bucket [7000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "User [testUserId] is in variation [group_exp_1_var_1] of experiment [group_experiment_1].")); Assert.AreEqual(variation1.DecisionReasons.ToReport(true).Count, 2); - Assert.AreEqual(variation1.DecisionReasons.ToReport(true)[0], "User [testUserId] is in experiment [group_experiment_1] of group [7722400015]."); - Assert.AreEqual(variation1.DecisionReasons.ToReport(true)[1], "User [testUserId] is in variation [group_exp_1_var_2] of experiment [group_experiment_1]."); + Assert.AreEqual(variation1.DecisionReasons.ToReport(true)[0], + "User [testUserId] is in experiment [group_experiment_1] of group [7722400015]."); + Assert.AreEqual(variation1.DecisionReasons.ToReport(true)[1], + "User [testUserId] is in variation [group_exp_1_var_2] of experiment [group_experiment_1]."); // User not in experiment bucketer.SetBucketValues(new[] { 5000, 7000 }); - var variation2 = bucketer.Bucket(Config, Config.GetExperimentFromKey("group_experiment_1"), TestBucketingIdControl, TestUserId); + var variation2 = bucketer.Bucket(Config, + Config.GetExperimentFromKey("group_experiment_1"), TestBucketingIdControl, + TestUserId); Assert.AreEqual(new Variation { }, variation2.ResultObject); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "Assigned bucket [5000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "User [testUserId] is not in experiment [group_experiment_1] of group [7722400015].")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + "Assigned bucket [5000] to user [testUserId] with bucketing ID [testBucketingIdControl!].")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "User [testUserId] is not in experiment [group_experiment_1] of group [7722400015].")); Assert.AreEqual(variation2.DecisionReasons.ToReport(true).Count, 1); - Assert.AreEqual(variation2.DecisionReasons.ToReport(true)[0], "User [testUserId] is not in experiment [group_experiment_1] of group [7722400015]."); + Assert.AreEqual(variation2.DecisionReasons.ToReport(true)[0], + "User [testUserId] is not in experiment [group_experiment_1] of group [7722400015]."); } [Test] public void TestBucketInvalidExperiment() { var bucketer = new Bucketer(LoggerMock.Object); - + Assert.AreEqual(new Variation { }, - bucketer.Bucket(Config, new Experiment(), TestBucketingIdControl, TestUserId).ResultObject); + bucketer.Bucket(Config, new Experiment(), TestBucketingIdControl, TestUserId). + ResultObject); LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), Times.Never); } @@ -193,15 +254,18 @@ public void TestBucketWithBucketingId() var expectedVariation2 = new Variation { Id = "7721010009", Key = "variation" }; // make sure that the bucketing ID is used for the variation bucketing and not the user ID - var variationResult = bucketer.Bucket(Config, experiment, TestBucketingIdControl, TestUserIdBucketsToVariation); + var variationResult = bucketer.Bucket(Config, experiment, TestBucketingIdControl, + TestUserIdBucketsToVariation); Assert.AreEqual(expectedVariation, variationResult.ResultObject); Assert.AreEqual(variationResult.DecisionReasons.ToReport().Count, 0); - variationResult = bucketer.Bucket(Config, experiment, TestBucketingIdControl, TestUserIdBucketsToVariation); + variationResult = bucketer.Bucket(Config, experiment, TestBucketingIdControl, + TestUserIdBucketsToVariation); Assert.AreEqual(expectedVariation, variationResult.ResultObject); Assert.AreEqual(variationResult.DecisionReasons.ToReport(true).Count, 1); - Assert.AreEqual(variationResult.DecisionReasons.ToReport(true)[0], "User [bucketsToVariation!] is in variation [control] of experiment [test_experiment]."); + Assert.AreEqual(variationResult.DecisionReasons.ToReport(true)[0], + "User [bucketsToVariation!] is in variation [control] of experiment [test_experiment]."); } // Test for invalid experiment keys, null variation should be returned @@ -210,8 +274,10 @@ public void TestBucketVariationInvalidExperimentsWithBucketingId() { var bucketer = new Bucketer(LoggerMock.Object); var expectedVariation = new Variation(); - var variationResult = bucketer.Bucket(Config, Config.GetExperimentFromKey("invalid_experiment"), TestBucketingIdVariation, TestUserId); - Assert.AreEqual(expectedVariation, + var variationResult = bucketer.Bucket(Config, + Config.GetExperimentFromKey("invalid_experiment"), TestBucketingIdVariation, + TestUserId); + Assert.AreEqual(expectedVariation, variationResult.ResultObject); Assert.AreEqual(variationResult.DecisionReasons.ToReport().Count, 0); } @@ -222,18 +288,22 @@ public void TestBucketVariationGroupedExperimentsWithBucketingId() { var bucketer = new Bucketer(LoggerMock.Object); var expectedVariation = new Variation(); - var expectedGroupVariation = new Variation{ Id = "7725250007", Key = "group_exp_2_var_2" }; - var variationResult = bucketer.Bucket(Config, Config.GetExperimentFromKey("group_experiment_2"), + var expectedGroupVariation = new Variation + { Id = "7725250007", Key = "group_exp_2_var_2" }; + var variationResult = bucketer.Bucket(Config, + Config.GetExperimentFromKey("group_experiment_2"), TestBucketingIdGroupExp2Var2, TestUserIdBucketsToNoGroup); Assert.AreEqual(expectedGroupVariation, variationResult.ResultObject); Assert.AreEqual(variationResult.DecisionReasons.ToReport().Count, 0); - bucketer.Bucket(Config, Config.GetExperimentFromKey("group_experiment_2"), + bucketer.Bucket(Config, Config.GetExperimentFromKey("group_experiment_2"), TestBucketingIdGroupExp2Var2, TestUserIdBucketsToNoGroup); var report = variationResult.DecisionReasons.ToReport(true); Assert.AreEqual(report.Count, 2); - Assert.AreEqual(report[0], "User [testUserId] is in experiment [group_experiment_2] of group [7722400015]."); - Assert.AreEqual(report[1], "User [testUserId] is in variation [group_exp_2_var_2] of experiment [group_experiment_2]."); + Assert.AreEqual(report[0], + "User [testUserId] is in experiment [group_experiment_2] of group [7722400015]."); + Assert.AreEqual(report[1], + "User [testUserId] is in variation [group_exp_2_var_2] of experiment [group_experiment_2]."); } // Make sure that user gets bucketed into the rollout rule. @@ -244,16 +314,19 @@ public void TestBucketRolloutRule() var rollout = Config.GetRolloutFromId("166660"); var rolloutRule = rollout.Experiments[1]; var expectedVariation = Config.GetVariationFromId(rolloutRule.Key, "177773"); - - var variationResult = bucketer.Bucket(Config, rolloutRule, "testBucketingId", TestUserId); + + var variationResult = + bucketer.Bucket(Config, rolloutRule, "testBucketingId", TestUserId); Assert.True(TestData.CompareObjects(expectedVariation, variationResult.ResultObject)); Assert.AreEqual(variationResult.DecisionReasons.ToReport().Count, 0); - var variationsResult = bucketer.Bucket(Config, rolloutRule, "testBucketingId", TestUserId); + var variationsResult = + bucketer.Bucket(Config, rolloutRule, "testBucketingId", TestUserId); Assert.True(TestData.CompareObjects(expectedVariation, variationsResult.ResultObject)); Assert.AreEqual(variationsResult.DecisionReasons.ToReport(true).Count, 1); - Assert.AreEqual(variationsResult.DecisionReasons.ToReport(true)[0], "User [testUserId] is in variation [177773] of experiment [177772]."); + Assert.AreEqual(variationsResult.DecisionReasons.ToReport(true)[0], + "User [testUserId] is in variation [177773] of experiment [177772]."); } } } diff --git a/OptimizelySDK.Tests/ClientConfigHandlerTest.cs b/OptimizelySDK.Tests/ClientConfigHandlerTest.cs index ce8a2e578..d7763f218 100644 --- a/OptimizelySDK.Tests/ClientConfigHandlerTest.cs +++ b/OptimizelySDK.Tests/ClientConfigHandlerTest.cs @@ -16,19 +16,20 @@ #if !NETSTANDARD1_6 && !NET35 -using NUnit.Framework; using System.Configuration; +using NUnit.Framework; namespace OptimizelySDK.Tests { [TestFixture] public class ClientConfigHandlerTest { - [Test] public void TestHTTPAppConfigSection() { - var configSection = ConfigurationManager.GetSection("optlySDKConfigSection") as OptimizelySDKConfigSection; + var configSection = + ConfigurationManager.GetSection("optlySDKConfigSection") as + OptimizelySDKConfigSection; var httpSetting = configSection.HttpProjectConfig; Assert.IsNotNull(httpSetting); Assert.IsTrue(httpSetting.AutoUpdate); @@ -44,7 +45,9 @@ public void TestHTTPAppConfigSection() [Test] public void TestBatchEventAppConfigSection() { - var configSection = ConfigurationManager.GetSection("optlySDKConfigSection") as OptimizelySDKConfigSection; + var configSection = + ConfigurationManager.GetSection("optlySDKConfigSection") as + OptimizelySDKConfigSection; var batchSetting = configSection.BatchEventProcessor; Assert.IsNotNull(batchSetting); Assert.AreEqual(batchSetting.BatchSize, 10); @@ -52,7 +55,6 @@ public void TestBatchEventAppConfigSection() Assert.AreEqual(batchSetting.TimeoutInterval, 10000); Assert.IsTrue(batchSetting.DefaultStart); } - } } #endif diff --git a/OptimizelySDK.Tests/ConfigTest/FallbackProjectConfigManagerTest.cs b/OptimizelySDK.Tests/ConfigTest/FallbackProjectConfigManagerTest.cs index 5610ad092..c40b6551f 100644 --- a/OptimizelySDK.Tests/ConfigTest/FallbackProjectConfigManagerTest.cs +++ b/OptimizelySDK.Tests/ConfigTest/FallbackProjectConfigManagerTest.cs @@ -27,7 +27,8 @@ public class AtomicProjectConfigManagerTest [Test] public void TestStaticProjectConfigManagerReturnsCorrectProjectConfig() { - var expectedConfig = DatafileProjectConfig.Create(TestData.TypedAudienceDatafile, null, null); + var expectedConfig = + DatafileProjectConfig.Create(TestData.TypedAudienceDatafile, null, null); ConfigManager = new FallbackProjectConfigManager(expectedConfig); Assert.True(TestData.CompareObjects(expectedConfig, ConfigManager.GetConfig())); diff --git a/OptimizelySDK.Tests/ConfigTest/HttpProjectConfigManagerTest.cs b/OptimizelySDK.Tests/ConfigTest/HttpProjectConfigManagerTest.cs index 9a3bbb87b..08cb1049d 100644 --- a/OptimizelySDK.Tests/ConfigTest/HttpProjectConfigManagerTest.cs +++ b/OptimizelySDK.Tests/ConfigTest/HttpProjectConfigManagerTest.cs @@ -14,18 +14,18 @@ * limitations under the License. */ -using Moq; -using NUnit.Framework; -using OptimizelySDK.Config; -using OptimizelySDK.Logger; -using OptimizelySDK.Tests.NotificationTests; -using OptimizelySDK.Tests.Utils; using System; using System.Diagnostics; using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Moq; +using NUnit.Framework; +using OptimizelySDK.Config; +using OptimizelySDK.Logger; +using OptimizelySDK.Tests.NotificationTests; +using OptimizelySDK.Tests.Utils; namespace OptimizelySDK.Tests.DatafileManagement_Tests { @@ -34,7 +34,9 @@ public class HttpProjectConfigManagerTest { private Mock LoggerMock; private Mock HttpClientMock; - private Mock NotificationCallbackMock = new Mock(); + + private Mock NotificationCallbackMock = + new Mock(); [SetUp] public void Setup() @@ -45,28 +47,28 @@ public void Setup() TestHttpProjectConfigManagerUtil.SetClientFieldValue(HttpClientMock.Object); LoggerMock.Setup(l => l.Log(It.IsAny(), It.IsAny())); NotificationCallbackMock.Setup(nc => nc.TestConfigUpdateCallback()); - } [Test] public void TestHttpConfigManagerRetreiveProjectConfigByURL() { var t = MockSendAsync(TestData.Datafile); - HttpProjectConfigManager httpManager = new HttpProjectConfigManager.Builder() - .WithUrl("https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json") - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromMilliseconds(1000)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)) - .WithStartByDefault() - .Build(); + var httpManager = new HttpProjectConfigManager.Builder(). + WithUrl("https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json"). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromMilliseconds(1000)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)). + WithStartByDefault(). + Build(); // This method waits until SendAsync is not triggered. // Time is given here to avoid hanging-up in any worst case. t.Wait(1000); HttpClientMock.Verify(_ => _.SendAsync( - It.Is(requestMessage => - requestMessage.RequestUri.ToString() == "https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json" + It.Is(requestMessage => + requestMessage.RequestUri.ToString() == + "https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json" ))); httpManager.Dispose(); } @@ -76,15 +78,17 @@ public void TestHttpConfigManagerWithInvalidStatus() { var t = MockSendAsync(statusCode: HttpStatusCode.Forbidden); - HttpProjectConfigManager httpManager = new HttpProjectConfigManager.Builder() - .WithUrl("https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json") - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromMilliseconds(1000)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)) - .WithStartByDefault() - .Build(); + var httpManager = new HttpProjectConfigManager.Builder(). + WithUrl("https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json"). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromMilliseconds(1000)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)). + WithStartByDefault(). + Build(); - LoggerMock.Verify(_ => _.Log(LogLevel.ERROR, $"Error fetching datafile \"{HttpStatusCode.Forbidden}\""), Times.AtLeastOnce); + LoggerMock.Verify( + _ => _.Log(LogLevel.ERROR, + $"Error fetching datafile \"{HttpStatusCode.Forbidden}\""), Times.AtLeastOnce); httpManager.Dispose(); } @@ -93,7 +97,8 @@ public void TestHttpConfigManagerWithInvalidStatus() public void TestHttpClientHandler() { var httpConfigHandler = HttpProjectConfigManager.HttpClient.GetHttpClientHandler(); - Assert.IsTrue(httpConfigHandler.AutomaticDecompression == (System.Net.DecompressionMethods.Deflate | System.Net.DecompressionMethods.GZip)); + Assert.IsTrue(httpConfigHandler.AutomaticDecompression == + (DecompressionMethods.Deflate | DecompressionMethods.GZip)); } [Test] @@ -101,21 +106,22 @@ public void TestHttpConfigManagerRetreiveProjectConfigGivenEmptyFormatUseDefault { var t = MockSendAsync(TestData.Datafile); - HttpProjectConfigManager httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithFormat("") - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromMilliseconds(1000)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)) - .WithStartByDefault() - .Build(); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithFormat(""). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromMilliseconds(1000)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)). + WithStartByDefault(). + Build(); // This "Wait" notifies When SendAsync is triggered. // Time is given here to avoid hanging-up in any worst case. t.Wait(1000); HttpClientMock.Verify(_ => _.SendAsync( - It.Is(requestMessage => - requestMessage.RequestUri.ToString() == "https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json" + It.Is(requestMessage => + requestMessage.RequestUri.ToString() == + "https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json" ))); httpManager.Dispose(); } @@ -125,18 +131,19 @@ public void TestHttpConfigManagerRetreiveProjectConfigBySDKKey() { var t = MockSendAsync(TestData.Datafile); - HttpProjectConfigManager httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromMilliseconds(1000)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)) - .WithStartByDefault() - .Build(); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromMilliseconds(1000)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)). + WithStartByDefault(). + Build(); t.Wait(1000); HttpClientMock.Verify(_ => _.SendAsync( - It.Is(requestMessage => - requestMessage.RequestUri.ToString() == "https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json" + It.Is(requestMessage => + requestMessage.RequestUri.ToString() == + "https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json" ))); Assert.IsNotNull(httpManager.GetConfig()); httpManager.Dispose(); @@ -147,24 +154,25 @@ public void TestHttpConfigManagerRetreiveProjectConfigByFormat() { var t = MockSendAsync(TestData.Datafile); - HttpProjectConfigManager httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("10192104166") - .WithFormat("https://cdn.optimizely.com/json/{0}.json") - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromMilliseconds(1000)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)) - .WithStartByDefault() - .Build(true); + var httpManager = new HttpProjectConfigManager.Builder().WithSdkKey("10192104166"). + WithFormat("https://cdn.optimizely.com/json/{0}.json"). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromMilliseconds(1000)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)). + WithStartByDefault(). + Build(true); t.Wait(1000); HttpClientMock.Verify(_ => _.SendAsync( - It.Is(requestMessage => - requestMessage.RequestUri.ToString() == "https://cdn.optimizely.com/json/10192104166.json" + It.Is(requestMessage => + requestMessage.RequestUri.ToString() == + "https://cdn.optimizely.com/json/10192104166.json" ))); - + Assert.IsNotNull(httpManager.GetConfig()); - LoggerMock.Verify(_ => _.Log(LogLevel.DEBUG, "Making datafile request to url \"https://cdn.optimizely.com/json/10192104166.json\"")); + LoggerMock.Verify(_ => _.Log(LogLevel.DEBUG, + "Making datafile request to url \"https://cdn.optimizely.com/json/10192104166.json\"")); httpManager.Dispose(); } @@ -173,24 +181,25 @@ public void TestHttpProjectConfigManagerDoesntRaiseExceptionForDefaultErrorHandl { var t = MockSendAsync(TestData.Datafile); - HttpProjectConfigManager httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("10192104166") - .WithFormat("https://cdn.optimizely.com/json/{0}.json") - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromMilliseconds(1000)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)) - .WithStartByDefault() - .Build(true); + var httpManager = new HttpProjectConfigManager.Builder().WithSdkKey("10192104166"). + WithFormat("https://cdn.optimizely.com/json/{0}.json"). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromMilliseconds(1000)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)). + WithStartByDefault(). + Build(true); t.Wait(1000); HttpClientMock.Verify(_ => _.SendAsync( - It.Is(requestMessage => - requestMessage.RequestUri.ToString() == "https://cdn.optimizely.com/json/10192104166.json" + It.Is(requestMessage => + requestMessage.RequestUri.ToString() == + "https://cdn.optimizely.com/json/10192104166.json" ))); var datafileConfig = httpManager.GetConfig(); Assert.IsNotNull(datafileConfig); Assert.IsNull(datafileConfig.GetExperimentFromKey("project_config_not_valid").Key); - LoggerMock.Verify(_ => _.Log(LogLevel.DEBUG, "Making datafile request to url \"https://cdn.optimizely.com/json/10192104166.json\"")); + LoggerMock.Verify(_ => _.Log(LogLevel.DEBUG, + "Making datafile request to url \"https://cdn.optimizely.com/json/10192104166.json\"")); httpManager.Dispose(); } @@ -198,17 +207,18 @@ public void TestHttpProjectConfigManagerDoesntRaiseExceptionForDefaultErrorHandl public void TestOnReadyPromiseResolvedImmediatelyWhenDatafileIsProvided() { // Revision - 42 - var t = MockSendAsync(TestData.SimpleABExperimentsDatafile, TimeSpan.FromMilliseconds(100)); + var t = MockSendAsync(TestData.SimpleABExperimentsDatafile, + TimeSpan.FromMilliseconds(100)); - HttpProjectConfigManager httpManager = new HttpProjectConfigManager.Builder() + var httpManager = new HttpProjectConfigManager.Builder() // Revision - 15 - .WithSdkKey("10192104166") - .WithDatafile(TestData.Datafile) - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromMilliseconds(1000)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)) - .WithStartByDefault() - .Build(); + .WithSdkKey("10192104166"). + WithDatafile(TestData.Datafile). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromMilliseconds(1000)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)). + WithStartByDefault(). + Build(); // OnReady waits until is resolved, need to add time in case of deadlock. httpManager.OnReady().Wait(10000); @@ -227,15 +237,16 @@ public void TestOnReadyPromiseResolvedImmediatelyWhenDatafileIsProvided() public void TestOnReadyPromiseWaitsForProjectConfigRetrievalWhenDatafileIsNotProvided() { // Revision - 42 - var t = MockSendAsync(TestData.SimpleABExperimentsDatafile, TimeSpan.FromMilliseconds(1000)); - - HttpProjectConfigManager httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromSeconds(2)) - .WithBlockingTimeoutPeriod(TimeSpan.FromSeconds(1)) - .WithStartByDefault(true) - .Build(); + var t = MockSendAsync(TestData.SimpleABExperimentsDatafile, + TimeSpan.FromMilliseconds(1000)); + + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromSeconds(2)). + WithBlockingTimeoutPeriod(TimeSpan.FromSeconds(1)). + WithStartByDefault(true). + Build(); t.Wait(); // OnReady waits until is resolved, need to add time in case of deadlock. @@ -249,14 +260,15 @@ public void TestHttpConfigManagerDoesNotWaitForTheConfigWhenDeferIsTrue() { var t = MockSendAsync(TestData.Datafile, TimeSpan.FromMilliseconds(150)); - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromSeconds(2)) + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromSeconds(2)) // negligible timeout - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(50)) - .WithStartByDefault() - .Build(false); + . + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(50)). + WithStartByDefault(). + Build(false); // When blocking timeout is 0 and defer is false and getconfig immediately called // should return null @@ -265,7 +277,7 @@ public void TestHttpConfigManagerDoesNotWaitForTheConfigWhenDeferIsTrue() t.Wait(); // in case deadlock, it will release after 3sec. httpManager.OnReady().Wait(8000); - + HttpClientMock.Verify(_ => _.SendAsync(It.IsAny())); Assert.NotNull(httpManager.GetConfig()); @@ -273,20 +285,22 @@ public void TestHttpConfigManagerDoesNotWaitForTheConfigWhenDeferIsTrue() } #region Notification + [Test] public void TestHttpConfigManagerSendConfigUpdateNotificationWhenProjectConfigGetsUpdated() - { + { var t = MockSendAsync(TestData.Datafile); - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromMilliseconds(1000)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(1000)) - .WithStartByDefault(false) - .Build(true); - - httpManager.NotifyOnProjectConfigUpdate += NotificationCallbackMock.Object.TestConfigUpdateCallback; + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromMilliseconds(1000)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(1000)). + WithStartByDefault(false). + Build(true); + + httpManager.NotifyOnProjectConfigUpdate += + NotificationCallbackMock.Object.TestConfigUpdateCallback; httpManager.Start(); Assert.NotNull(httpManager.GetConfig()); @@ -297,130 +311,148 @@ public void TestHttpConfigManagerSendConfigUpdateNotificationWhenProjectConfigGe [Test] public void TestHttpConfigManagerDoesNotSendConfigUpdateNotificationWhenDatafileIsProvided() - { + { var t = MockSendAsync(TestData.Datafile, TimeSpan.FromMilliseconds(100)); - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithDatafile(TestData.Datafile) - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromMilliseconds(1000)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)) - .Build(); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithDatafile(TestData.Datafile). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromMilliseconds(1000)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)). + Build(); - httpManager.NotifyOnProjectConfigUpdate += NotificationCallbackMock.Object.TestConfigUpdateCallback; + httpManager.NotifyOnProjectConfigUpdate += + NotificationCallbackMock.Object.TestConfigUpdateCallback; NotificationCallbackMock.Verify(nc => nc.TestConfigUpdateCallback(), Times.Never); - Assert.NotNull(httpManager.GetConfig()); Assert.NotNull(httpManager.GetConfig()); + Assert.NotNull(httpManager.GetConfig()); + Assert.NotNull(httpManager.GetConfig()); httpManager.Dispose(); } [Test] public void TestDefaultBlockingTimeoutWhileProvidingZero() { - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithDatafile(TestData.Datafile) - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromMilliseconds(1000)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(0)) - .WithStartByDefault(true) - .Build(true); - - var fieldInfo = httpManager.GetType().GetField("BlockingTimeout", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithDatafile(TestData.Datafile). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromMilliseconds(1000)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(0)). + WithStartByDefault(true). + Build(true); + + var fieldInfo = httpManager.GetType(). + GetField("BlockingTimeout", + System.Reflection.BindingFlags.Instance | + System.Reflection.BindingFlags.NonPublic); var expectedBlockingTimeout = (TimeSpan)fieldInfo.GetValue(httpManager); Assert.AreNotEqual(expectedBlockingTimeout.TotalSeconds, TimeSpan.Zero.TotalSeconds); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, $"Blocking timeout is not valid, using default blocking timeout {TimeSpan.FromSeconds(15).TotalMilliseconds}ms")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + $"Blocking timeout is not valid, using default blocking timeout {TimeSpan.FromSeconds(15).TotalMilliseconds}ms")); httpManager.Dispose(); } [Test] public void TestDefaultPeriodWhileProvidingZero() { - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithDatafile(TestData.Datafile) - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromMilliseconds(0)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(1000)) - .WithStartByDefault(true) - .Build(true); - - var fieldInfo = typeof(PollingProjectConfigManager).GetField("PollingInterval", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithDatafile(TestData.Datafile). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromMilliseconds(0)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(1000)). + WithStartByDefault(true). + Build(true); + + var fieldInfo = typeof(PollingProjectConfigManager).GetField("PollingInterval", + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); var expectedPollingInterval = (TimeSpan)fieldInfo.GetValue(httpManager); Assert.AreNotEqual(expectedPollingInterval.TotalSeconds, TimeSpan.Zero.TotalSeconds); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, $"Polling interval is not valid for periodic calls, using default period {TimeSpan.FromMinutes(5).TotalMilliseconds}ms")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + $"Polling interval is not valid for periodic calls, using default period {TimeSpan.FromMinutes(5).TotalMilliseconds}ms")); httpManager.Dispose(); } [Test] public void TestDefaultPeriodWhileProvidingNegative() { - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithDatafile(TestData.Datafile) - .WithLogger(LoggerMock.Object) - .WithPollingInterval(TimeSpan.FromMilliseconds(-1)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(1000)) - .WithStartByDefault(true) - .Build(true); - - var fieldInfo = typeof(PollingProjectConfigManager).GetField("PollingInterval", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithDatafile(TestData.Datafile). + WithLogger(LoggerMock.Object). + WithPollingInterval(TimeSpan.FromMilliseconds(-1)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(1000)). + WithStartByDefault(true). + Build(true); + + var fieldInfo = typeof(PollingProjectConfigManager).GetField("PollingInterval", + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); var expectedPollingInterval = (TimeSpan)fieldInfo.GetValue(httpManager); Assert.AreNotEqual(expectedPollingInterval.TotalSeconds, TimeSpan.Zero.TotalSeconds); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, $"Polling interval is not valid for periodic calls, using default period {TimeSpan.FromMinutes(5).TotalMilliseconds}ms")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + $"Polling interval is not valid for periodic calls, using default period {TimeSpan.FromMinutes(5).TotalMilliseconds}ms")); httpManager.Dispose(); } [Test] public void TestDefaultPeriodWhileNotProvidingValue() { - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithDatafile(TestData.Datafile) - .WithLogger(LoggerMock.Object) - .Build(true); - - var fieldInfo = typeof(PollingProjectConfigManager).GetField("PollingInterval", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithDatafile(TestData.Datafile). + WithLogger(LoggerMock.Object). + Build(true); + + var fieldInfo = typeof(PollingProjectConfigManager).GetField("PollingInterval", + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); var expectedPollingInterval = (TimeSpan)fieldInfo.GetValue(httpManager); Assert.AreNotEqual(expectedPollingInterval.TotalSeconds, TimeSpan.Zero.TotalSeconds); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, $"No polling interval provided, using default period {TimeSpan.FromMinutes(5).TotalMilliseconds}ms")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + $"No polling interval provided, using default period {TimeSpan.FromMinutes(5).TotalMilliseconds}ms")); httpManager.Dispose(); } [Test] public void TestDefaultBlockingTimeoutWhileNotProvidingValue() { - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithDatafile(TestData.Datafile) - .WithLogger(LoggerMock.Object) - .Build(true); - - var fieldInfo = httpManager.GetType().GetField("BlockingTimeout", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithDatafile(TestData.Datafile). + WithLogger(LoggerMock.Object). + Build(true); + + var fieldInfo = httpManager.GetType(). + GetField("BlockingTimeout", + System.Reflection.BindingFlags.Instance | + System.Reflection.BindingFlags.NonPublic); var expectedBlockingTimeout = (TimeSpan)fieldInfo.GetValue(httpManager); Assert.AreNotEqual(expectedBlockingTimeout.TotalSeconds, TimeSpan.Zero.TotalSeconds); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, $"No Blocking timeout provided, using default blocking timeout {TimeSpan.FromSeconds(15).TotalMilliseconds}ms")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + $"No Blocking timeout provided, using default blocking timeout {TimeSpan.FromSeconds(15).TotalMilliseconds}ms")); httpManager.Dispose(); } [Test] public void TestDefaultValuesWhenNotProvided() { - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithDatafile(TestData.Datafile) - .WithLogger(LoggerMock.Object) - .Build(true); - - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, $"No polling interval provided, using default period {TimeSpan.FromMinutes(5).TotalMilliseconds}ms")); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, $"No Blocking timeout provided, using default blocking timeout {TimeSpan.FromSeconds(15).TotalMilliseconds}ms")); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithDatafile(TestData.Datafile). + WithLogger(LoggerMock.Object). + Build(true); + + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + $"No polling interval provided, using default period {TimeSpan.FromMinutes(5).TotalMilliseconds}ms")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + $"No Blocking timeout provided, using default blocking timeout {TimeSpan.FromSeconds(15).TotalMilliseconds}ms")); httpManager.Dispose(); } @@ -429,19 +461,20 @@ public void TestAuthUrlWhenTokenProvided() { var t = MockSendAsync(); - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithLogger(LoggerMock.Object) - .WithAccessToken("datafile1") - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(50)) - .Build(true); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithLogger(LoggerMock.Object). + WithAccessToken("datafile1"). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(50)). + Build(true); // it's to wait if SendAsync is not triggered. t.Wait(2000); HttpClientMock.Verify(_ => _.SendAsync( - It.Is(requestMessage => - requestMessage.RequestUri.ToString() == "https://config.optimizely.com/datafiles/auth/QBw9gFM8oTn7ogY9ANCC1z.json" + It.Is(requestMessage => + requestMessage.RequestUri.ToString() == + "https://config.optimizely.com/datafiles/auth/QBw9gFM8oTn7ogY9ANCC1z.json" ))); httpManager.Dispose(); } @@ -451,17 +484,18 @@ public void TestDefaultUrlWhenTokenNotProvided() { var t = MockSendAsync(); - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithLogger(LoggerMock.Object) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(50)) - .Build(true); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithLogger(LoggerMock.Object). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(50)). + Build(true); // it's to wait if SendAsync is not triggered. t.Wait(2000); HttpClientMock.Verify(_ => _.SendAsync( - It.Is(requestMessage => - requestMessage.RequestUri.ToString() == "https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json" + It.Is(requestMessage => + requestMessage.RequestUri.ToString() == + "https://cdn.optimizely.com/datafiles/QBw9gFM8oTn7ogY9ANCC1z.json" ))); httpManager.Dispose(); } @@ -471,19 +505,19 @@ public void TestAuthenticationHeaderWhenTokenProvided() { var t = MockSendAsync(); - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithLogger(LoggerMock.Object) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(50)) - .WithAccessToken("datafile1") - .Build(true); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithLogger(LoggerMock.Object). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(50)). + WithAccessToken("datafile1"). + Build(true); // it's to wait if SendAsync is not triggered. t.Wait(2000); HttpClientMock.Verify(_ => _.SendAsync( - It.Is(requestMessage => - requestMessage.Headers.Authorization.ToString() == "Bearer datafile1" + It.Is(requestMessage => + requestMessage.Headers.Authorization.ToString() == "Bearer datafile1" ))); httpManager.Dispose(); } @@ -492,27 +526,31 @@ public void TestAuthenticationHeaderWhenTokenProvided() public void TestFormatUrlHigherPriorityThanDefaultUrl() { var t = MockSendAsync(); - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithLogger(LoggerMock.Object) - .WithFormat("http://customformat/{0}.json") - .WithAccessToken("datafile1") - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(50)) - .Build(true); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithLogger(LoggerMock.Object). + WithFormat("http://customformat/{0}.json"). + WithAccessToken("datafile1"). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(50)). + Build(true); // it's to wait if SendAsync is not triggered. t.Wait(2000); HttpClientMock.Verify(_ => _.SendAsync( - It.Is(requestMessage => - requestMessage.RequestUri.ToString() == "http://customformat/QBw9gFM8oTn7ogY9ANCC1z.json" + It.Is(requestMessage => + requestMessage.RequestUri.ToString() == + "http://customformat/QBw9gFM8oTn7ogY9ANCC1z.json" ))); httpManager.Dispose(); - } - public Task MockSendAsync(string datafile = null, TimeSpan? delay = null, HttpStatusCode statusCode = HttpStatusCode.OK) + public Task MockSendAsync(string datafile = null, TimeSpan? delay = null, + HttpStatusCode statusCode = HttpStatusCode.OK + ) { - return TestHttpProjectConfigManagerUtil.MockSendAsync(HttpClientMock, datafile, delay, statusCode); + return TestHttpProjectConfigManagerUtil.MockSendAsync(HttpClientMock, datafile, delay, + statusCode); } + #endregion } } diff --git a/OptimizelySDK.Tests/ConfigTest/PollingProjectConfigManagerTest.cs b/OptimizelySDK.Tests/ConfigTest/PollingProjectConfigManagerTest.cs index 96603d6b8..ba9bb110b 100644 --- a/OptimizelySDK.Tests/ConfigTest/PollingProjectConfigManagerTest.cs +++ b/OptimizelySDK.Tests/ConfigTest/PollingProjectConfigManagerTest.cs @@ -14,14 +14,14 @@ * limitations under the License. */ +using System; +using System.Collections.Generic; +using System.Diagnostics; using Moq; using NUnit.Framework; using OptimizelySDK.Config; using OptimizelySDK.Logger; using OptimizelySDK.Tests.DatafileManagementTests; -using System; -using System.Collections.Generic; -using System.Diagnostics; namespace OptimizelySDK.Tests.DatafileManagement_Tests { @@ -85,7 +85,7 @@ public void TestImmediatelyCalledScheduledRequestIfPreviousRequestDelayedInRespo var configManager = new TestPollingProjectConfigManager(TimeSpan.FromSeconds(1), TimeSpan.FromMilliseconds(1500), true, LoggerMock.Object, new int[] { - 1200, 500, 500 + 1200, 500, 500, }); configManager.Start(); @@ -110,7 +110,7 @@ public void TestTimedoutIfTakingMorethanBlockingTimeout() var configManager = new TestPollingProjectConfigManager(TimeSpan.FromSeconds(3), TimeSpan.FromMilliseconds(1000), true, LoggerMock.Object, new int[] { - 1300, 500, 500 + 1300, 500, 500, }); configManager.Start(); @@ -128,9 +128,9 @@ public void TestTimedoutOnlyIfSchedulerStarted() var configManager = new TestPollingProjectConfigManager(TimeSpan.FromSeconds(3), TimeSpan.FromMilliseconds(1000), true, LoggerMock.Object, new int[] { - 1300, 500, 500 + 1300, 500, 500, }); - Stopwatch sw = new Stopwatch(); + var sw = new Stopwatch(); sw.Start(); var config = configManager.GetConfig(); sw.Stop(); @@ -146,9 +146,9 @@ public void TestDontTimedoutIfSchedulerNotStarted() var configManager = new TestPollingProjectConfigManager(TimeSpan.FromSeconds(3), TimeSpan.FromMilliseconds(1000), true, LoggerMock.Object, new int[] { - 1300, 500, 500 + 1300, 500, 500, }); - Stopwatch sw = new Stopwatch(); + var sw = new Stopwatch(); sw.Start(); var config = configManager.GetConfig(); sw.Stop(); @@ -167,14 +167,14 @@ public void TestReturnDatafileImmediatelyOnceGetValidDatafileRemotely() { PollingTime = 500, ChangeVersion = false, - ConfigDatafile = projConfig + ConfigDatafile = projConfig, }, new TestPollingData { PollingTime = 500, ChangeVersion = false, - ConfigDatafile = projConfig - } + ConfigDatafile = projConfig, + }, }; var configManager = new TestPollingProjectConfigManager(TimeSpan.FromSeconds(3), @@ -204,20 +204,20 @@ public void TestWaitUntilValidDatfileIsNotGiven() { PollingTime = 50, ChangeVersion = false, - ConfigDatafile = null + ConfigDatafile = null, }, new TestPollingData { PollingTime = 50, ChangeVersion = false, - ConfigDatafile = null + ConfigDatafile = null, }, new TestPollingData { PollingTime = 50, ChangeVersion = false, - ConfigDatafile = projConfig - } + ConfigDatafile = projConfig, + }, }; @@ -241,20 +241,20 @@ public void TestWaitUntilValidDatafileIsNotGivenOrTimedout() { PollingTime = 50, ChangeVersion = false, - ConfigDatafile = null + ConfigDatafile = null, }, new TestPollingData { PollingTime = 50, ChangeVersion = false, - ConfigDatafile = null + ConfigDatafile = null, }, new TestPollingData { PollingTime = 50, ChangeVersion = false, - ConfigDatafile = null - } + ConfigDatafile = null, + }, }; var configManager = new TestPollingProjectConfigManager(TimeSpan.FromMilliseconds(1000), diff --git a/OptimizelySDK.Tests/ConfigTest/ProjectConfigProps.cs b/OptimizelySDK.Tests/ConfigTest/ProjectConfigProps.cs index 2b5e9ff5f..e26414c49 100644 --- a/OptimizelySDK.Tests/ConfigTest/ProjectConfigProps.cs +++ b/OptimizelySDK.Tests/ConfigTest/ProjectConfigProps.cs @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using System; using OptimizelySDK.Config; using OptimizelySDK.Tests.Utils; @@ -34,27 +35,37 @@ public class ProjectConfigManagerProps public ProjectConfigManagerProps(HttpProjectConfigManager projectConfigManager) { - LastModified = Reflection.GetFieldValue(projectConfigManager, "LastModifiedSince"); - Url = Reflection.GetFieldValue(projectConfigManager, "Url"); - DatafileAccessToken = Reflection.GetFieldValue(projectConfigManager, "DatafileAccessToken"); + LastModified = + Reflection.GetFieldValue(projectConfigManager, + "LastModifiedSince"); + Url = Reflection.GetFieldValue(projectConfigManager, + "Url"); + DatafileAccessToken = + Reflection.GetFieldValue(projectConfigManager, + "DatafileAccessToken"); - AutoUpdate = Reflection.GetPropertyValue(projectConfigManager, "AutoUpdate"); - PollingInterval = Reflection.GetFieldValue(projectConfigManager, "PollingInterval"); - BlockingTimeout = Reflection.GetFieldValue(projectConfigManager, "BlockingTimeout"); + AutoUpdate = + Reflection.GetPropertyValue(projectConfigManager, + "AutoUpdate"); + PollingInterval = + Reflection.GetFieldValue(projectConfigManager, + "PollingInterval"); + BlockingTimeout = + Reflection.GetFieldValue(projectConfigManager, + "BlockingTimeout"); } /// /// To create default instance of expected values. /// - public ProjectConfigManagerProps() - { - - } + public ProjectConfigManagerProps() { } public override bool Equals(object obj) { if (obj == null) + { return false; + } var projectConfigManager = obj as ProjectConfigManagerProps; if (projectConfigManager == null) diff --git a/OptimizelySDK.Tests/ConfigTest/TestPollingProjectConfigManager.cs b/OptimizelySDK.Tests/ConfigTest/TestPollingProjectConfigManager.cs index b35621ae0..9d3d27fb8 100644 --- a/OptimizelySDK.Tests/ConfigTest/TestPollingProjectConfigManager.cs +++ b/OptimizelySDK.Tests/ConfigTest/TestPollingProjectConfigManager.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright 2019, Optimizely * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,51 +24,70 @@ public class TestPollingData { public int PollingTime { get; set; } public ProjectConfig ConfigDatafile { get; set; } - public ProjectConfig ConfigVersioned { - get { + + public ProjectConfig ConfigVersioned + { + get + { if (ConfigDatafile == null) + { return null; + } + if (ChangeVersion) + { ConfigDatafile.Version = DateTime.Now.Ticks.ToString(); + } return ConfigDatafile; } } + public bool ChangeVersion { get; set; } } public class TestPollingProjectConfigManager : PollingProjectConfigManager { - TestPollingData[] PollingData; + private TestPollingData[] PollingData; public int Counter = 0; - public TestPollingProjectConfigManager(TimeSpan period, TimeSpan blockingTimeout, bool autoUpdate, ILogger logger, int[] pollingSequence) + public TestPollingProjectConfigManager(TimeSpan period, TimeSpan blockingTimeout, + bool autoUpdate, ILogger logger, int[] pollingSequence + ) : base(period, blockingTimeout, autoUpdate, logger, null) { - if (pollingSequence != null) { - System.Collections.Generic.List pollingData = new System.Collections.Generic.List(); - foreach (var pollingTime in pollingSequence) { + if (pollingSequence != null) + { + var pollingData = new System.Collections.Generic.List(); + foreach (var pollingTime in pollingSequence) + { pollingData.Add(new TestPollingData { PollingTime = pollingTime }); } - this.PollingData = pollingData.ToArray(); + + PollingData = pollingData.ToArray(); } } - public TestPollingProjectConfigManager(TimeSpan period, TimeSpan blockingTimeout, bool autoUpdate, ILogger logger, TestPollingData[] pollingData, bool startByDefault = true) + public TestPollingProjectConfigManager(TimeSpan period, TimeSpan blockingTimeout, + bool autoUpdate, ILogger logger, TestPollingData[] pollingData, + bool startByDefault = true + ) : base(period, blockingTimeout, autoUpdate, logger, null) { - if (pollingData != null) { - this.PollingData = pollingData; + if (pollingData != null) + { + PollingData = pollingData; } } protected override ProjectConfig Poll() { - TimeSpan waitingTime = TimeSpan.FromMilliseconds(500); + var waitingTime = TimeSpan.FromMilliseconds(500); ProjectConfig response = null; - if (PollingData.Length > Counter) { + if (PollingData.Length > Counter) + { waitingTime = TimeSpan.FromMilliseconds(PollingData[Counter].PollingTime); // Will automatically change version if ChangeVersion is true. response = PollingData[Counter].ConfigVersioned; diff --git a/OptimizelySDK.Tests/DecisionServiceTest.cs b/OptimizelySDK.Tests/DecisionServiceTest.cs index f15d41ea9..633847ae1 100644 --- a/OptimizelySDK.Tests/DecisionServiceTest.cs +++ b/OptimizelySDK.Tests/DecisionServiceTest.cs @@ -15,6 +15,7 @@ * limitations under the License. */ +using System.Collections.Generic; using Moq; using NUnit.Framework; using OptimizelySDK.Bucketing; @@ -24,7 +25,6 @@ using OptimizelySDK.Logger; using OptimizelySDK.OptimizelyDecisions; using OptimizelySDK.Utils; -using System.Collections.Generic; namespace OptimizelySDK.Tests { @@ -57,29 +57,39 @@ public void SetUp() ErrorHandlerMock = new Mock(); UserProfileServiceMock = new Mock(); BucketerMock = new Mock(LoggerMock.Object); - ProjectConfig = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, ErrorHandlerMock.Object); + ProjectConfig = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, + ErrorHandlerMock.Object); WhitelistedExperiment = ProjectConfig.ExperimentIdMap["224"]; WhitelistedVariation = WhitelistedExperiment.VariationKeyToVariationMap["vtag5"]; - DecisionService = new DecisionService(new Bucketer(LoggerMock.Object), ErrorHandlerMock.Object, null, LoggerMock.Object); - DecisionServiceMock = new Mock(BucketerMock.Object, ErrorHandlerMock.Object, null, LoggerMock.Object) { CallBase = true }; - DecisionReasons = new OptimizelySDK.OptimizelyDecisions.DecisionReasons(); + DecisionService = new DecisionService(new Bucketer(LoggerMock.Object), + ErrorHandlerMock.Object, null, LoggerMock.Object); + DecisionServiceMock = new Mock(BucketerMock.Object, + ErrorHandlerMock.Object, null, LoggerMock.Object) + { CallBase = true }; + DecisionReasons = new DecisionReasons(); - VariationWithKeyControl = ProjectConfig.GetVariationFromKey("test_experiment", "control"); - VariationWithKeyVariation = ProjectConfig.GetVariationFromKey("test_experiment", "variation"); + VariationWithKeyControl = + ProjectConfig.GetVariationFromKey("test_experiment", "control"); + VariationWithKeyVariation = + ProjectConfig.GetVariationFromKey("test_experiment", "variation"); - Config = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, ErrorHandlerMock.Object); + Config = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, + ErrorHandlerMock.Object); } [Test] public void TestFindValidatedForcedDecisionReturnsCorrectDecisionWithNullVariation() { - DecisionService decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, null, LoggerMock.Object); + var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, + null, LoggerMock.Object); - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); var decisionReasons = new DecisionReasons(); - decisionReasons.AddInfo("{0}", "Invalid variation is mapped to flag: flagKey and rule: rule forced decision map."); + decisionReasons.AddInfo("{0}", + "Invalid variation is mapped to flag: flagKey and rule: rule forced decision map."); var expectedResult = Result.NullResult(decisionReasons); var user = optlyObject.CreateUserContext(GenericUserId); @@ -93,115 +103,151 @@ public void TestFindValidatedForcedDecisionReturnsCorrectDecisionWithNullVariati [Test] public void TestGetVariationForcedVariationPrecedesAudienceEval() { - DecisionService decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, null, LoggerMock.Object); - Experiment experiment = ProjectConfig.Experiments[8]; - Variation expectedVariation = experiment.Variations[0]; - - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); - OptimizelyUserContextMock = new Mock(optlyObject, WhitelistedUserId, new UserAttributes(), ErrorHandlerMock.Object, LoggerMock.Object); + var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, + null, LoggerMock.Object); + var experiment = ProjectConfig.Experiments[8]; + var expectedVariation = experiment.Variations[0]; + + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); + OptimizelyUserContextMock = new Mock(optlyObject, + WhitelistedUserId, new UserAttributes(), ErrorHandlerMock.Object, + LoggerMock.Object); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(GenericUserId); // user excluded without audiences and whitelisting - Assert.IsNull(decisionService.GetVariation(experiment, OptimizelyUserContextMock.Object, ProjectConfig).ResultObject); + Assert.IsNull(decisionService. + GetVariation(experiment, OptimizelyUserContextMock.Object, ProjectConfig). + ResultObject); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(WhitelistedUserId); - var actualVariation = decisionService.GetVariation(experiment, OptimizelyUserContextMock.Object, ProjectConfig); + var actualVariation = decisionService.GetVariation(experiment, + OptimizelyUserContextMock.Object, ProjectConfig); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("User \"{0}\" is forced in variation \"vtag5\".", WhitelistedUserId)), Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.INFO, + string.Format("User \"{0}\" is forced in variation \"vtag5\".", + WhitelistedUserId)), Times.Once); // no attributes provided for a experiment that has an audience Assertions.AreEqual(expectedVariation, actualVariation.ResultObject); - BucketerMock.Verify(_ => _.Bucket(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + BucketerMock.Verify( + _ => _.Bucket(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny()), Times.Never); } [Test] public void TestGetVariationLogsErrorWhenUserProfileMapItsNull() { - Experiment experiment = ProjectConfig.Experiments[8]; - Variation variation = experiment.Variations[0]; + var experiment = ProjectConfig.Experiments[8]; + var variation = experiment.Variations[0]; - Decision decision = new Decision(variation.Id); + var decision = new Decision(variation.Id); Dictionary userProfile = null; UserProfileServiceMock.Setup(up => up.Lookup(WhitelistedUserId)).Returns(userProfile); - DecisionService decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, UserProfileServiceMock.Object, LoggerMock.Object); + var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, + UserProfileServiceMock.Object, LoggerMock.Object); var options = new OptimizelyDecideOption[] { OptimizelyDecideOption.INCLUDE_REASONS }; OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(GenericUserId); - var variationResult = decisionService.GetVariation(experiment, OptimizelyUserContextMock.Object, ProjectConfig, options); - Assert.AreEqual(variationResult.DecisionReasons.ToReport(true)[0], "We were unable to get a user profile map from the UserProfileService."); - Assert.AreEqual(variationResult.DecisionReasons.ToReport(true)[1], "Audiences for experiment \"etag3\" collectively evaluated to FALSE"); - Assert.AreEqual(variationResult.DecisionReasons.ToReport(true)[2], "User \"genericUserId\" does not meet conditions to be in experiment \"etag3\"."); + var variationResult = decisionService.GetVariation(experiment, + OptimizelyUserContextMock.Object, ProjectConfig, options); + Assert.AreEqual(variationResult.DecisionReasons.ToReport(true)[0], + "We were unable to get a user profile map from the UserProfileService."); + Assert.AreEqual(variationResult.DecisionReasons.ToReport(true)[1], + "Audiences for experiment \"etag3\" collectively evaluated to FALSE"); + Assert.AreEqual(variationResult.DecisionReasons.ToReport(true)[2], + "User \"genericUserId\" does not meet conditions to be in experiment \"etag3\"."); } [Test] public void TestGetVariationEvaluatesUserProfileBeforeAudienceTargeting() { - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); - OptimizelyUserContextMock = new Mock(optlyObject, WhitelistedUserId, new UserAttributes(), ErrorHandlerMock.Object, LoggerMock.Object); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); + OptimizelyUserContextMock = new Mock(optlyObject, + WhitelistedUserId, new UserAttributes(), ErrorHandlerMock.Object, + LoggerMock.Object); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(GenericUserId); - Experiment experiment = ProjectConfig.Experiments[8]; - Variation variation = experiment.Variations[0]; + var experiment = ProjectConfig.Experiments[8]; + var variation = experiment.Variations[0]; - Decision decision = new Decision(variation.Id); - UserProfile userProfile = new UserProfile(UserProfileId, new Dictionary + var decision = new Decision(variation.Id); + var userProfile = new UserProfile(UserProfileId, new Dictionary { - { experiment.Id, decision } + { experiment.Id, decision }, }); - UserProfileServiceMock.Setup(up => up.Lookup(WhitelistedUserId)).Returns(userProfile.ToMap()); + UserProfileServiceMock.Setup(up => up.Lookup(WhitelistedUserId)). + Returns(userProfile.ToMap()); - DecisionService decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, UserProfileServiceMock.Object, LoggerMock.Object); + var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, + UserProfileServiceMock.Object, LoggerMock.Object); - decisionService.GetVariation(experiment, OptimizelyUserContextMock.Object, ProjectConfig); + decisionService.GetVariation(experiment, OptimizelyUserContextMock.Object, + ProjectConfig); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("User \"{0}\" does not meet conditions to be in experiment \"{1}\".", + LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format( + "User \"{0}\" does not meet conditions to be in experiment \"{1}\".", GenericUserId, experiment.Key)), Times.Once); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(UserProfileId); // ensure that a user with a saved user profile, sees the same variation regardless of audience evaluation - decisionService.GetVariation(experiment, OptimizelyUserContextMock.Object, ProjectConfig); + decisionService.GetVariation(experiment, OptimizelyUserContextMock.Object, + ProjectConfig); - BucketerMock.Verify(_ => _.Bucket(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + BucketerMock.Verify( + _ => _.Bucket(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny()), Times.Never); } [Test] public void TestGetForcedVariationReturnsForcedVariation() { - DecisionService decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, null, LoggerMock.Object); - var expectedVariation = decisionService.GetWhitelistedVariation(WhitelistedExperiment, WhitelistedUserId).ResultObject; + var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, + null, LoggerMock.Object); + var expectedVariation = decisionService. + GetWhitelistedVariation(WhitelistedExperiment, WhitelistedUserId). + ResultObject; Assertions.AreEqual(WhitelistedVariation, expectedVariation); - Assert.IsTrue(TestData.CompareObjects(WhitelistedVariation, decisionService.GetWhitelistedVariation(WhitelistedExperiment, WhitelistedUserId).ResultObject)); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("User \"{0}\" is forced in variation \"{1}\".", + Assert.IsTrue(TestData.CompareObjects(WhitelistedVariation, + decisionService.GetWhitelistedVariation(WhitelistedExperiment, WhitelistedUserId). + ResultObject)); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format( + "User \"{0}\" is forced in variation \"{1}\".", WhitelistedUserId, WhitelistedVariation.Key)), Times.Exactly(2)); - BucketerMock.Verify(_ => _.Bucket(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + BucketerMock.Verify( + _ => _.Bucket(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny()), Times.Never); } [Test] public void TestGetForcedVariationWithInvalidVariation() { - string userId = "testUser1"; - string invalidVariationKey = "invalidVarKey"; + var userId = "testUser1"; + var invalidVariationKey = "invalidVarKey"; - DecisionService decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, null, LoggerMock.Object); + var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, + null, LoggerMock.Object); var variations = new Variation[] { - new Variation {Id = "1", Key = "var1" } + new Variation { Id = "1", Key = "var1" }, }; var trafficAllocation = new TrafficAllocation[] { - new TrafficAllocation {EntityId = "1", EndOfRange = 1000 } + new TrafficAllocation { EntityId = "1", EndOfRange = 1000 }, }; var userIdToVariationKeyMap = new Dictionary { - {userId, invalidVariationKey } + { userId, invalidVariationKey }, }; var experiment = new Experiment @@ -213,54 +259,68 @@ public void TestGetForcedVariationWithInvalidVariation() AudienceIds = new string[0], Variations = variations, TrafficAllocation = trafficAllocation, - ForcedVariations = userIdToVariationKeyMap + ForcedVariations = userIdToVariationKeyMap, }; Assert.IsNull(decisionService.GetWhitelistedVariation(experiment, userId).ResultObject); LoggerMock.Verify(l => l.Log(LogLevel.ERROR, - string.Format("Variation \"{0}\" is not in the datafile. Not activating user \"{1}\".", invalidVariationKey, userId)), + string.Format( + "Variation \"{0}\" is not in the datafile. Not activating user \"{1}\".", + invalidVariationKey, userId)), Times.Once); - BucketerMock.Verify(_ => _.Bucket(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + BucketerMock.Verify( + _ => _.Bucket(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny()), Times.Never); } [Test] public void TestGetForcedVariationReturnsNullWhenUserIsNotWhitelisted() { - Bucketer bucketer = new Bucketer(LoggerMock.Object); - DecisionService decisionService = new DecisionService(bucketer, ErrorHandlerMock.Object, null, LoggerMock.Object); + var bucketer = new Bucketer(LoggerMock.Object); + var decisionService = new DecisionService(bucketer, ErrorHandlerMock.Object, null, + LoggerMock.Object); - Assert.IsNull(decisionService.GetWhitelistedVariation(WhitelistedExperiment, GenericUserId).ResultObject); + Assert.IsNull(decisionService. + GetWhitelistedVariation(WhitelistedExperiment, GenericUserId). + ResultObject); } [Test] public void TestBucketReturnsVariationStoredInUserProfile() { - Experiment experiment = ProjectConfig.Experiments[6]; - Variation variation = experiment.Variations[0]; - Decision decision = new Decision(variation.Id); + var experiment = ProjectConfig.Experiments[6]; + var variation = experiment.Variations[0]; + var decision = new Decision(variation.Id); - UserProfile userProfile = new UserProfile(UserProfileId, new Dictionary + var userProfile = new UserProfile(UserProfileId, new Dictionary { - { experiment.Id, decision } + { experiment.Id, decision }, }); UserProfileServiceMock.Setup(_ => _.Lookup(UserProfileId)).Returns(userProfile.ToMap()); - DecisionService decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, UserProfileServiceMock.Object, LoggerMock.Object); + var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, + UserProfileServiceMock.Object, LoggerMock.Object); - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); - OptimizelyUserContextMock = new Mock(optlyObject, WhitelistedUserId, new UserAttributes(), ErrorHandlerMock.Object, LoggerMock.Object); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); + OptimizelyUserContextMock = new Mock(optlyObject, + WhitelistedUserId, new UserAttributes(), ErrorHandlerMock.Object, + LoggerMock.Object); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(UserProfileId); - var actualVariation = decisionService.GetVariation(experiment, OptimizelyUserContextMock.Object, ProjectConfig); + var actualVariation = decisionService.GetVariation(experiment, + OptimizelyUserContextMock.Object, ProjectConfig); Assertions.AreEqual(variation, actualVariation.ResultObject); Assert.AreEqual(actualVariation.DecisionReasons.ToReport(true).Count, 1); - Assert.AreEqual(actualVariation.DecisionReasons.ToReport(true)[0], "Returning previously activated variation \"vtag1\" of experiment \"etag1\" for user \"userProfileId\" from user profile."); + Assert.AreEqual(actualVariation.DecisionReasons.ToReport(true)[0], + "Returning previously activated variation \"vtag1\" of experiment \"etag1\" for user \"userProfileId\" from user profile."); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("Returning previously activated variation \"{0}\" of experiment \"{1}\" for user \"{2}\" from user profile.", + LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format( + "Returning previously activated variation \"{0}\" of experiment \"{1}\" for user \"{2}\" from user profile.", variation.Key, experiment.Key, UserProfileId))); //BucketerMock.Verify(_ => _.Bucket(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); @@ -269,135 +329,162 @@ public void TestBucketReturnsVariationStoredInUserProfile() [Test] public void TestGetStoredVariationLogsWhenLookupReturnsNull() { - Experiment experiment = ProjectConfig.Experiments[6]; + var experiment = ProjectConfig.Experiments[6]; - UserProfileService userProfileService = UserProfileServiceMock.Object; - UserProfile userProfile = new UserProfile(UserProfileId, new Dictionary()); + var userProfileService = UserProfileServiceMock.Object; + var userProfile = new UserProfile(UserProfileId, new Dictionary()); - Bucketer bucketer = new Bucketer(LoggerMock.Object); + var bucketer = new Bucketer(LoggerMock.Object); UserProfileServiceMock.Setup(_ => _.Lookup(UserProfileId)).Returns(userProfile.ToMap()); - DecisionService decisionService = new DecisionService(bucketer, - ErrorHandlerMock.Object, userProfileService, LoggerMock.Object); + var decisionService = new DecisionService(bucketer, + ErrorHandlerMock.Object, userProfileService, LoggerMock.Object); - Assert.IsNull(decisionService.GetStoredVariation(experiment, userProfile, ProjectConfig).ResultObject); + Assert.IsNull(decisionService. + GetStoredVariation(experiment, userProfile, ProjectConfig). + ResultObject); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("No previously activated variation of experiment \"{0}\" for user \"{1}\" found in user profile." + LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format( + "No previously activated variation of experiment \"{0}\" for user \"{1}\" found in user profile." , experiment.Key, UserProfileId)), Times.Once); } [Test] public void TestGetStoredVariationReturnsNullWhenVariationIsNoLongerInConfig() { - Experiment experiment = ProjectConfig.Experiments[6]; - string storedVariationId = "missingVariation"; - Decision storedDecision = new Decision(storedVariationId); + var experiment = ProjectConfig.Experiments[6]; + var storedVariationId = "missingVariation"; + var storedDecision = new Decision(storedVariationId); var storedDecisions = new Dictionary(); storedDecisions[experiment.Id] = storedDecision; - UserProfile storedUserProfile = new UserProfile(UserProfileId, storedDecisions); + var storedUserProfile = new UserProfile(UserProfileId, storedDecisions); - Bucketer bucketer = new Bucketer(LoggerMock.Object); + var bucketer = new Bucketer(LoggerMock.Object); - UserProfileServiceMock.Setup(up => up.Lookup(UserProfileId)).Returns(storedUserProfile.ToMap()); + UserProfileServiceMock.Setup(up => up.Lookup(UserProfileId)). + Returns(storedUserProfile.ToMap()); - DecisionService decisionService = new DecisionService(bucketer, ErrorHandlerMock.Object, + var decisionService = new DecisionService(bucketer, ErrorHandlerMock.Object, UserProfileServiceMock.Object, LoggerMock.Object); - Assert.IsNull(decisionService.GetStoredVariation(experiment, storedUserProfile, ProjectConfig).ResultObject); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("User \"{0}\" was previously bucketed into variation with ID \"{1}\" for experiment \"{2}\", but no matching variation was found for that user. We will re-bucket the user." + Assert.IsNull(decisionService. + GetStoredVariation(experiment, storedUserProfile, ProjectConfig). + ResultObject); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format( + "User \"{0}\" was previously bucketed into variation with ID \"{1}\" for experiment \"{2}\", but no matching variation was found for that user. We will re-bucket the user." , UserProfileId, storedVariationId, experiment.Id)), Times.Once); } [Test] public void TestGetVariationSavesBucketedVariationIntoUserProfile() { - Experiment experiment = ProjectConfig.Experiments[6]; + var experiment = ProjectConfig.Experiments[6]; var variation = Result.NewResult(experiment.Variations[0], DecisionReasons); - Decision decision = new Decision(variation.ResultObject.Id); + var decision = new Decision(variation.ResultObject.Id); - UserProfile originalUserProfile = new UserProfile(UserProfileId, + var originalUserProfile = new UserProfile(UserProfileId, new Dictionary()); - UserProfileServiceMock.Setup(ups => ups.Lookup(UserProfileId)).Returns(originalUserProfile.ToMap()); + UserProfileServiceMock.Setup(ups => ups.Lookup(UserProfileId)). + Returns(originalUserProfile.ToMap()); - UserProfile expectedUserProfile = new UserProfile(UserProfileId, + var expectedUserProfile = new UserProfile(UserProfileId, new Dictionary { - {experiment.Id, decision } + { experiment.Id, decision }, }); var mockBucketer = new Mock(LoggerMock.Object); - mockBucketer.Setup(m => m.Bucket(ProjectConfig, experiment, UserProfileId, UserProfileId)).Returns(variation); + mockBucketer. + Setup(m => m.Bucket(ProjectConfig, experiment, UserProfileId, UserProfileId)). + Returns(variation); - DecisionService decisionService = new DecisionService(mockBucketer.Object, ErrorHandlerMock.Object, UserProfileServiceMock.Object, LoggerMock.Object); + var decisionService = new DecisionService(mockBucketer.Object, ErrorHandlerMock.Object, + UserProfileServiceMock.Object, LoggerMock.Object); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(UserProfileId); - Assert.IsTrue(TestData.CompareObjects(variation.ResultObject, decisionService.GetVariation(experiment, OptimizelyUserContextMock.Object, ProjectConfig).ResultObject)); + Assert.IsTrue(TestData.CompareObjects(variation.ResultObject, + decisionService. + GetVariation(experiment, OptimizelyUserContextMock.Object, ProjectConfig). + ResultObject)); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("Saved variation \"{0}\" of experiment \"{1}\" for user \"{2}\".", variation.ResultObject.Id, - experiment.Id, UserProfileId)), Times.Once); - UserProfileServiceMock.Verify(_ => _.Save(It.IsAny>()), Times.Once); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format( + "Saved variation \"{0}\" of experiment \"{1}\" for user \"{2}\".", + variation.ResultObject.Id, + experiment.Id, UserProfileId)), Times.Once); + UserProfileServiceMock.Verify(_ => _.Save(It.IsAny>()), + Times.Once); } [Test] public void TestBucketLogsCorrectlyWhenUserProfileFailsToSave() { - Experiment experiment = ProjectConfig.Experiments[6]; - Variation variation = experiment.Variations[0]; - Decision decision = new Decision(variation.Id); - Bucketer bucketer = new Bucketer(LoggerMock.Object); + var experiment = ProjectConfig.Experiments[6]; + var variation = experiment.Variations[0]; + var decision = new Decision(variation.Id); + var bucketer = new Bucketer(LoggerMock.Object); - UserProfileServiceMock.Setup(up => up.Save(It.IsAny>())).Throws(new System.Exception()); + UserProfileServiceMock.Setup(up => up.Save(It.IsAny>())). + Throws(new System.Exception()); var experimentBucketMap = new Dictionary(); experimentBucketMap[experiment.Id] = decision; - UserProfile expectedUserProfile = new UserProfile(UserProfileId, experimentBucketMap); - UserProfile saveUserProfile = new UserProfile(UserProfileId, new Dictionary()); + var expectedUserProfile = new UserProfile(UserProfileId, experimentBucketMap); + var saveUserProfile = + new UserProfile(UserProfileId, new Dictionary()); - DecisionService decisionService = new DecisionService(bucketer, + var decisionService = new DecisionService(bucketer, ErrorHandlerMock.Object, UserProfileServiceMock.Object, LoggerMock.Object); decisionService.SaveVariation(experiment, variation, saveUserProfile); LoggerMock.Verify(l => l.Log(LogLevel.ERROR, string.Format - ("Failed to save variation \"{0}\" of experiment \"{1}\" for user \"{2}\".", variation.Id, experiment.Id, UserProfileId)) + ("Failed to save variation \"{0}\" of experiment \"{1}\" for user \"{2}\".", + variation.Id, experiment.Id, UserProfileId)) , Times.Once); - ErrorHandlerMock.Verify(er => er.HandleError(It.IsAny()), Times.Once); + ErrorHandlerMock.Verify( + er => er.HandleError(It.IsAny()), + Times.Once); } [Test] public void TestGetVariationSavesANewUserProfile() { - Experiment experiment = ProjectConfig.Experiments[6]; + var experiment = ProjectConfig.Experiments[6]; var variation = Result.NewResult(experiment.Variations[0], DecisionReasons); - Decision decision = new Decision(variation.ResultObject.Id); + var decision = new Decision(variation.ResultObject.Id); - UserProfile expectedUserProfile = new UserProfile(UserProfileId, new Dictionary - { - { experiment.Id, decision } - }); + var expectedUserProfile = new UserProfile(UserProfileId, + new Dictionary + { + { experiment.Id, decision }, + }); var mockBucketer = new Mock(LoggerMock.Object); - mockBucketer.Setup(m => m.Bucket(ProjectConfig, experiment, UserProfileId, UserProfileId)).Returns(variation); + mockBucketer. + Setup(m => m.Bucket(ProjectConfig, experiment, UserProfileId, UserProfileId)). + Returns(variation); Dictionary userProfile = null; UserProfileServiceMock.Setup(up => up.Lookup(UserProfileId)).Returns(userProfile); - DecisionService decisionService = new DecisionService(mockBucketer.Object, ErrorHandlerMock.Object, + var decisionService = new DecisionService(mockBucketer.Object, ErrorHandlerMock.Object, UserProfileServiceMock.Object, LoggerMock.Object); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(UserProfileId); - var actualVariation = decisionService.GetVariation(experiment, OptimizelyUserContextMock.Object, ProjectConfig); + var actualVariation = decisionService.GetVariation(experiment, + OptimizelyUserContextMock.Object, ProjectConfig); Assertions.AreEqual(variation.ResultObject, actualVariation.ResultObject); - UserProfileServiceMock.Verify(_ => _.Save(It.IsAny>()), Times.Once); + UserProfileServiceMock.Verify(_ => _.Save(It.IsAny>()), + Times.Once); } [Test] @@ -407,12 +494,13 @@ public void TestGetVariationUserWithSetForcedVariation() var pausedExperimentKey = "paused_experiment"; var userId = "test_user"; var expectedForcedVariationKey = "variation"; - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); var userAttributes = new UserAttributes { - {"device_type", "iPhone" }, - {"location", "San Francisco" } + { "device_type", "iPhone" }, + { "location", "San Francisco" }, }; optlyObject.Activate(experimentKey, userId, userAttributes); @@ -422,9 +510,12 @@ public void TestGetVariationUserWithSetForcedVariation() Assertions.AreEqual(VariationWithKeyControl, actualVariation); // test valid experiment - Assert.IsTrue(optlyObject.SetForcedVariation(experimentKey, userId, expectedForcedVariationKey), string.Format(@"Set variation to ""{0}"" failed.", expectedForcedVariationKey)); + Assert.IsTrue( + optlyObject.SetForcedVariation(experimentKey, userId, expectedForcedVariationKey), + string.Format(@"Set variation to ""{0}"" failed.", expectedForcedVariationKey)); - var actualForcedVariation = optlyObject.GetVariation(experimentKey, userId, userAttributes); + var actualForcedVariation = + optlyObject.GetVariation(experimentKey, userId, userAttributes); Assertions.AreEqual(VariationWithKeyVariation, actualForcedVariation); @@ -435,8 +526,12 @@ public void TestGetVariationUserWithSetForcedVariation() Assertions.AreEqual(VariationWithKeyControl, actualVariation); // check that a paused experiment returns null - Assert.IsTrue(optlyObject.SetForcedVariation(pausedExperimentKey, userId, expectedForcedVariationKey), string.Format(@"Set variation to ""{0}"" failed.", expectedForcedVariationKey)); - actualForcedVariation = optlyObject.GetVariation(pausedExperimentKey, userId, userAttributes); + Assert.IsTrue( + optlyObject.SetForcedVariation(pausedExperimentKey, userId, + expectedForcedVariationKey), + string.Format(@"Set variation to ""{0}"" failed.", expectedForcedVariationKey)); + actualForcedVariation = + optlyObject.GetVariation(pausedExperimentKey, userId, userAttributes); Assert.IsNull(actualForcedVariation); } @@ -448,57 +543,65 @@ public void TestGetVariationWithBucketingId() var userId = "test_user"; var testUserIdWhitelisted = "user1"; var experimentKey = "test_experiment"; - var testBucketingIdControl = "testBucketingIdControl!"; // generates bucketing number 3741 + var testBucketingIdControl = + "testBucketingIdControl!"; // generates bucketing number 3741 var testBucketingIdVariation = "123456789"; // generates bucketing number 4567 var variationKeyControl = "control"; var testUserAttributes = new UserAttributes { - {"device_type", "iPhone" }, - {"company", "Optimizely" }, - {"location", "San Francisco" } + { "device_type", "iPhone" }, + { "company", "Optimizely" }, + { "location", "San Francisco" }, }; var userAttributesWithBucketingId = new UserAttributes { - {"device_type", "iPhone"}, - {"company", "Optimizely"}, - {"location", "San Francisco"}, - {ControlAttributes.BUCKETING_ID_ATTRIBUTE, testBucketingIdVariation} + { "device_type", "iPhone" }, + { "company", "Optimizely" }, + { "location", "San Francisco" }, + { ControlAttributes.BUCKETING_ID_ATTRIBUTE, testBucketingIdVariation }, }; var userAttributesWithInvalidBucketingId = new UserAttributes { - {"device_type", "iPhone"}, - {"company", "Optimizely"}, - {"location", "San Francisco"}, - {ControlAttributes.BUCKETING_ID_ATTRIBUTE, 1.59} + { "device_type", "iPhone" }, + { "company", "Optimizely" }, + { "location", "San Francisco" }, + { ControlAttributes.BUCKETING_ID_ATTRIBUTE, 1.59 }, }; var invalidUserAttributesWithBucketingId = new UserAttributes { - {"company", "Optimizely"}, - {ControlAttributes.BUCKETING_ID_ATTRIBUTE, testBucketingIdControl} + { "company", "Optimizely" }, + { ControlAttributes.BUCKETING_ID_ATTRIBUTE, testBucketingIdControl }, }; - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); // confirm normal bucketing occurs before setting the bucketing ID - var actualVariation = optlyObject.GetVariation(experimentKey, userId, testUserAttributes); + var actualVariation = + optlyObject.GetVariation(experimentKey, userId, testUserAttributes); Assert.IsTrue(TestData.CompareObjects(VariationWithKeyControl, actualVariation)); // confirm valid bucketing with bucketing ID set in attributes - actualVariation = optlyObject.GetVariation(experimentKey, userId, userAttributesWithBucketingId); + actualVariation = + optlyObject.GetVariation(experimentKey, userId, userAttributesWithBucketingId); Assert.IsTrue(TestData.CompareObjects(VariationWithKeyVariation, actualVariation)); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, $"BucketingId is valid: \"{testBucketingIdVariation}\"")); + LoggerMock.Verify(l => + l.Log(LogLevel.DEBUG, $"BucketingId is valid: \"{testBucketingIdVariation}\"")); // check audience with invalid bucketing Id - actualVariation = optlyObject.GetVariation(experimentKey, userId, userAttributesWithInvalidBucketingId); + actualVariation = optlyObject.GetVariation(experimentKey, userId, + userAttributesWithInvalidBucketingId); Assert.IsTrue(TestData.CompareObjects(VariationWithKeyControl, actualVariation)); - LoggerMock.Verify(l => l.Log(LogLevel.WARN, "BucketingID attribute is not a string. Defaulted to userId")); + LoggerMock.Verify(l => l.Log(LogLevel.WARN, + "BucketingID attribute is not a string. Defaulted to userId")); // check invalid audience with bucketing ID - actualVariation = optlyObject.GetVariation(experimentKey, userId, invalidUserAttributesWithBucketingId); + actualVariation = optlyObject.GetVariation(experimentKey, userId, + invalidUserAttributesWithBucketingId); Assert.Null(actualVariation); // check null audience with bucketing Id @@ -506,30 +609,41 @@ public void TestGetVariationWithBucketingId() Assert.Null(actualVariation); // test that an experiment that's not running returns a null variation - actualVariation = optlyObject.GetVariation(pausedExperimentKey, userId, userAttributesWithBucketingId); + actualVariation = optlyObject.GetVariation(pausedExperimentKey, userId, + userAttributesWithBucketingId); Assert.Null(actualVariation); // check forced variation - Assert.IsTrue(optlyObject.SetForcedVariation(experimentKey, userId, variationKeyControl), string.Format("Set variation to \"{0}\" failed.", variationKeyControl)); - actualVariation = optlyObject.GetVariation(experimentKey, userId, userAttributesWithBucketingId); + Assert.IsTrue( + optlyObject.SetForcedVariation(experimentKey, userId, variationKeyControl), + string.Format("Set variation to \"{0}\" failed.", variationKeyControl)); + actualVariation = + optlyObject.GetVariation(experimentKey, userId, userAttributesWithBucketingId); Assert.IsTrue(TestData.CompareObjects(VariationWithKeyControl, actualVariation)); // check whitelisted variation - actualVariation = optlyObject.GetVariation(experimentKey, testUserIdWhitelisted, userAttributesWithBucketingId); + actualVariation = optlyObject.GetVariation(experimentKey, testUserIdWhitelisted, + userAttributesWithBucketingId); Assert.IsTrue(TestData.CompareObjects(VariationWithKeyControl, actualVariation)); var bucketerMock = new Mock(LoggerMock.Object); var decision = new Decision("7722370027"); - UserProfile storedUserProfile = new UserProfile(userId, new Dictionary + var storedUserProfile = new UserProfile(userId, new Dictionary { - { "7716830082", decision } + { "7716830082", decision }, }); - UserProfileServiceMock.Setup(up => up.Lookup(userId)).Returns(storedUserProfile.ToMap()); - DecisionService decisionService = new DecisionService(bucketerMock.Object, ErrorHandlerMock.Object, UserProfileServiceMock.Object, LoggerMock.Object); + UserProfileServiceMock.Setup(up => up.Lookup(userId)). + Returns(storedUserProfile.ToMap()); + var decisionService = new DecisionService(bucketerMock.Object, ErrorHandlerMock.Object, + UserProfileServiceMock.Object, LoggerMock.Object); - actualVariation = optlyObject.GetVariation(experimentKey, userId, userAttributesWithBucketingId); - Assert.IsTrue(TestData.CompareObjects(VariationWithKeyControl, actualVariation), string.Format("Variation \"{0}\" does not match expected user profile variation \"{1}\".", actualVariation?.Key, variationKeyControl)); + actualVariation = + optlyObject.GetVariation(experimentKey, userId, userAttributesWithBucketingId); + Assert.IsTrue(TestData.CompareObjects(VariationWithKeyControl, actualVariation), + string.Format( + "Variation \"{0}\" does not match expected user profile variation \"{1}\".", + actualVariation?.Key, variationKeyControl)); } #region GetVariationForFeatureExperiment Tests @@ -541,11 +655,14 @@ public void TestGetVariationForFeatureExperimentGivenNullExperimentIds() var featureFlag = ProjectConfig.GetFeatureFlagFromKey("empty_feature"); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(GenericUserId); - var decision = DecisionService.GetVariationForFeatureExperiment(featureFlag, OptimizelyUserContextMock.Object, new UserAttributes() { }, ProjectConfig, new OptimizelyDecideOption[] { }); + var decision = DecisionService.GetVariationForFeatureExperiment(featureFlag, + OptimizelyUserContextMock.Object, new UserAttributes() { }, ProjectConfig, + new OptimizelyDecideOption[] { }); Assert.IsNull(decision.ResultObject); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, $"The feature flag \"{featureFlag.Key}\" is not used in any experiments.")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + $"The feature flag \"{featureFlag.Key}\" is not used in any experiments.")); } // Should return null and log when the experiment is not in the datafile @@ -558,32 +675,42 @@ public void TestGetVariationForFeatureExperimentGivenExperimentNotInDataFile() Id = booleanFeature.Id, Key = booleanFeature.Key, RolloutId = booleanFeature.RolloutId, - ExperimentIds = new List { "29039203" } + ExperimentIds = new List { "29039203" }, }; OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(GenericUserId); - var decision = DecisionService.GetVariationForFeatureExperiment(featureFlag, OptimizelyUserContextMock.Object, new UserAttributes() { }, ProjectConfig, new OptimizelyDecideOption[] { }); + var decision = DecisionService.GetVariationForFeatureExperiment(featureFlag, + OptimizelyUserContextMock.Object, new UserAttributes() { }, ProjectConfig, + new OptimizelyDecideOption[] { }); Assert.IsNull(decision.ResultObject); - LoggerMock.Verify(l => l.Log(LogLevel.ERROR, "Experiment ID \"29039203\" is not in datafile.")); + LoggerMock.Verify(l => + l.Log(LogLevel.ERROR, "Experiment ID \"29039203\" is not in datafile.")); } // Should return null and log when the user is not bucketed into the feature flag's experiments [Test] public void TestGetVariationForFeatureExperimentGivenNonMutexGroupAndUserNotBucketed() { - var multiVariateExp = ProjectConfig.GetExperimentFromKey("test_experiment_multivariate"); + var multiVariateExp = + ProjectConfig.GetExperimentFromKey("test_experiment_multivariate"); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns("user1"); - DecisionServiceMock.Setup(ds => ds.GetVariation(multiVariateExp, OptimizelyUserContextMock.Object, ProjectConfig, null)).Returns(null); + DecisionServiceMock. + Setup(ds => ds.GetVariation(multiVariateExp, OptimizelyUserContextMock.Object, + ProjectConfig, null)). + Returns(null); var featureFlag = ProjectConfig.GetFeatureFlagFromKey("multi_variate_feature"); - var decision = DecisionServiceMock.Object.GetVariationForFeatureExperiment(featureFlag, OptimizelyUserContextMock.Object, new UserAttributes(), ProjectConfig, new OptimizelyDecideOption[] { }); + var decision = DecisionServiceMock.Object.GetVariationForFeatureExperiment(featureFlag, + OptimizelyUserContextMock.Object, new UserAttributes(), ProjectConfig, + new OptimizelyDecideOption[] { }); Assert.IsNull(decision.ResultObject); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "The user \"user1\" is not bucketed into any of the experiments on the feature \"multi_variate_feature\".")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "The user \"user1\" is not bucketed into any of the experiments on the feature \"multi_variate_feature\".")); } // Should return the variation when the user is bucketed into a variation for the experiment on the feature flag @@ -591,25 +718,36 @@ public void TestGetVariationForFeatureExperimentGivenNonMutexGroupAndUserNotBuck public void TestGetVariationForFeatureExperimentGivenNonMutexGroupAndUserIsBucketed() { var experiment = ProjectConfig.GetExperimentFromKey("test_experiment_multivariate"); - var variation = Result.NewResult(ProjectConfig.GetVariationFromId("test_experiment_multivariate", "122231"), DecisionReasons); - var expectedDecision = new FeatureDecision(experiment, variation.ResultObject, FeatureDecision.DECISION_SOURCE_FEATURE_TEST); + var variation = Result.NewResult( + ProjectConfig.GetVariationFromId("test_experiment_multivariate", "122231"), + DecisionReasons); + var expectedDecision = new FeatureDecision(experiment, variation.ResultObject, + FeatureDecision.DECISION_SOURCE_FEATURE_TEST); var userAttributes = new UserAttributes(); - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); - OptimizelyUserContextMock = new Mock(optlyObject, WhitelistedUserId, userAttributes, ErrorHandlerMock.Object, LoggerMock.Object); + OptimizelyUserContextMock = new Mock(optlyObject, + WhitelistedUserId, userAttributes, ErrorHandlerMock.Object, LoggerMock.Object); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns("user1"); - DecisionServiceMock.Setup(ds => ds.GetVariation(ProjectConfig.GetExperimentFromKey("test_experiment_multivariate"), - OptimizelyUserContextMock.Object, ProjectConfig, It.IsAny())).Returns(variation); + DecisionServiceMock.Setup(ds => ds.GetVariation( + ProjectConfig.GetExperimentFromKey("test_experiment_multivariate"), + OptimizelyUserContextMock.Object, ProjectConfig, + It.IsAny())). + Returns(variation); var featureFlag = ProjectConfig.GetFeatureFlagFromKey("multi_variate_feature"); - var decision = DecisionServiceMock.Object.GetVariationForFeatureExperiment(featureFlag, OptimizelyUserContextMock.Object, userAttributes, ProjectConfig, new OptimizelyDecideOption[] { }); + var decision = DecisionServiceMock.Object.GetVariationForFeatureExperiment(featureFlag, + OptimizelyUserContextMock.Object, userAttributes, ProjectConfig, + new OptimizelyDecideOption[] { }); Assert.IsTrue(TestData.CompareObjects(expectedDecision, decision.ResultObject)); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "The user \"user1\" is bucketed into experiment \"test_experiment_multivariate\" of feature \"multi_variate_feature\".")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "The user \"user1\" is bucketed into experiment \"test_experiment_multivariate\" of feature \"multi_variate_feature\".")); } // Should return the variation the user is bucketed into when the user is bucketed into one of the experiments @@ -617,23 +755,34 @@ public void TestGetVariationForFeatureExperimentGivenNonMutexGroupAndUserIsBucke public void TestGetVariationForFeatureExperimentGivenMutexGroupAndUserIsBucketed() { var mutexExperiment = ProjectConfig.GetExperimentFromKey("group_experiment_1"); - var variation = Result.NewResult(mutexExperiment.Variations[0], DecisionReasons); + var variation = + Result.NewResult(mutexExperiment.Variations[0], DecisionReasons); var userAttributes = new UserAttributes(); - var expectedDecision = new FeatureDecision(mutexExperiment, variation.ResultObject, FeatureDecision.DECISION_SOURCE_FEATURE_TEST); + var expectedDecision = new FeatureDecision(mutexExperiment, variation.ResultObject, + FeatureDecision.DECISION_SOURCE_FEATURE_TEST); - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); - OptimizelyUserContextMock = new Mock(optlyObject, WhitelistedUserId, userAttributes, ErrorHandlerMock.Object, LoggerMock.Object); + OptimizelyUserContextMock = new Mock(optlyObject, + WhitelistedUserId, userAttributes, ErrorHandlerMock.Object, LoggerMock.Object); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns("user1"); - DecisionServiceMock.Setup(ds => ds.GetVariation(ProjectConfig.GetExperimentFromKey("group_experiment_1"), OptimizelyUserContextMock.Object, ProjectConfig)).Returns(variation); + DecisionServiceMock. + Setup(ds => + ds.GetVariation(ProjectConfig.GetExperimentFromKey("group_experiment_1"), + OptimizelyUserContextMock.Object, ProjectConfig)). + Returns(variation); var featureFlag = ProjectConfig.GetFeatureFlagFromKey("boolean_feature"); - var actualDecision = DecisionServiceMock.Object.GetVariationForFeatureExperiment(featureFlag, OptimizelyUserContextMock.Object, userAttributes, ProjectConfig, new OptimizelyDecideOption[] { }); + var actualDecision = DecisionServiceMock.Object.GetVariationForFeatureExperiment( + featureFlag, OptimizelyUserContextMock.Object, userAttributes, ProjectConfig, + new OptimizelyDecideOption[] { }); Assertions.AreEqual(expectedDecision, actualDecision.ResultObject); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "The user \"user1\" is bucketed into experiment \"group_experiment_1\" of feature \"boolean_feature\".")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "The user \"user1\" is bucketed into experiment \"group_experiment_1\" of feature \"boolean_feature\".")); } // Should return null and log a message when the user is not bucketed into any of the mutex experiments @@ -643,15 +792,21 @@ public void TestGetVariationForFeatureExperimentGivenMutexGroupAndUserNotBuckete var mutexExperiment = ProjectConfig.GetExperimentFromKey("group_experiment_1"); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns("user1"); - DecisionServiceMock.Setup(ds => ds.GetVariation(It.IsAny(), It.IsAny(), ProjectConfig, It.IsAny())) - .Returns(Result.NullResult(null)); + DecisionServiceMock. + Setup(ds => ds.GetVariation(It.IsAny(), + It.IsAny(), ProjectConfig, + It.IsAny())). + Returns(Result.NullResult(null)); var featureFlag = ProjectConfig.GetFeatureFlagFromKey("boolean_feature"); - var actualDecision = DecisionServiceMock.Object.GetVariationForFeatureExperiment(featureFlag, OptimizelyUserContextMock.Object, new UserAttributes(), ProjectConfig, new OptimizelyDecideOption[] { }); + var actualDecision = DecisionServiceMock.Object.GetVariationForFeatureExperiment( + featureFlag, OptimizelyUserContextMock.Object, new UserAttributes(), ProjectConfig, + new OptimizelyDecideOption[] { }); Assert.IsNull(actualDecision.ResultObject); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "The user \"user1\" is not bucketed into any of the experiments on the feature \"boolean_feature\".")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "The user \"user1\" is not bucketed into any of the experiments on the feature \"boolean_feature\".")); } #endregion GetVariationForFeatureExperiment Tests @@ -662,18 +817,24 @@ public void TestGetVariationForFeatureExperimentGivenMutexGroupAndUserNotBuckete [Test] public void TestGetVariationForFeatureRolloutWhenNoRuleInRollouts() { - var projectConfig = DatafileProjectConfig.Create(TestData.EmptyRolloutDatafile, new NoOpLogger(), new NoOpErrorHandler()); + var projectConfig = DatafileProjectConfig.Create(TestData.EmptyRolloutDatafile, + new NoOpLogger(), new NoOpErrorHandler()); Assert.IsNotNull(projectConfig); var featureFlag = projectConfig.FeatureKeyMap["empty_rollout"]; var rollout = projectConfig.GetRolloutFromId(featureFlag.RolloutId); Assert.AreEqual(rollout.Experiments.Count, 0); - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); - var optimizelyUserContext = new OptimizelyUserContext(optlyObject, "userId1", null, ErrorHandlerMock.Object, LoggerMock.Object); - var decisionService = new DecisionService(new Bucketer(new NoOpLogger()), new NoOpErrorHandler(), null, new NoOpLogger()); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); + var optimizelyUserContext = new OptimizelyUserContext(optlyObject, "userId1", null, + ErrorHandlerMock.Object, LoggerMock.Object); + var decisionService = new DecisionService(new Bucketer(new NoOpLogger()), + new NoOpErrorHandler(), null, new NoOpLogger()); - var variation = decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, projectConfig); + var variation = + decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, + projectConfig); Assert.IsNull(variation.ResultObject); } @@ -681,7 +842,6 @@ public void TestGetVariationForFeatureRolloutWhenNoRuleInRollouts() [Test] public void TestGetVariationForFeatureRolloutWhenRolloutIsNotInDataFile() { - var featureFlag = ProjectConfig.GetFeatureFlagFromKey("boolean_feature"); var invalidRolloutFeature = new FeatureFlag { @@ -689,89 +849,135 @@ public void TestGetVariationForFeatureRolloutWhenRolloutIsNotInDataFile() Id = featureFlag.Id, Key = featureFlag.Key, ExperimentIds = new List(featureFlag.ExperimentIds), - Variables = featureFlag.Variables + Variables = featureFlag.Variables, }; - DecisionServiceMock.Setup(ds => ds.GetVariationForFeatureExperiment(It.IsAny(), It.IsAny(), It.IsAny(), ProjectConfig, new OptimizelyDecideOption[] { })).Returns(null); - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); - var optimizelyUserContext = new OptimizelyUserContext(optlyObject, "user1", new UserAttributes(), ErrorHandlerMock.Object, LoggerMock.Object); - var actualDecision = DecisionServiceMock.Object.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, ProjectConfig); + DecisionServiceMock.Setup(ds => + ds.GetVariationForFeatureExperiment(It.IsAny(), + It.IsAny(), It.IsAny(), + ProjectConfig, + new OptimizelyDecideOption[] { })). + Returns(null); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); + var optimizelyUserContext = new OptimizelyUserContext(optlyObject, "user1", + new UserAttributes(), ErrorHandlerMock.Object, LoggerMock.Object); + var actualDecision = + DecisionServiceMock.Object.GetVariationForFeatureRollout(featureFlag, + optimizelyUserContext, ProjectConfig); Assert.IsNull(actualDecision.ResultObject); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "The feature flag \"boolean_feature\" is not used in a rollout.")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "The feature flag \"boolean_feature\" is not used in a rollout.")); } // Should return the variation the user is bucketed into when the user is bucketed into the targeting rule [Test] public void TestGetVariationForFeatureRolloutWhenUserIsBucketedInTheTargetingRule() { - var featureFlag = ProjectConfig.GetFeatureFlagFromKey("boolean_single_variable_feature"); + var featureFlag = + ProjectConfig.GetFeatureFlagFromKey("boolean_single_variable_feature"); var rolloutId = featureFlag.RolloutId; var rollout = ProjectConfig.GetRolloutFromId(rolloutId); var experiment = rollout.Experiments[0]; var variation = Result.NewResult(experiment.Variations[0], DecisionReasons); - var expectedDecision = new FeatureDecision(experiment, variation.ResultObject, FeatureDecision.DECISION_SOURCE_ROLLOUT); + var expectedDecision = new FeatureDecision(experiment, variation.ResultObject, + FeatureDecision.DECISION_SOURCE_ROLLOUT); - var userAttributes = new UserAttributes { - { "browser_type", "chrome" } + var userAttributes = new UserAttributes + { + { "browser_type", "chrome" }, }; - BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny())).Returns(variation); - var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, null, LoggerMock.Object); - - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); - var optimizelyUserContext = new OptimizelyUserContext(optlyObject, "user_1", userAttributes, ErrorHandlerMock.Object, LoggerMock.Object); - - var actualDecision = decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, ProjectConfig); + BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), It.IsAny(), + It.IsAny(), + It.IsAny())). + Returns(variation); + var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, + null, LoggerMock.Object); + + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); + var optimizelyUserContext = new OptimizelyUserContext(optlyObject, "user_1", + userAttributes, ErrorHandlerMock.Object, LoggerMock.Object); + + var actualDecision = + decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, + ProjectConfig); Assert.IsTrue(TestData.CompareObjects(expectedDecision, actualDecision.ResultObject)); } // Should return the variation the user is bucketed into when the user is bucketed into the "Everyone Else" rule // and the user is not bucketed into the targeting rule [Test] - public void TestGetVariationForFeatureRolloutWhenUserIsNotBucketedInTheTargetingRuleButBucketedToEveryoneElseRule() + public void + TestGetVariationForFeatureRolloutWhenUserIsNotBucketedInTheTargetingRuleButBucketedToEveryoneElseRule() { - var featureFlag = ProjectConfig.GetFeatureFlagFromKey("boolean_single_variable_feature"); + var featureFlag = + ProjectConfig.GetFeatureFlagFromKey("boolean_single_variable_feature"); var rolloutId = featureFlag.RolloutId; var rollout = ProjectConfig.GetRolloutFromId(rolloutId); var experiment = rollout.Experiments[0]; var everyoneElseRule = rollout.Experiments[rollout.Experiments.Count - 1]; - var variation = Result.NewResult(everyoneElseRule.Variations[0], DecisionReasons); - var expectedDecision = new FeatureDecision(everyoneElseRule, variation.ResultObject, FeatureDecision.DECISION_SOURCE_ROLLOUT); + var variation = + Result.NewResult(everyoneElseRule.Variations[0], DecisionReasons); + var expectedDecision = new FeatureDecision(everyoneElseRule, variation.ResultObject, + FeatureDecision.DECISION_SOURCE_ROLLOUT); - var userAttributes = new UserAttributes { - { "browser_type", "chrome" } + var userAttributes = new UserAttributes + { + { "browser_type", "chrome" }, }; - BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), experiment, It.IsAny(), It.IsAny())).Returns(Result.NullResult(null)); - BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), everyoneElseRule, It.IsAny(), It.IsAny())).Returns(variation); - var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, null, LoggerMock.Object); - - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); - var optimizelyUserContext = new OptimizelyUserContext(optlyObject, "user_1", userAttributes, ErrorHandlerMock.Object, LoggerMock.Object); - var actualDecision = decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, ProjectConfig); + BucketerMock. + Setup(bm => bm.Bucket(It.IsAny(), experiment, It.IsAny(), + It.IsAny())). + Returns(Result.NullResult(null)); + BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), everyoneElseRule, + It.IsAny(), It.IsAny())). + Returns(variation); + var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, + null, LoggerMock.Object); + + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); + var optimizelyUserContext = new OptimizelyUserContext(optlyObject, "user_1", + userAttributes, ErrorHandlerMock.Object, LoggerMock.Object); + var actualDecision = + decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, + ProjectConfig); Assert.IsTrue(TestData.CompareObjects(expectedDecision, actualDecision.ResultObject)); } // Should log and return null when the user is not bucketed into the targeting rule // as well as "Everyone Else" rule. [Test] - public void TestGetVariationForFeatureRolloutWhenUserIsNeitherBucketedInTheTargetingRuleNorToEveryoneElseRule() + public void + TestGetVariationForFeatureRolloutWhenUserIsNeitherBucketedInTheTargetingRuleNorToEveryoneElseRule() { - var featureFlag = ProjectConfig.GetFeatureFlagFromKey("boolean_single_variable_feature"); + var featureFlag = + ProjectConfig.GetFeatureFlagFromKey("boolean_single_variable_feature"); var rolloutId = featureFlag.RolloutId; var rollout = ProjectConfig.GetRolloutFromId(rolloutId); - var userAttributes = new UserAttributes { - { "browser_type", "chrome" } + var userAttributes = new UserAttributes + { + { "browser_type", "chrome" }, }; - BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(Result.NullResult(null)); - var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, null, LoggerMock.Object); - - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); - var optimizelyUserContext = new OptimizelyUserContext(optlyObject, "user_1", userAttributes, ErrorHandlerMock.Object, LoggerMock.Object); - var actualDecision = decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, ProjectConfig); + BucketerMock. + Setup(bm => bm.Bucket(It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny())). + Returns(Result.NullResult(null)); + var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, + null, LoggerMock.Object); + + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); + var optimizelyUserContext = new OptimizelyUserContext(optlyObject, "user_1", + userAttributes, ErrorHandlerMock.Object, LoggerMock.Object); + var actualDecision = + decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, + ProjectConfig); Assert.IsNull(actualDecision.ResultObject); } @@ -780,34 +986,51 @@ public void TestGetVariationForFeatureRolloutWhenUserIsNeitherBucketedInTheTarge [Test] public void TestGetVariationForFeatureRolloutWhenUserDoesNotQualifyForAnyTargetingRule() { - var featureFlag = ProjectConfig.GetFeatureFlagFromKey("boolean_single_variable_feature"); + var featureFlag = + ProjectConfig.GetFeatureFlagFromKey("boolean_single_variable_feature"); var rolloutId = featureFlag.RolloutId; var rollout = ProjectConfig.GetRolloutFromId(rolloutId); var experiment0 = rollout.Experiments[0]; var experiment1 = rollout.Experiments[1]; var everyoneElseRule = rollout.Experiments[rollout.Experiments.Count - 1]; - var variation = Result.NewResult(everyoneElseRule.Variations[0], DecisionReasons); - var expectedDecision = new FeatureDecision(everyoneElseRule, variation.ResultObject, FeatureDecision.DECISION_SOURCE_ROLLOUT); + var variation = + Result.NewResult(everyoneElseRule.Variations[0], DecisionReasons); + var expectedDecision = new FeatureDecision(everyoneElseRule, variation.ResultObject, + FeatureDecision.DECISION_SOURCE_ROLLOUT); //BucketerMock.CallBase = true; - BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), It.IsNotIn(everyoneElseRule), It.IsAny(), It.IsAny())).Returns(Result.NullResult(null)); - BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), everyoneElseRule, It.IsAny(), It.IsAny())).Returns(variation); - var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, null, LoggerMock.Object); + BucketerMock. + Setup(bm => bm.Bucket(It.IsAny(), + It.IsNotIn(everyoneElseRule), It.IsAny(), + It.IsAny())). + Returns(Result.NullResult(null)); + BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), everyoneElseRule, + It.IsAny(), It.IsAny())). + Returns(variation); + var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, + null, LoggerMock.Object); // Provide null attributes so that user does not qualify for audience. - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); - var optimizelyUserContext = new OptimizelyUserContext(optlyObject, "user_1", null, ErrorHandlerMock.Object, LoggerMock.Object); - var actualDecision = decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, ProjectConfig); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); + var optimizelyUserContext = new OptimizelyUserContext(optlyObject, "user_1", null, + ErrorHandlerMock.Object, LoggerMock.Object); + var actualDecision = + decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, + ProjectConfig); Assert.IsTrue(TestData.CompareObjects(expectedDecision, actualDecision.ResultObject)); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, $"User \"user_1\" does not meet the conditions for targeting rule \"1\".")); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, $"User \"user_1\" does not meet the conditions for targeting rule \"2\".")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + $"User \"user_1\" does not meet the conditions for targeting rule \"1\".")); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + $"User \"user_1\" does not meet the conditions for targeting rule \"2\".")); } [Test] public void TestGetVariationForFeatureRolloutAudienceAndTrafficeAllocationCheck() { - var featureFlag = ProjectConfig.GetFeatureFlagFromKey("boolean_single_variable_feature"); + var featureFlag = + ProjectConfig.GetFeatureFlagFromKey("boolean_single_variable_feature"); var rolloutId = featureFlag.RolloutId; var rollout = ProjectConfig.GetRolloutFromId(rolloutId); var expWithAudienceiPhoneUsers = rollout.Experiments[1]; @@ -819,48 +1042,65 @@ public void TestGetVariationForFeatureRolloutAudienceAndTrafficeAllocationCheck( var mockBucketer = new Mock(LoggerMock.Object) { CallBase = true }; mockBucketer.Setup(bm => bm.GenerateBucketValue(It.IsAny())).Returns(980); - var decisionService = new DecisionService(mockBucketer.Object, ErrorHandlerMock.Object, null, LoggerMock.Object); + var decisionService = new DecisionService(mockBucketer.Object, ErrorHandlerMock.Object, + null, LoggerMock.Object); // Calling with audience iPhone users in San Francisco. - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); - var optimizelyUserContext = new OptimizelyUserContext(optlyObject, GenericUserId, new UserAttributes - { - { "device_type", "iPhone" }, - { "location", "San Francisco" } - }, ErrorHandlerMock.Object, LoggerMock.Object); - var actualDecision = decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, ProjectConfig); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); + var optimizelyUserContext = new OptimizelyUserContext(optlyObject, GenericUserId, + new UserAttributes + { + { "device_type", "iPhone" }, + { "location", "San Francisco" }, + }, ErrorHandlerMock.Object, LoggerMock.Object); + var actualDecision = + decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, + ProjectConfig); // Returned variation id should be '177773' because of audience 'iPhone users in San Francisco'. - var expectedDecision = new FeatureDecision(expWithAudienceiPhoneUsers, varWithAudienceiPhoneUsers, FeatureDecision.DECISION_SOURCE_ROLLOUT); + var expectedDecision = new FeatureDecision(expWithAudienceiPhoneUsers, + varWithAudienceiPhoneUsers, FeatureDecision.DECISION_SOURCE_ROLLOUT); Assert.IsTrue(TestData.CompareObjects(expectedDecision, actualDecision.ResultObject)); // Calling with audience Chrome users. - var optimizelyUserContext2 = new OptimizelyUserContext(optlyObject, GenericUserId, new UserAttributes - { - { "browser_type", "chrome" } - }, ErrorHandlerMock.Object, LoggerMock.Object); - actualDecision = decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext2, ProjectConfig); + var optimizelyUserContext2 = new OptimizelyUserContext(optlyObject, GenericUserId, + new UserAttributes + { + { "browser_type", "chrome" }, + }, ErrorHandlerMock.Object, LoggerMock.Object); + actualDecision = + decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext2, + ProjectConfig); // Returned variation id should be '177771' because of audience 'Chrome users'. - expectedDecision = new FeatureDecision(expWithAudienceChromeUsers, varWithAudienceChromeUsers, FeatureDecision.DECISION_SOURCE_ROLLOUT); + expectedDecision = new FeatureDecision(expWithAudienceChromeUsers, + varWithAudienceChromeUsers, FeatureDecision.DECISION_SOURCE_ROLLOUT); Assert.IsTrue(TestData.CompareObjects(expectedDecision, actualDecision.ResultObject)); // Calling with no audience. mockBucketer.Setup(bm => bm.GenerateBucketValue(It.IsAny())).Returns(8000); - var optimizelyUserContext3 = new OptimizelyUserContext(optlyObject, GenericUserId, new UserAttributes(), ErrorHandlerMock.Object, LoggerMock.Object); - actualDecision = decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext3, ProjectConfig); + var optimizelyUserContext3 = new OptimizelyUserContext(optlyObject, GenericUserId, + new UserAttributes(), ErrorHandlerMock.Object, LoggerMock.Object); + actualDecision = + decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext3, + ProjectConfig); // Returned variation id should be of everyone else rule because of no audience. - expectedDecision = new FeatureDecision(expWithNoAudience, varWithNoAudience, FeatureDecision.DECISION_SOURCE_ROLLOUT); + expectedDecision = new FeatureDecision(expWithNoAudience, varWithNoAudience, + FeatureDecision.DECISION_SOURCE_ROLLOUT); Assert.IsTrue(TestData.CompareObjects(expectedDecision, actualDecision.ResultObject)); // Calling with audience 'Chrome users' and traffice allocation '9500'. mockBucketer.Setup(bm => bm.GenerateBucketValue(It.IsAny())).Returns(9500); - var optimizelyUserContext4 = new OptimizelyUserContext(optlyObject, GenericUserId, new UserAttributes - { - { "browser_type", "chrome" } - }, ErrorHandlerMock.Object, LoggerMock.Object); - actualDecision = decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext4, ProjectConfig); + var optimizelyUserContext4 = new OptimizelyUserContext(optlyObject, GenericUserId, + new UserAttributes + { + { "browser_type", "chrome" }, + }, ErrorHandlerMock.Object, LoggerMock.Object); + actualDecision = + decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext4, + ProjectConfig); // Returned decision entity should be null because bucket value exceeds traffic allocation of everyone else rule. Assert.Null(actualDecision.ResultObject?.Variation?.Key); @@ -869,41 +1109,77 @@ public void TestGetVariationForFeatureRolloutAudienceAndTrafficeAllocationCheck( [Test] public void TestGetVariationForFeatureRolloutCheckAudienceInEveryoneElseRule() { - var featureFlag = ProjectConfig.GetFeatureFlagFromKey("boolean_single_variable_feature"); + var featureFlag = + ProjectConfig.GetFeatureFlagFromKey("boolean_single_variable_feature"); var rolloutId = featureFlag.RolloutId; var rollout = ProjectConfig.GetRolloutFromId(rolloutId); var everyoneElseRule = rollout.Experiments[2]; - var variation = Result.NewResult(everyoneElseRule.Variations[0], DecisionReasons); - var expectedDecision = new FeatureDecision(everyoneElseRule, variation.ResultObject, FeatureDecision.DECISION_SOURCE_ROLLOUT); - - BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), everyoneElseRule, It.IsAny(), WhitelistedUserId)).Returns(variation); - BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), everyoneElseRule, It.IsAny(), GenericUserId)).Returns(Result.NullResult(DecisionReasons)); - - var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, null, LoggerMock.Object); - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); + var variation = + Result.NewResult(everyoneElseRule.Variations[0], DecisionReasons); + var expectedDecision = new FeatureDecision(everyoneElseRule, variation.ResultObject, + FeatureDecision.DECISION_SOURCE_ROLLOUT); + + BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), everyoneElseRule, + It.IsAny(), WhitelistedUserId)). + Returns(variation); + BucketerMock. + Setup(bm => bm.Bucket(It.IsAny(), everyoneElseRule, + It.IsAny(), GenericUserId)). + Returns(Result.NullResult(DecisionReasons)); + + var decisionService = new DecisionService(BucketerMock.Object, ErrorHandlerMock.Object, + null, LoggerMock.Object); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); // Returned variation id should be of everyone else rule as it passes audience Id checking. - var optimizelyUserContext = new OptimizelyUserContext(optlyObject, WhitelistedUserId, null, ErrorHandlerMock.Object, LoggerMock.Object); - var actualDecision = decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, ProjectConfig); + var optimizelyUserContext = new OptimizelyUserContext(optlyObject, WhitelistedUserId, + null, ErrorHandlerMock.Object, LoggerMock.Object); + var actualDecision = + decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext, + ProjectConfig); Assert.True(TestData.CompareObjects(expectedDecision, actualDecision.ResultObject)); // Returned variation id should be null. - var optimizelyUserContext2 = new OptimizelyUserContext(optlyObject, GenericUserId, null, ErrorHandlerMock.Object, LoggerMock.Object); - actualDecision = decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext2, ProjectConfig); + var optimizelyUserContext2 = new OptimizelyUserContext(optlyObject, GenericUserId, null, + ErrorHandlerMock.Object, LoggerMock.Object); + actualDecision = + decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext2, + ProjectConfig); Assert.Null(actualDecision.ResultObject); // Returned variation id should be null as it fails audience Id checking. everyoneElseRule.AudienceIds = new string[] { ProjectConfig.Audiences[0].Id }; - BucketerMock.Setup(bm => bm.Bucket(It.IsAny(), It.IsAny(), It.IsAny(), GenericUserId)).Returns(Result.NullResult(DecisionReasons)); - actualDecision = decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext2, ProjectConfig) ?? Result.NullResult(DecisionReasons); + BucketerMock. + Setup(bm => bm.Bucket(It.IsAny(), It.IsAny(), + It.IsAny(), GenericUserId)). + Returns(Result.NullResult(DecisionReasons)); + actualDecision = + decisionService.GetVariationForFeatureRollout(featureFlag, optimizelyUserContext2, + ProjectConfig) ?? Result.NullResult(DecisionReasons); Assert.Null(actualDecision.ResultObject); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "User \"testUser1\" does not meet the conditions for targeting rule \"1\"."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "User \"testUser1\" does not meet the conditions for targeting rule \"2\"."), Times.Once); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "User \"genericUserId\" does not meet the conditions for targeting rule \"1\"."), Times.Exactly(2)); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "User \"genericUserId\" does not meet the conditions for targeting rule \"2\"."), Times.Exactly(2)); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, "User \"genericUserId\" does not meet the conditions for targeting rule \"3\"."), Times.Exactly(1)); + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + "User \"testUser1\" does not meet the conditions for targeting rule \"1\"."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + "User \"testUser1\" does not meet the conditions for targeting rule \"2\"."), + Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + "User \"genericUserId\" does not meet the conditions for targeting rule \"1\"."), + Times.Exactly(2)); + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + "User \"genericUserId\" does not meet the conditions for targeting rule \"2\"."), + Times.Exactly(2)); + LoggerMock.Verify( + l => l.Log(LogLevel.DEBUG, + "User \"genericUserId\" does not meet the conditions for targeting rule \"3\"."), + Times.Exactly(1)); } #endregion GetVariationForFeatureRollout Tests @@ -918,61 +1194,94 @@ public void TestGetVariationForFeatureWhenTheUserIsBucketedIntoFeatureExperiment var expectedExperimentId = featureFlag.ExperimentIds[0]; var expectedExperiment = ProjectConfig.GetExperimentFromId(expectedExperimentId); var variation = expectedExperiment.Variations[0]; - var expectedDecision = Result.NewResult(new FeatureDecision(expectedExperiment, variation, FeatureDecision.DECISION_SOURCE_FEATURE_TEST), DecisionReasons); - - DecisionServiceMock.Setup(ds => ds.GetVariationForFeatureExperiment(It.IsAny(), It.IsAny(), - It.IsAny(), ProjectConfig, It.IsAny())).Returns(expectedDecision); + var expectedDecision = Result.NewResult( + new FeatureDecision(expectedExperiment, variation, + FeatureDecision.DECISION_SOURCE_FEATURE_TEST), DecisionReasons); + + DecisionServiceMock.Setup(ds => ds.GetVariationForFeatureExperiment( + It.IsAny(), It.IsAny(), + It.IsAny(), ProjectConfig, + It.IsAny())). + Returns(expectedDecision); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns("user1"); - var actualDecision = DecisionServiceMock.Object.GetVariationForFeature(featureFlag, OptimizelyUserContextMock.Object, ProjectConfig); + var actualDecision = DecisionServiceMock.Object.GetVariationForFeature(featureFlag, + OptimizelyUserContextMock.Object, ProjectConfig); Assert.IsTrue(TestData.CompareObjects(expectedDecision, actualDecision)); } // Should return the bucketed variation when the user is not bucketed in the feature flag experiment, // but is bucketed into a variation of the feature flag's rollout. [Test] - public void TestGetVariationForFeatureWhenTheUserIsNotBucketedIntoFeatureExperimentAndBucketedToFeatureRollout() + public void + TestGetVariationForFeatureWhenTheUserIsNotBucketedIntoFeatureExperimentAndBucketedToFeatureRollout() { var featureFlag = ProjectConfig.GetFeatureFlagFromKey("string_single_variable_feature"); var rolloutId = featureFlag.RolloutId; var rollout = ProjectConfig.GetRolloutFromId(rolloutId); var expectedExperiment = rollout.Experiments[0]; var variation = expectedExperiment.Variations[0]; - var expectedDecision = Result.NewResult(new FeatureDecision(expectedExperiment, variation, FeatureDecision.DECISION_SOURCE_ROLLOUT), DecisionReasons); - - DecisionServiceMock.Setup(ds => ds.GetVariationForFeatureExperiment(It.IsAny(), It.IsAny(), - It.IsAny(), ProjectConfig, It.IsAny())).Returns(Result.NullResult(null)); - DecisionServiceMock.Setup(ds => ds.GetVariationForFeatureRollout(It.IsAny(), It.IsAny(), - ProjectConfig)).Returns(expectedDecision); - - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); - OptimizelyUserContextMock = new Mock(optlyObject, WhitelistedUserId, new UserAttributes(), ErrorHandlerMock.Object, LoggerMock.Object); + var expectedDecision = Result.NewResult( + new FeatureDecision(expectedExperiment, variation, + FeatureDecision.DECISION_SOURCE_ROLLOUT), DecisionReasons); + + DecisionServiceMock.Setup(ds => ds.GetVariationForFeatureExperiment( + It.IsAny(), It.IsAny(), + It.IsAny(), ProjectConfig, + It.IsAny())). + Returns(Result.NullResult(null)); + DecisionServiceMock.Setup(ds => ds.GetVariationForFeatureRollout( + It.IsAny(), It.IsAny(), + ProjectConfig)). + Returns(expectedDecision); + + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); + OptimizelyUserContextMock = new Mock(optlyObject, + WhitelistedUserId, new UserAttributes(), ErrorHandlerMock.Object, + LoggerMock.Object); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(UserProfileId); - var actualDecision = DecisionServiceMock.Object.GetVariationForFeature(featureFlag, OptimizelyUserContextMock.Object, ProjectConfig); + var actualDecision = DecisionServiceMock.Object.GetVariationForFeature(featureFlag, + OptimizelyUserContextMock.Object, ProjectConfig); Assert.IsTrue(TestData.CompareObjects(expectedDecision, actualDecision)); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "The user \"userProfileId\" is bucketed into a rollout for feature flag \"string_single_variable_feature\".")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "The user \"userProfileId\" is bucketed into a rollout for feature flag \"string_single_variable_feature\".")); } // Should return null when the user neither gets bucketed into feature experiment nor in feature rollout. [Test] - public void TestGetVariationForFeatureWhenTheUserIsNeitherBucketedIntoFeatureExperimentNorToFeatureRollout() + public void + TestGetVariationForFeatureWhenTheUserIsNeitherBucketedIntoFeatureExperimentNorToFeatureRollout() { var featureFlag = ProjectConfig.GetFeatureFlagFromKey("string_single_variable_feature"); - DecisionServiceMock.Setup(ds => ds.GetVariationForFeatureExperiment(It.IsAny(), It.IsAny(), It.IsAny(), ProjectConfig, new OptimizelyDecideOption[] { })).Returns(Result.NullResult(null)); - DecisionServiceMock.Setup(ds => ds.GetVariationForFeatureRollout(It.IsAny(), It.IsAny(), ProjectConfig)).Returns(Result.NullResult(null)); - - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); - OptimizelyUserContextMock = new Mock(optlyObject, WhitelistedUserId, new UserAttributes(), ErrorHandlerMock.Object, LoggerMock.Object); + DecisionServiceMock.Setup(ds => + ds.GetVariationForFeatureExperiment(It.IsAny(), + It.IsAny(), It.IsAny(), + ProjectConfig, + new OptimizelyDecideOption[] { })). + Returns(Result.NullResult(null)); + DecisionServiceMock. + Setup(ds => ds.GetVariationForFeatureRollout(It.IsAny(), + It.IsAny(), ProjectConfig)). + Returns(Result.NullResult(null)); + + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); + OptimizelyUserContextMock = new Mock(optlyObject, + WhitelistedUserId, new UserAttributes(), ErrorHandlerMock.Object, + LoggerMock.Object); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(UserProfileId); - var actualDecision = DecisionServiceMock.Object.GetVariationForFeature(featureFlag, OptimizelyUserContextMock.Object, ProjectConfig); + var actualDecision = DecisionServiceMock.Object.GetVariationForFeature(featureFlag, + OptimizelyUserContextMock.Object, ProjectConfig); Assert.IsNull(actualDecision.ResultObject.Variation); - LoggerMock.Verify(l => l.Log(LogLevel.INFO, "The user \"userProfileId\" is not bucketed into a rollout for feature flag \"string_single_variable_feature\".")); + LoggerMock.Verify(l => l.Log(LogLevel.INFO, + "The user \"userProfileId\" is not bucketed into a rollout for feature flag \"string_single_variable_feature\".")); } // Verify that the user is bucketed into the experiment's variation when the user satisfies bucketing and traffic allocation @@ -981,37 +1290,58 @@ public void TestGetVariationForFeatureWhenTheUserIsNeitherBucketedIntoFeatureExp public void TestGetVariationForFeatureWhenTheUserIsBuckedtedInBothExperimentAndRollout() { var featureFlag = ProjectConfig.GetFeatureFlagFromKey("string_single_variable_feature"); - var experiment = ProjectConfig.GetExperimentFromKey("test_experiment_with_feature_rollout"); - var variation = Result.NewResult(ProjectConfig.GetVariationFromId("test_experiment_with_feature_rollout", "122236"), DecisionReasons); - var expectedDecision = new FeatureDecision(experiment, variation.ResultObject, FeatureDecision.DECISION_SOURCE_FEATURE_TEST); - var userAttributes = new UserAttributes { - { "browser_type", "chrome" } + var experiment = + ProjectConfig.GetExperimentFromKey("test_experiment_with_feature_rollout"); + var variation = Result.NewResult( + ProjectConfig.GetVariationFromId("test_experiment_with_feature_rollout", "122236"), + DecisionReasons); + var expectedDecision = new FeatureDecision(experiment, variation.ResultObject, + FeatureDecision.DECISION_SOURCE_FEATURE_TEST); + var userAttributes = new UserAttributes + { + { "browser_type", "chrome" }, }; - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); - OptimizelyUserContextMock = new Mock(optlyObject, WhitelistedUserId, userAttributes, ErrorHandlerMock.Object, LoggerMock.Object); + OptimizelyUserContextMock = new Mock(optlyObject, + WhitelistedUserId, userAttributes, ErrorHandlerMock.Object, LoggerMock.Object); OptimizelyUserContextMock.Setup(ouc => ouc.GetUserId()).Returns(UserProfileId); - DecisionServiceMock.Setup(ds => ds.GetVariation(experiment, OptimizelyUserContextMock.Object, ProjectConfig, It.IsAny())).Returns(variation); - var actualDecision = DecisionServiceMock.Object.GetVariationForFeatureExperiment(featureFlag, OptimizelyUserContextMock.Object, userAttributes, ProjectConfig, new OptimizelyDecideOption[] { }); + DecisionServiceMock.Setup(ds => ds.GetVariation(experiment, + OptimizelyUserContextMock.Object, ProjectConfig, + It.IsAny())). + Returns(variation); + var actualDecision = DecisionServiceMock.Object.GetVariationForFeatureExperiment( + featureFlag, OptimizelyUserContextMock.Object, userAttributes, ProjectConfig, + new OptimizelyDecideOption[] { }); // The user is bucketed into feature experiment's variation. Assert.IsTrue(TestData.CompareObjects(expectedDecision, actualDecision.ResultObject)); var rollout = ProjectConfig.GetRolloutFromId(featureFlag.RolloutId); var rolloutExperiment = rollout.Experiments[0]; - var rolloutVariation = Result.NewResult(rolloutExperiment.Variations[0], DecisionReasons); - var expectedRolloutDecision = new FeatureDecision(rolloutExperiment, rolloutVariation.ResultObject, FeatureDecision.DECISION_SOURCE_ROLLOUT); - - BucketerMock.Setup(bm => bm.Bucket(ProjectConfig, rolloutExperiment, It.IsAny(), It.IsAny())).Returns(rolloutVariation); - var actualRolloutDecision = DecisionServiceMock.Object.GetVariationForFeatureRollout(featureFlag, OptimizelyUserContextMock.Object, ProjectConfig); + var rolloutVariation = + Result.NewResult(rolloutExperiment.Variations[0], DecisionReasons); + var expectedRolloutDecision = new FeatureDecision(rolloutExperiment, + rolloutVariation.ResultObject, FeatureDecision.DECISION_SOURCE_ROLLOUT); + + BucketerMock. + Setup(bm => bm.Bucket(ProjectConfig, rolloutExperiment, It.IsAny(), + It.IsAny())). + Returns(rolloutVariation); + var actualRolloutDecision = + DecisionServiceMock.Object.GetVariationForFeatureRollout(featureFlag, + OptimizelyUserContextMock.Object, ProjectConfig); // The user is bucketed into feature rollout's variation. - Assert.IsTrue(TestData.CompareObjects(expectedRolloutDecision, actualRolloutDecision.ResultObject)); + Assert.IsTrue(TestData.CompareObjects(expectedRolloutDecision, + actualRolloutDecision.ResultObject)); - actualDecision = DecisionServiceMock.Object.GetVariationForFeature(featureFlag, OptimizelyUserContextMock.Object, ProjectConfig); + actualDecision = DecisionServiceMock.Object.GetVariationForFeature(featureFlag, + OptimizelyUserContextMock.Object, ProjectConfig); // The user is bucketed into feature experiment's variation and not the rollout's variation. Assert.IsTrue(TestData.CompareObjects(expectedDecision, actualDecision.ResultObject)); @@ -1035,45 +1365,58 @@ public void TestSetGetForcedVariation() var userAttributes = new UserAttributes { - {"device_type", "iPhone" }, - {"location", "San Francisco" } + { "device_type", "iPhone" }, + { "location", "San Francisco" }, }; - var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), LoggerMock.Object); + var optlyObject = new Optimizely(TestData.Datafile, new ValidEventDispatcher(), + LoggerMock.Object); optlyObject.Activate("test_experiment", "test_user", userAttributes); // invalid experiment key should return a null variation - Assert.False(DecisionService.SetForcedVariation(invalidExperimentKey, userId, expectedVariationKey, Config)); - Assert.Null(DecisionService.GetForcedVariation(invalidExperimentKey, userId, Config).ResultObject); + Assert.False(DecisionService.SetForcedVariation(invalidExperimentKey, userId, + expectedVariationKey, Config)); + Assert.Null(DecisionService.GetForcedVariation(invalidExperimentKey, userId, Config). + ResultObject); // setting a null variation should return a null variation Assert.True(DecisionService.SetForcedVariation(experimentKey, userId, null, Config)); - Assert.Null(DecisionService.GetForcedVariation(experimentKey, userId, Config).ResultObject); + Assert.Null(DecisionService.GetForcedVariation(experimentKey, userId, Config). + ResultObject); // setting an invalid variation should return a null variation - Assert.False(DecisionService.SetForcedVariation(experimentKey, userId, invalidVariationKey, Config)); - Assert.Null(DecisionService.GetForcedVariation(experimentKey, userId, Config).ResultObject); + Assert.False(DecisionService.SetForcedVariation(experimentKey, userId, + invalidVariationKey, Config)); + Assert.Null(DecisionService.GetForcedVariation(experimentKey, userId, Config). + ResultObject); // confirm the forced variation is returned after a set - Assert.True(DecisionService.SetForcedVariation(experimentKey, userId, expectedVariationKey, Config)); - var actualForcedVariation = DecisionService.GetForcedVariation(experimentKey, userId, Config); + Assert.True(DecisionService.SetForcedVariation(experimentKey, userId, + expectedVariationKey, Config)); + var actualForcedVariation = + DecisionService.GetForcedVariation(experimentKey, userId, Config); Assert.AreEqual(expectedVariationKey, actualForcedVariation.ResultObject.Key); // check multiple sets - Assert.True(DecisionService.SetForcedVariation(experimentKey2, userId, expectedVariationKey2, Config)); - var actualForcedVariation2 = DecisionService.GetForcedVariation(experimentKey2, userId, Config); + Assert.True(DecisionService.SetForcedVariation(experimentKey2, userId, + expectedVariationKey2, Config)); + var actualForcedVariation2 = + DecisionService.GetForcedVariation(experimentKey2, userId, Config); Assert.AreEqual(expectedVariationKey2, actualForcedVariation2.ResultObject.Key); // make sure the second set does not overwrite the first set - actualForcedVariation = DecisionService.GetForcedVariation(experimentKey, userId, Config); + actualForcedVariation = + DecisionService.GetForcedVariation(experimentKey, userId, Config); Assert.AreEqual(expectedVariationKey, actualForcedVariation.ResultObject.Key); // make sure unsetting the second experiment-to-variation mapping does not unset the // first experiment-to-variation mapping Assert.True(DecisionService.SetForcedVariation(experimentKey2, userId, null, Config)); - actualForcedVariation = DecisionService.GetForcedVariation(experimentKey, userId, Config); + actualForcedVariation = + DecisionService.GetForcedVariation(experimentKey, userId, Config); Assert.AreEqual(expectedVariationKey, actualForcedVariation.ResultObject.Key); // an invalid user ID should return a null variation - Assert.Null(DecisionService.GetForcedVariation(experimentKey, invalidUserId, Config).ResultObject); + Assert.Null(DecisionService.GetForcedVariation(experimentKey, invalidUserId, Config). + ResultObject); } // test that all the logs in setForcedVariation are getting called @@ -1093,11 +1436,23 @@ public void TestSetForcedVariationLogs() DecisionService.SetForcedVariation(experimentKey, userId, invalidVariationKey, Config); DecisionService.SetForcedVariation(experimentKey, userId, variationKey, Config); - LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), Times.Exactly(4)); - LoggerMock.Verify(l => l.Log(LogLevel.ERROR, string.Format(@"Experiment key ""{0}"" is not in datafile.", invalidExperimentKey))); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, string.Format(@"Variation mapped to experiment ""{0}"" has been removed for user ""{1}"".", experimentKey, userId))); - LoggerMock.Verify(l => l.Log(LogLevel.ERROR, string.Format(@"No variation key ""{0}"" defined in datafile for experiment ""{1}"".", invalidVariationKey, experimentKey))); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, string.Format(@"Set variation ""{0}"" for experiment ""{1}"" and user ""{2}"" in the forced variation map.", variationId, experimentId, userId))); + LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), + Times.Exactly(4)); + LoggerMock.Verify(l => l.Log(LogLevel.ERROR, + string.Format(@"Experiment key ""{0}"" is not in datafile.", + invalidExperimentKey))); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + string.Format( + @"Variation mapped to experiment ""{0}"" has been removed for user ""{1}"".", + experimentKey, userId))); + LoggerMock.Verify(l => l.Log(LogLevel.ERROR, + string.Format( + @"No variation key ""{0}"" defined in datafile for experiment ""{1}"".", + invalidVariationKey, experimentKey))); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + string.Format( + @"Set variation ""{0}"" for experiment ""{1}"" and user ""{2}"" in the forced variation map.", + variationId, experimentId, userId))); } // test that all the logs in getForcedVariation are getting called @@ -1119,39 +1474,71 @@ public void TestGetForcedVariationLogs() DecisionService.GetForcedVariation(pausedExperimentKey, userId, Config); DecisionService.GetForcedVariation(experimentKey, userId, Config); - LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), Times.Exactly(5)); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, string.Format(@"Set variation ""{0}"" for experiment ""{1}"" and user ""{2}"" in the forced variation map.", variationId, experimentId, userId))); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, string.Format(@"User ""{0}"" is not in the forced variation map.", invalidUserId))); - LoggerMock.Verify(l => l.Log(LogLevel.ERROR, string.Format(@"Experiment key ""{0}"" is not in datafile.", invalidExperimentKey))); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, string.Format(@"No experiment ""{0}"" mapped to user ""{1}"" in the forced variation map.", pausedExperimentKey, userId))); - LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, string.Format(@"Variation ""{0}"" is mapped to experiment ""{1}"" and user ""{2}"" in the forced variation map", variationKey, experimentKey, userId))); + LoggerMock.Verify(l => l.Log(It.IsAny(), It.IsAny()), + Times.Exactly(5)); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + string.Format( + @"Set variation ""{0}"" for experiment ""{1}"" and user ""{2}"" in the forced variation map.", + variationId, experimentId, userId))); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + string.Format(@"User ""{0}"" is not in the forced variation map.", invalidUserId))); + LoggerMock.Verify(l => l.Log(LogLevel.ERROR, + string.Format(@"Experiment key ""{0}"" is not in datafile.", + invalidExperimentKey))); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + string.Format( + @"No experiment ""{0}"" mapped to user ""{1}"" in the forced variation map.", + pausedExperimentKey, userId))); + LoggerMock.Verify(l => l.Log(LogLevel.DEBUG, + string.Format( + @"Variation ""{0}"" is mapped to experiment ""{1}"" and user ""{2}"" in the forced variation map", + variationKey, experimentKey, userId))); } [Test] public void TestSetForcedVariationMultipleSets() { - Assert.True(DecisionService.SetForcedVariation("test_experiment", "test_user_1", "variation", Config)); - Assert.AreEqual(DecisionService.GetForcedVariation("test_experiment", "test_user_1", Config).ResultObject.Key, "variation"); + Assert.True(DecisionService.SetForcedVariation("test_experiment", "test_user_1", + "variation", Config)); + Assert.AreEqual( + DecisionService.GetForcedVariation("test_experiment", "test_user_1", Config). + ResultObject.Key, "variation"); // same user, same experiment, different variation - Assert.True(DecisionService.SetForcedVariation("test_experiment", "test_user_1", "control", Config)); - Assert.AreEqual(DecisionService.GetForcedVariation("test_experiment", "test_user_1", Config).ResultObject.Key, "control"); + Assert.True(DecisionService.SetForcedVariation("test_experiment", "test_user_1", + "control", Config)); + Assert.AreEqual( + DecisionService.GetForcedVariation("test_experiment", "test_user_1", Config). + ResultObject.Key, "control"); // same user, different experiment - Assert.True(DecisionService.SetForcedVariation("group_experiment_1", "test_user_1", "group_exp_1_var_1", Config)); - Assert.AreEqual(DecisionService.GetForcedVariation("group_experiment_1", "test_user_1", Config).ResultObject.Key, "group_exp_1_var_1"); + Assert.True(DecisionService.SetForcedVariation("group_experiment_1", "test_user_1", + "group_exp_1_var_1", Config)); + Assert.AreEqual( + DecisionService.GetForcedVariation("group_experiment_1", "test_user_1", Config). + ResultObject.Key, "group_exp_1_var_1"); // different user - Assert.True(DecisionService.SetForcedVariation("test_experiment", "test_user_2", "variation", Config)); - Assert.AreEqual(DecisionService.GetForcedVariation("test_experiment", "test_user_2", Config).ResultObject.Key, "variation"); + Assert.True(DecisionService.SetForcedVariation("test_experiment", "test_user_2", + "variation", Config)); + Assert.AreEqual( + DecisionService.GetForcedVariation("test_experiment", "test_user_2", Config). + ResultObject.Key, "variation"); // different user, different experiment - Assert.True(DecisionService.SetForcedVariation("group_experiment_1", "test_user_2", "group_exp_1_var_1", Config)); - Assert.AreEqual(DecisionService.GetForcedVariation("group_experiment_1", "test_user_2", Config).ResultObject.Key, "group_exp_1_var_1"); + Assert.True(DecisionService.SetForcedVariation("group_experiment_1", "test_user_2", + "group_exp_1_var_1", Config)); + Assert.AreEqual( + DecisionService.GetForcedVariation("group_experiment_1", "test_user_2", Config). + ResultObject.Key, "group_exp_1_var_1"); // make sure the first user forced variations are still valid - Assert.AreEqual(DecisionService.GetForcedVariation("test_experiment", "test_user_1", Config).ResultObject.Key, "control"); - Assert.AreEqual(DecisionService.GetForcedVariation("group_experiment_1", "test_user_1", Config).ResultObject.Key, "group_exp_1_var_1"); + Assert.AreEqual( + DecisionService.GetForcedVariation("test_experiment", "test_user_1", Config). + ResultObject.Key, "control"); + Assert.AreEqual( + DecisionService.GetForcedVariation("group_experiment_1", "test_user_1", Config). + ResultObject.Key, "group_exp_1_var_1"); } #endregion Forced variation Tests diff --git a/OptimizelySDK.Tests/DefaultErrorHandlerTest.cs b/OptimizelySDK.Tests/DefaultErrorHandlerTest.cs index 07db44935..7138165ad 100644 --- a/OptimizelySDK.Tests/DefaultErrorHandlerTest.cs +++ b/OptimizelySDK.Tests/DefaultErrorHandlerTest.cs @@ -14,15 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using System; using System.Collections.Generic; using Moq; -using OptimizelySDK.Logger; -using OptimizelySDK.ErrorHandler; -using OptimizelySDK.Entity; using NUnit.Framework; using OptimizelySDK.Bucketing; +using OptimizelySDK.Entity; +using OptimizelySDK.ErrorHandler; using OptimizelySDK.Exceptions; +using OptimizelySDK.Logger; namespace OptimizelySDK.Tests { @@ -41,12 +42,12 @@ public void Setup() public void TestErrorHandlerMessage() { DefaultErrorHandler = new DefaultErrorHandler(LoggerMock.Object, false); - string testingException = "Testing exception"; + var testingException = "Testing exception"; try { throw new OptimizelyException("Testing exception"); } - catch(OptimizelyException ex) + catch (OptimizelyException ex) { DefaultErrorHandler.HandleError(ex); } @@ -54,12 +55,11 @@ public void TestErrorHandlerMessage() LoggerMock.Verify(log => log.Log(LogLevel.ERROR, testingException), Times.Once); } - [Test] - [ExpectedException] + [Test, ExpectedException] public void TestErrorHandlerMessageWithThrowException() { DefaultErrorHandler = new DefaultErrorHandler(LoggerMock.Object, true); - string testingException = "Testing and throwing exception"; + var testingException = "Testing and throwing exception"; try { throw new OptimizelyException("Testing exception"); @@ -72,6 +72,5 @@ public void TestErrorHandlerMessageWithThrowException() LoggerMock.Verify(log => log.Log(LogLevel.ERROR, testingException), Times.Once); } - } } diff --git a/OptimizelySDK.Tests/EntityTests/FeatureVariableTest.cs b/OptimizelySDK.Tests/EntityTests/FeatureVariableTest.cs index b44b31945..254e90ed4 100644 --- a/OptimizelySDK.Tests/EntityTests/FeatureVariableTest.cs +++ b/OptimizelySDK.Tests/EntityTests/FeatureVariableTest.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright 2019-2020, Optimizely * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,11 +26,18 @@ public class FeatureVariableTest [Test] public void TestFeatureVariableTypeName() { - Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.BOOLEAN_TYPE), "GetFeatureVariableBoolean"); - Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.DOUBLE_TYPE), "GetFeatureVariableDouble"); - Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.INTEGER_TYPE), "GetFeatureVariableInteger"); - Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.STRING_TYPE), "GetFeatureVariableString"); - Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.JSON_TYPE), "GetFeatureVariableJSON"); + Assert.AreEqual( + FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.BOOLEAN_TYPE), + "GetFeatureVariableBoolean"); + Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.DOUBLE_TYPE), + "GetFeatureVariableDouble"); + Assert.AreEqual( + FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.INTEGER_TYPE), + "GetFeatureVariableInteger"); + Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.STRING_TYPE), + "GetFeatureVariableString"); + Assert.AreEqual(FeatureVariable.GetFeatureVariableTypeName(FeatureVariable.JSON_TYPE), + "GetFeatureVariableJSON"); } [Test] diff --git a/OptimizelySDK.Tests/EventTests/BatchEventProcessorTest.cs b/OptimizelySDK.Tests/EventTests/BatchEventProcessorTest.cs index 5e0174a65..6a212f6a3 100644 --- a/OptimizelySDK.Tests/EventTests/BatchEventProcessorTest.cs +++ b/OptimizelySDK.Tests/EventTests/BatchEventProcessorTest.cs @@ -1,4 +1,7 @@ -using Moq; +using System; +using System.Collections.Concurrent; +using System.Threading; +using Moq; using NUnit.Framework; using OptimizelySDK.Config; using OptimizelySDK.Entity; @@ -9,14 +12,11 @@ using OptimizelySDK.Logger; using OptimizelySDK.Notifications; using OptimizelySDK.Tests.NotificationTests; -using System; -using System.Collections.Concurrent; -using System.Threading; namespace OptimizelySDK.Tests.EventTests { [TestFixture] - class BatchEventProcessorTest + internal class BatchEventProcessorTest { private static string TestUserId = "testUserId"; private const string EventName = "purchase"; @@ -24,12 +24,12 @@ class BatchEventProcessorTest public const int MAX_BATCH_SIZE = 10; public const int MAX_DURATION_MS = 1000; public const int TIMEOUT_INTERVAL_MS = 5000; - + private ProjectConfig Config; private Mock LoggerMock; private BlockingCollection eventQueue; private BatchEventProcessor EventProcessor; - private Mock EventDispatcherMock; + private Mock EventDispatcherMock; private NotificationCenter NotificationCenter = new NotificationCenter(); private Mock NotificationCallbackMock; @@ -39,8 +39,9 @@ public void Setup() LoggerMock = new Mock(); LoggerMock.Setup(l => l.Log(It.IsAny(), It.IsAny())); - Config = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, new ErrorHandler.NoOpErrorHandler()); - + Config = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, + new NoOpErrorHandler()); + eventQueue = new BlockingCollection(100); EventDispatcherMock = new Mock(); @@ -56,7 +57,7 @@ public void TearDown() { EventProcessor.Stop(); } - + [Test] public void TestDrainOnClose() { @@ -68,7 +69,7 @@ public void TestDrainOnClose() eventDispatcher.ExpectConversion(EventName, TestUserId); Thread.Sleep(1500); - + Assert.True(eventDispatcher.CompareEvents()); Assert.AreEqual(0, EventProcessor.EventQueue.Count); } @@ -87,7 +88,8 @@ public void TestFlushOnMaxTimeout() Thread.Sleep(1500); Assert.True(eventDispatcher.CompareEvents()); - Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS * 3)), "Exceeded timeout waiting for notification."); + Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS * 3)), + "Exceeded timeout waiting for notification."); Assert.AreEqual(0, EventProcessor.EventQueue.Count); } @@ -95,10 +97,11 @@ public void TestFlushOnMaxTimeout() public void TestFlushMaxBatchSize() { var countdownEvent = new CountdownEvent(1); - var eventDispatcher = new TestEventDispatcher(countdownEvent) { Logger = LoggerMock.Object }; + var eventDispatcher = new TestEventDispatcher(countdownEvent) + { Logger = LoggerMock.Object }; SetEventProcessor(eventDispatcher); - for (int i = 0; i < MAX_BATCH_SIZE; i++) + for (var i = 0; i < MAX_BATCH_SIZE; i++) { UserEvent userEvent = BuildConversionEvent(EventName); EventProcessor.Process(userEvent); @@ -133,7 +136,8 @@ public void TestFlush() Thread.Sleep(1500); Assert.True(eventDispatcher.CompareEvents()); - Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS / 2)), "Exceeded timeout waiting for notification."); + Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS / 2)), + "Exceeded timeout waiting for notification."); Assert.AreEqual(0, EventProcessor.EventQueue.Count); } @@ -150,7 +154,7 @@ public void TestNoOpLoggerIfNotProvided() { EventProcessor = new BatchEventProcessor.Builder().Build(); - Assert.True(EventProcessor.Logger is OptimizelySDK.Logger.NoOpLogger); + Assert.True(EventProcessor.Logger is NoOpLogger); } [Test] @@ -182,7 +186,8 @@ public void TestFlushOnMismatchRevision() Thread.Sleep(1500); Assert.True(eventDispatcher.CompareEvents()); - Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS * 3)), "Exceeded timeout waiting for notification."); + Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS * 3)), + "Exceeded timeout waiting for notification."); } [Test] @@ -207,7 +212,8 @@ public void TestFlushOnMismatchProjectId() Thread.Sleep(1500); Assert.True(eventDispatcher.CompareEvents()); - Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS * 3)), "Exceeded timeout waiting for notification."); + Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS * 3)), + "Exceeded timeout waiting for notification."); Assert.AreEqual(0, EventProcessor.EventQueue.Count); } @@ -231,7 +237,8 @@ public void TestStopAndStart() EventProcessor.Start(); EventProcessor.Stop(); - Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS * 3)), "Exceeded timeout waiting for notification."); + Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS * 3)), + "Exceeded timeout waiting for notification."); } [Test] @@ -277,21 +284,22 @@ public void TestDisposeDontRaiseException() // Need to make sure, after dispose, process shouldn't raise exception EventProcessor.Process(userEvent); - } [Test] public void TestNotificationCenter() { var countdownEvent = new CountdownEvent(1); - NotificationCenter.AddNotification(NotificationCenter.NotificationType.LogEvent, logEvent => countdownEvent.Signal()); + NotificationCenter.AddNotification(NotificationCenter.NotificationType.LogEvent, + logEvent => countdownEvent.Signal()); SetEventProcessor(EventDispatcherMock.Object); UserEvent userEvent = BuildConversionEvent(EventName); EventProcessor.Process(userEvent); - + EventProcessor.Stop(); - Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS * 3)), "Exceeded timeout waiting for notification."); + Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS * 3)), + "Exceeded timeout waiting for notification."); } [Test] @@ -310,15 +318,14 @@ public void TestCloseTimeout() private void SetEventProcessor(IEventDispatcher eventDispatcher) { - EventProcessor = new BatchEventProcessor.Builder() - .WithEventQueue(eventQueue) - .WithEventDispatcher(eventDispatcher) - .WithMaxBatchSize(MAX_BATCH_SIZE) - .WithFlushInterval(TimeSpan.FromMilliseconds(MAX_DURATION_MS)) - .WithTimeoutInterval(TimeSpan.FromMilliseconds(TIMEOUT_INTERVAL_MS)) - .WithLogger(LoggerMock.Object) - .WithNotificationCenter(NotificationCenter) - .Build(); + EventProcessor = new BatchEventProcessor.Builder().WithEventQueue(eventQueue). + WithEventDispatcher(eventDispatcher). + WithMaxBatchSize(MAX_BATCH_SIZE). + WithFlushInterval(TimeSpan.FromMilliseconds(MAX_DURATION_MS)). + WithTimeoutInterval(TimeSpan.FromMilliseconds(TIMEOUT_INTERVAL_MS)). + WithLogger(LoggerMock.Object). + WithNotificationCenter(NotificationCenter). + Build(); } private ConversionEvent BuildConversionEvent(string eventName) @@ -326,17 +333,24 @@ private ConversionEvent BuildConversionEvent(string eventName) return BuildConversionEvent(eventName, Config); } - private static ConversionEvent BuildConversionEvent(string eventName, ProjectConfig projectConfig) + private static ConversionEvent BuildConversionEvent(string eventName, + ProjectConfig projectConfig + ) { return UserEventFactory.CreateConversionEvent(projectConfig, eventName, TestUserId, new UserAttributes(), new EventTags()); } } - class CountdownEventDispatcher : IEventDispatcher + internal class CountdownEventDispatcher : IEventDispatcher { public ILogger Logger { get; set; } public CountdownEvent CountdownEvent { get; set; } - public void DispatchEvent(LogEvent logEvent) => Assert.False(!CountdownEvent.Wait(TimeSpan.FromMilliseconds(BatchEventProcessorTest.TIMEOUT_INTERVAL_MS * 2))); + + public void DispatchEvent(LogEvent logEvent) + { + Assert.False(!CountdownEvent.Wait( + TimeSpan.FromMilliseconds(BatchEventProcessorTest.TIMEOUT_INTERVAL_MS * 2))); + } } } diff --git a/OptimizelySDK.Tests/EventTests/CanonicalEvent.cs b/OptimizelySDK.Tests/EventTests/CanonicalEvent.cs index cbefd0667..95a9ead37 100644 --- a/OptimizelySDK.Tests/EventTests/CanonicalEvent.cs +++ b/OptimizelySDK.Tests/EventTests/CanonicalEvent.cs @@ -1,7 +1,7 @@ -using OptimizelySDK.Entity; -using System; +using System; using System.Collections.Generic; using System.Linq; +using OptimizelySDK.Entity; namespace OptimizelySDK.Tests.EventTests { @@ -14,7 +14,9 @@ public class CanonicalEvent private UserAttributes Attributes; private EventTags Tags; - public CanonicalEvent(string experimentId, string variationId, string eventName, string visitorId, UserAttributes attributes, EventTags tags) + public CanonicalEvent(string experimentId, string variationId, string eventName, + string visitorId, UserAttributes attributes, EventTags tags + ) { ExperimentId = experimentId; VariationId = variationId; @@ -24,29 +26,39 @@ public CanonicalEvent(string experimentId, string variationId, string eventName, Attributes = attributes ?? new UserAttributes(); Tags = tags ?? new EventTags(); } - + public override bool Equals(object obj) { if (obj == null) + { return false; + } - CanonicalEvent canonicalEvent = obj as CanonicalEvent; + var canonicalEvent = obj as CanonicalEvent; if (canonicalEvent == null) + { return false; + } if (ExperimentId != canonicalEvent.ExperimentId || VariationId != canonicalEvent.VariationId || EventName != canonicalEvent.EventName || VisitorId != canonicalEvent.VisitorId) + { return false; + } - if (!Attributes.OrderBy(pair => pair.Key) - .SequenceEqual(canonicalEvent.Attributes.OrderBy(pair => pair.Key))) + if (!Attributes.OrderBy(pair => pair.Key). + SequenceEqual(canonicalEvent.Attributes.OrderBy(pair => pair.Key))) + { return false; + } - if (!Tags.OrderBy(pair => pair.Key) - .SequenceEqual(canonicalEvent.Tags.OrderBy(pair => pair.Key))) + if (!Tags.OrderBy(pair => pair.Key). + SequenceEqual(canonicalEvent.Tags.OrderBy(pair => pair.Key))) + { return false; + } return true; } @@ -54,21 +66,29 @@ public override bool Equals(object obj) public override int GetHashCode() { var hashCode = -907746114; - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(ExperimentId); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(VariationId); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(EventName); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(VisitorId); - hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(Attributes); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Tags); + hashCode = (hashCode * -1521134295) + + EqualityComparer.Default.GetHashCode(ExperimentId); + hashCode = (hashCode * -1521134295) + + EqualityComparer.Default.GetHashCode(VariationId); + hashCode = (hashCode * -1521134295) + + EqualityComparer.Default.GetHashCode(EventName); + hashCode = (hashCode * -1521134295) + + EqualityComparer.Default.GetHashCode(VisitorId); + hashCode = (hashCode * -1521134295) + + EqualityComparer>.Default.GetHashCode(Attributes); + hashCode = (hashCode * -1521134295) + + EqualityComparer.Default.GetHashCode(Tags); return hashCode; } public static bool operator ==(CanonicalEvent lhs, CanonicalEvent rhs) { - if (Object.ReferenceEquals(lhs, null)) + if (ReferenceEquals(lhs, null)) { - if (Object.ReferenceEquals(rhs, null)) + if (ReferenceEquals(rhs, null)) + { return true; + } return false; } diff --git a/OptimizelySDK.Tests/EventTests/DefaultEventDispatcherTest.cs b/OptimizelySDK.Tests/EventTests/DefaultEventDispatcherTest.cs index 6de01dd5d..0c7b5806e 100644 --- a/OptimizelySDK.Tests/EventTests/DefaultEventDispatcherTest.cs +++ b/OptimizelySDK.Tests/EventTests/DefaultEventDispatcherTest.cs @@ -1,13 +1,13 @@ -using OptimizelySDK.Entity; -using OptimizelySDK.Logger; -using Moq; -using OptimizelySDK.Event.Builder; -using OptimizelySDK.Event; +using System; using System.Collections.Generic; +using Moq; using Newtonsoft.Json.Linq; -using System; -using OptimizelySDK.Event.Dispatcher; using NUnit.Framework; +using OptimizelySDK.Entity; +using OptimizelySDK.Event; +using OptimizelySDK.Event.Builder; +using OptimizelySDK.Event.Dispatcher; +using OptimizelySDK.Logger; namespace OptimizelySDK.Tests.EventTests { @@ -20,22 +20,22 @@ public void TestDispatchEvent() var logEvent = new LogEvent("", new Dictionary { - {"accountId", "1234" }, - {"projectId", "9876" }, - {"visitorId", "testUser" } + { "accountId", "1234" }, + { "projectId", "9876" }, + { "visitorId", "testUser" }, }, "POST", new Dictionary { - {"Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var expectionedOptions = new Dictionary { - {"headers", logEvent.Headers }, - {"json", logEvent.Params }, - {"timeout", 10 }, - {"connect_timeout", 10 } + { "headers", logEvent.Headers }, + { "json", logEvent.Params }, + { "timeout", 10 }, + { "connect_timeout", 10 }, }; //TODO: Have to mock http calls. Will discuss with Randall. diff --git a/OptimizelySDK.Tests/EventTests/EventBuilderTest.cs b/OptimizelySDK.Tests/EventTests/EventBuilderTest.cs index da731223e..c869d831b 100644 --- a/OptimizelySDK.Tests/EventTests/EventBuilderTest.cs +++ b/OptimizelySDK.Tests/EventTests/EventBuilderTest.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright 2017-2019, Optimizely * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,16 +14,16 @@ * limitations under the License. */ -using OptimizelySDK.Entity; -using OptimizelySDK.Logger; -using OptimizelySDK.Event.Builder; -using OptimizelySDK.Event; -using System.Collections.Generic; using System; +using System.Collections.Generic; using NUnit.Framework; using OptimizelySDK.Bucketing; -using OptimizelySDK.Utils; using OptimizelySDK.Config; +using OptimizelySDK.Entity; +using OptimizelySDK.Event; +using OptimizelySDK.Event.Builder; +using OptimizelySDK.Logger; +using OptimizelySDK.Utils; namespace OptimizelySDK.Tests.EventTests { @@ -32,15 +32,17 @@ public class EventBuilderTest { private string TestUserId = string.Empty; private ProjectConfig Config; - + [Obsolete] private EventBuilder EventBuilder; [TestFixtureSetUp] + [Obsolete] public void Setup() { TestUserId = "testUserId"; var logger = new NoOpLogger(); - Config = DatafileProjectConfig.Create(TestData.Datafile, logger, new ErrorHandler.NoOpErrorHandler()); + Config = DatafileProjectConfig.Create(TestData.Datafile, logger, + new ErrorHandler.NoOpErrorHandler()); EventBuilder = new EventBuilder(new Bucketer(logger)); } @@ -52,60 +54,65 @@ public void TestCreateImpressionEventNoAttributes() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "77210100090" } - } + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "77210100090" }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - {"visitor_id", TestUserId} - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -113,15 +120,15 @@ public void TestCreateImpressionEventNoAttributes() "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); - var logEvent = EventBuilder.CreateImpressionEvent(Config, Config.GetExperimentFromKey("test_experiment"), "77210100090", TestUserId, null); + var logEvent = EventBuilder.CreateImpressionEvent(Config, + Config.GetExperimentFromKey("test_experiment"), "77210100090", TestUserId, null); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); - } [Test] @@ -132,67 +139,72 @@ public void TestCreateImpressionEventWithAttributes() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "77210100090" } - } + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "77210100090" }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -200,17 +212,18 @@ public void TestCreateImpressionEventWithAttributes() "POST", new Dictionary { - { "Content-Type", "application/json" } - + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { { "device_type", "iPhone" }, - { "company", "Optimizely" } + { "company", "Optimizely" }, }; - var logEvent = EventBuilder.CreateImpressionEvent(Config, Config.GetExperimentFromKey("test_experiment"), "77210100090", TestUserId, userAttributes); + var logEvent = EventBuilder.CreateImpressionEvent(Config, + Config.GetExperimentFromKey("test_experiment"), "77210100090", TestUserId, + userAttributes); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -225,88 +238,93 @@ public void TestCreateImpressionEventWithTypedAttributes() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "7722370027" } - } + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", "323434545" }, - {"key", "boolean_key" }, - {"type", "custom" }, - {"value", true} + { "entity_id", "323434545" }, + { "key", "boolean_key" }, + { "type", "custom" }, + { "value", true }, }, new Dictionary { - {"entity_id", "616727838" }, - {"key", "integer_key" }, - {"type", "custom" }, - {"value", 15} + { "entity_id", "616727838" }, + { "key", "integer_key" }, + { "type", "custom" }, + { "value", 15 }, }, new Dictionary { - {"entity_id", "808797686" }, - {"key", "double_key" }, - {"type", "custom" }, - {"value", 3.14} + { "entity_id", "808797686" }, + { "key", "double_key" }, + { "type", "custom" }, + { "value", 3.14 }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -314,18 +332,20 @@ public void TestCreateImpressionEventWithTypedAttributes() "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { - {"device_type", "iPhone" }, - {"boolean_key", true }, - {"integer_key", 15 }, - {"double_key", 3.14 } + { "device_type", "iPhone" }, + { "boolean_key", true }, + { "integer_key", 15 }, + { "double_key", 3.14 }, }; - var logEvent = EventBuilder.CreateImpressionEvent(Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, userAttributes); + var logEvent = EventBuilder.CreateImpressionEvent(Config, + Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, + userAttributes); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); @@ -339,81 +359,86 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayload() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "7722370027" } - } + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", "323434545" }, - {"key", "boolean_key" }, - {"type", "custom" }, - {"value", true} + { "entity_id", "323434545" }, + { "key", "boolean_key" }, + { "type", "custom" }, + { "value", true }, }, new Dictionary { - {"entity_id", "808797686" }, - {"key", "double_key" }, - {"type", "custom" }, - {"value", 3.14} + { "entity_id", "808797686" }, + { "key", "double_key" }, + { "type", "custom" }, + { "value", 3.14 }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -421,7 +446,7 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayload() "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes @@ -439,7 +464,9 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayload() { "invalid_num_value", Math.Pow(2, 53) + 2 }, }; - var logEvent = EventBuilder.CreateImpressionEvent(Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, userAttributes); + var logEvent = EventBuilder.CreateImpressionEvent(Config, + Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, + userAttributes); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); @@ -453,50 +480,54 @@ public void TestCreateConversionEventNoAttributesNoValue() var payloadParams = new Dictionary { - {"visitors", new object[] + { + "visitors", new object[] { new Dictionary { - {"snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - {"events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063"}, - {"timestamp", timeStamp}, - {"uuid", guid}, - {"key", "purchase"}, - } + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, } - } - } + }, + }, } }, - {"visitor_id", TestUserId }, - {"attributes", new object[] + { "visitor_id", TestUserId }, + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } - } - } + }, + }, } }, - {"project_id", "7720880029"}, - {"enrich_decisions", true} , - {"account_id", "1592310167"}, - {"client_name", "csharp-sdk"}, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -505,14 +536,15 @@ public void TestCreateConversionEventNoAttributesNoValue() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, null, null); + var logEvent = + EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, null, null); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -527,57 +559,61 @@ public void TestCreateConversionEventWithAttributesNoValue() var payloadParams = new Dictionary { - {"visitors", new object[] + { + "visitors", new object[] { new Dictionary { - {"snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - {"events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063"}, - {"timestamp", timeStamp}, - {"uuid", guid}, - {"key", "purchase"}, - } + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, } - } - } + }, + }, } }, - {"visitor_id", TestUserId }, - {"attributes", new object[] + { "visitor_id", TestUserId }, + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } - } - } + }, + }, } }, - {"project_id", "7720880029"}, - {"account_id", "1592310167"}, - {"enrich_decisions", true}, - {"client_name", "csharp-sdk"}, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -586,19 +622,20 @@ public void TestCreateConversionEventWithAttributesNoValue() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { { "device_type", "iPhone" }, - { "company", "Optimizely" } + { "company", "Optimizely" }, }; var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, userAttributes, null); + var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, + userAttributes, null); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -613,57 +650,62 @@ public void TestCreateConversionEventNoAttributesWithValue() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 42 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 42 }, + { + "tags", new Dictionary { - {"revenue", 42 } + { "revenue", 42 }, } - } - } + }, + }, } - } - } + }, + }, } }, - { "attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true}, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -672,20 +714,20 @@ public void TestCreateConversionEventNoAttributesWithValue() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, null, new EventTags - { - {"revenue", 42 } - }); + { + { "revenue", 42 }, + }); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -700,65 +742,70 @@ public void TestCreateConversionEventWithAttributesWithValue() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 42 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 42 }, + { + "tags", new Dictionary { - {"revenue", 42}, - {"non-revenue", "definitely"} + { "revenue", 42 }, + { "non-revenue", "definitely" }, } - } - } + }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -767,25 +814,26 @@ public void TestCreateConversionEventWithAttributesWithValue() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { - { "device_type", "iPhone"}, - {"company", "Optimizely" } + { "device_type", "iPhone" }, + { "company", "Optimizely" }, }; var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, userAttributes, + var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, + userAttributes, new EventTags { - {"revenue", 42 }, - {"non-revenue", "definitely" } + { "revenue", 42 }, + { "non-revenue", "definitely" }, }); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -801,58 +849,63 @@ public void TestCreateConversionEventNoAttributesWithInvalidValue() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 42 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 42 }, + { + "tags", new Dictionary { - {"revenue", "42" }, - {"non-revenue", "definitely"} + { "revenue", "42" }, + { "non-revenue", "definitely" }, } - } - } + }, + }, } - } - } + }, + }, } }, { "visitor_id", TestUserId }, - { "attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } - } - } + }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -861,19 +914,19 @@ public void TestCreateConversionEventNoAttributesWithInvalidValue() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, null, new EventTags { - {"revenue", "42" }, - {"non-revenue", "definitely" } + { "revenue", "42" }, + { "non-revenue", "definitely" }, }); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -889,59 +942,64 @@ public void TestConversionEventWithNumericTag() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 42 }, - {"value", 400.0 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 42 }, + { "value", 400.0 }, + { + "tags", new Dictionary { - {"revenue", 42 }, - {"value", 400 } + { "revenue", 42 }, + { "value", 400 }, } - } - } + }, + }, } - } - } + }, + }, } }, - { "attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -950,20 +1008,20 @@ public void TestConversionEventWithNumericTag() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, null, new EventTags - { - {"revenue", 42 }, - {"value", 400 } - }); + { + { "revenue", 42 }, + { "value", 400 }, + }); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -977,59 +1035,64 @@ public void TestConversionEventWithFalsyNumericAndRevenueValues() var timeStamp = TestData.SecondsSince1970(); var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 0 }, - {"value", 0.0 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 0 }, + { "value", 0.0 }, + { + "tags", new Dictionary { - {"revenue", 0 }, - {"value", 0.0 } + { "revenue", 0 }, + { "value", 0.0 }, } - } - } + }, + }, } - } - } + }, + }, } }, - { "attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1038,20 +1101,20 @@ public void TestConversionEventWithFalsyNumericAndRevenueValues() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, null, new EventTags - { - {"revenue", 0 }, - {"value", 0.0 } - }); + { + { "revenue", 0 }, + { "value", 0.0 }, + }); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -1065,59 +1128,64 @@ public void TestConversionEventWithNumericValue1() var timeStamp = TestData.SecondsSince1970(); var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 10 }, - {"value", 1.0 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 10 }, + { "value", 1.0 }, + { + "tags", new Dictionary { - {"revenue", 10 }, - {"value", 1.0 } + { "revenue", 10 }, + { "value", 1.0 }, } - } - } + }, + }, } - } - } + }, + }, } }, - { "attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1126,25 +1194,26 @@ public void TestConversionEventWithNumericValue1() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, null, new EventTags - { - {"revenue", 10 }, - {"value", 1.0 } - }); + { + { "revenue", 10 }, + { "value", 1.0 }, + }); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } + [Test] public void TestConversionEventWithRevenueValue1() { @@ -1152,59 +1221,64 @@ public void TestConversionEventWithRevenueValue1() var timeStamp = TestData.SecondsSince1970(); var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 1 }, - {"value", 10.0 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 1 }, + { "value", 10.0 }, + { + "tags", new Dictionary { - {"revenue", 1 }, - {"value", 10.0 } + { "revenue", 1 }, + { "value", 10.0 }, } - } - } + }, + }, } - } - } + }, + }, } }, - { "attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1213,20 +1287,20 @@ public void TestConversionEventWithRevenueValue1() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, null, new EventTags - { - {"revenue", 1 }, - {"value", 10.0 } - }); + { + { "revenue", 1 }, + { "value", 10.0 }, + }); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -1242,83 +1316,88 @@ public void TestCreateConversionEventWithBucketingIDAttribute() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - } + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, - {"key", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, - {"type", "custom" }, - {"value", "variation"} + { "entity_id", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, + { "key", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, + { "type", "custom" }, + { "value", "variation" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", - payloadParams, - "POST", - new Dictionary - { - { "Content-Type", "application/json"} - }); + "https://logx.optimizely.com/v1/events", + payloadParams, + "POST", + new Dictionary + { + { "Content-Type", "application/json" }, + }); var userAttributes = new UserAttributes { - { "device_type", "iPhone"}, - {"company", "Optimizely" }, - {ControlAttributes.BUCKETING_ID_ATTRIBUTE, "variation" } + { "device_type", "iPhone" }, + { "company", "Optimizely" }, + { ControlAttributes.BUCKETING_ID_ATTRIBUTE, "variation" }, }; - var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, userAttributes, null); + var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, + userAttributes, null); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -1333,74 +1412,79 @@ public void TestCreateImpressionEventWithBucketingIDAttribute() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "7722370027" } - } + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, - {"key", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, - {"type", "custom" }, - {"value", "variation"} + { "entity_id", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, + { "key", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, + { "type", "custom" }, + { "value", "variation" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -1408,17 +1492,19 @@ public void TestCreateImpressionEventWithBucketingIDAttribute() "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { { "device_type", "iPhone" }, { "company", "Optimizely" }, - {ControlAttributes.BUCKETING_ID_ATTRIBUTE, "variation" } + { ControlAttributes.BUCKETING_ID_ATTRIBUTE, "variation" }, }; - var logEvent = EventBuilder.CreateImpressionEvent(Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, userAttributes); + var logEvent = EventBuilder.CreateImpressionEvent(Config, + Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, + userAttributes); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -1433,67 +1519,72 @@ public void TestCreateImpressionEventWhenBotFilteringIsProvidedInDatafile() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "7722370027" } - } + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"key", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"type", "custom" }, - {"value", "chrome"} + { "entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "key", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "type", "custom" }, + { "value", "chrome" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -1501,19 +1592,20 @@ public void TestCreateImpressionEventWhenBotFilteringIsProvidedInDatafile() "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { - {ControlAttributes.USER_AGENT_ATTRIBUTE, "chrome" } + { ControlAttributes.USER_AGENT_ATTRIBUTE, "chrome" }, }; var botFilteringEnabledConfig = Config; botFilteringEnabledConfig.BotFiltering = true; var experiment = botFilteringEnabledConfig.GetExperimentFromKey("test_experiment"); - var logEvent = EventBuilder.CreateImpressionEvent(botFilteringEnabledConfig, experiment, "7722370027", TestUserId, userAttributes); + var logEvent = EventBuilder.CreateImpressionEvent(botFilteringEnabledConfig, experiment, + "7722370027", TestUserId, userAttributes); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); @@ -1527,60 +1619,65 @@ public void TestCreateImpressionEventWhenBotFilteringIsNotProvidedInDatafile() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "7722370027" } - } + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"key", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"type", "custom" }, - {"value", "chrome"} - } + { "entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "key", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "type", "custom" }, + { "value", "chrome" }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -1588,19 +1685,20 @@ public void TestCreateImpressionEventWhenBotFilteringIsNotProvidedInDatafile() "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { - {ControlAttributes.USER_AGENT_ATTRIBUTE, "chrome" } + { ControlAttributes.USER_AGENT_ATTRIBUTE, "chrome" }, }; var botFilteringDisabledConfig = Config; botFilteringDisabledConfig.BotFiltering = null; var experiment = botFilteringDisabledConfig.GetExperimentFromKey("test_experiment"); - var logEvent = EventBuilder.CreateImpressionEvent(botFilteringDisabledConfig, experiment, "7722370027", TestUserId, userAttributes); + var logEvent = EventBuilder.CreateImpressionEvent(botFilteringDisabledConfig, + experiment, "7722370027", TestUserId, userAttributes); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); @@ -1614,57 +1712,61 @@ public void TestCreateConversionEventWhenBotFilteringIsProvidedInDatafile() var payloadParams = new Dictionary { - {"visitors", new object[] + { + "visitors", new object[] { new Dictionary { - {"snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - {"events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063"}, - {"timestamp", timeStamp}, - {"uuid", guid}, - {"key", "purchase"}, - } + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, } - } - } + }, + }, } }, - {"visitor_id", TestUserId }, - {"attributes", new object[] + { "visitor_id", TestUserId }, + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"key", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"type", "custom" }, - {"value", "safari"} + { "entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "key", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "type", "custom" }, + { "value", "safari" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } - } - } + }, + }, } }, - {"project_id", "7720880029"}, - {"account_id", "1592310167"}, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk"}, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1673,21 +1775,22 @@ public void TestCreateConversionEventWhenBotFilteringIsProvidedInDatafile() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { - {ControlAttributes.USER_AGENT_ATTRIBUTE, "safari" } + { ControlAttributes.USER_AGENT_ATTRIBUTE, "safari" }, }; var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; var botFilteringEnabledConfig = Config; botFilteringEnabledConfig.BotFiltering = true; - var logEvent = EventBuilder.CreateConversionEvent(botFilteringEnabledConfig, "purchase", TestUserId, userAttributes, null); + var logEvent = EventBuilder.CreateConversionEvent(botFilteringEnabledConfig, "purchase", + TestUserId, userAttributes, null); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -1702,50 +1805,54 @@ public void TestCreateConversionEventWhenBotFilteringIsNotProvidedInDatafile() var payloadParams = new Dictionary { - {"visitors", new object[] + { + "visitors", new object[] { new Dictionary { - {"snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - {"events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063"}, - {"timestamp", timeStamp}, - {"uuid", guid}, - {"key", "purchase"}, - } + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, } - } - } + }, + }, } }, - {"visitor_id", TestUserId }, - {"attributes", new object[] + { "visitor_id", TestUserId }, + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"key", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"type", "custom" }, - {"value", "safari"} - } + { "entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "key", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "type", "custom" }, + { "value", "safari" }, + }, } - } - } + }, + }, } }, - {"project_id", "7720880029"}, - {"enrich_decisions", true}, - {"account_id", "1592310167"}, - {"client_name", "csharp-sdk"}, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1754,21 +1861,22 @@ public void TestCreateConversionEventWhenBotFilteringIsNotProvidedInDatafile() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { - {ControlAttributes.USER_AGENT_ATTRIBUTE, "safari" } + { ControlAttributes.USER_AGENT_ATTRIBUTE, "safari" }, }; var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; var botFilteringDisabledConfig = Config; botFilteringDisabledConfig.BotFiltering = null; - var logEvent = EventBuilder.CreateConversionEvent(botFilteringDisabledConfig, "purchase", TestUserId, userAttributes, null); + var logEvent = EventBuilder.CreateConversionEvent(botFilteringDisabledConfig, + "purchase", TestUserId, userAttributes, null); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -1780,39 +1888,45 @@ public void TestCreateConversionEventWhenEventUsedInMultipleExp() { var guid = Guid.NewGuid(); var timeStamp = TestData.SecondsSince1970(); - - var eventInMultiExperimentConfig = DatafileProjectConfig.Create(TestData.SimpleABExperimentsDatafile, new NoOpLogger(), new ErrorHandler.NoOpErrorHandler()); + + var eventInMultiExperimentConfig = DatafileProjectConfig.Create( + TestData.SimpleABExperimentsDatafile, new NoOpLogger(), + new ErrorHandler.NoOpErrorHandler()); var experimentIdVariationMap = new Dictionary { { - "111127", new Variation{Id="111129", Key="variation"} + "111127", new Variation { Id = "111129", Key = "variation" } }, { - "111130", new Variation{Id="111131", Key="variation"} - } + "111130", new Variation { Id = "111131", Key = "variation" } + }, }; - var logEvent = EventBuilder.CreateConversionEvent(eventInMultiExperimentConfig, "event_with_multiple_running_experiments", "test_user", - new UserAttributes { - {"test_attribute", "test_value"} - }, - new EventTags { - {"revenue", 4200}, - {"value", 1.234}, - {"non-revenue", "abc"} - }); - + var logEvent = EventBuilder.CreateConversionEvent(eventInMultiExperimentConfig, + "event_with_multiple_running_experiments", "test_user", + new UserAttributes + { + { "test_attribute", "test_value" }, + }, + new EventTags + { + { "revenue", 4200 }, + { "value", 1.234 }, + { "non-revenue", "abc" }, + }); + var payloadParams = new Dictionary + { + { "client_version", Optimizely.SDK_VERSION }, + { "project_id", "111001" }, + { "enrich_decisions", true }, + { "account_id", "12001" }, + { "client_name", "csharp-sdk" }, + { "anonymize_ip", false }, + { "revision", eventInMultiExperimentConfig.Revision }, { - {"client_version", Optimizely.SDK_VERSION}, - {"project_id", "111001"}, - {"enrich_decisions", true}, - {"account_id", "12001"}, - {"client_name", "csharp-sdk"}, - {"anonymize_ip", false}, - {"revision", eventInMultiExperimentConfig.Revision}, - {"visitors", new object[] + "visitors", new object[] { //visitors[0] new Dictionary @@ -1823,17 +1937,18 @@ public void TestCreateConversionEventWhenEventUsedInMultipleExp() { new Dictionary { - {"entity_id", "111094"}, - {"type", "custom"}, - {"value", "test_value"}, - {"key", "test_attribute"} - } + { "entity_id", "111094" }, + { "type", "custom" }, + { "value", "test_value" }, + { "key", "test_attribute" }, + }, } }, //visitors[0].visitor_id - {"visitor_id", "test_user"}, + { "visitor_id", "test_user" }, //visitors[0].snapshots - {"snapshots", new object[] + { + "snapshots", new object[] { //snapshots[0] new Dictionary @@ -1844,34 +1959,32 @@ public void TestCreateConversionEventWhenEventUsedInMultipleExp() { new Dictionary { - {"uuid", guid}, - {"timestamp", timeStamp}, - {"revenue", 4200}, - {"value", 1.234}, - {"key", "event_with_multiple_running_experiments"}, - {"entity_id", "111095"}, + { "uuid", guid }, + { "timestamp", timeStamp }, + { "revenue", 4200 }, + { "value", 1.234 }, + { + "key", + "event_with_multiple_running_experiments" + }, + { "entity_id", "111095" }, { "tags", new Dictionary { - {"non-revenue", "abc"}, - {"revenue", 4200}, - {"value", 1.234}, + { "non-revenue", "abc" }, + { "revenue", 4200 }, + { "value", 1.234 }, } - } - - } + }, + }, } - } - - } - + }, + }, } - } - - } + }, + }, } - - } + }, }; @@ -1881,7 +1994,7 @@ public void TestCreateConversionEventWhenEventUsedInMultipleExp() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); @@ -1897,71 +2010,75 @@ public void TestCreateConversionEventRemovesInvalidAttributesFromPayload() var payloadParams = new Dictionary { - {"visitors", new object[] + { + "visitors", new object[] { new Dictionary { - {"snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - {"events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063"}, - {"timestamp", timeStamp}, - {"uuid", guid}, - {"key", "purchase"}, - } + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, } - } - } + }, + }, } }, - {"visitor_id", TestUserId }, - {"attributes", new object[] + { "visitor_id", TestUserId }, + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", "323434545" }, - {"key", "boolean_key" }, - {"type", "custom" }, - {"value", true} + { "entity_id", "323434545" }, + { "key", "boolean_key" }, + { "type", "custom" }, + { "value", true }, }, new Dictionary { - {"entity_id", "808797686" }, - {"key", "double_key" }, - {"type", "custom" }, - {"value", 3.14} + { "entity_id", "808797686" }, + { "key", "double_key" }, + { "type", "custom" }, + { "value", 3.14 }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } - } - } + }, + }, } }, - {"project_id", "7720880029"}, - {"account_id", "1592310167"}, - {"enrich_decisions", true}, - {"client_name", "csharp-sdk"}, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1970,7 +2087,7 @@ public void TestCreateConversionEventRemovesInvalidAttributesFromPayload() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes @@ -1990,10 +2107,11 @@ public void TestCreateConversionEventRemovesInvalidAttributesFromPayload() var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - - var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, userAttributes, null); + + var logEvent = EventBuilder.CreateConversionEvent(Config, "purchase", TestUserId, + userAttributes, null); TestData.ChangeGUIDAndTimeStamp(logEvent.Params, timeStamp, guid); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); diff --git a/OptimizelySDK.Tests/EventTests/EventEntitiesTest.cs b/OptimizelySDK.Tests/EventTests/EventEntitiesTest.cs index 10e5c3e41..d91f40f2c 100644 --- a/OptimizelySDK.Tests/EventTests/EventEntitiesTest.cs +++ b/OptimizelySDK.Tests/EventTests/EventEntitiesTest.cs @@ -39,104 +39,114 @@ public void TestImpressionEventEqualsSerializedPayload() var expectedPayload = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "77210100090" } - } + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "77210100090" }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", userId } - } + { "visitor_id", userId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; - EventBatch.Builder builder = new EventBatch.Builder(); - builder.WithAccountId("1592310167") - .WithProjectID("7720880029") - .WithClientVersion(Optimizely.SDK_VERSION) - .WithRevision("15") - .WithClientName("csharp-sdk") - .WithAnonymizeIP(false) - .WithEnrichDecisions(true); + var builder = new EventBatch.Builder(); + builder.WithAccountId("1592310167"). + WithProjectID("7720880029"). + WithClientVersion(Optimizely.SDK_VERSION). + WithRevision("15"). + WithClientName("csharp-sdk"). + WithAnonymizeIP(false). + WithEnrichDecisions(true); - var visitorAttribute1 = new VisitorAttribute(entityId: "7723280020", type: "custom", value: "iPhone", key: "device_type"); - var visitorAttribute2 = new VisitorAttribute(entityId: ControlAttributes.BOT_FILTERING_ATTRIBUTE, type: "custom", value: true, key: ControlAttributes.BOT_FILTERING_ATTRIBUTE); - var snapshotEvent = new SnapshotEvent.Builder() - .WithUUID(guid.ToString()) - .WithEntityId("7719770039") - .WithKey("campaign_activated") - .WithValue(null) - .WithRevenue(null) - .WithTimeStamp(timeStamp) - .WithEventTags(null) - .Build(); + var visitorAttribute1 = new VisitorAttribute("7723280020", type: "custom", + value: "iPhone", key: "device_type"); + var visitorAttribute2 = new VisitorAttribute(ControlAttributes.BOT_FILTERING_ATTRIBUTE, + type: "custom", value: true, key: ControlAttributes.BOT_FILTERING_ATTRIBUTE); + var snapshotEvent = new SnapshotEvent.Builder().WithUUID(guid.ToString()). + WithEntityId("7719770039"). + WithKey("campaign_activated"). + WithValue(null). + WithRevenue(null). + WithTimeStamp(timeStamp). + WithEventTags(null). + Build(); var metadata = new DecisionMetadata("experiment", "experiment_key", "7716830082"); var decision = new Decision("7719770039", "7716830082", "77210100090"); - var snapshot = new Snapshot(events: new SnapshotEvent[] { snapshotEvent }, decisions: new Decision[] { decision }); + var snapshot = new Snapshot(new SnapshotEvent[] { snapshotEvent }, + new Decision[] { decision }); var visitor = new Visitor( - snapshots: new Snapshot[] { - snapshot + new Snapshot[] + { + snapshot, + }, + new VisitorAttribute[] + { + visitorAttribute1, visitorAttribute2, }, - attributes: new VisitorAttribute[]{ - visitorAttribute1, visitorAttribute2}, - visitorId: "test_user"); + "test_user"); builder.WithVisitors(new Visitor[] { visitor }); - EventBatch eventBatch = builder.Build(); + var eventBatch = builder.Build(); // Single Conversion Event TestData.CompareObjects(expectedPayload, eventBatch); } @@ -144,20 +154,20 @@ public void TestImpressionEventEqualsSerializedPayload() [Test] public void TestConversionEventEqualsSerializedPayload() { - var guid = Guid.NewGuid(); var timeStamp = TestData.SecondsSince1970(); var expectdPayload = new Dictionary + { + { "client_version", Optimizely.SDK_VERSION }, + { "project_id", "111001" }, + { "enrich_decisions", true }, + { "account_id", "12001" }, + { "client_name", "csharp-sdk" }, + { "anonymize_ip", false }, + { "revision", "2" }, { - {"client_version", Optimizely.SDK_VERSION}, - {"project_id", "111001"}, - {"enrich_decisions", true}, - {"account_id", "12001"}, - {"client_name", "csharp-sdk"}, - {"anonymize_ip", false}, - {"revision", "2"}, - {"visitors", new object[] + "visitors", new object[] { new Dictionary { @@ -167,17 +177,18 @@ public void TestConversionEventEqualsSerializedPayload() { new Dictionary { - {"entity_id", "111094"}, - {"type", "custom"}, - {"value", "test_value"}, - {"key", "test_attribute"} - } + { "entity_id", "111094" }, + { "type", "custom" }, + { "value", "test_value" }, + { "key", "test_attribute" }, + }, } }, //visitors[0].visitor_id - {"visitor_id", "test_user"}, + { "visitor_id", "test_user" }, //visitors[0].snapshots - {"snapshots", new object[] + { + "snapshots", new object[] { //snapshots[0] new Dictionary @@ -188,79 +199,78 @@ public void TestConversionEventEqualsSerializedPayload() { new Dictionary { - {"uuid", guid}, - {"timestamp", timeStamp}, - {"revenue", 4200}, - {"value", 1.234}, - {"key", "event_with_multiple_running_experiments"}, - {"entity_id", "111095"}, + { "uuid", guid }, + { "timestamp", timeStamp }, + { "revenue", 4200 }, + { "value", 1.234 }, + { + "key", + "event_with_multiple_running_experiments" + }, + { "entity_id", "111095" }, { "tags", new Dictionary { - {"non-revenue", "abc"}, - {"revenue", 4200}, - {"value", 1.234}, + { "non-revenue", "abc" }, + { "revenue", 4200 }, + { "value", 1.234 }, } - } - - } + }, + }, } - } - - } - + }, + }, } - } - - } + }, + }, } - - } + }, }; - EventBatch.Builder builder = new EventBatch.Builder(); - builder.WithAccountId("12001") - .WithProjectID("111001") - .WithClientVersion(Optimizely.SDK_VERSION) - .WithRevision("2") - .WithClientName("csharp-sdk") - .WithAnonymizeIP(false) - .WithEnrichDecisions(true); - - var visitorAttribute = new VisitorAttribute(entityId: "111094", type: "custom", value: "test_value", key: "test_attribute"); + var builder = new EventBatch.Builder(); + builder.WithAccountId("12001"). + WithProjectID("111001"). + WithClientVersion(Optimizely.SDK_VERSION). + WithRevision("2"). + WithClientName("csharp-sdk"). + WithAnonymizeIP(false). + WithEnrichDecisions(true); - var snapshotEvent = new SnapshotEvent.Builder() - .WithUUID(guid.ToString()) - .WithEntityId("111095") - .WithKey("event_with_multiple_running_experiments") - .WithValue((long?)1.234) - .WithRevenue(4200) - .WithTimeStamp(timeStamp) - .WithEventTags(new EventTags + var visitorAttribute = new VisitorAttribute("111094", type: "custom", + value: "test_value", key: "test_attribute"); + + var snapshotEvent = new SnapshotEvent.Builder().WithUUID(guid.ToString()). + WithEntityId("111095"). + WithKey("event_with_multiple_running_experiments"). + WithValue((long?)1.234). + WithRevenue(4200). + WithTimeStamp(timeStamp). + WithEventTags(new EventTags { - {"non-revenue", "abc"}, - {"revenue", 4200}, - {"value", 1.234} - }) - .Build(); + { "non-revenue", "abc" }, + { "revenue", 4200 }, + { "value", 1.234 }, + }). + Build(); - var snapshot = new Snapshot(events: new SnapshotEvent[] { snapshotEvent }); + var snapshot = new Snapshot(new SnapshotEvent[] { snapshotEvent }); var visitor = new Visitor( - snapshots: new Snapshot[] { - snapshot + new Snapshot[] + { + snapshot, }, - attributes: new VisitorAttribute[]{ - visitorAttribute}, - visitorId: "test_user"); + new VisitorAttribute[] + { + visitorAttribute, + }, + "test_user"); builder.WithVisitors(new Visitor[] { visitor }); - EventBatch eventBatch = builder.Build(); + var eventBatch = builder.Build(); // Single Conversion Event TestData.CompareObjects(expectdPayload, eventBatch); } - - } } diff --git a/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs b/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs index b17cff2c4..3199a8ae3 100644 --- a/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs +++ b/OptimizelySDK.Tests/EventTests/EventFactoryTest.cs @@ -31,7 +31,6 @@ namespace OptimizelySDK.Tests.EventTests [TestFixture] public class EventFactoryTest { - private string TestUserId = string.Empty; private ProjectConfig Config; private ILogger Logger; @@ -41,7 +40,8 @@ public void Setup() { TestUserId = "testUserId"; var logger = new NoOpLogger(); - Config = DatafileProjectConfig.Create(TestData.Datafile, logger, new ErrorHandler.NoOpErrorHandler()); + Config = DatafileProjectConfig.Create(TestData.Datafile, logger, + new NoOpErrorHandler()); } [Test] @@ -49,17 +49,20 @@ public void TestCreateImpressionEventReturnsNullWhenSendFlagDecisionsIsFalseAndI { Config.SendFlagDecisions = false; var impressionEvent = UserEventFactory.CreateImpressionEvent( - Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, null, "test_feature", "rollout"); + Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, + null, "test_feature", "rollout"); Assert.IsNull(impressionEvent); } [Test] - public void TestCreateImpressionEventReturnsNullWhenSendFlagDecisionsIsFalseAndVariationIsNull() + public void + TestCreateImpressionEventReturnsNullWhenSendFlagDecisionsIsFalseAndVariationIsNull() { Config.SendFlagDecisions = false; Variation variation = null; var impressionEvent = UserEventFactory.CreateImpressionEvent( - Config, Config.GetExperimentFromKey("test_experiment"), variation, TestUserId, null, "test_experiment", "experiment"); + Config, Config.GetExperimentFromKey("test_experiment"), variation, TestUserId, null, + "test_experiment", "experiment"); Assert.IsNull(impressionEvent); } @@ -69,79 +72,95 @@ public void TestCreateImpressionEventNoAttributes() var guid = Guid.NewGuid(); var timeStamp = TestData.SecondsSince1970(); - var payloadParams = new Dictionary { + var payloadParams = new Dictionary + { { - "visitors", new object[] { - new Dictionary() { + "visitors", new object[] + { + new Dictionary() + { + { + "snapshots", new object[] { - "snapshots", new object[] { - new Dictionary { + new Dictionary + { + { + "decisions", new object[] { - "decisions", new object[] { - new Dictionary { - { "campaign_id", "7719770039" }, - { "experiment_id", "7716830082" }, - { "variation_id", "7722370027" }, - { "metadata", - new Dictionary { + new Dictionary + { + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + { + "metadata", + new Dictionary + { { "rule_type", "experiment" }, { "rule_key", "test_experiment" }, { "flag_key", "test_experiment" }, { "variation_key", "control" }, - { "enabled", false } - } } - } - } - }, + { "enabled", false }, + } + }, + }, + } + }, + { + "events", new object[] { - "events", new object[] { - new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } - } + new Dictionary + { + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } - }, + }, + }, + } + }, + { + "attributes", new object[] { - "attributes", new object[] { - new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } - } - }, - {"visitor_id", TestUserId} - } - } - }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} - }; + new Dictionary + { + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, + } + }, + { "visitor_id", TestUserId }, + }, + } + }, + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, + }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", payloadParams, "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var impressionEvent = UserEventFactory.CreateImpressionEvent( - Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, null, "test_experiment", "experiment"); + Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, + null, "test_experiment", "experiment"); var logEvent = EventFactory.CreateLogEvent(impressionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, Guid.Parse(impressionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, + Guid.Parse(impressionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); } @@ -152,73 +171,84 @@ public void TestCreateImpressionEventWithAttributes() var guid = Guid.NewGuid(); var timeStamp = TestData.SecondsSince1970(); var variationId = "7722370027"; - var payloadParams = new Dictionary { + var payloadParams = new Dictionary + { { - "visitors", new object[] { - new Dictionary() { + "visitors", new object[] + { + new Dictionary() + { { - "snapshots", new object[] { - new Dictionary { + "snapshots", new object[] + { + new Dictionary + { { - "decisions", new object[] { - new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "7722370027" }, - { "metadata", new Dictionary { + "decisions", new object[] + { + new Dictionary + { + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + { + "metadata", new Dictionary + { { "rule_type", "experiment" }, { "rule_key", "test_experiment" }, { "flag_key", "test_experiment" }, { "variation_key", "control" }, - {"enabled", false } - + { "enabled", false }, } - } - } + }, + }, } }, { - "events", new object[] { - new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + "events", new object[] + { + new Dictionary + { + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, { - "attributes", new object[] { + "attributes", new object[] + { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -226,20 +256,22 @@ public void TestCreateImpressionEventWithAttributes() "POST", new Dictionary { - { "Content-Type", "application/json" } - + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { { "device_type", "iPhone" }, - { "company", "Optimizely" } + { "company", "Optimizely" }, }; // - var impressionEvent = UserEventFactory.CreateImpressionEvent(Config, Config.GetExperimentFromKey("test_experiment"), variationId, TestUserId, userAttributes, "test_experiment", "experiment"); + var impressionEvent = UserEventFactory.CreateImpressionEvent(Config, + Config.GetExperimentFromKey("test_experiment"), variationId, TestUserId, + userAttributes, "test_experiment", "experiment"); var logEvent = EventFactory.CreateLogEvent(impressionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, Guid.Parse(impressionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, + Guid.Parse(impressionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); } @@ -252,96 +284,103 @@ public void TestCreateImpressionEventWithTypedAttributes() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "7722370027" }, - { "metadata", new Dictionary { + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + { + "metadata", new Dictionary + { { "rule_type", "experiment" }, { "rule_key", "test_experiment" }, { "flag_key", "test_experiment" }, { "variation_key", "control" }, - {"enabled", false } + { "enabled", false }, } - } - } + }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", "323434545" }, - {"key", "boolean_key" }, - {"type", "custom" }, - {"value", true} + { "entity_id", "323434545" }, + { "key", "boolean_key" }, + { "type", "custom" }, + { "value", true }, }, new Dictionary { - {"entity_id", "616727838" }, - {"key", "integer_key" }, - {"type", "custom" }, - {"value", 15} + { "entity_id", "616727838" }, + { "key", "integer_key" }, + { "type", "custom" }, + { "value", 15 }, }, new Dictionary { - {"entity_id", "808797686" }, - {"key", "double_key" }, - {"type", "custom" }, - {"value", 3.14} + { "entity_id", "808797686" }, + { "key", "double_key" }, + { "type", "custom" }, + { "value", 3.14 }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -349,20 +388,23 @@ public void TestCreateImpressionEventWithTypedAttributes() "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { - {"device_type", "iPhone" }, - {"boolean_key", true }, - {"integer_key", 15 }, - {"double_key", 3.14 } + { "device_type", "iPhone" }, + { "boolean_key", true }, + { "integer_key", 15 }, + { "double_key", 3.14 }, }; - var impressionEvent = UserEventFactory.CreateImpressionEvent(Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, userAttributes, "test_experiment", "experiment"); + var impressionEvent = UserEventFactory.CreateImpressionEvent(Config, + Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, + userAttributes, "test_experiment", "experiment"); var logEvent = EventFactory.CreateLogEvent(impressionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, Guid.Parse(impressionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, + Guid.Parse(impressionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); } @@ -375,89 +417,96 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayload() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "7722370027" }, - { "metadata", new Dictionary { - { "rule_type", "experiment" }, - { "rule_key", "test_experiment" }, - { "flag_key", "test_experiment" }, - { "variation_key", "control" }, - {"enabled", false } + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + { + "metadata", new Dictionary + { + { "rule_type", "experiment" }, + { "rule_key", "test_experiment" }, + { "flag_key", "test_experiment" }, + { "variation_key", "control" }, + { "enabled", false }, } - } - } + }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", "323434545" }, - {"key", "boolean_key" }, - {"type", "custom" }, - {"value", true} + { "entity_id", "323434545" }, + { "key", "boolean_key" }, + { "type", "custom" }, + { "value", true }, }, new Dictionary { - {"entity_id", "808797686" }, - {"key", "double_key" }, - {"type", "custom" }, - {"value", 3.14} + { "entity_id", "808797686" }, + { "key", "double_key" }, + { "type", "custom" }, + { "value", 3.14 }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -465,7 +514,7 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayload() "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes @@ -482,10 +531,13 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayload() { "nan", double.NaN }, { "invalid_num_value", Math.Pow(2, 53) + 2 }, }; - var impressionEvent = UserEventFactory.CreateImpressionEvent(Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, userAttributes, "test_experiment", "experiment"); + var impressionEvent = UserEventFactory.CreateImpressionEvent(Config, + Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, + userAttributes, "test_experiment", "experiment"); var logEvent = EventFactory.CreateLogEvent(impressionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, Guid.Parse(impressionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, + Guid.Parse(impressionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); } @@ -498,89 +550,96 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayloadRollout( var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", null }, - {"experiment_id", string.Empty }, - {"variation_id", null }, - { "metadata", new Dictionary { + { "campaign_id", null }, + { "experiment_id", string.Empty }, + { "variation_id", null }, + { + "metadata", new Dictionary + { { "rule_type", "rollout" }, { "rule_key", string.Empty }, { "flag_key", "test_feature" }, { "variation_key", string.Empty }, - { "enabled", false } + { "enabled", false }, } - } - } + }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", null }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", null }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", "323434545" }, - {"key", "boolean_key" }, - {"type", "custom" }, - {"value", true} + { "entity_id", "323434545" }, + { "key", "boolean_key" }, + { "type", "custom" }, + { "value", true }, }, new Dictionary { - {"entity_id", "808797686" }, - {"key", "double_key" }, - {"type", "custom" }, - {"value", 3.14} + { "entity_id", "808797686" }, + { "key", "double_key" }, + { "type", "custom" }, + { "value", 3.14 }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -588,7 +647,7 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayloadRollout( "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes @@ -607,10 +666,12 @@ public void TestCreateImpressionEventRemovesInvalidAttributesFromPayloadRollout( }; Variation variation = null; - var impressionEvent = UserEventFactory.CreateImpressionEvent(Config, null, variation, TestUserId, userAttributes, "test_feature", "rollout"); + var impressionEvent = UserEventFactory.CreateImpressionEvent(Config, null, variation, + TestUserId, userAttributes, "test_feature", "rollout"); var logEvent = EventFactory.CreateLogEvent(impressionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, Guid.Parse(impressionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, + Guid.Parse(impressionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); } @@ -623,50 +684,54 @@ public void TestCreateConversionEventNoAttributesNoValue() var payloadParams = new Dictionary { - {"visitors", new object[] + { + "visitors", new object[] { new Dictionary { - {"snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - {"events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063"}, - {"timestamp", timeStamp}, - {"uuid", guid}, - {"key", "purchase"}, - } + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, } - } - } + }, + }, } }, - {"visitor_id", TestUserId }, - {"attributes", new object[] + { "visitor_id", TestUserId }, + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } - } - } + }, + }, } }, - {"project_id", "7720880029"}, - {"enrich_decisions", true} , - {"account_id", "1592310167"}, - {"client_name", "csharp-sdk"}, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -675,17 +740,19 @@ public void TestCreateConversionEventNoAttributesNoValue() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, null); + var conversionEvent = + UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, null); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } @@ -698,57 +765,61 @@ public void TestCreateConversionEventWithAttributesNoValue() var payloadParams = new Dictionary { - {"visitors", new object[] + { + "visitors", new object[] { new Dictionary { - {"snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - {"events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063"}, - {"timestamp", timeStamp}, - {"uuid", guid}, - {"key", "purchase"}, - } + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, } - } - } + }, + }, } }, - {"visitor_id", TestUserId }, - {"attributes", new object[] + { "visitor_id", TestUserId }, + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } - } - } + }, + }, } }, - {"project_id", "7720880029"}, - {"account_id", "1592310167"}, - {"enrich_decisions", true}, - {"client_name", "csharp-sdk"}, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -757,22 +828,25 @@ public void TestCreateConversionEventWithAttributesNoValue() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { { "device_type", "iPhone" }, - { "company", "Optimizely" } + { "company", "Optimizely" }, }; var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, userAttributes, null); + var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", + TestUserId, userAttributes, null); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); ; + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); + ; Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } @@ -785,57 +859,62 @@ public void TestCreateConversionEventNoAttributesWithValue() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 42 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 42 }, + { + "tags", new Dictionary { - {"revenue", 42 } + { "revenue", 42 }, } - } - } + }, + }, } - } - } + }, + }, } }, - { "attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true}, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -844,22 +923,24 @@ public void TestCreateConversionEventNoAttributesWithValue() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, + var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", + TestUserId, null, new EventTags - { - {"revenue", 42 } - }); + { + { "revenue", 42 }, + }); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } @@ -872,65 +953,70 @@ public void TestCreateConversionEventWithAttributesWithValue() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 42 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 42 }, + { + "tags", new Dictionary { - {"revenue", 42}, - {"non-revenue", "definitely"} + { "revenue", 42 }, + { "non-revenue", "definitely" }, } - } - } + }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -939,29 +1025,31 @@ public void TestCreateConversionEventWithAttributesWithValue() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { - { "device_type", "iPhone"}, - {"company", "Optimizely" } + { "device_type", "iPhone" }, + { "company", "Optimizely" }, }; var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, userAttributes, + var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", + TestUserId, userAttributes, new EventTags { - {"revenue", 42 }, - {"non-revenue", "definitely" } + { "revenue", 42 }, + { "non-revenue", "definitely" }, }); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } @@ -974,58 +1062,63 @@ public void TestCreateConversionEventNoAttributesWithInvalidValue() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 42 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 42 }, + { + "tags", new Dictionary { - {"revenue", "42" }, - {"non-revenue", "definitely"} + { "revenue", "42" }, + { "non-revenue", "definitely" }, } - } - } + }, + }, } - } - } + }, + }, } }, { "visitor_id", TestUserId }, - { "attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } - } - } + }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1034,22 +1127,24 @@ public void TestCreateConversionEventNoAttributesWithInvalidValue() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, + var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", + TestUserId, null, new EventTags { - {"revenue", "42" }, - {"non-revenue", "definitely" } + { "revenue", "42" }, + { "non-revenue", "definitely" }, }); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } @@ -1062,59 +1157,64 @@ public void TestConversionEventWithNumericTag() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 42 }, - {"value", 400.0 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 42 }, + { "value", 400.0 }, + { + "tags", new Dictionary { - {"revenue", 42 }, - {"value", 400 } + { "revenue", 42 }, + { "value", 400 }, } - } - } + }, + }, } - } - } + }, + }, } }, - { "attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1123,25 +1223,27 @@ public void TestConversionEventWithNumericTag() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, + var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", + TestUserId, null, new EventTags - { - {"revenue", 42 }, - {"value", 400 } - }); + { + { "revenue", 42 }, + { "value", 400 }, + }); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } @@ -1153,59 +1255,64 @@ public void TestConversionEventWithFalsyNumericAndRevenueValues() var timeStamp = TestData.SecondsSince1970(); var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 0 }, - {"value", 0.0 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 0 }, + { "value", 0.0 }, + { + "tags", new Dictionary { - {"revenue", 0 }, - {"value", 0.0 } + { "revenue", 0 }, + { "value", 0.0 }, } - } - } + }, + }, } - } - } + }, + }, } }, - { "attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1214,23 +1321,25 @@ public void TestConversionEventWithFalsyNumericAndRevenueValues() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, + var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", + TestUserId, null, new EventTags - { - {"revenue", 0 }, - {"value", 0.0 } - }); + { + { "revenue", 0 }, + { "value", 0.0 }, + }); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } @@ -1242,59 +1351,64 @@ public void TestConversionEventWithNumericValue1() var timeStamp = TestData.SecondsSince1970(); var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 10 }, - {"value", 1.0 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 10 }, + { "value", 1.0 }, + { + "tags", new Dictionary { - {"revenue", 10 }, - {"value", 1.0 } + { "revenue", 10 }, + { "value", 1.0 }, } - } - } + }, + }, } - } - } + }, + }, } }, - { "attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1303,22 +1417,24 @@ public void TestConversionEventWithNumericValue1() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, + var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", + TestUserId, null, new EventTags - { - {"revenue", 10 }, - {"value", 1.0 } - }); + { + { "revenue", 10 }, + { "value", 1.0 }, + }); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } @@ -1330,59 +1446,64 @@ public void TestConversionEventWithRevenueValue1() var timeStamp = TestData.SecondsSince1970(); var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - {"revenue", 1 }, - {"value", 10.0 }, - {"tags", + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + { "revenue", 1 }, + { "value", 10.0 }, + { + "tags", new Dictionary { - {"revenue", 1 }, - {"value", 10.0 } + { "revenue", 1 }, + { "value", 10.0 }, } - } - } + }, + }, } - } - } + }, + }, } }, - { "attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1391,23 +1512,25 @@ public void TestConversionEventWithRevenueValue1() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, null, + var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", + TestUserId, null, new EventTags - { - {"revenue", 1 }, - {"value", 10.0 } - }); + { + { "revenue", 1 }, + { "value", 10.0 }, + }); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } @@ -1421,86 +1544,92 @@ public void TestCreateConversionEventWithBucketingIDAttribute() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "purchase" }, - } + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, - {"key", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, - {"type", "custom" }, - {"value", "variation"} + { "entity_id", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, + { "key", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, + { "type", "custom" }, + { "value", "variation" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( - "https://logx.optimizely.com/v1/events", - payloadParams, - "POST", - new Dictionary - { - { "Content-Type", "application/json"} - }); + "https://logx.optimizely.com/v1/events", + payloadParams, + "POST", + new Dictionary + { + { "Content-Type", "application/json" }, + }); var userAttributes = new UserAttributes { - { "device_type", "iPhone"}, - {"company", "Optimizely" }, - {ControlAttributes.BUCKETING_ID_ATTRIBUTE, "variation" } + { "device_type", "iPhone" }, + { "company", "Optimizely" }, + { ControlAttributes.BUCKETING_ID_ATTRIBUTE, "variation" }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, userAttributes, null); + var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", + TestUserId, userAttributes, null); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } @@ -1513,82 +1642,89 @@ public void TestCreateImpressionEventWithBucketingIDAttribute() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "7722370027" }, - { "metadata", new Dictionary { + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + { + "metadata", new Dictionary + { { "rule_type", "experiment" }, { "rule_key", "test_experiment" }, { "flag_key", "test_experiment" }, { "variation_key", "control" }, - {"enabled", false } + { "enabled", false }, } - } - } + }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, - {"key", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, - {"type", "custom" }, - {"value", "variation"} + { "entity_id", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, + { "key", ControlAttributes.BUCKETING_ID_ATTRIBUTE }, + { "type", "custom" }, + { "value", "variation" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"enrich_decisions", true}, - {"account_id", "1592310167" }, - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -1596,19 +1732,22 @@ public void TestCreateImpressionEventWithBucketingIDAttribute() "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { { "device_type", "iPhone" }, { "company", "Optimizely" }, - {ControlAttributes.BUCKETING_ID_ATTRIBUTE, "variation" } + { ControlAttributes.BUCKETING_ID_ATTRIBUTE, "variation" }, }; - var impressionEvent = UserEventFactory.CreateImpressionEvent(Config, Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, userAttributes, "test_experiment", "experiment"); + var impressionEvent = UserEventFactory.CreateImpressionEvent(Config, + Config.GetExperimentFromKey("test_experiment"), "7722370027", TestUserId, + userAttributes, "test_experiment", "experiment"); var logEvent = EventFactory.CreateLogEvent(impressionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, Guid.Parse(impressionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, + Guid.Parse(impressionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); } @@ -1621,75 +1760,82 @@ public void TestCreateImpressionEventWhenBotFilteringIsProvidedInDatafile() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "7722370027" }, - { "metadata", new Dictionary { + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + { + "metadata", new Dictionary + { { "rule_type", "experiment" }, { "rule_key", "test_experiment" }, { "flag_key", "test_experiment" }, { "variation_key", "control" }, - {"enabled", false } + { "enabled", false }, } - } - } + }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"key", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"type", "custom" }, - {"value", "chrome"} + { "entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "key", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "type", "custom" }, + { "value", "chrome" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -1697,22 +1843,25 @@ public void TestCreateImpressionEventWhenBotFilteringIsProvidedInDatafile() "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { - {ControlAttributes.USER_AGENT_ATTRIBUTE, "chrome" } + { ControlAttributes.USER_AGENT_ATTRIBUTE, "chrome" }, }; var botFilteringEnabledConfig = Config; botFilteringEnabledConfig.BotFiltering = true; var experiment = botFilteringEnabledConfig.GetExperimentFromKey("test_experiment"); - var impressionEvent = UserEventFactory.CreateImpressionEvent(botFilteringEnabledConfig, experiment, "7722370027", TestUserId, userAttributes, "test_experiment", "experiment"); + var impressionEvent = UserEventFactory.CreateImpressionEvent(botFilteringEnabledConfig, + experiment, "7722370027", TestUserId, userAttributes, "test_experiment", + "experiment"); var logEvent = EventFactory.CreateLogEvent(impressionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, Guid.Parse(impressionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, + Guid.Parse(impressionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); } @@ -1725,68 +1874,75 @@ public void TestCreateImpressionEventWhenBotFilteringIsNotProvidedInDatafile() var payloadParams = new Dictionary { - { "visitors", new object[] + { + "visitors", new object[] { new Dictionary() { - { "snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - { "decisions", new object[] + { + "decisions", new object[] { new Dictionary { - {"campaign_id", "7719770039" }, - {"experiment_id", "7716830082" }, - {"variation_id", "7722370027" }, - { "metadata", new Dictionary { + { "campaign_id", "7719770039" }, + { "experiment_id", "7716830082" }, + { "variation_id", "7722370027" }, + { + "metadata", new Dictionary + { { "rule_type", "experiment" }, { "rule_key", "test_experiment" }, { "flag_key", "test_experiment" }, { "variation_key", "control" }, - {"enabled", false } + { "enabled", false }, } - } - } + }, + }, } }, - { "events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7719770039" }, - {"timestamp", timeStamp }, - {"uuid", guid }, - {"key", "campaign_activated" } - } + { "entity_id", "7719770039" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "campaign_activated" }, + }, } - } - } + }, + }, } }, - {"attributes", new object[] + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"key", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"type", "custom" }, - {"value", "chrome"} - } + { "entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "key", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "type", "custom" }, + { "value", "chrome" }, + }, } }, - { "visitor_id", TestUserId } - } + { "visitor_id", TestUserId }, + }, } }, - {"project_id", "7720880029" }, - {"account_id", "1592310167" }, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk" }, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedLogEvent = new LogEvent("https://logx.optimizely.com/v1/events", @@ -1794,22 +1950,25 @@ public void TestCreateImpressionEventWhenBotFilteringIsNotProvidedInDatafile() "POST", new Dictionary { - { "Content-Type", "application/json" } + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { - {ControlAttributes.USER_AGENT_ATTRIBUTE, "chrome" } + { ControlAttributes.USER_AGENT_ATTRIBUTE, "chrome" }, }; var botFilteringDisabledConfig = Config; botFilteringDisabledConfig.BotFiltering = null; var experiment = botFilteringDisabledConfig.GetExperimentFromKey("test_experiment"); - var impressionEvent = UserEventFactory.CreateImpressionEvent(botFilteringDisabledConfig, experiment, "7722370027", TestUserId, userAttributes, "test_experiment", "experiment"); + var impressionEvent = UserEventFactory.CreateImpressionEvent(botFilteringDisabledConfig, + experiment, "7722370027", TestUserId, userAttributes, "test_experiment", + "experiment"); var logEvent = EventFactory.CreateLogEvent(impressionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, Guid.Parse(impressionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, impressionEvent.Timestamp, + Guid.Parse(impressionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); } @@ -1822,57 +1981,61 @@ public void TestCreateConversionEventWhenBotFilteringIsProvidedInDatafile() var payloadParams = new Dictionary { - {"visitors", new object[] + { + "visitors", new object[] { new Dictionary { - {"snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - {"events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063"}, - {"timestamp", timeStamp}, - {"uuid", guid}, - {"key", "purchase"}, - } + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, } - } - } + }, + }, } }, - {"visitor_id", TestUserId }, - {"attributes", new object[] + { "visitor_id", TestUserId }, + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"key", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"type", "custom" }, - {"value", "safari"} + { "entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "key", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "type", "custom" }, + { "value", "safari" }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } - } - } + }, + }, } }, - {"project_id", "7720880029"}, - {"account_id", "1592310167"}, - {"enrich_decisions", true} , - {"client_name", "csharp-sdk"}, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1881,25 +2044,27 @@ public void TestCreateConversionEventWhenBotFilteringIsProvidedInDatafile() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { - {ControlAttributes.USER_AGENT_ATTRIBUTE, "safari" } + { ControlAttributes.USER_AGENT_ATTRIBUTE, "safari" }, }; var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; var botFilteringEnabledConfig = Config; botFilteringEnabledConfig.BotFiltering = true; - var conversionEvent = UserEventFactory.CreateConversionEvent(botFilteringEnabledConfig, "purchase", TestUserId, userAttributes, null); + var conversionEvent = UserEventFactory.CreateConversionEvent(botFilteringEnabledConfig, + "purchase", TestUserId, userAttributes, null); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } @@ -1912,50 +2077,54 @@ public void TestCreateConversionEventWhenBotFilteringIsNotProvidedInDatafile() var payloadParams = new Dictionary { - {"visitors", new object[] + { + "visitors", new object[] { new Dictionary { - {"snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - {"events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063"}, - {"timestamp", timeStamp}, - {"uuid", guid}, - {"key", "purchase"}, - } + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, } - } - } + }, + }, } }, - {"visitor_id", TestUserId }, - {"attributes", new object[] + { "visitor_id", TestUserId }, + { + "attributes", new object[] { new Dictionary { - {"entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"key", ControlAttributes.USER_AGENT_ATTRIBUTE }, - {"type", "custom" }, - {"value", "safari"} - } + { "entity_id", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "key", ControlAttributes.USER_AGENT_ATTRIBUTE }, + { "type", "custom" }, + { "value", "safari" }, + }, } - } - } + }, + }, } }, - {"project_id", "7720880029"}, - {"enrich_decisions", true}, - {"account_id", "1592310167"}, - {"client_name", "csharp-sdk"}, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "enrich_decisions", true }, + { "account_id", "1592310167" }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -1964,25 +2133,27 @@ public void TestCreateConversionEventWhenBotFilteringIsNotProvidedInDatafile() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes { - {ControlAttributes.USER_AGENT_ATTRIBUTE, "safari" } + { ControlAttributes.USER_AGENT_ATTRIBUTE, "safari" }, }; var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; var botFilteringDisabledConfig = Config; botFilteringDisabledConfig.BotFiltering = null; - var conversionEvent = UserEventFactory.CreateConversionEvent(botFilteringDisabledConfig, "purchase", TestUserId, userAttributes, null); + var conversionEvent = UserEventFactory.CreateConversionEvent(botFilteringDisabledConfig, + "purchase", TestUserId, userAttributes, null); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } @@ -1993,28 +2164,30 @@ public void TestCreateConversionEventWhenEventUsedInMultipleExp() var guid = Guid.NewGuid(); var timeStamp = TestData.SecondsSince1970(); - var eventInMultiExperimentConfig = DatafileProjectConfig.Create(TestData.SimpleABExperimentsDatafile, new NoOpLogger(), new ErrorHandler.NoOpErrorHandler()); + var eventInMultiExperimentConfig = DatafileProjectConfig.Create( + TestData.SimpleABExperimentsDatafile, new NoOpLogger(), new NoOpErrorHandler()); var experimentIdVariationMap = new Dictionary { { - "111127", new Variation{Id="111129", Key="variation"} + "111127", new Variation { Id = "111129", Key = "variation" } }, { - "111130", new Variation{Id="111131", Key="variation"} - } + "111130", new Variation { Id = "111131", Key = "variation" } + }, }; var payloadParams = new Dictionary + { + { "client_version", Optimizely.SDK_VERSION }, + { "project_id", "111001" }, + { "enrich_decisions", true }, + { "account_id", "12001" }, + { "client_name", "csharp-sdk" }, + { "anonymize_ip", false }, + { "revision", eventInMultiExperimentConfig.Revision }, { - {"client_version", Optimizely.SDK_VERSION}, - {"project_id", "111001"}, - {"enrich_decisions", true}, - {"account_id", "12001"}, - {"client_name", "csharp-sdk"}, - {"anonymize_ip", false}, - {"revision", eventInMultiExperimentConfig.Revision}, - {"visitors", new object[] + "visitors", new object[] { //visitors[0] new Dictionary @@ -2025,17 +2198,18 @@ public void TestCreateConversionEventWhenEventUsedInMultipleExp() { new Dictionary { - {"entity_id", "111094"}, - {"type", "custom"}, - {"value", "test_value"}, - {"key", "test_attribute"} - } + { "entity_id", "111094" }, + { "type", "custom" }, + { "value", "test_value" }, + { "key", "test_attribute" }, + }, } }, //visitors[0].visitor_id - {"visitor_id", "test_user"}, + { "visitor_id", "test_user" }, //visitors[0].snapshots - {"snapshots", new object[] + { + "snapshots", new object[] { //snapshots[0] new Dictionary @@ -2046,34 +2220,32 @@ public void TestCreateConversionEventWhenEventUsedInMultipleExp() { new Dictionary { - {"uuid", guid}, - {"timestamp", timeStamp}, - {"revenue", 4200}, - {"value", 1.234}, - {"key", "event_with_multiple_running_experiments"}, - {"entity_id", "111095"}, + { "uuid", guid }, + { "timestamp", timeStamp }, + { "revenue", 4200 }, + { "value", 1.234 }, + { + "key", + "event_with_multiple_running_experiments" + }, + { "entity_id", "111095" }, { "tags", new Dictionary { - {"non-revenue", "abc"}, - {"revenue", 4200}, - {"value", 1.234}, + { "non-revenue", "abc" }, + { "revenue", 4200 }, + { "value", 1.234 }, } - } - - } + }, + }, } - } - - } - + }, + }, } - } - - } + }, + }, } - - } + }, }; @@ -2083,20 +2255,25 @@ public void TestCreateConversionEventWhenEventUsedInMultipleExp() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, + }); + var conversionEvent = UserEventFactory.CreateConversionEvent( + eventInMultiExperimentConfig, "event_with_multiple_running_experiments", + "test_user", + new UserAttributes + { + { "test_attribute", "test_value" }, + }, + new EventTags + { + { "revenue", 4200 }, + { "value", 1.234 }, + { "non-revenue", "abc" }, }); - var conversionEvent = UserEventFactory.CreateConversionEvent(eventInMultiExperimentConfig, "event_with_multiple_running_experiments", "test_user", - new UserAttributes { - {"test_attribute", "test_value"} - }, - new EventTags { - {"revenue", 4200}, - {"value", 1.234}, - {"non-revenue", "abc"} - }); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedLogEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedLogEvent, logEvent)); } @@ -2109,71 +2286,75 @@ public void TestCreateConversionEventRemovesInvalidAttributesFromPayload() var payloadParams = new Dictionary { - {"visitors", new object[] + { + "visitors", new object[] { new Dictionary { - {"snapshots", new object[] + { + "snapshots", new object[] { new Dictionary { - {"events", new object[] + { + "events", new object[] { new Dictionary { - {"entity_id", "7718020063"}, - {"timestamp", timeStamp}, - {"uuid", guid}, - {"key", "purchase"}, - } + { "entity_id", "7718020063" }, + { "timestamp", timeStamp }, + { "uuid", guid }, + { "key", "purchase" }, + }, } - } - } + }, + }, } }, - {"visitor_id", TestUserId }, - {"attributes", new object[] + { "visitor_id", TestUserId }, + { + "attributes", new object[] { new Dictionary { - {"entity_id", "7723280020" }, - {"key", "device_type" }, - {"type", "custom" }, - {"value", "iPhone"} + { "entity_id", "7723280020" }, + { "key", "device_type" }, + { "type", "custom" }, + { "value", "iPhone" }, }, new Dictionary { - {"entity_id", "323434545" }, - {"key", "boolean_key" }, - {"type", "custom" }, - {"value", true} + { "entity_id", "323434545" }, + { "key", "boolean_key" }, + { "type", "custom" }, + { "value", true }, }, new Dictionary { - {"entity_id", "808797686" }, - {"key", "double_key" }, - {"type", "custom" }, - {"value", 3.14} + { "entity_id", "808797686" }, + { "key", "double_key" }, + { "type", "custom" }, + { "value", 3.14 }, }, new Dictionary { - {"entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"key", ControlAttributes.BOT_FILTERING_ATTRIBUTE}, - {"type", "custom" }, - {"value", true } - } + { "entity_id", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "key", ControlAttributes.BOT_FILTERING_ATTRIBUTE }, + { "type", "custom" }, + { "value", true }, + }, } - } - } + }, + }, } }, - {"project_id", "7720880029"}, - {"account_id", "1592310167"}, - {"enrich_decisions", true}, - {"client_name", "csharp-sdk"}, - {"client_version", Optimizely.SDK_VERSION }, - {"revision", "15" }, - {"anonymize_ip", false} + { "project_id", "7720880029" }, + { "account_id", "1592310167" }, + { "enrich_decisions", true }, + { "client_name", "csharp-sdk" }, + { "client_version", Optimizely.SDK_VERSION }, + { "revision", "15" }, + { "anonymize_ip", false }, }; var expectedEvent = new LogEvent( @@ -2182,7 +2363,7 @@ public void TestCreateConversionEventRemovesInvalidAttributesFromPayload() "POST", new Dictionary { - { "Content-Type", "application/json"} + { "Content-Type", "application/json" }, }); var userAttributes = new UserAttributes @@ -2202,14 +2383,15 @@ public void TestCreateConversionEventRemovesInvalidAttributesFromPayload() var experimentToVariationMap = new Dictionary { - {"7716830082", new Variation{Id="7722370027", Key="control"} } + { "7716830082", new Variation { Id = "7722370027", Key = "control" } }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", TestUserId, userAttributes, null); + var conversionEvent = UserEventFactory.CreateConversionEvent(Config, "purchase", + TestUserId, userAttributes, null); var logEvent = EventFactory.CreateLogEvent(conversionEvent, Logger); - TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, Guid.Parse(conversionEvent.UUID)); + TestData.ChangeGUIDAndTimeStamp(expectedEvent.Params, conversionEvent.Timestamp, + Guid.Parse(conversionEvent.UUID)); Assert.IsTrue(TestData.CompareObjects(expectedEvent, logEvent)); } } } - diff --git a/OptimizelySDK.Tests/EventTests/EventProcessorProps.cs b/OptimizelySDK.Tests/EventTests/EventProcessorProps.cs index 9919af197..33c013c11 100644 --- a/OptimizelySDK.Tests/EventTests/EventProcessorProps.cs +++ b/OptimizelySDK.Tests/EventTests/EventProcessorProps.cs @@ -33,23 +33,28 @@ public class EventProcessorProps public EventProcessorProps(BatchEventProcessor eventProcessor) { var fieldsInfo = Reflection.GetAllFields(eventProcessor.GetType()); - BatchSize = Reflection.GetFieldValue(eventProcessor, "BatchSize", fieldsInfo); - FlushInterval = Reflection.GetFieldValue(eventProcessor, "FlushInterval", fieldsInfo); - TimeoutInterval = Reflection.GetFieldValue(eventProcessor, "TimeoutInterval", fieldsInfo); + BatchSize = + Reflection.GetFieldValue(eventProcessor, "BatchSize", + fieldsInfo); + FlushInterval = + Reflection.GetFieldValue(eventProcessor, + "FlushInterval", fieldsInfo); + TimeoutInterval = + Reflection.GetFieldValue(eventProcessor, + "TimeoutInterval", fieldsInfo); } /// /// To create default instance of expected values. /// - public EventProcessorProps() - { - - } + public EventProcessorProps() { } public override bool Equals(object obj) { if (obj == null) + { return false; + } var eventProcessor = obj as EventProcessorProps; if (eventProcessor == null) @@ -59,7 +64,8 @@ public override bool Equals(object obj) if (BatchSize != eventProcessor.BatchSize || FlushInterval.TotalMilliseconds != eventProcessor.FlushInterval.TotalMilliseconds || - TimeoutInterval.TotalMilliseconds != eventProcessor.TimeoutInterval.TotalMilliseconds) + TimeoutInterval.TotalMilliseconds != + eventProcessor.TimeoutInterval.TotalMilliseconds) { return false; } diff --git a/OptimizelySDK.Tests/EventTests/ForwardingEventProcessorTest.cs b/OptimizelySDK.Tests/EventTests/ForwardingEventProcessorTest.cs index 0661c7ad0..805e92413 100644 --- a/OptimizelySDK.Tests/EventTests/ForwardingEventProcessorTest.cs +++ b/OptimizelySDK.Tests/EventTests/ForwardingEventProcessorTest.cs @@ -12,7 +12,7 @@ namespace OptimizelySDK.Tests.EventTests { [TestFixture] - class ForwardingEventProcessorTest + internal class ForwardingEventProcessorTest { private const string UserId = "userId"; private const string EventName = "purchase"; @@ -21,10 +21,10 @@ class ForwardingEventProcessorTest private TestForwardingEventDispatcher EventDispatcher; private NotificationCenter NotificationCenter = new NotificationCenter(); - Mock LoggerMock; - Mock ErrorHandlerMock; + private Mock LoggerMock; + private Mock ErrorHandlerMock; - ProjectConfig ProjectConfig; + private ProjectConfig ProjectConfig; [SetUp] public void Setup() @@ -35,17 +35,19 @@ public void Setup() ErrorHandlerMock = new Mock(); ErrorHandlerMock.Setup(e => e.HandleError(It.IsAny())); - ProjectConfig = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, new NoOpErrorHandler()); + ProjectConfig = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, + new NoOpErrorHandler()); EventDispatcher = new TestForwardingEventDispatcher { IsUpdated = false }; - EventProcessor = new ForwardingEventProcessor(EventDispatcher, NotificationCenter, LoggerMock.Object, ErrorHandlerMock.Object); + EventProcessor = new ForwardingEventProcessor(EventDispatcher, NotificationCenter, + LoggerMock.Object, ErrorHandlerMock.Object); } [Test] public void TestEventHandlerWithConversionEvent() { var userEvent = CreateConversionEvent(EventName); - EventProcessor.Process(userEvent); + EventProcessor.Process(userEvent); Assert.True(EventDispatcher.IsUpdated); } @@ -54,19 +56,22 @@ public void TestEventHandlerWithConversionEvent() [Test] public void TestExceptionWhileDispatching() { - var eventProcessor = new ForwardingEventProcessor(new InvalidEventDispatcher(), NotificationCenter, LoggerMock.Object, ErrorHandlerMock.Object); + var eventProcessor = new ForwardingEventProcessor(new InvalidEventDispatcher(), + NotificationCenter, LoggerMock.Object, ErrorHandlerMock.Object); var userEvent = CreateConversionEvent(EventName); eventProcessor.Process(userEvent); - - ErrorHandlerMock.Verify(errorHandler => errorHandler.HandleError(It.IsAny()), Times.Once ); + + ErrorHandlerMock.Verify(errorHandler => errorHandler.HandleError(It.IsAny()), + Times.Once); } [Test] public void TestNotifications() { - bool notificationTriggered = false; - NotificationCenter.AddNotification(NotificationCenter.NotificationType.LogEvent, logEvent => notificationTriggered = true); + var notificationTriggered = false; + NotificationCenter.AddNotification(NotificationCenter.NotificationType.LogEvent, + logEvent => notificationTriggered = true); var userEvent = CreateConversionEvent(EventName); EventProcessor.Process(userEvent); @@ -77,7 +82,8 @@ public void TestNotifications() private ConversionEvent CreateConversionEvent(string eventName) { - return UserEventFactory.CreateConversionEvent(ProjectConfig, eventName, UserId, new UserAttributes(), new EventTags()); + return UserEventFactory.CreateConversionEvent(ProjectConfig, eventName, UserId, + new UserAttributes(), new EventTags()); } } } diff --git a/OptimizelySDK.Tests/EventTests/LogEventTest.cs b/OptimizelySDK.Tests/EventTests/LogEventTest.cs index 1ef7e32be..ba6cc9c5c 100644 --- a/OptimizelySDK.Tests/EventTests/LogEventTest.cs +++ b/OptimizelySDK.Tests/EventTests/LogEventTest.cs @@ -1,12 +1,11 @@ - -using Newtonsoft.Json.Linq; -using NUnit.Framework; -using OptimizelySDK.Event; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using OptimizelySDK.Event; namespace OptimizelySDK.Tests.EventTests { @@ -17,7 +16,6 @@ public class LogEventTest public static bool CompareObjects(object o1, object o2) { - var str1 = Newtonsoft.Json.JsonConvert.SerializeObject(o1); var str2 = Newtonsoft.Json.JsonConvert.SerializeObject(o2); var jtoken1 = JToken.Parse(Newtonsoft.Json.JsonConvert.SerializeObject(o1)); @@ -30,17 +28,17 @@ public static bool CompareObjects(object o1, object o2) public void Setup() { LogEvent = new LogEvent( - url: "https://logx.optimizely.com", - parameters: new Dictionary + "https://logx.optimizely.com", + new Dictionary { { "accountId", "1234" }, { "projectId", "9876" }, - { "visitorId", "testUser" } + { "visitorId", "testUser" }, }, - httpVerb: "POST", - headers: new Dictionary + "POST", + new Dictionary { - { "Content-type", "application/json" } + { "Content-type", "application/json" }, }); } @@ -57,7 +55,7 @@ public void TestGetParams() { { "accountId", "1234" }, { "projectId", "9876" }, - { "visitorId", "testUser" } + { "visitorId", "testUser" }, }; Assert.IsTrue(CompareObjects(testParams, LogEvent.Params)); } @@ -73,7 +71,7 @@ public void TestGetHeaders() { var headers = new Dictionary { - { "Content-type", "application/json" } + { "Content-type", "application/json" }, }; Assert.IsTrue(CompareObjects(headers, LogEvent.Headers)); } diff --git a/OptimizelySDK.Tests/EventTests/TestEventDispatcher.cs b/OptimizelySDK.Tests/EventTests/TestEventDispatcher.cs index cfeab5d33..0eedba02d 100644 --- a/OptimizelySDK.Tests/EventTests/TestEventDispatcher.cs +++ b/OptimizelySDK.Tests/EventTests/TestEventDispatcher.cs @@ -1,4 +1,8 @@ -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using OptimizelySDK.Config; using OptimizelySDK.Entity; @@ -6,10 +10,6 @@ using OptimizelySDK.Event.Dispatcher; using OptimizelySDK.Event.Entity; using OptimizelySDK.Logger; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; namespace OptimizelySDK.Tests.EventTests { @@ -30,16 +30,20 @@ public TestEventDispatcher(CountdownEvent countdownEvent = null) public bool CompareEvents() { if (ExpectedEvents.Count != ActualEvents.Count) + { return false; + } - for (int count = 0; count < ExpectedEvents.Count; ++count) + for (var count = 0; count < ExpectedEvents.Count; ++count) { var expectedEvent = ExpectedEvents[count]; var actualEvent = ActualEvents[count]; if (expectedEvent != actualEvent) + { return false; + } } return true; @@ -50,12 +54,14 @@ public void DispatchEvent(LogEvent actualLogEvent) Visitor[] visitors = null; if (actualLogEvent.Params.ContainsKey("visitors")) { - JArray jArray = (JArray)actualLogEvent.Params["visitors"]; + var jArray = (JArray)actualLogEvent.Params["visitors"]; visitors = jArray.ToObject(); } if (visitors == null) + { return; + } foreach (var visitor in visitors) { @@ -67,11 +73,15 @@ public void DispatchEvent(LogEvent actualLogEvent) foreach (var @event in snapshot.Events) { var userAttributes = new UserAttributes(); - foreach (var attribute in visitor.Attributes.Where(attr => !attr.Key.StartsWith(DatafileProjectConfig.RESERVED_ATTRIBUTE_PREFIX))) { + foreach (var attribute in visitor.Attributes.Where(attr => + !attr.Key.StartsWith(DatafileProjectConfig. + RESERVED_ATTRIBUTE_PREFIX))) + { userAttributes.Add(attribute.Key, attribute.Value); } - ActualEvents.Add(new CanonicalEvent(decision.ExperimentId, decision.VariationId, @event.Key, + ActualEvents.Add(new CanonicalEvent(decision.ExperimentId, + decision.VariationId, @event.Key, visitor.VisitorId, userAttributes, @event.EventTags)); } } @@ -84,7 +94,8 @@ public void DispatchEvent(LogEvent actualLogEvent) } catch (ObjectDisposedException) { - Logger.Log(LogLevel.ERROR, "The CountdownEvent instance has already been disposed."); + Logger.Log(LogLevel.ERROR, + "The CountdownEvent instance has already been disposed."); } catch (InvalidOperationException) { @@ -92,19 +103,26 @@ public void DispatchEvent(LogEvent actualLogEvent) } } - public void ExpectImpression(string experimentId, string variationId, string userId, UserAttributes attributes = null) + public void ExpectImpression(string experimentId, string variationId, string userId, + UserAttributes attributes = null + ) { Expect(experimentId, variationId, IMPRESSION_EVENT_NAME, userId, attributes, null); } - public void ExpectConversion(string eventName, string userId, UserAttributes attributes = null, EventTags tags = null) + public void ExpectConversion(string eventName, string userId, + UserAttributes attributes = null, EventTags tags = null + ) { Expect(null, null, eventName, userId, attributes, tags); } - private void Expect(string experimentId, string variationId, string eventName, string visitorId, UserAttributes attributes, EventTags tags) + private void Expect(string experimentId, string variationId, string eventName, + string visitorId, UserAttributes attributes, EventTags tags + ) { - var expectedEvent = new CanonicalEvent(experimentId, variationId, eventName, visitorId, attributes, tags); + var expectedEvent = new CanonicalEvent(experimentId, variationId, eventName, visitorId, + attributes, tags); ExpectedEvents.Add(expectedEvent); } } diff --git a/OptimizelySDK.Tests/EventTests/TestForwardingEventDispatcher.cs b/OptimizelySDK.Tests/EventTests/TestForwardingEventDispatcher.cs index b31dd9951..01eca1ee6 100644 --- a/OptimizelySDK.Tests/EventTests/TestForwardingEventDispatcher.cs +++ b/OptimizelySDK.Tests/EventTests/TestForwardingEventDispatcher.cs @@ -1,12 +1,12 @@ -using NUnit.Framework; -using OptimizelySDK.Event; -using OptimizelySDK.Event.Dispatcher; -using OptimizelySDK.Logger; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using NUnit.Framework; +using OptimizelySDK.Event; +using OptimizelySDK.Event.Dispatcher; +using OptimizelySDK.Logger; namespace OptimizelySDK.Tests.EventTests { diff --git a/OptimizelySDK.Tests/EventTests/UserEventFactoryTest.cs b/OptimizelySDK.Tests/EventTests/UserEventFactoryTest.cs index 80acd1a66..ecf42fcad 100644 --- a/OptimizelySDK.Tests/EventTests/UserEventFactoryTest.cs +++ b/OptimizelySDK.Tests/EventTests/UserEventFactoryTest.cs @@ -38,7 +38,8 @@ public void Setup() LoggerMock = new Mock(); ErrorHandlerMock = new Mock(); - Config = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, ErrorHandlerMock.Object); + Config = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, + ErrorHandlerMock.Object); } [Test] @@ -49,7 +50,8 @@ public void ImpressionEventTest() var variation = Config.GetVariationFromId(experiment.Key, "77210100090"); var userId = TestUserId; - var impressionEvent = UserEventFactory.CreateImpressionEvent(projectConfig, experiment, variation, userId, null, "test_experiment", "experiment"); + var impressionEvent = UserEventFactory.CreateImpressionEvent(projectConfig, experiment, + variation, userId, null, "test_experiment", "experiment"); Assert.AreEqual(Config.ProjectId, impressionEvent.Context.ProjectId); Assert.AreEqual(Config.Revision, impressionEvent.Context.Revision); @@ -70,12 +72,14 @@ public void ImpressionEventTestWithAttributes() var variation = Config.GetVariationFromId(experiment.Key, "77210100090"); var userId = TestUserId; - var userAttributes = new UserAttributes { + var userAttributes = new UserAttributes + { { "device_type", "iPhone" }, - { "company", "Optimizely" } + { "company", "Optimizely" }, }; - var impressionEvent = UserEventFactory.CreateImpressionEvent(projectConfig, experiment, variation, userId, userAttributes, "test_experiment", "experiment"); + var impressionEvent = UserEventFactory.CreateImpressionEvent(projectConfig, experiment, + variation, userId, userAttributes, "test_experiment", "experiment"); Assert.AreEqual(Config.ProjectId, impressionEvent.Context.ProjectId); Assert.AreEqual(Config.Revision, impressionEvent.Context.Revision); @@ -87,7 +91,8 @@ public void ImpressionEventTestWithAttributes() Assert.AreEqual(userId, impressionEvent.UserId); Assert.AreEqual(Config.BotFiltering, impressionEvent.BotFiltering); - var expectedVisitorAttributes = EventFactory.BuildAttributeList(userAttributes, projectConfig); + var expectedVisitorAttributes = + EventFactory.BuildAttributeList(userAttributes, projectConfig); TestData.CompareObjects(expectedVisitorAttributes, impressionEvent.VisitorAttributes); } @@ -99,12 +104,14 @@ public void ConversionEventTest() var variation = Config.GetVariationFromId(experiment.Key, "77210100090"); var userId = TestUserId; var eventKey = "purchase"; - var userAttributes = new UserAttributes { + var userAttributes = new UserAttributes + { { "device_type", "iPhone" }, - { "company", "Optimizely" } + { "company", "Optimizely" }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(projectConfig, eventKey, userId, userAttributes, null); + var conversionEvent = UserEventFactory.CreateConversionEvent(projectConfig, eventKey, + userId, userAttributes, null); Assert.AreEqual(Config.ProjectId, conversionEvent.Context.ProjectId); Assert.AreEqual(Config.Revision, conversionEvent.Context.Revision); @@ -115,7 +122,8 @@ public void ConversionEventTest() Assert.AreEqual(userId, conversionEvent.UserId); Assert.AreEqual(Config.BotFiltering, conversionEvent.BotFiltering); - var expectedVisitorAttributes = EventFactory.BuildAttributeList(userAttributes, projectConfig); + var expectedVisitorAttributes = + EventFactory.BuildAttributeList(userAttributes, projectConfig); TestData.CompareObjects(expectedVisitorAttributes, conversionEvent.VisitorAttributes); } @@ -128,17 +136,20 @@ public void ConversionEventWithEventTagsTest() var userId = TestUserId; var eventKey = "purchase"; - var eventTags = new EventTags { + var eventTags = new EventTags + { { "revenue", 4200 }, { "value", 1.234 }, - { "non-revenue", "abc" } + { "non-revenue", "abc" }, }; - var userAttributes = new UserAttributes { + var userAttributes = new UserAttributes + { { "device_type", "iPhone" }, - { "company", "Optimizely" } + { "company", "Optimizely" }, }; - var conversionEvent = UserEventFactory.CreateConversionEvent(projectConfig, eventKey, userId, userAttributes, eventTags); + var conversionEvent = UserEventFactory.CreateConversionEvent(projectConfig, eventKey, + userId, userAttributes, eventTags); Assert.AreEqual(Config.ProjectId, conversionEvent.Context.ProjectId); Assert.AreEqual(Config.Revision, conversionEvent.Context.Revision); @@ -150,7 +161,8 @@ public void ConversionEventWithEventTagsTest() Assert.AreEqual(Config.BotFiltering, conversionEvent.BotFiltering); Assert.AreEqual(eventTags, conversionEvent.EventTags); - var expectedVisitorAttributes = EventFactory.BuildAttributeList(userAttributes, projectConfig); + var expectedVisitorAttributes = + EventFactory.BuildAttributeList(userAttributes, projectConfig); TestData.CompareObjects(expectedVisitorAttributes, conversionEvent.VisitorAttributes); } } diff --git a/OptimizelySDK.Tests/ForcedDecisionsStoreTest.cs b/OptimizelySDK.Tests/ForcedDecisionsStoreTest.cs index 6cf2dfc8e..d3e1fbb8d 100644 --- a/OptimizelySDK.Tests/ForcedDecisionsStoreTest.cs +++ b/OptimizelySDK.Tests/ForcedDecisionsStoreTest.cs @@ -34,8 +34,10 @@ public void ForcedDecisionStoreGetSetForcedDecisionWithBothRuleAndFlagKey() forcedDecisionStore[context2] = expectedForcedDecision2; Assert.AreEqual(forcedDecisionStore.Count, 2); - Assert.AreEqual(forcedDecisionStore[context1].VariationKey, expectedForcedDecision1.VariationKey); - Assert.AreEqual(forcedDecisionStore[context2].VariationKey, expectedForcedDecision2.VariationKey); + Assert.AreEqual(forcedDecisionStore[context1].VariationKey, + expectedForcedDecision1.VariationKey); + Assert.AreEqual(forcedDecisionStore[context2].VariationKey, + expectedForcedDecision2.VariationKey); } [Test] @@ -70,7 +72,8 @@ public void ForcedDecisionStoreGetForcedDecisionWithBothRuleAndFlagKey() forcedDecisionStore[context1] = expectedForcedDecision1; Assert.AreEqual(forcedDecisionStore.Count, 1); - Assert.AreEqual(forcedDecisionStore[context1].VariationKey, expectedForcedDecision1.VariationKey); + Assert.AreEqual(forcedDecisionStore[context1].VariationKey, + expectedForcedDecision1.VariationKey); Assert.IsNull(forcedDecisionStore[NullFlagKeyContext]); } @@ -88,7 +91,8 @@ public void ForcedDecisionStoreRemoveForcedDecisionTrue() Assert.AreEqual(forcedDecisionStore.Count, 2); Assert.IsTrue(forcedDecisionStore.Remove(context2)); Assert.AreEqual(forcedDecisionStore.Count, 1); - Assert.AreEqual(forcedDecisionStore[context1].VariationKey, expectedForcedDecision1.VariationKey); + Assert.AreEqual(forcedDecisionStore[context1].VariationKey, + expectedForcedDecision1.VariationKey); Assert.IsNull(forcedDecisionStore[context2]); } @@ -118,6 +122,5 @@ public void ForcedDecisionStoreRemoveAllForcedDecisionContext() forcedDecisionStore.RemoveAll(); Assert.AreEqual(forcedDecisionStore.Count, 0); } - } } diff --git a/OptimizelySDK.Tests/IntegrationOdpDatafile.json b/OptimizelySDK.Tests/IntegrationOdpDatafile.json index d5c94dc0c..f0eac9985 100644 --- a/OptimizelySDK.Tests/IntegrationOdpDatafile.json +++ b/OptimizelySDK.Tests/IntegrationOdpDatafile.json @@ -1,318 +1,442 @@ { - "version": "4", - "rollouts": [{ - "experiments": [{ - "status": "Running", - "key": "feat_no_vars_rule", - "layerId": "11551226731", - "trafficAllocation": [{ - "entityId": "11557362669", - "endOfRange": 10000 - }], - "audienceIds": ["3468206642", "3988293898", "3988293899", "3468206646", "3468206647", "3468206644", "3468206643"], - "variations": [{ - "variables": [], - "id": "11557362669", - "key": "11557362669", - "featureEnabled": true - }], - "forcedVariations": {}, - "id": "11488548027" - }], - "id": "11551226731" - }, - { - "experiments": [{ - "status": "Paused", - "key": "feat_with_var_rule", - "layerId": "11638870867", - "trafficAllocation": [{ - "entityId": "11475708558", - "endOfRange": 0 - }], - "audienceIds": [], - "variations": [{ - "variables": [], - "id": "11475708558", - "key": "11475708558", - "featureEnabled": false - }], - "forcedVariations": {}, - "id": "11630490911" - }], - "id": "11638870867" - }, - { - "experiments": [{ - "status": "Running", - "key": "11488548028", - "layerId": "11551226732", - "trafficAllocation": [{ - "entityId": "11557362670", - "endOfRange": 10000 - }], - "audienceIds": ["0"], - "audienceConditions": ["and", ["or", "3468206642", "3988293898"], - ["or", "3988293899", "3468206646", "3468206647", "3468206644", "3468206643"] - ], - "variations": [{ - "variables": [], - "id": "11557362670", - "key": "11557362670", - "featureEnabled": true - }], - "forcedVariations": {}, - "id": "11488548028" - }], - "id": "11551226732" - }, - { - "experiments": [{ - "status": "Paused", - "key": "11630490912", - "layerId": "11638870868", - "trafficAllocation": [{ - "entityId": "11475708559", - "endOfRange": 0 - }], - "audienceIds": [], - "variations": [{ - "variables": [], - "id": "11475708559", - "key": "11475708559", - "featureEnabled": false - }], - "forcedVariations": {}, - "id": "11630490912" - }], - "id": "11638870868" - } - ], - "anonymizeIP": false, - "projectId": "11624721371", - "variables": [], - "featureFlags": [{ - "experimentIds": [], - "rolloutId": "11551226731", - "variables": [], - "id": "11477755619", - "key": "feat_no_vars" - }, - { - "experimentIds": [ - "11564051718" - ], - "rolloutId": "11638870867", - "variables": [{ - "defaultValue": "x", - "type": "string", - "id": "11535264366", - "key": "x" - }], - "id": "11567102051", - "key": "feat_with_var" - }, - { - "experimentIds": [], - "rolloutId": "11551226732", - "variables": [], - "id": "11567102052", - "key": "feat2" - }, - { - "experimentIds": ["1323241599"], - "rolloutId": "11638870868", - "variables": [{ - "defaultValue": "10", - "type": "integer", - "id": "11535264367", - "key": "z" - }], - "id": "11567102053", - "key": "feat2_with_var" - } - ], - "experiments": [{ - "status": "Running", - "key": "feat_with_var_test", - "layerId": "11504144555", - "trafficAllocation": [{ - "entityId": "11617170975", - "endOfRange": 10000 - }], - "audienceIds": ["3468206642", "3988293898", "3988293899", "3468206646", "3468206647", "3468206644", "3468206643"], - "variations": [{ - "variables": [{ - "id": "11535264366", - "value": "xyz" - }], - "id": "11617170975", - "key": "variation_2", - "featureEnabled": true - }], - "forcedVariations": {}, - "id": "11564051718" - }, - { - "id": "1323241597", - "key": "typed_audience_experiment", - "layerId": "1630555627", - "status": "Running", - "variations": [{ - "id": "1423767503", - "key": "A", - "variables": [] - }], - "trafficAllocation": [{ - "entityId": "1423767503", - "endOfRange": 10000 - }], - "audienceIds": ["3468206642", "3988293898", "3988293899", "3468206646", "3468206647", "3468206644", "3468206643"], - "forcedVariations": {} - }, - { - "id": "1323241598", - "key": "audience_combinations_experiment", - "layerId": "1323241598", - "status": "Running", - "variations": [{ - "id": "1423767504", - "key": "A", - "variables": [] - }], - "trafficAllocation": [{ - "entityId": "1423767504", - "endOfRange": 10000 - }], - "audienceIds": ["0"], - "audienceConditions": ["and", ["or", "3468206642", "3988293898"], - ["or", "3988293899", "3468206646", "3468206647", "3468206644", "3468206643"] - ], - "forcedVariations": {} - }, - { - "id": "1323241599", - "key": "feat2_with_var_test", - "layerId": "1323241600", - "status": "Running", - "variations": [{ - "variables": [{ - "id": "11535264367", - "value": "150" - }], - "id": "1423767505", - "key": "variation_2", - "featureEnabled": true - }], - "trafficAllocation": [{ - "entityId": "1423767505", - "endOfRange": 10000 - }], - "audienceIds": ["0"], - "audienceConditions": ["and", ["or", "3468206642", "3988293898"], - ["or", "3988293899", "3468206646", "3468206647", "3468206644", "3468206643"] - ], - "forcedVariations": {} - } - ], - "audiences": [ - { - "id": "3468206642", - "name": "exactString", - "conditions": "[\"and\", [\"or\", [\"or\", {\"name\": \"house\", \"type\": \"custom_attribute\", \"value\": \"Gryffindor\"}]]]" - }, - { - "id": "3468206645", - "name": "notChrome", - "conditions": "[\"and\", [\"or\", [\"not\", [\"or\", {\"name\": \"browser_type\", \"type\": \"custom_attribute\", \"value\":\"Chrome\"}]]]]" - }, - { - "id": "3988293898", - "name": "$$dummySubstringString", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "3988293899", - "name": "$$dummyExists", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "3468206646", - "name": "$$dummyExactNumber", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "3468206647", - "name": "$$dummyGtNumber", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "3468206644", - "name": "$$dummyLtNumber", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "3468206643", - "name": "$$dummyExactBoolean", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "0", - "name": "$$dummy", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "$opt_dummy_audience", - "name": "dummy_audience", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - } - ], - "typedAudiences": [], - "groups": [], - "integrations": [ - { - "key": "odp", - "host": "https://api.zaius.com", - "publicKey": "fake-public-key" - } - ], - "attributes": [{ - "key": "house", - "id": "594015" - }, - { - "key": "lasers", - "id": "594016" - }, - { - "key": "should_do_it", - "id": "594017" - }, - { - "key": "favorite_ice_cream", - "id": "594018" - } - ], - "botFiltering": false, - "accountId": "4879520872", - "events": [{ - "key": "item_bought", - "id": "594089", - "experimentIds": [ - "11564051718", - "1323241597" - ] - }, - { - "key": "user_signed_up", - "id": "594090", - "experimentIds": [ - "1323241598", - "1323241599" - ] - } - ], - "revision": "3", - "sdkKey": "typedAudienceDatafile", - "environmentKey": "Production" + "version": "4", + "rollouts": [ + { + "experiments": [ + { + "status": "Running", + "key": "feat_no_vars_rule", + "layerId": "11551226731", + "trafficAllocation": [ + { + "entityId": "11557362669", + "endOfRange": 10000 + } + ], + "audienceIds": [ + "3468206642", + "3988293898", + "3988293899", + "3468206646", + "3468206647", + "3468206644", + "3468206643" + ], + "variations": [ + { + "variables": [], + "id": "11557362669", + "key": "11557362669", + "featureEnabled": true + } + ], + "forcedVariations": {}, + "id": "11488548027" + } + ], + "id": "11551226731" + }, + { + "experiments": [ + { + "status": "Paused", + "key": "feat_with_var_rule", + "layerId": "11638870867", + "trafficAllocation": [ + { + "entityId": "11475708558", + "endOfRange": 0 + } + ], + "audienceIds": [], + "variations": [ + { + "variables": [], + "id": "11475708558", + "key": "11475708558", + "featureEnabled": false + } + ], + "forcedVariations": {}, + "id": "11630490911" + } + ], + "id": "11638870867" + }, + { + "experiments": [ + { + "status": "Running", + "key": "11488548028", + "layerId": "11551226732", + "trafficAllocation": [ + { + "entityId": "11557362670", + "endOfRange": 10000 + } + ], + "audienceIds": [ + "0" + ], + "audienceConditions": [ + "and", + [ + "or", + "3468206642", + "3988293898" + ], + [ + "or", + "3988293899", + "3468206646", + "3468206647", + "3468206644", + "3468206643" + ] + ], + "variations": [ + { + "variables": [], + "id": "11557362670", + "key": "11557362670", + "featureEnabled": true + } + ], + "forcedVariations": {}, + "id": "11488548028" + } + ], + "id": "11551226732" + }, + { + "experiments": [ + { + "status": "Paused", + "key": "11630490912", + "layerId": "11638870868", + "trafficAllocation": [ + { + "entityId": "11475708559", + "endOfRange": 0 + } + ], + "audienceIds": [], + "variations": [ + { + "variables": [], + "id": "11475708559", + "key": "11475708559", + "featureEnabled": false + } + ], + "forcedVariations": {}, + "id": "11630490912" + } + ], + "id": "11638870868" + } + ], + "anonymizeIP": false, + "projectId": "11624721371", + "variables": [], + "featureFlags": [ + { + "experimentIds": [], + "rolloutId": "11551226731", + "variables": [], + "id": "11477755619", + "key": "feat_no_vars" + }, + { + "experimentIds": [ + "11564051718" + ], + "rolloutId": "11638870867", + "variables": [ + { + "defaultValue": "x", + "type": "string", + "id": "11535264366", + "key": "x" + } + ], + "id": "11567102051", + "key": "feat_with_var" + }, + { + "experimentIds": [], + "rolloutId": "11551226732", + "variables": [], + "id": "11567102052", + "key": "feat2" + }, + { + "experimentIds": [ + "1323241599" + ], + "rolloutId": "11638870868", + "variables": [ + { + "defaultValue": "10", + "type": "integer", + "id": "11535264367", + "key": "z" + } + ], + "id": "11567102053", + "key": "feat2_with_var" + } + ], + "experiments": [ + { + "status": "Running", + "key": "feat_with_var_test", + "layerId": "11504144555", + "trafficAllocation": [ + { + "entityId": "11617170975", + "endOfRange": 10000 + } + ], + "audienceIds": [ + "3468206642", + "3988293898", + "3988293899", + "3468206646", + "3468206647", + "3468206644", + "3468206643" + ], + "variations": [ + { + "variables": [ + { + "id": "11535264366", + "value": "xyz" + } + ], + "id": "11617170975", + "key": "variation_2", + "featureEnabled": true + } + ], + "forcedVariations": {}, + "id": "11564051718" + }, + { + "id": "1323241597", + "key": "typed_audience_experiment", + "layerId": "1630555627", + "status": "Running", + "variations": [ + { + "id": "1423767503", + "key": "A", + "variables": [] + } + ], + "trafficAllocation": [ + { + "entityId": "1423767503", + "endOfRange": 10000 + } + ], + "audienceIds": [ + "3468206642", + "3988293898", + "3988293899", + "3468206646", + "3468206647", + "3468206644", + "3468206643" + ], + "forcedVariations": {} + }, + { + "id": "1323241598", + "key": "audience_combinations_experiment", + "layerId": "1323241598", + "status": "Running", + "variations": [ + { + "id": "1423767504", + "key": "A", + "variables": [] + } + ], + "trafficAllocation": [ + { + "entityId": "1423767504", + "endOfRange": 10000 + } + ], + "audienceIds": [ + "0" + ], + "audienceConditions": [ + "and", + [ + "or", + "3468206642", + "3988293898" + ], + [ + "or", + "3988293899", + "3468206646", + "3468206647", + "3468206644", + "3468206643" + ] + ], + "forcedVariations": {} + }, + { + "id": "1323241599", + "key": "feat2_with_var_test", + "layerId": "1323241600", + "status": "Running", + "variations": [ + { + "variables": [ + { + "id": "11535264367", + "value": "150" + } + ], + "id": "1423767505", + "key": "variation_2", + "featureEnabled": true + } + ], + "trafficAllocation": [ + { + "entityId": "1423767505", + "endOfRange": 10000 + } + ], + "audienceIds": [ + "0" + ], + "audienceConditions": [ + "and", + [ + "or", + "3468206642", + "3988293898" + ], + [ + "or", + "3988293899", + "3468206646", + "3468206647", + "3468206644", + "3468206643" + ] + ], + "forcedVariations": {} + } + ], + "audiences": [ + { + "id": "3468206642", + "name": "exactString", + "conditions": "[\"and\", [\"or\", [\"or\", {\"name\": \"house\", \"type\": \"custom_attribute\", \"value\": \"Gryffindor\"}]]]" + }, + { + "id": "3468206645", + "name": "notChrome", + "conditions": "[\"and\", [\"or\", [\"not\", [\"or\", {\"name\": \"browser_type\", \"type\": \"custom_attribute\", \"value\":\"Chrome\"}]]]]" + }, + { + "id": "3988293898", + "name": "$$dummySubstringString", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "3988293899", + "name": "$$dummyExists", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "3468206646", + "name": "$$dummyExactNumber", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "3468206647", + "name": "$$dummyGtNumber", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "3468206644", + "name": "$$dummyLtNumber", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "3468206643", + "name": "$$dummyExactBoolean", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "0", + "name": "$$dummy", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "$opt_dummy_audience", + "name": "dummy_audience", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + } + ], + "typedAudiences": [], + "groups": [], + "integrations": [ + { + "key": "odp", + "host": "https://api.zaius.com", + "publicKey": "fake-public-key" + } + ], + "attributes": [ + { + "key": "house", + "id": "594015" + }, + { + "key": "lasers", + "id": "594016" + }, + { + "key": "should_do_it", + "id": "594017" + }, + { + "key": "favorite_ice_cream", + "id": "594018" + } + ], + "botFiltering": false, + "accountId": "4879520872", + "events": [ + { + "key": "item_bought", + "id": "594089", + "experimentIds": [ + "11564051718", + "1323241597" + ] + }, + { + "key": "user_signed_up", + "id": "594090", + "experimentIds": [ + "1323241598", + "1323241599" + ] + } + ], + "revision": "3", + "sdkKey": "typedAudienceDatafile", + "environmentKey": "Production" } diff --git a/OptimizelySDK.Tests/IntegrationOdpWithOtherFieldsDatafile.json b/OptimizelySDK.Tests/IntegrationOdpWithOtherFieldsDatafile.json index 3fea39e72..c66ac3319 100644 --- a/OptimizelySDK.Tests/IntegrationOdpWithOtherFieldsDatafile.json +++ b/OptimizelySDK.Tests/IntegrationOdpWithOtherFieldsDatafile.json @@ -1,321 +1,445 @@ { - "version": "4", - "rollouts": [{ - "experiments": [{ - "status": "Running", - "key": "feat_no_vars_rule", - "layerId": "11551226731", - "trafficAllocation": [{ - "entityId": "11557362669", - "endOfRange": 10000 - }], - "audienceIds": ["3468206642", "3988293898", "3988293899", "3468206646", "3468206647", "3468206644", "3468206643"], - "variations": [{ - "variables": [], - "id": "11557362669", - "key": "11557362669", - "featureEnabled": true - }], - "forcedVariations": {}, - "id": "11488548027" - }], - "id": "11551226731" - }, - { - "experiments": [{ - "status": "Paused", - "key": "feat_with_var_rule", - "layerId": "11638870867", - "trafficAllocation": [{ - "entityId": "11475708558", - "endOfRange": 0 - }], - "audienceIds": [], - "variations": [{ - "variables": [], - "id": "11475708558", - "key": "11475708558", - "featureEnabled": false - }], - "forcedVariations": {}, - "id": "11630490911" - }], - "id": "11638870867" - }, - { - "experiments": [{ - "status": "Running", - "key": "11488548028", - "layerId": "11551226732", - "trafficAllocation": [{ - "entityId": "11557362670", - "endOfRange": 10000 - }], - "audienceIds": ["0"], - "audienceConditions": ["and", ["or", "3468206642", "3988293898"], - ["or", "3988293899", "3468206646", "3468206647", "3468206644", "3468206643"] - ], - "variations": [{ - "variables": [], - "id": "11557362670", - "key": "11557362670", - "featureEnabled": true - }], - "forcedVariations": {}, - "id": "11488548028" - }], - "id": "11551226732" - }, - { - "experiments": [{ - "status": "Paused", - "key": "11630490912", - "layerId": "11638870868", - "trafficAllocation": [{ - "entityId": "11475708559", - "endOfRange": 0 - }], - "audienceIds": [], - "variations": [{ - "variables": [], - "id": "11475708559", - "key": "11475708559", - "featureEnabled": false - }], - "forcedVariations": {}, - "id": "11630490912" - }], - "id": "11638870868" - } - ], - "anonymizeIP": false, - "projectId": "11624721371", - "variables": [], - "featureFlags": [{ - "experimentIds": [], - "rolloutId": "11551226731", - "variables": [], - "id": "11477755619", - "key": "feat_no_vars" - }, - { - "experimentIds": [ - "11564051718" - ], - "rolloutId": "11638870867", - "variables": [{ - "defaultValue": "x", - "type": "string", - "id": "11535264366", - "key": "x" - }], - "id": "11567102051", - "key": "feat_with_var" - }, - { - "experimentIds": [], - "rolloutId": "11551226732", - "variables": [], - "id": "11567102052", - "key": "feat2" - }, - { - "experimentIds": ["1323241599"], - "rolloutId": "11638870868", - "variables": [{ - "defaultValue": "10", - "type": "integer", - "id": "11535264367", - "key": "z" - }], - "id": "11567102053", - "key": "feat2_with_var" - } - ], - "experiments": [{ - "status": "Running", - "key": "feat_with_var_test", - "layerId": "11504144555", - "trafficAllocation": [{ - "entityId": "11617170975", - "endOfRange": 10000 - }], - "audienceIds": ["3468206642", "3988293898", "3988293899", "3468206646", "3468206647", "3468206644", "3468206643"], - "variations": [{ - "variables": [{ - "id": "11535264366", - "value": "xyz" - }], - "id": "11617170975", - "key": "variation_2", - "featureEnabled": true - }], - "forcedVariations": {}, - "id": "11564051718" - }, - { - "id": "1323241597", - "key": "typed_audience_experiment", - "layerId": "1630555627", - "status": "Running", - "variations": [{ - "id": "1423767503", - "key": "A", - "variables": [] - }], - "trafficAllocation": [{ - "entityId": "1423767503", - "endOfRange": 10000 - }], - "audienceIds": ["3468206642", "3988293898", "3988293899", "3468206646", "3468206647", "3468206644", "3468206643"], - "forcedVariations": {} - }, - { - "id": "1323241598", - "key": "audience_combinations_experiment", - "layerId": "1323241598", - "status": "Running", - "variations": [{ - "id": "1423767504", - "key": "A", - "variables": [] - }], - "trafficAllocation": [{ - "entityId": "1423767504", - "endOfRange": 10000 - }], - "audienceIds": ["0"], - "audienceConditions": ["and", ["or", "3468206642", "3988293898"], - ["or", "3988293899", "3468206646", "3468206647", "3468206644", "3468206643"] - ], - "forcedVariations": {} - }, - { - "id": "1323241599", - "key": "feat2_with_var_test", - "layerId": "1323241600", - "status": "Running", - "variations": [{ - "variables": [{ - "id": "11535264367", - "value": "150" - }], - "id": "1423767505", - "key": "variation_2", - "featureEnabled": true - }], - "trafficAllocation": [{ - "entityId": "1423767505", - "endOfRange": 10000 - }], - "audienceIds": ["0"], - "audienceConditions": ["and", ["or", "3468206642", "3988293898"], - ["or", "3988293899", "3468206646", "3468206647", "3468206644", "3468206643"] - ], - "forcedVariations": {} - } - ], - "audiences": [ - { - "id": "3468206642", - "name": "exactString", - "conditions": "[\"and\", [\"or\", [\"or\", {\"name\": \"house\", \"type\": \"custom_attribute\", \"value\": \"Gryffindor\"}]]]" - }, - { - "id": "3468206645", - "name": "notChrome", - "conditions": "[\"and\", [\"or\", [\"not\", [\"or\", {\"name\": \"browser_type\", \"type\": \"custom_attribute\", \"value\":\"Chrome\"}]]]]" - }, - { - "id": "3988293898", - "name": "$$dummySubstringString", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "3988293899", - "name": "$$dummyExists", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "3468206646", - "name": "$$dummyExactNumber", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "3468206647", - "name": "$$dummyGtNumber", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "3468206644", - "name": "$$dummyLtNumber", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "3468206643", - "name": "$$dummyExactBoolean", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "0", - "name": "$$dummy", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - }, - { - "id": "$opt_dummy_audience", - "name": "dummy_audience", - "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" - } - ], - "typedAudiences": [], - "groups": [], - "integrations": [ - { - "key": "odp", - "host": "https://api.zaius.com", - "publicKey": "fake-public-key", - "k1": 10, - "k2": true, - "k3": "any-value" - } - ], - "attributes": [{ - "key": "house", - "id": "594015" - }, - { - "key": "lasers", - "id": "594016" - }, - { - "key": "should_do_it", - "id": "594017" - }, - { - "key": "favorite_ice_cream", - "id": "594018" - } - ], - "botFiltering": false, - "accountId": "4879520872", - "events": [{ - "key": "item_bought", - "id": "594089", - "experimentIds": [ - "11564051718", - "1323241597" - ] - }, - { - "key": "user_signed_up", - "id": "594090", - "experimentIds": [ - "1323241598", - "1323241599" - ] - } - ], - "revision": "3", - "sdkKey": "typedAudienceDatafile", - "environmentKey": "Production" + "version": "4", + "rollouts": [ + { + "experiments": [ + { + "status": "Running", + "key": "feat_no_vars_rule", + "layerId": "11551226731", + "trafficAllocation": [ + { + "entityId": "11557362669", + "endOfRange": 10000 + } + ], + "audienceIds": [ + "3468206642", + "3988293898", + "3988293899", + "3468206646", + "3468206647", + "3468206644", + "3468206643" + ], + "variations": [ + { + "variables": [], + "id": "11557362669", + "key": "11557362669", + "featureEnabled": true + } + ], + "forcedVariations": {}, + "id": "11488548027" + } + ], + "id": "11551226731" + }, + { + "experiments": [ + { + "status": "Paused", + "key": "feat_with_var_rule", + "layerId": "11638870867", + "trafficAllocation": [ + { + "entityId": "11475708558", + "endOfRange": 0 + } + ], + "audienceIds": [], + "variations": [ + { + "variables": [], + "id": "11475708558", + "key": "11475708558", + "featureEnabled": false + } + ], + "forcedVariations": {}, + "id": "11630490911" + } + ], + "id": "11638870867" + }, + { + "experiments": [ + { + "status": "Running", + "key": "11488548028", + "layerId": "11551226732", + "trafficAllocation": [ + { + "entityId": "11557362670", + "endOfRange": 10000 + } + ], + "audienceIds": [ + "0" + ], + "audienceConditions": [ + "and", + [ + "or", + "3468206642", + "3988293898" + ], + [ + "or", + "3988293899", + "3468206646", + "3468206647", + "3468206644", + "3468206643" + ] + ], + "variations": [ + { + "variables": [], + "id": "11557362670", + "key": "11557362670", + "featureEnabled": true + } + ], + "forcedVariations": {}, + "id": "11488548028" + } + ], + "id": "11551226732" + }, + { + "experiments": [ + { + "status": "Paused", + "key": "11630490912", + "layerId": "11638870868", + "trafficAllocation": [ + { + "entityId": "11475708559", + "endOfRange": 0 + } + ], + "audienceIds": [], + "variations": [ + { + "variables": [], + "id": "11475708559", + "key": "11475708559", + "featureEnabled": false + } + ], + "forcedVariations": {}, + "id": "11630490912" + } + ], + "id": "11638870868" + } + ], + "anonymizeIP": false, + "projectId": "11624721371", + "variables": [], + "featureFlags": [ + { + "experimentIds": [], + "rolloutId": "11551226731", + "variables": [], + "id": "11477755619", + "key": "feat_no_vars" + }, + { + "experimentIds": [ + "11564051718" + ], + "rolloutId": "11638870867", + "variables": [ + { + "defaultValue": "x", + "type": "string", + "id": "11535264366", + "key": "x" + } + ], + "id": "11567102051", + "key": "feat_with_var" + }, + { + "experimentIds": [], + "rolloutId": "11551226732", + "variables": [], + "id": "11567102052", + "key": "feat2" + }, + { + "experimentIds": [ + "1323241599" + ], + "rolloutId": "11638870868", + "variables": [ + { + "defaultValue": "10", + "type": "integer", + "id": "11535264367", + "key": "z" + } + ], + "id": "11567102053", + "key": "feat2_with_var" + } + ], + "experiments": [ + { + "status": "Running", + "key": "feat_with_var_test", + "layerId": "11504144555", + "trafficAllocation": [ + { + "entityId": "11617170975", + "endOfRange": 10000 + } + ], + "audienceIds": [ + "3468206642", + "3988293898", + "3988293899", + "3468206646", + "3468206647", + "3468206644", + "3468206643" + ], + "variations": [ + { + "variables": [ + { + "id": "11535264366", + "value": "xyz" + } + ], + "id": "11617170975", + "key": "variation_2", + "featureEnabled": true + } + ], + "forcedVariations": {}, + "id": "11564051718" + }, + { + "id": "1323241597", + "key": "typed_audience_experiment", + "layerId": "1630555627", + "status": "Running", + "variations": [ + { + "id": "1423767503", + "key": "A", + "variables": [] + } + ], + "trafficAllocation": [ + { + "entityId": "1423767503", + "endOfRange": 10000 + } + ], + "audienceIds": [ + "3468206642", + "3988293898", + "3988293899", + "3468206646", + "3468206647", + "3468206644", + "3468206643" + ], + "forcedVariations": {} + }, + { + "id": "1323241598", + "key": "audience_combinations_experiment", + "layerId": "1323241598", + "status": "Running", + "variations": [ + { + "id": "1423767504", + "key": "A", + "variables": [] + } + ], + "trafficAllocation": [ + { + "entityId": "1423767504", + "endOfRange": 10000 + } + ], + "audienceIds": [ + "0" + ], + "audienceConditions": [ + "and", + [ + "or", + "3468206642", + "3988293898" + ], + [ + "or", + "3988293899", + "3468206646", + "3468206647", + "3468206644", + "3468206643" + ] + ], + "forcedVariations": {} + }, + { + "id": "1323241599", + "key": "feat2_with_var_test", + "layerId": "1323241600", + "status": "Running", + "variations": [ + { + "variables": [ + { + "id": "11535264367", + "value": "150" + } + ], + "id": "1423767505", + "key": "variation_2", + "featureEnabled": true + } + ], + "trafficAllocation": [ + { + "entityId": "1423767505", + "endOfRange": 10000 + } + ], + "audienceIds": [ + "0" + ], + "audienceConditions": [ + "and", + [ + "or", + "3468206642", + "3988293898" + ], + [ + "or", + "3988293899", + "3468206646", + "3468206647", + "3468206644", + "3468206643" + ] + ], + "forcedVariations": {} + } + ], + "audiences": [ + { + "id": "3468206642", + "name": "exactString", + "conditions": "[\"and\", [\"or\", [\"or\", {\"name\": \"house\", \"type\": \"custom_attribute\", \"value\": \"Gryffindor\"}]]]" + }, + { + "id": "3468206645", + "name": "notChrome", + "conditions": "[\"and\", [\"or\", [\"not\", [\"or\", {\"name\": \"browser_type\", \"type\": \"custom_attribute\", \"value\":\"Chrome\"}]]]]" + }, + { + "id": "3988293898", + "name": "$$dummySubstringString", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "3988293899", + "name": "$$dummyExists", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "3468206646", + "name": "$$dummyExactNumber", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "3468206647", + "name": "$$dummyGtNumber", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "3468206644", + "name": "$$dummyLtNumber", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "3468206643", + "name": "$$dummyExactBoolean", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "0", + "name": "$$dummy", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + }, + { + "id": "$opt_dummy_audience", + "name": "dummy_audience", + "conditions": "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}" + } + ], + "typedAudiences": [], + "groups": [], + "integrations": [ + { + "key": "odp", + "host": "https://api.zaius.com", + "publicKey": "fake-public-key", + "k1": 10, + "k2": true, + "k3": "any-value" + } + ], + "attributes": [ + { + "key": "house", + "id": "594015" + }, + { + "key": "lasers", + "id": "594016" + }, + { + "key": "should_do_it", + "id": "594017" + }, + { + "key": "favorite_ice_cream", + "id": "594018" + } + ], + "botFiltering": false, + "accountId": "4879520872", + "events": [ + { + "key": "item_bought", + "id": "594089", + "experimentIds": [ + "11564051718", + "1323241597" + ] + }, + { + "key": "user_signed_up", + "id": "594090", + "experimentIds": [ + "1323241598", + "1323241599" + ] + } + ], + "revision": "3", + "sdkKey": "typedAudienceDatafile", + "environmentKey": "Production" } diff --git a/OptimizelySDK.Tests/InvalidEventDispatcher.cs b/OptimizelySDK.Tests/InvalidEventDispatcher.cs index db88a3a95..be6ea26f5 100644 --- a/OptimizelySDK.Tests/InvalidEventDispatcher.cs +++ b/OptimizelySDK.Tests/InvalidEventDispatcher.cs @@ -13,18 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +using System; using OptimizelySDK.Event.Dispatcher; using OptimizelySDK.Logger; -using System; namespace OptimizelySDK.Tests { - class InvalidEventDispatcher : IEventDispatcher + internal class InvalidEventDispatcher : IEventDispatcher { public ILogger Logger { get; set; } + public void DispatchEvent(Event.LogEvent logEvent) { throw new Exception("Invalid dispatch event"); } } -} \ No newline at end of file +} diff --git a/OptimizelySDK.Tests/NotificationTests/NotificationCenterTests.cs b/OptimizelySDK.Tests/NotificationTests/NotificationCenterTests.cs index 8b6d68066..5683373eb 100644 --- a/OptimizelySDK.Tests/NotificationTests/NotificationCenterTests.cs +++ b/OptimizelySDK.Tests/NotificationTests/NotificationCenterTests.cs @@ -14,6 +14,8 @@ * limitations under the License. */ +using System; +using System.Collections.Generic; using Moq; using NUnit.Framework; using OptimizelySDK.Config; @@ -22,8 +24,6 @@ using OptimizelySDK.Event; using OptimizelySDK.Logger; using OptimizelySDK.Notifications; -using System; -using System.Collections.Generic; using NotificationType = OptimizelySDK.Notifications.NotificationCenter.NotificationType; namespace OptimizelySDK.Tests.NotificationTests @@ -48,10 +48,13 @@ public void Setup() } [Test] + [Obsolete] public void TestAddAndRemoveNotificationListener() { // Verify that callback added successfully. - Assert.AreEqual(1, NotificationCenter.AddNotification(NotificationTypeActivate, TestNotificationCallbacks.TestActivateCallback)); + Assert.AreEqual(1, + NotificationCenter.AddNotification(NotificationTypeActivate, + TestNotificationCallbacks.TestActivateCallback)); Assert.AreEqual(1, NotificationCenter.NotificationsCount); // Verify that callback removed successfully. @@ -62,44 +65,59 @@ public void TestAddAndRemoveNotificationListener() Assert.AreEqual(false, NotificationCenter.RemoveNotification(1)); // Verify that callback added successfully and return right notification ID. - Assert.AreEqual(NotificationCenter.NotificationId, NotificationCenter.AddNotification(NotificationTypeActivate, TestNotificationCallbacks.TestActivateCallback)); + Assert.AreEqual(NotificationCenter.NotificationId, + NotificationCenter.AddNotification(NotificationTypeActivate, + TestNotificationCallbacks.TestActivateCallback)); Assert.AreEqual(1, NotificationCenter.NotificationsCount); } [Test] + [Obsolete] public void TestAddMultipleNotificationListeners() { - NotificationCenter.AddNotification(NotificationTypeActivate, TestNotificationCallbacks.TestActivateCallback); - NotificationCenter.AddNotification(NotificationTypeActivate, TestNotificationCallbacks.TestAnotherActivateCallback); + NotificationCenter.AddNotification(NotificationTypeActivate, + TestNotificationCallbacks.TestActivateCallback); + NotificationCenter.AddNotification(NotificationTypeActivate, + TestNotificationCallbacks.TestAnotherActivateCallback); // Verify that multiple notifications will be added for same notification type. Assert.AreEqual(2, NotificationCenter.NotificationsCount); // Verify that notifications of other types will also gets added successfully. - NotificationCenter.AddNotification(NotificationTypeTrack, TestNotificationCallbacks.TestTrackCallback); + NotificationCenter.AddNotification(NotificationTypeTrack, + TestNotificationCallbacks.TestTrackCallback); Assert.AreEqual(3, NotificationCenter.NotificationsCount); // Verify that notifications of other types will also gets added successfully. - NotificationCenter.AddNotification(NotificationType.OptimizelyConfigUpdate, TestNotificationCallbacks.TestConfigUpdateCallback); + NotificationCenter.AddNotification(NotificationType.OptimizelyConfigUpdate, + TestNotificationCallbacks.TestConfigUpdateCallback); Assert.AreEqual(4, NotificationCenter.NotificationsCount); // Verify that notifications of other types will also gets added successfully. - NotificationCenter.AddNotification(NotificationType.LogEvent, TestNotificationCallbacks.TestLogEventCallback); + NotificationCenter.AddNotification(NotificationType.LogEvent, + TestNotificationCallbacks.TestLogEventCallback); Assert.AreEqual(5, NotificationCenter.NotificationsCount); } [Test] + [Obsolete] public void TestAddSameNotificationListenerMultipleTimes() { - NotificationCenter.AddNotification(NotificationTypeActivate, TestNotificationCallbacks.TestActivateCallback); + NotificationCenter.AddNotification(NotificationTypeActivate, + TestNotificationCallbacks.TestActivateCallback); // Verify that adding same callback multiple times will gets failed. - Assert.AreEqual(-1, NotificationCenter.AddNotification(NotificationTypeActivate, TestNotificationCallbacks.TestActivateCallback)); + Assert.AreEqual(-1, + NotificationCenter.AddNotification(NotificationTypeActivate, + TestNotificationCallbacks.TestActivateCallback)); Assert.AreEqual(1, NotificationCenter.NotificationsCount); - LoggerMock.Verify(l => l.Log(LogLevel.ERROR, "The notification callback already exists."), Times.Once); + LoggerMock.Verify( + l => l.Log(LogLevel.ERROR, "The notification callback already exists."), + Times.Once); } [Test] + [Obsolete] public void TestAddInvalidNotificationListeners() { // Verify that AddNotification gets failed on adding invalid notification listeners. @@ -107,7 +125,10 @@ public void TestAddInvalidNotificationListeners() TestNotificationCallbacks.TestActivateCallback)); - LoggerMock.Verify(l => l.Log(LogLevel.ERROR, $@"Invalid notification type provided for ""{NotificationTypeActivate}"" callback."), + LoggerMock.Verify( + l => l.Log(LogLevel.ERROR, + $@"Invalid notification type provided for ""{NotificationTypeActivate + }"" callback."), Times.Once); // Verify that no notifion has been added. @@ -115,20 +136,25 @@ public void TestAddInvalidNotificationListeners() } [Test] + [Obsolete] public void TestClearNotifications() { // Add decision notifications. - NotificationCenter.AddNotification(NotificationTypeActivate, TestNotificationCallbacks.TestActivateCallback); - NotificationCenter.AddNotification(NotificationTypeActivate, TestNotificationCallbacks.TestAnotherActivateCallback); + NotificationCenter.AddNotification(NotificationTypeActivate, + TestNotificationCallbacks.TestActivateCallback); + NotificationCenter.AddNotification(NotificationTypeActivate, + TestNotificationCallbacks.TestAnotherActivateCallback); // Add track notification. - NotificationCenter.AddNotification(NotificationTypeTrack, TestNotificationCallbacks.TestTrackCallback); + NotificationCenter.AddNotification(NotificationTypeTrack, + TestNotificationCallbacks.TestTrackCallback); // Verify that callbacks added successfully. Assert.AreEqual(3, NotificationCenter.NotificationsCount); // Add config update callback. - NotificationCenter.AddNotification(NotificationType.OptimizelyConfigUpdate, TestNotificationCallbacks.TestConfigUpdateCallback); + NotificationCenter.AddNotification(NotificationType.OptimizelyConfigUpdate, + TestNotificationCallbacks.TestConfigUpdateCallback); // Verify that callbacks added successfully. Assert.AreEqual(4, NotificationCenter.NotificationsCount); @@ -147,14 +173,18 @@ public void TestClearNotifications() } [Test] + [Obsolete] public void TestClearAllNotifications() { // Add decision notifications. - NotificationCenter.AddNotification(NotificationTypeActivate, TestNotificationCallbacks.TestActivateCallback); - NotificationCenter.AddNotification(NotificationTypeActivate, TestNotificationCallbacks.TestAnotherActivateCallback); + NotificationCenter.AddNotification(NotificationTypeActivate, + TestNotificationCallbacks.TestActivateCallback); + NotificationCenter.AddNotification(NotificationTypeActivate, + TestNotificationCallbacks.TestAnotherActivateCallback); // Add track notification. - NotificationCenter.AddNotification(NotificationTypeTrack, TestNotificationCallbacks.TestTrackCallback); + NotificationCenter.AddNotification(NotificationTypeTrack, + TestNotificationCallbacks.TestTrackCallback); // Verify that callbacks added successfully. Assert.AreEqual(3, NotificationCenter.NotificationsCount); @@ -170,71 +200,97 @@ public void TestClearAllNotifications() } [Test] + [Obsolete] public void TestSendNotifications() { - var config = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, new NoOpErrorHandler()); - var logEventMocker = new Mock("http://mockedurl", new Dictionary(), "POST", new Dictionary()); + var config = DatafileProjectConfig.Create(TestData.Datafile, LoggerMock.Object, + new NoOpErrorHandler()); + var logEventMocker = new Mock("http://mockedurl", + new Dictionary(), "POST", new Dictionary()); // Mocking notification callbacks. var notificationCallbackMock = new Mock(); - notificationCallbackMock.Setup(nc => nc.TestActivateCallback(It.IsAny(), It.IsAny(), + notificationCallbackMock.Setup(nc => nc.TestActivateCallback(It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())); - notificationCallbackMock.Setup(nc => nc.TestAnotherActivateCallback(It.IsAny(), - It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())); + notificationCallbackMock.Setup(nc => nc.TestAnotherActivateCallback( + It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny())); notificationCallbackMock.Setup(nc => nc.TestLogEventCallback(It.IsAny())); // Adding decision notifications. - NotificationCenter.AddNotification(NotificationTypeActivate, notificationCallbackMock.Object.TestActivateCallback); - NotificationCenter.AddNotification(NotificationTypeActivate, notificationCallbackMock.Object.TestAnotherActivateCallback); + NotificationCenter.AddNotification(NotificationTypeActivate, + notificationCallbackMock.Object.TestActivateCallback); + NotificationCenter.AddNotification(NotificationTypeActivate, + notificationCallbackMock.Object.TestAnotherActivateCallback); // Adding track notifications. - NotificationCenter.AddNotification(NotificationTypeTrack, notificationCallbackMock.Object.TestTrackCallback); + NotificationCenter.AddNotification(NotificationTypeTrack, + notificationCallbackMock.Object.TestTrackCallback); // Fire decision type notifications. - NotificationCenter.SendNotifications(NotificationTypeActivate, config.GetExperimentFromKey("test_experiment"), - "testUser", new UserAttributes(), config.GetVariationFromId("test_experiment", "7722370027"), logEventMocker.Object); + NotificationCenter.SendNotifications(NotificationTypeActivate, + config.GetExperimentFromKey("test_experiment"), + "testUser", new UserAttributes(), + config.GetVariationFromId("test_experiment", "7722370027"), logEventMocker.Object); // Verify that only the registered notifications of decision type are called. - notificationCallbackMock.Verify(nc => nc.TestActivateCallback(It.IsAny(), It.IsAny(), - It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + notificationCallbackMock.Verify(nc => nc.TestActivateCallback(It.IsAny(), + It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny()), + Times.Once); - notificationCallbackMock.Verify(nc => nc.TestAnotherActivateCallback(It.IsAny(), It.IsAny(), - It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + notificationCallbackMock.Verify(nc => nc.TestAnotherActivateCallback( + It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny()), + Times.Once); - notificationCallbackMock.Verify(nc => nc.TestTrackCallback(It.IsAny(), It.IsAny(), - It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + notificationCallbackMock.Verify(nc => nc.TestTrackCallback(It.IsAny(), + It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny()), + Times.Never); // Add logEvent Notification. - NotificationCenter.AddNotification(NotificationType.LogEvent, notificationCallbackMock.Object.TestLogEventCallback); + NotificationCenter.AddNotification(NotificationType.LogEvent, + notificationCallbackMock.Object.TestLogEventCallback); // Fire logEvent Notification. NotificationCenter.SendNotifications(NotificationType.LogEvent, logEventMocker.Object); // Verify that registered notifications of logEvent type are called. - notificationCallbackMock.Verify(nc => nc.TestLogEventCallback(It.IsAny()), Times.Once); + notificationCallbackMock.Verify(nc => nc.TestLogEventCallback(It.IsAny()), + Times.Once); // Verify that after clearing notifications, SendNotification should not call any notification // which were previously registered. NotificationCenter.ClearAllNotifications(); notificationCallbackMock.ResetCalls(); - NotificationCenter.SendNotifications(NotificationTypeActivate, config.GetExperimentFromKey("test_experiment"), - "testUser", new UserAttributes(), config.GetVariationFromId("test_experiment", "7722370027"), null); + NotificationCenter.SendNotifications(NotificationTypeActivate, + config.GetExperimentFromKey("test_experiment"), + "testUser", new UserAttributes(), + config.GetVariationFromId("test_experiment", "7722370027"), null); // Again verify notifications which were registered are not called. - notificationCallbackMock.Verify(nc => nc.TestActivateCallback(It.IsAny(), It.IsAny(), - It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); - - notificationCallbackMock.Verify(nc => nc.TestAnotherActivateCallback(It.IsAny(), It.IsAny(), - It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); - - notificationCallbackMock.Verify(nc => nc.TestTrackCallback(It.IsAny(), It.IsAny(), - It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + notificationCallbackMock.Verify(nc => nc.TestActivateCallback(It.IsAny(), + It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny()), + Times.Never); + + notificationCallbackMock.Verify(nc => nc.TestAnotherActivateCallback( + It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny()), + Times.Never); + + notificationCallbackMock.Verify(nc => nc.TestTrackCallback(It.IsAny(), + It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny()), + Times.Never); } - } #region Test Notification callbacks class. @@ -244,31 +300,40 @@ public void TestSendNotifications() /// public class TestNotificationCallbacks { - public virtual void TestActivateCallback(Experiment experiment, string userId, UserAttributes userAttributes, - Variation variation, LogEvent logEvent) { - } - - public virtual void TestAnotherActivateCallback(Experiment experiment, string userId, UserAttributes userAttributes, - Variation variation, LogEvent logEvent) { - } - - public virtual void TestTrackCallback(string eventKey, string userId, UserAttributes userAttributes, - EventTags eventTags, LogEvent logEvent) { - } - - public virtual void TestAnotherTrackCallback(string eventKey, string userId, UserAttributes userAttributes, - EventTags eventTags, LogEvent logEvent) { - } - - public virtual void TestDecisionCallback(string type, string userId, UserAttributes userAttributes, - Dictionary decisionInfo) { - } - - public virtual void TestConfigUpdateCallback() { - } - - public virtual void TestLogEventCallback(LogEvent logEvent) { - } + public virtual void TestActivateCallback(Experiment experiment, string userId, + UserAttributes userAttributes, + Variation variation, LogEvent logEvent + ) + { } + + public virtual void TestAnotherActivateCallback(Experiment experiment, string userId, + UserAttributes userAttributes, + Variation variation, LogEvent logEvent + ) + { } + + public virtual void TestTrackCallback(string eventKey, string userId, + UserAttributes userAttributes, + EventTags eventTags, LogEvent logEvent + ) + { } + + public virtual void TestAnotherTrackCallback(string eventKey, string userId, + UserAttributes userAttributes, + EventTags eventTags, LogEvent logEvent + ) + { } + + public virtual void TestDecisionCallback(string type, string userId, + UserAttributes userAttributes, + Dictionary decisionInfo + ) + { } + + public virtual void TestConfigUpdateCallback() { } + + public virtual void TestLogEventCallback(LogEvent logEvent) { } } + #endregion // Test Notification callbacks class. } diff --git a/OptimizelySDK.Tests/OdpTests/HttpClientTestUtil.cs b/OptimizelySDK.Tests/OdpTests/HttpClientTestUtil.cs index 8e2f0ac95..121e84020 100644 --- a/OptimizelySDK.Tests/OdpTests/HttpClientTestUtil.cs +++ b/OptimizelySDK.Tests/OdpTests/HttpClientTestUtil.cs @@ -14,13 +14,13 @@ * limitations under the License. */ -using Moq; -using Moq.Protected; using System; using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Moq; +using Moq.Protected; namespace OptimizelySDK.Tests.OdpTests { @@ -47,12 +47,12 @@ public static HttpClient MakeHttpClient(HttpStatusCode statusCode, } var mockedHandler = new Mock(); - mockedHandler.Protected() - .Setup>( + mockedHandler.Protected(). + Setup>( "SendAsync", ItExpr.IsAny(), - ItExpr.IsAny()) - .ReturnsAsync(response); + ItExpr.IsAny()). + ReturnsAsync(response); return new HttpClient(mockedHandler.Object); } @@ -63,12 +63,12 @@ public static HttpClient MakeHttpClient(HttpStatusCode statusCode, public static HttpClient MakeHttpClientWithTimeout() { var mockedHandler = new Mock(); - mockedHandler.Protected() - .Setup>( + mockedHandler.Protected(). + Setup>( "SendAsync", ItExpr.IsAny(), - ItExpr.IsAny()) - .Throws(); + ItExpr.IsAny()). + Throws(); return new HttpClient(mockedHandler.Object); } } diff --git a/OptimizelySDK.Tests/OdpTests/LruCacheTest.cs b/OptimizelySDK.Tests/OdpTests/LruCacheTest.cs index 27f8ee169..426240c54 100644 --- a/OptimizelySDK.Tests/OdpTests/LruCacheTest.cs +++ b/OptimizelySDK.Tests/OdpTests/LruCacheTest.cs @@ -14,11 +14,11 @@ * limitations under the License. */ -using NUnit.Framework; -using OptimizelySDK.Odp; using System; using System.Collections.Generic; using System.Threading; +using NUnit.Framework; +using OptimizelySDK.Odp; namespace OptimizelySDK.Tests.OdpTests { @@ -142,7 +142,7 @@ public void ShouldReorderListOnSave() [Test] public void ShouldHandleWhenCacheIsDisabled() { - var cache = new LruCache>(maxSize: 0); + var cache = new LruCache>(0); cache.Save("user1", _segments1And2); cache.Save("user2", _segments3And4); @@ -172,7 +172,7 @@ public void ShouldHandleWhenItemsExpire() [Test] public void ShouldHandleWhenCacheReachesMaxSize() { - var cache = new LruCache>(maxSize: 2); + var cache = new LruCache>(2); cache.Save("user1", _segments1And2); cache.Save("user2", _segments3And4); diff --git a/OptimizelySDK.Tests/OdpTests/OdpConfigTest.cs b/OptimizelySDK.Tests/OdpTests/OdpConfigTest.cs index a948e6610..dc28a9fe5 100644 --- a/OptimizelySDK.Tests/OdpTests/OdpConfigTest.cs +++ b/OptimizelySDK.Tests/OdpTests/OdpConfigTest.cs @@ -14,9 +14,9 @@ * limitations under the License. */ +using System.Collections.Generic; using NUnit.Framework; using OptimizelySDK.Odp; -using System.Collections.Generic; namespace OptimizelySDK.Tests.OdpTests { diff --git a/OptimizelySDK.Tests/OdpTests/OdpEventApiManagerTest.cs b/OptimizelySDK.Tests/OdpTests/OdpEventApiManagerTest.cs index 2a987625b..f509775df 100644 --- a/OptimizelySDK.Tests/OdpTests/OdpEventApiManagerTest.cs +++ b/OptimizelySDK.Tests/OdpTests/OdpEventApiManagerTest.cs @@ -14,14 +14,14 @@ * limitations under the License. */ +using System.Collections.Generic; +using System.Net; using Moq; using NUnit.Framework; using OptimizelySDK.ErrorHandler; using OptimizelySDK.Logger; using OptimizelySDK.Odp; using OptimizelySDK.Odp.Entity; -using System.Collections.Generic; -using System.Net; namespace OptimizelySDK.Tests.OdpTests { @@ -121,7 +121,8 @@ public void ShouldSuggestRetryFor500HttpResponse() } [Test] - public void ShouldSuggestRetryForNetworkTimeout() { + public void ShouldSuggestRetryForNetworkTimeout() + { var httpClient = HttpClientTestUtil.MakeHttpClientWithTimeout(); var manger = new OdpEventApiManager(_mockLogger.Object, _mockErrorHandler.Object, httpClient); @@ -129,6 +130,7 @@ public void ShouldSuggestRetryForNetworkTimeout() { var shouldRetry = manger.SendEvents(VALID_ODP_PUBLIC_KEY, ODP_REST_API_HOST, _odpEvents); - Assert.IsTrue(shouldRetry);} + Assert.IsTrue(shouldRetry); + } } } diff --git a/OptimizelySDK.Tests/OdpTests/OdpEventManagerTests.cs b/OptimizelySDK.Tests/OdpTests/OdpEventManagerTests.cs index 87ce608da..38f5b4b6e 100644 --- a/OptimizelySDK.Tests/OdpTests/OdpEventManagerTests.cs +++ b/OptimizelySDK.Tests/OdpTests/OdpEventManagerTests.cs @@ -14,17 +14,17 @@ * limitations under the License. */ -using Moq; -using NUnit.Framework; -using OptimizelySDK.Logger; -using OptimizelySDK.Odp; -using OptimizelySDK.Odp.Entity; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Moq; +using NUnit.Framework; +using OptimizelySDK.Logger; +using OptimizelySDK.Odp; +using OptimizelySDK.Odp.Entity; namespace OptimizelySDK.Tests.OdpTests { @@ -345,7 +345,7 @@ public void ShouldDispatchEventsInCorrectNumberOfBatches() Build(); eventManager.UpdateSettings(_odpConfig); - for (int i = 0; i < 25; i++) + for (var i = 0; i < 25; i++) { eventManager.SendEvent(MakeEvent(i)); } @@ -412,7 +412,7 @@ public void ShouldRetryFailedEvents() Build(); eventManager.UpdateSettings(_odpConfig); - for (int i = 0; i < 4; i++) // send 4 events in batches of 1 + for (var i = 0; i < 4; i++) // send 4 events in batches of 1 { eventManager.SendEvent(MakeEvent(i)); } @@ -436,7 +436,7 @@ public void ShouldFlushAllScheduledEventsBeforeStopping() Build(); eventManager.UpdateSettings(_odpConfig); - for (int i = 0; i < 25; i++) + for (var i = 0; i < 25; i++) { eventManager.SendEvent(MakeEvent(i)); } @@ -509,23 +509,26 @@ public void ShouldApplyUpdatedOdpConfigurationWhenAvailable() Assert.IsFalse(_odpConfig.Equals(eventManager.OdpConfigForTesting)); } - private static OdpEvent MakeEvent(int id) => - new OdpEvent($"test-type-{id}", $"test-action-{id}", new Dictionary - { - { - "an-identifier", $"value1-{id}" - }, - { - "another-identity", $"value2-{id}" - }, - }, new Dictionary - { + private static OdpEvent MakeEvent(int id) + { + return new OdpEvent($"test-type-{id}", $"test-action-{id}", + new Dictionary { - "data1", $"data1-value1-{id}" - }, + { + "an-identifier", $"value1-{id}" + }, + { + "another-identity", $"value2-{id}" + }, + }, new Dictionary { - "data2", id - }, - }); + { + "data1", $"data1-value1-{id}" + }, + { + "data2", id + }, + }); + } } } diff --git a/OptimizelySDK.Tests/OdpTests/OdpManagerTest.cs b/OptimizelySDK.Tests/OdpTests/OdpManagerTest.cs index a1adaafcb..6b2bc9aca 100644 --- a/OptimizelySDK.Tests/OdpTests/OdpManagerTest.cs +++ b/OptimizelySDK.Tests/OdpTests/OdpManagerTest.cs @@ -14,14 +14,14 @@ * limitations under the License. */ +using System; +using System.Collections.Generic; +using System.Linq; using Moq; using NUnit.Framework; using OptimizelySDK.Logger; using OptimizelySDK.Odp; using OptimizelySDK.Odp.Entity; -using System; -using System.Collections.Generic; -using System.Linq; namespace OptimizelySDK.Tests.OdpTests { @@ -87,7 +87,7 @@ public void ShouldInitializeWithCorrectDefaults() WithLogger(_mockLogger.Object). Build(); - var eventManager = (manager.EventManager as OdpEventManager); + var eventManager = manager.EventManager as OdpEventManager; var segmentCache = (manager.SegmentManager as OdpSegmentManager)?.SegmentsCacheForTesting as LruCache>; @@ -96,7 +96,8 @@ public void ShouldInitializeWithCorrectDefaults() Assert.AreEqual(Constants.DEFAULT_TIMEOUT_INTERVAL, eventManager.TimeoutIntervalForTesting); Assert.AreEqual(Constants.DEFAULT_MAX_CACHE_SIZE, segmentCache?.MaxSizeForTesting); - Assert.AreEqual(TimeSpan.FromSeconds(Constants.DEFAULT_CACHE_SECONDS), segmentCache.TimeoutForTesting); + Assert.AreEqual(TimeSpan.FromSeconds(Constants.DEFAULT_CACHE_SECONDS), + segmentCache.TimeoutForTesting); } [Test] diff --git a/OptimizelySDK.Tests/OdpTests/OdpSegmentApiManagerTest.cs b/OptimizelySDK.Tests/OdpTests/OdpSegmentApiManagerTest.cs index 67b668c1a..014d92f89 100644 --- a/OptimizelySDK.Tests/OdpTests/OdpSegmentApiManagerTest.cs +++ b/OptimizelySDK.Tests/OdpTests/OdpSegmentApiManagerTest.cs @@ -14,14 +14,14 @@ * limitations under the License. */ +using System.Collections.Generic; +using System.Net; using Moq; using NUnit.Framework; using OptimizelySDK.AudienceConditions; using OptimizelySDK.ErrorHandler; using OptimizelySDK.Logger; using OptimizelySDK.Odp; -using System.Collections.Generic; -using System.Net; namespace OptimizelySDK.Tests.OdpTests { diff --git a/OptimizelySDK.Tests/OdpTests/OdpSegmentManagerTest.cs b/OptimizelySDK.Tests/OdpTests/OdpSegmentManagerTest.cs index d1db2d6b3..ac4e37a7e 100644 --- a/OptimizelySDK.Tests/OdpTests/OdpSegmentManagerTest.cs +++ b/OptimizelySDK.Tests/OdpTests/OdpSegmentManagerTest.cs @@ -14,16 +14,16 @@ * limitations under the License. */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; using Moq; using NUnit.Framework; using OptimizelySDK.AudienceConditions; using OptimizelySDK.ErrorHandler; using OptimizelySDK.Logger; using OptimizelySDK.Odp; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; namespace OptimizelySDK.Tests.OdpTests { @@ -36,7 +36,8 @@ public class OdpSegmentManagerTest private static readonly string expectedCacheKey = $"fs_user_id-$-{FS_USER_ID}"; - private static readonly List segmentsToCheck = new List { "segment1", "segment2", }; + private static readonly List segmentsToCheck = new List + { "segment1", "segment2" }; private OdpConfig _odpConfig; private Mock _mockApiManager; @@ -60,10 +61,11 @@ public void Setup() public void ShouldFetchSegmentsOnCacheMiss() { var keyCollector = new List(); - _mockCache.Setup(c => c.Lookup(Capture.In(keyCollector))).Returns(default(List)); + _mockCache.Setup(c => c.Lookup(Capture.In(keyCollector))). + Returns(default(List)); _mockApiManager.Setup(a => a.FetchSegments(It.IsAny(), It.IsAny(), - It.IsAny(), It.IsAny(), It.IsAny>())) - .Returns(segmentsToCheck.ToArray()); + It.IsAny(), It.IsAny(), It.IsAny>())). + Returns(segmentsToCheck.ToArray()); var manager = new OdpSegmentManager(_mockApiManager.Object, _mockCache.Object, _mockLogger.Object); manager.UpdateSettings(_odpConfig); @@ -119,8 +121,8 @@ public void ShouldHandleFetchSegmentsWithError() { // OdpSegmentApiManager.FetchSegments() return null on any error _mockApiManager.Setup(a => a.FetchSegments(It.IsAny(), It.IsAny(), - It.IsAny(), It.IsAny(), It.IsAny>())) - .Returns(null as string[]); + It.IsAny(), It.IsAny(), It.IsAny>())). + Returns(null as string[]); var manager = new OdpSegmentManager(_mockApiManager.Object, _mockCache.Object, _mockLogger.Object); manager.UpdateSettings(_odpConfig); @@ -178,7 +180,8 @@ public void ShouldIgnoreCache() _mockLogger.Object); manager.UpdateSettings(_odpConfig); - manager.FetchQualifiedSegments(FS_USER_ID, new List { OdpSegmentOption.IGNORE_CACHE, }); + manager.FetchQualifiedSegments(FS_USER_ID, + new List { OdpSegmentOption.IGNORE_CACHE }); _mockCache.Verify(c => c.Reset(), Times.Never); _mockCache.Verify(c => c.Lookup(It.IsAny()), Times.Never); @@ -196,7 +199,8 @@ public void ShouldResetCache() _mockLogger.Object); manager.UpdateSettings(_odpConfig); - manager.FetchQualifiedSegments(FS_USER_ID, new List { OdpSegmentOption.RESET_CACHE, }); + manager.FetchQualifiedSegments(FS_USER_ID, + new List { OdpSegmentOption.RESET_CACHE }); _mockCache.Verify(c => c.Reset(), Times.Once); _mockCache.Verify(c => c.Lookup(It.IsAny()), Times.Once); diff --git a/OptimizelySDK.Tests/OptimizelyConfigTests/OptimizelyConfigTest.cs b/OptimizelySDK.Tests/OptimizelyConfigTests/OptimizelyConfigTest.cs index 0689e6a2f..108834164 100644 --- a/OptimizelySDK.Tests/OptimizelyConfigTests/OptimizelyConfigTest.cs +++ b/OptimizelySDK.Tests/OptimizelyConfigTests/OptimizelyConfigTest.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright 2020-2022, Optimizely * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,6 +14,8 @@ * limitations under the License. */ +using System; +using System.Collections.Generic; using Moq; using Newtonsoft.Json.Linq; using NUnit.Framework; @@ -21,8 +23,6 @@ using OptimizelySDK.Logger; using OptimizelySDK.OptlyConfig; using OptimizelySDK.Tests.UtilsTests; -using System; -using System.Collections.Generic; namespace OptimizelySDK.Tests.OptimizelyConfigTests { @@ -40,23 +40,25 @@ public void Setup() #region Test OptimizelyConfigService - private static Type[] ParameterTypes = { - typeof(ProjectConfig), - }; + private static Type[] ParameterTypes = + { + typeof(ProjectConfig), + }; private PrivateObject CreatePrivateOptimizelyConfigService(ProjectConfig projectConfig) { return new PrivateObject(typeof(OptimizelyConfigService), ParameterTypes, - new object[] - { - projectConfig - }); + new object[] + { + projectConfig, + }); } [Test] public void TestGetOptimizelyConfigServiceSerializedAudiences() { - var datafileProjectConfig = DatafileProjectConfig.Create(TestData.TypedAudienceDatafile, new NoOpLogger(), new ErrorHandler.NoOpErrorHandler()); + var datafileProjectConfig = DatafileProjectConfig.Create(TestData.TypedAudienceDatafile, + new NoOpLogger(), new ErrorHandler.NoOpErrorHandler()); var optlyConfigService = CreatePrivateOptimizelyConfigService(datafileProjectConfig); var audienceConditions = new List> @@ -68,8 +70,16 @@ public void TestGetOptimizelyConfigServiceSerializedAudiences() new List() { "and", "3468206642" }, new List() { "3468206642" }, new List() { "3468206642", "3988293898" }, - new List() { "and", new JArray() { "or", "3468206642", "3988293898" }, "3468206646" }, - new List() { "and", new JArray() { "or", "3468206642", new JArray() { "and", "3988293898", "3468206646" } }, new JArray() { "and", "3988293899", new JArray() { "or", "3468206647", "3468206643" } } }, + new List() + { "and", new JArray() { "or", "3468206642", "3988293898" }, "3468206646" }, + new List() + { + "and", + new JArray() + { "or", "3468206642", new JArray() { "and", "3988293898", "3468206646" } }, + new JArray() + { "and", "3988293899", new JArray() { "or", "3468206647", "3468206643" } }, + }, new List() { "and", "and" }, new List() { "not", new JArray() { "and", "3468206642", "3988293898" } }, new List() { }, @@ -93,9 +103,10 @@ public void TestGetOptimizelyConfigServiceSerializedAudiences() "\"exactString\" OR \"999999999\"", }; - for (int testNo = 0; testNo < audienceConditions.Count; testNo++) + for (var testNo = 0; testNo < audienceConditions.Count; testNo++) { - var result = (string)optlyConfigService.Invoke("GetSerializedAudiences", audienceConditions[testNo], datafileProjectConfig.AudienceIdMap); + var result = (string)optlyConfigService.Invoke("GetSerializedAudiences", + audienceConditions[testNo], datafileProjectConfig.AudienceIdMap); Assert.AreEqual(result, expectedAudienceOutputs[testNo]); } } @@ -103,12 +114,12 @@ public void TestGetOptimizelyConfigServiceSerializedAudiences() [Test] public void TestAfterDisposeGetOptimizelyConfigIsNoLongerValid() { - var httpManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z") - .WithDatafile(TestData.Datafile) - .WithPollingInterval(TimeSpan.FromMilliseconds(50000)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)) - .Build(true); + var httpManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("QBw9gFM8oTn7ogY9ANCC1z"). + WithDatafile(TestData.Datafile). + WithPollingInterval(TimeSpan.FromMilliseconds(50000)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(500)). + Build(true); var optimizely = new Optimizely(httpManager); httpManager.Start(); @@ -128,20 +139,25 @@ public void TestAfterDisposeGetOptimizelyConfigIsNoLongerValid() [Test] public void TestGetOptimizelyConfigServiceNullConfig() { - OptimizelyConfig optimizelyConfig = new OptimizelyConfigService(null).GetOptimizelyConfig(); + var optimizelyConfig = new OptimizelyConfigService(null).GetOptimizelyConfig(); Assert.IsNull(optimizelyConfig); } [Test] + [Obsolete] public void TestGetOptimizelyConfigWithDuplicateExperimentKeys() { - var datafileProjectConfig = DatafileProjectConfig.Create(TestData.DuplicateExpKeysDatafile, new NoOpLogger(), new ErrorHandler.NoOpErrorHandler()); + var datafileProjectConfig = DatafileProjectConfig.Create( + TestData.DuplicateExpKeysDatafile, new NoOpLogger(), + new ErrorHandler.NoOpErrorHandler()); var optimizelyConfigService = new OptimizelyConfigService(datafileProjectConfig); var optimizelyConfig = optimizelyConfigService.GetOptimizelyConfig(); Assert.AreEqual(optimizelyConfig.ExperimentsMap.Count, 1); - var experimentMapFlag1 = optimizelyConfig.FeaturesMap["flag1"].ExperimentsMap; //9300000007569 - var experimentMapFlag2 = optimizelyConfig.FeaturesMap["flag2"].ExperimentsMap; // 9300000007573 + var experimentMapFlag1 = + optimizelyConfig.FeaturesMap["flag1"].ExperimentsMap; //9300000007569 + var experimentMapFlag2 = + optimizelyConfig.FeaturesMap["flag2"].ExperimentsMap; // 9300000007573 Assert.AreEqual(experimentMapFlag1["targeted_delivery"].Id, "9300000007569"); Assert.AreEqual(experimentMapFlag2["targeted_delivery"].Id, "9300000007573"); } @@ -149,14 +165,19 @@ public void TestGetOptimizelyConfigWithDuplicateExperimentKeys() [Test] public void TestGetOptimizelyConfigWithDuplicateRuleKeys() { - var datafileProjectConfig = DatafileProjectConfig.Create(TestData.DuplicateRuleKeysDatafile, new NoOpLogger(), new ErrorHandler.NoOpErrorHandler()); + var datafileProjectConfig = DatafileProjectConfig.Create( + TestData.DuplicateRuleKeysDatafile, new NoOpLogger(), + new ErrorHandler.NoOpErrorHandler()); var optimizelyConfigService = new OptimizelyConfigService(datafileProjectConfig); var optimizelyConfig = optimizelyConfigService.GetOptimizelyConfig(); Assert.AreEqual(optimizelyConfig.ExperimentsMap.Count, 0); - var rolloutFlag1 = optimizelyConfig.FeaturesMap["flag_1"].DeliveryRules[0]; // 9300000004977, - var rolloutFlag2 = optimizelyConfig.FeaturesMap["flag_2"].DeliveryRules[0]; // 9300000004979 - var rolloutFlag3 = optimizelyConfig.FeaturesMap["flag_3"].DeliveryRules[0]; // 9300000004981 + var rolloutFlag1 = + optimizelyConfig.FeaturesMap["flag_1"].DeliveryRules[0]; // 9300000004977, + var rolloutFlag2 = + optimizelyConfig.FeaturesMap["flag_2"].DeliveryRules[0]; // 9300000004979 + var rolloutFlag3 = + optimizelyConfig.FeaturesMap["flag_3"].DeliveryRules[0]; // 9300000004981 Assert.AreEqual(rolloutFlag1.Id, "9300000004977"); Assert.AreEqual(rolloutFlag1.Key, "targeted_delivery"); Assert.AreEqual(rolloutFlag2.Id, "9300000004979"); @@ -168,7 +189,9 @@ public void TestGetOptimizelyConfigWithDuplicateRuleKeys() [Test] public void TestGetOptimizelyConfigSDKAndEnvironmentKeyDefault() { - var datafileProjectConfig = DatafileProjectConfig.Create(TestData.DuplicateRuleKeysDatafile, new NoOpLogger(), new ErrorHandler.NoOpErrorHandler()); + var datafileProjectConfig = DatafileProjectConfig.Create( + TestData.DuplicateRuleKeysDatafile, new NoOpLogger(), + new ErrorHandler.NoOpErrorHandler()); var optimizelyConfigService = new OptimizelyConfigService(datafileProjectConfig); var optimizelyConfig = optimizelyConfigService.GetOptimizelyConfig(); @@ -179,376 +202,405 @@ public void TestGetOptimizelyConfigSDKAndEnvironmentKeyDefault() [Test] public void TestGetOptimizelyConfigService() { - var datafileProjectConfig = DatafileProjectConfig.Create(TestData.TypedAudienceDatafile, new NoOpLogger(), new ErrorHandler.NoOpErrorHandler()); - IDictionary experimentsMap = new Dictionary - { + var datafileProjectConfig = DatafileProjectConfig.Create(TestData.TypedAudienceDatafile, + new NoOpLogger(), new ErrorHandler.NoOpErrorHandler()); + IDictionary experimentsMap = + new Dictionary { - "feat_with_var_test", new OptimizelyExperiment ( - id: "11564051718", - key:"feat_with_var_test", - audiences: "", - variationsMap: new Dictionary - { + { + "feat_with_var_test", new OptimizelyExperiment( + "11564051718", + "feat_with_var_test", + "", + new Dictionary { - "variation_2", new OptimizelyVariation ( - id: "11617170975", - key: "variation_2", - featureEnabled: true, - variablesMap: new Dictionary - { + { + "variation_2", new OptimizelyVariation( + "11617170975", + "variation_2", + true, + new Dictionary { - "x" , new OptimizelyVariable ( - id: "11535264366", - key: "x", - type: "string", - value: "xyz") - } - }) + { + "x", new OptimizelyVariable( + "11535264366", + "x", + "string", + "xyz") + }, + }) + }, } - } - ) - }, - { - "typed_audience_experiment", new OptimizelyExperiment ( - id: "1323241597", - key:"typed_audience_experiment", - audiences: "", - variationsMap: new Dictionary - { + ) + }, + { + "typed_audience_experiment", new OptimizelyExperiment( + "1323241597", + "typed_audience_experiment", + "", + new Dictionary { - "A", new OptimizelyVariation ( - id: "1423767503", - key: "A", - featureEnabled: null, - variablesMap: new Dictionary ()) + { + "A", new OptimizelyVariation( + "1423767503", + "A", + null, + new Dictionary()) + }, } - } - ) - }, - { - "audience_combinations_experiment", new OptimizelyExperiment ( - id: "1323241598", - key:"audience_combinations_experiment", - audiences: "(\"exactString\" OR \"substringString\") AND (\"exists\" OR \"exactNumber\" OR \"gtNumber\" OR \"ltNumber\" OR \"exactBoolean\")", - variationsMap: new Dictionary - { + ) + }, + { + "audience_combinations_experiment", new OptimizelyExperiment( + "1323241598", + "audience_combinations_experiment", + "(\"exactString\" OR \"substringString\") AND (\"exists\" OR \"exactNumber\" OR \"gtNumber\" OR \"ltNumber\" OR \"exactBoolean\")", + new Dictionary { - "A", new OptimizelyVariation ( - id: "1423767504", - key: "A", - featureEnabled: null, - variablesMap: new Dictionary ()) + { + "A", new OptimizelyVariation( + "1423767504", + "A", + null, + new Dictionary()) + }, } - } - ) - }, - { - "feat2_with_var_test", new OptimizelyExperiment( - id: "1323241599", - key:"feat2_with_var_test", - audiences: "(\"exactString\" OR \"substringString\") AND (\"exists\" OR \"exactNumber\" OR \"gtNumber\" OR \"ltNumber\" OR \"exactBoolean\")", - variationsMap: new Dictionary - { + ) + }, + { + "feat2_with_var_test", new OptimizelyExperiment( + "1323241599", + "feat2_with_var_test", + "(\"exactString\" OR \"substringString\") AND (\"exists\" OR \"exactNumber\" OR \"gtNumber\" OR \"ltNumber\" OR \"exactBoolean\")", + new Dictionary { - "variation_2", new OptimizelyVariation ( - id: "1423767505", - key: "variation_2", - featureEnabled: true, - variablesMap: new Dictionary - { + { + "variation_2", new OptimizelyVariation( + "1423767505", + "variation_2", + true, + new Dictionary { - "z" , new OptimizelyVariable ( - id: "11535264367", - key: "z", - type: "integer", - value: "150") - } - }) + { + "z", new OptimizelyVariable( + "11535264367", + "z", + "integer", + "150") + }, + }) + }, } - } - ) - } - }; + ) + }, + }; var featuresMap = new Dictionary { { - "feat_no_vars", new OptimizelyFeature ( - id: "11477755619", - key: "feat_no_vars", - experimentRules: new List(), - deliveryRules: new List() { new OptimizelyExperiment( - id: "11488548027", - key:"feat_no_vars_rule", - audiences: "", - variationsMap: new Dictionary - { - { - "11557362669", new OptimizelyVariation ( - id: "11557362669", - key: "11557362669", - featureEnabled: true, - variablesMap: new Dictionary()) - } - } - ) }, - experimentsMap: new Dictionary(), - variablesMap: new Dictionary()) + "feat_no_vars", new OptimizelyFeature( + "11477755619", + "feat_no_vars", + new List(), + new List() + { + new OptimizelyExperiment( + "11488548027", + "feat_no_vars_rule", + "", + new Dictionary + { + { + "11557362669", new OptimizelyVariation( + "11557362669", + "11557362669", + true, + new Dictionary()) + }, + } + ), + }, + new Dictionary(), + new Dictionary()) }, { - "feat_with_var", new OptimizelyFeature ( - id: "11567102051", - key: "feat_with_var", - experimentRules: new List() { + "feat_with_var", new OptimizelyFeature( + "11567102051", + "feat_with_var", + new List() + { new OptimizelyExperiment( - id: "11564051718", - key:"feat_with_var_test", - audiences: "", - variationsMap: new Dictionary + "11564051718", + "feat_with_var_test", + "", + new Dictionary + { { - { - "variation_2", new OptimizelyVariation ( - id: "11617170975", - key: "variation_2", - featureEnabled: true, - variablesMap: new Dictionary + "variation_2", new OptimizelyVariation( + "11617170975", + "variation_2", + true, + new Dictionary + { { - { - "x" , new OptimizelyVariable ( - id: "11535264366", - key: "x", - type: "string", - value: "xyz") - } - }) - } - } - ) + "x", new OptimizelyVariable( + "11535264366", + "x", + "string", + "xyz") + }, + }) + }, + } + ), }, - deliveryRules: new List() { new OptimizelyExperiment( - id: "11630490911", - key:"feat_with_var_rule", - audiences: "", - variationsMap: new Dictionary + new List() + { + new OptimizelyExperiment( + "11630490911", + "feat_with_var_rule", + "", + new Dictionary + { + { + "11475708558", new OptimizelyVariation( + "11475708558", + "11475708558", + false, + new Dictionary() { { - "11475708558", new OptimizelyVariation ( - id: "11475708558", - key: "11475708558", - featureEnabled: false, - variablesMap: new Dictionary() - { - { "x" , new OptimizelyVariable("11535264366", "x", "string", "x") } - }) - } - } - ) }, - experimentsMap: new Dictionary + "x", + new OptimizelyVariable("11535264366", "x", + "string", "x") + }, + }) + }, + } + ), + }, + new Dictionary { { "feat_with_var_test", new OptimizelyExperiment( - id: "11564051718", - key:"feat_with_var_test", - audiences: "", - variationsMap: new Dictionary + "11564051718", + "feat_with_var_test", + "", + new Dictionary { { - "variation_2", new OptimizelyVariation ( - id: "11617170975", - key: "variation_2", - featureEnabled: true, - variablesMap: new Dictionary + "variation_2", new OptimizelyVariation( + "11617170975", + "variation_2", + true, + new Dictionary { { - "x" , new OptimizelyVariable ( - id: "11535264366", - key: "x", - type: "string", - value: "xyz") - } + "x", new OptimizelyVariable( + "11535264366", + "x", + "string", + "xyz") + }, }) - } + }, } ) - } + }, }, - variablesMap: new Dictionary + new Dictionary { { - "x", new OptimizelyVariable (id: "11535264366" , key: "x", type: "string", value: "x") - } + "x", new OptimizelyVariable("11535264366", "x", "string", "x") + }, }) }, { - "feat2", new OptimizelyFeature ( - id: "11567102052", - key: "feat2", - deliveryRules: new List() { new OptimizelyExperiment( - id: "11488548028", - key:"11488548028", - audiences: "(\"exactString\" OR \"substringString\") AND (\"exists\" OR \"exactNumber\" OR \"gtNumber\" OR \"ltNumber\" OR \"exactBoolean\")", - variationsMap: new Dictionary - { - { - "11557362670", new OptimizelyVariation ( - id: "11557362670", - key: "11557362670", - featureEnabled: true, - variablesMap: new Dictionary() - ) - } - } - ) }, + "feat2", new OptimizelyFeature( + "11567102052", + "feat2", + deliveryRules: new List() + { + new OptimizelyExperiment( + "11488548028", + "11488548028", + "(\"exactString\" OR \"substringString\") AND (\"exists\" OR \"exactNumber\" OR \"gtNumber\" OR \"ltNumber\" OR \"exactBoolean\")", + new Dictionary + { + { + "11557362670", new OptimizelyVariation( + "11557362670", + "11557362670", + true, + new Dictionary() + ) + }, + } + ), + }, experimentRules: new List(), experimentsMap: new Dictionary(), variablesMap: new Dictionary()) }, { - "feat2_with_var", new OptimizelyFeature ( - id: "11567102053", - key: "feat2_with_var", + "feat2_with_var", new OptimizelyFeature( + "11567102053", + "feat2_with_var", deliveryRules: new List() { new OptimizelyExperiment( - id: "11630490912", - key:"11630490912", - audiences: "", - variationsMap: new Dictionary + "11630490912", + "11630490912", + "", + new Dictionary + { + { + "11475708559", new OptimizelyVariation( + "11475708559", + "11475708559", + false, + new Dictionary() { { - "11475708559", new OptimizelyVariation ( - id: "11475708559", - key: "11475708559", - featureEnabled: false, - variablesMap: new Dictionary() - { - { - "z" , new OptimizelyVariable ( - id: "11535264367", - key: "z", - type: "integer", - value: "10") - } - }) - } - } - ) + "z", new OptimizelyVariable( + "11535264367", + "z", + "integer", + "10") + }, + }) + }, + } + ), }, experimentRules: new List() { - new OptimizelyExperiment ( - id: "1323241599", - key:"feat2_with_var_test", - audiences: "(\"exactString\" OR \"substringString\") AND (\"exists\" OR \"exactNumber\" OR \"gtNumber\" OR \"ltNumber\" OR \"exactBoolean\")", - variationsMap: new Dictionary + new OptimizelyExperiment( + "1323241599", + "feat2_with_var_test", + "(\"exactString\" OR \"substringString\") AND (\"exists\" OR \"exactNumber\" OR \"gtNumber\" OR \"ltNumber\" OR \"exactBoolean\")", + new Dictionary + { { - { - "variation_2", new OptimizelyVariation ( - id: "1423767505", - key: "variation_2", - featureEnabled: true, - variablesMap: new Dictionary + "variation_2", new OptimizelyVariation( + "1423767505", + "variation_2", + true, + new Dictionary + { { - { - "z" , new OptimizelyVariable ( - id: "11535264367", - key: "z", - type: "integer", - value: "150") - } - }) - } - } - ) + "z", new OptimizelyVariable( + "11535264367", + "z", + "integer", + "150") + }, + }) + }, + } + ), }, experimentsMap: new Dictionary { { - "feat2_with_var_test", new OptimizelyExperiment ( - id: "1323241599", - key:"feat2_with_var_test", - audiences: "(\"exactString\" OR \"substringString\") AND (\"exists\" OR \"exactNumber\" OR \"gtNumber\" OR \"ltNumber\" OR \"exactBoolean\")", - variationsMap: new Dictionary + "feat2_with_var_test", new OptimizelyExperiment( + "1323241599", + "feat2_with_var_test", + "(\"exactString\" OR \"substringString\") AND (\"exists\" OR \"exactNumber\" OR \"gtNumber\" OR \"ltNumber\" OR \"exactBoolean\")", + new Dictionary { { - "variation_2", new OptimizelyVariation ( - id: "1423767505", - key: "variation_2", - featureEnabled: true, - variablesMap: new Dictionary + "variation_2", new OptimizelyVariation( + "1423767505", + "variation_2", + true, + new Dictionary { { - "z" , new OptimizelyVariable ( - id: "11535264367", - key: "z", - type: "integer", - value: "150") - } + "z", new OptimizelyVariable( + "11535264367", + "z", + "integer", + "150") + }, }) - } + }, } ) - } + }, }, variablesMap: new Dictionary { { - "z", new OptimizelyVariable (id: "11535264367" , key: "z", type: "integer", value: "10") - } + "z", new OptimizelyVariable("11535264367", "z", "integer", "10") + }, }) - } + }, }; - OptimizelyConfig optimizelyConfig = new OptimizelyConfigService(datafileProjectConfig).GetOptimizelyConfig(); - OptimizelyConfig expectedOptimizelyConfig = new OptimizelyConfig(datafileProjectConfig.Revision, + var optimizelyConfig = + new OptimizelyConfigService(datafileProjectConfig).GetOptimizelyConfig(); + var expectedOptimizelyConfig = new OptimizelyConfig(datafileProjectConfig.Revision, datafileProjectConfig.SDKKey, datafileProjectConfig.EnvironmentKey, - attributes: new OptimizelyAttribute[] + new OptimizelyAttribute[] { new OptimizelyAttribute { - Id = "594015", Key = "house" + Id = "594015", Key = "house", }, new OptimizelyAttribute { - Id = "594016", Key = "lasers" + Id = "594016", Key = "lasers", }, new OptimizelyAttribute { - Id = "594017", Key = "should_do_it" + Id = "594017", Key = "should_do_it", }, new OptimizelyAttribute { - Id = "594018", Key = "favorite_ice_cream" - } + Id = "594018", Key = "favorite_ice_cream", + }, }, - audiences: new OptimizelyAudience[] + new OptimizelyAudience[] { - new OptimizelyAudience("0", "$$dummy", "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}"), - new OptimizelyAudience("3468206643", "exactBoolean", "[\"and\",[\"or\",[\"or\",{\"name\":\"should_do_it\",\"type\":\"custom_attribute\",\"match\":\"exact\",\"value\":true}]]]"), - new OptimizelyAudience("3468206646", "exactNumber", "[\"and\",[\"or\",[\"or\",{\"name\":\"lasers\",\"type\":\"custom_attribute\",\"match\":\"exact\",\"value\":45.5}]]]"), - new OptimizelyAudience("3468206642", "exactString", "[\"and\", [\"or\", [\"or\", {\"name\": \"house\", \"type\": \"custom_attribute\", \"value\": \"Gryffindor\"}]]]"), - new OptimizelyAudience("3988293899", "exists", "[\"and\",[\"or\",[\"or\",{\"name\":\"favorite_ice_cream\",\"type\":\"custom_attribute\",\"match\":\"exists\"}]]]"), - new OptimizelyAudience("3468206647", "gtNumber", "[\"and\",[\"or\",[\"or\",{\"name\":\"lasers\",\"type\":\"custom_attribute\",\"match\":\"gt\",\"value\":70}]]]"), - new OptimizelyAudience("3468206644", "ltNumber", "[\"and\",[\"or\",[\"or\",{\"name\":\"lasers\",\"type\":\"custom_attribute\",\"match\":\"lt\",\"value\":1.0}]]]"), - new OptimizelyAudience("3468206645", "notChrome", "[\"and\", [\"or\", [\"not\", [\"or\", {\"name\": \"browser_type\", \"type\": \"custom_attribute\", \"value\":\"Chrome\"}]]]]"), - new OptimizelyAudience("3468206648", "notExist", "[\"not\",{\"name\":\"input_value\",\"type\":\"custom_attribute\",\"match\":\"exists\"}]"), - new OptimizelyAudience("3988293898", "substringString", "[\"and\",[\"or\",[\"or\",{\"name\":\"house\",\"type\":\"custom_attribute\",\"match\":\"substring\",\"value\":\"Slytherin\"}]]]"), + new OptimizelyAudience("0", "$$dummy", + "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}"), + new OptimizelyAudience("3468206643", "exactBoolean", + "[\"and\",[\"or\",[\"or\",{\"name\":\"should_do_it\",\"type\":\"custom_attribute\",\"match\":\"exact\",\"value\":true}]]]"), + new OptimizelyAudience("3468206646", "exactNumber", + "[\"and\",[\"or\",[\"or\",{\"name\":\"lasers\",\"type\":\"custom_attribute\",\"match\":\"exact\",\"value\":45.5}]]]"), + new OptimizelyAudience("3468206642", "exactString", + "[\"and\", [\"or\", [\"or\", {\"name\": \"house\", \"type\": \"custom_attribute\", \"value\": \"Gryffindor\"}]]]"), + new OptimizelyAudience("3988293899", "exists", + "[\"and\",[\"or\",[\"or\",{\"name\":\"favorite_ice_cream\",\"type\":\"custom_attribute\",\"match\":\"exists\"}]]]"), + new OptimizelyAudience("3468206647", "gtNumber", + "[\"and\",[\"or\",[\"or\",{\"name\":\"lasers\",\"type\":\"custom_attribute\",\"match\":\"gt\",\"value\":70}]]]"), + new OptimizelyAudience("3468206644", "ltNumber", + "[\"and\",[\"or\",[\"or\",{\"name\":\"lasers\",\"type\":\"custom_attribute\",\"match\":\"lt\",\"value\":1.0}]]]"), + new OptimizelyAudience("3468206645", "notChrome", + "[\"and\", [\"or\", [\"not\", [\"or\", {\"name\": \"browser_type\", \"type\": \"custom_attribute\", \"value\":\"Chrome\"}]]]]"), + new OptimizelyAudience("3468206648", "notExist", + "[\"not\",{\"name\":\"input_value\",\"type\":\"custom_attribute\",\"match\":\"exists\"}]"), + new OptimizelyAudience("3988293898", "substringString", + "[\"and\",[\"or\",[\"or\",{\"name\":\"house\",\"type\":\"custom_attribute\",\"match\":\"substring\",\"value\":\"Slytherin\"}]]]"), }, - events: new OptimizelyEvent[] + new OptimizelyEvent[] { new OptimizelyEvent() { - Id = "594089", Key = "item_bought", ExperimentIds = new string[] { "11564051718", "1323241597" } + Id = "594089", Key = "item_bought", + ExperimentIds = new string[] { "11564051718", "1323241597" }, }, new OptimizelyEvent() { - Id = "594090", Key = "user_signed_up", ExperimentIds = new string[] { "1323241598", "1323241599" } - } + Id = "594090", Key = "user_signed_up", + ExperimentIds = new string[] { "1323241598", "1323241599" }, + }, }, - experimentsMap: experimentsMap, - featuresMap: featuresMap, - datafile: TestData.TypedAudienceDatafile); + experimentsMap, + featuresMap, + TestData.TypedAudienceDatafile); Assertions.AreEqual(expectedOptimizelyConfig, optimizelyConfig); } @@ -560,75 +612,92 @@ public void TestGetOptimizelyConfigService() [Test] public void TestOptimizelyConfigEntity() { - OptimizelyConfig expectedOptlyFeature = new OptimizelyConfig("123", + var expectedOptlyFeature = new OptimizelyConfig("123", "testSdkKey", "Development", - attributes: new OptimizelyAttribute[0], - audiences: new OptimizelyAudience[0], - events: new OptimizelyEvent[0], - experimentsMap: new Dictionary(), - featuresMap: new Dictionary() - ); + new OptimizelyAttribute[0], + new OptimizelyAudience[0], + new OptimizelyEvent[0], + new Dictionary(), + new Dictionary() + ); Assert.AreEqual(expectedOptlyFeature.Revision, "123"); Assert.AreEqual(expectedOptlyFeature.SDKKey, "testSdkKey"); Assert.AreEqual(expectedOptlyFeature.EnvironmentKey, "Development"); Assert.AreEqual(expectedOptlyFeature.Attributes, new Entity.Attribute[0]); Assert.AreEqual(expectedOptlyFeature.Audiences, new OptimizelyAudience[0]); Assert.AreEqual(expectedOptlyFeature.Events, new Entity.Event[0]); - Assert.AreEqual(expectedOptlyFeature.ExperimentsMap, new Dictionary()); - Assert.AreEqual(expectedOptlyFeature.FeaturesMap, new Dictionary()); + Assert.AreEqual(expectedOptlyFeature.ExperimentsMap, + new Dictionary()); + Assert.AreEqual(expectedOptlyFeature.FeaturesMap, + new Dictionary()); } [Test] + [Obsolete] public void TestOptimizelyFeatureEntity() { - OptimizelyFeature expectedOptlyFeature = new OptimizelyFeature("1", "featKey", + var expectedOptlyFeature = new OptimizelyFeature("1", "featKey", new List(), new List(), new Dictionary(), new Dictionary() - ); + ); Assert.AreEqual(expectedOptlyFeature.Id, "1"); Assert.AreEqual(expectedOptlyFeature.Key, "featKey"); Assert.AreEqual(expectedOptlyFeature.ExperimentRules, new List()); Assert.AreEqual(expectedOptlyFeature.DeliveryRules, new List()); Assert.AreEqual(expectedOptlyFeature.Key, "featKey"); - Assert.AreEqual(expectedOptlyFeature.ExperimentsMap, new Dictionary()); - Assert.AreEqual(expectedOptlyFeature.VariablesMap, new Dictionary()); + Assert.AreEqual(expectedOptlyFeature.ExperimentsMap, + new Dictionary()); + Assert.AreEqual(expectedOptlyFeature.VariablesMap, + new Dictionary()); } [Test] public void TestOptimizelyExperimentEntity() { - OptimizelyExperiment expectedOptlyExp = new OptimizelyExperiment("1", "exKey", + var expectedOptlyExp = new OptimizelyExperiment("1", "exKey", "", - new Dictionary { + new Dictionary + { { - "varKey", new OptimizelyVariation("1", "varKey", true, new Dictionary()) - } + "varKey", + new OptimizelyVariation("1", "varKey", true, + new Dictionary()) + }, }); Assert.AreEqual(expectedOptlyExp.Id, "1"); Assert.AreEqual(expectedOptlyExp.Key, "exKey"); Assert.AreEqual(expectedOptlyExp.Audiences, ""); - Assert.AreEqual(expectedOptlyExp.VariationsMap["varKey"], new OptimizelyVariation("1", "varKey", true, new Dictionary())); + Assert.AreEqual(expectedOptlyExp.VariationsMap["varKey"], + new OptimizelyVariation("1", "varKey", true, + new Dictionary())); } [Test] public void TestOptimizelyVariationEntity() { - OptimizelyVariation expectedOptlyVariation = new OptimizelyVariation("1", "varKey", true, new Dictionary { - { "variableKey", new OptimizelyVariable("varId", "variableKey", "integer", "2")} - }); + var expectedOptlyVariation = new OptimizelyVariation("1", "varKey", true, + new Dictionary + { + { + "variableKey", + new OptimizelyVariable("varId", "variableKey", "integer", "2") + }, + }); Assert.AreEqual(expectedOptlyVariation.Id, "1"); Assert.AreEqual(expectedOptlyVariation.Key, "varKey"); Assert.AreEqual(expectedOptlyVariation.FeatureEnabled, true); - Assert.AreEqual(expectedOptlyVariation.VariablesMap["variableKey"], new OptimizelyVariable("varId", "variableKey", "integer", "2")); + Assert.AreEqual(expectedOptlyVariation.VariablesMap["variableKey"], + new OptimizelyVariable("varId", "variableKey", "integer", "2")); } [Test] public void TestOptimizelyVariableEntity() { - OptimizelyVariable expectedOptlyVariable = new OptimizelyVariable("varId", "variableKey", "integer", "2"); + var expectedOptlyVariable = + new OptimizelyVariable("varId", "variableKey", "integer", "2"); Assert.AreEqual(expectedOptlyVariable.Id, "varId"); Assert.AreEqual(expectedOptlyVariable.Key, "variableKey"); Assert.AreEqual(expectedOptlyVariable.Type, "integer"); diff --git a/OptimizelySDK.Tests/OptimizelyDecisions/OptimizelyDecisionTest.cs b/OptimizelySDK.Tests/OptimizelyDecisions/OptimizelyDecisionTest.cs index 23c25b223..834a33e27 100644 --- a/OptimizelySDK.Tests/OptimizelyDecisions/OptimizelyDecisionTest.cs +++ b/OptimizelySDK.Tests/OptimizelyDecisions/OptimizelyDecisionTest.cs @@ -14,14 +14,14 @@ * limitations under the License. */ +using System; +using System.Collections.Generic; +using System.Linq; using Moq; using NUnit.Framework; using OptimizelySDK.ErrorHandler; using OptimizelySDK.Logger; using OptimizelySDK.OptimizelyDecisions; -using System; -using System.Collections.Generic; -using System.Linq; namespace OptimizelySDK.Tests.OptimizelyDecisions { @@ -40,15 +40,18 @@ public void Initialize() LoggerMock = new Mock(); LoggerMock.Setup(i => i.Log(It.IsAny(), It.IsAny())); } - + [Test] public void TestNewErrorDecision() { - var optimizelyDecision = OptimizelyDecision.NewErrorDecision("var_key", null, "some error message", ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyDecision = OptimizelyDecision.NewErrorDecision("var_key", null, + "some error message", ErrorHandlerMock.Object, LoggerMock.Object); Assert.IsNull(optimizelyDecision.VariationKey); Assert.AreEqual(optimizelyDecision.FlagKey, "var_key"); - Assert.AreEqual(optimizelyDecision.Variables.ToDictionary(), new Dictionary()); - Assert.AreEqual(optimizelyDecision.Reasons, new List() { "some error message" }); + Assert.AreEqual(optimizelyDecision.Variables.ToDictionary(), + new Dictionary()); + Assert.AreEqual(optimizelyDecision.Reasons, + new List() { "some error message" }); Assert.IsNull(optimizelyDecision.RuleKey); Assert.False(optimizelyDecision.Enabled); } @@ -56,16 +59,21 @@ public void TestNewErrorDecision() [Test] public void TestNewDecision() { - var variableMap = new Dictionary() { + var variableMap = new Dictionary() + { { "strField", "john doe" }, { "intField", 12 }, - { "objectField", new Dictionary () { - { "inner_field_int", 3 } + { + "objectField", new Dictionary() + { + { "inner_field_int", 3 }, } - } + }, }; - var optimizelyJSONUsingMap = new OptimizelyJSON(variableMap, ErrorHandlerMock.Object, LoggerMock.Object); - string expectedStringObj = "{\"strField\":\"john doe\",\"intField\":12,\"objectField\":{\"inner_field_int\":3}}"; + var optimizelyJSONUsingMap = + new OptimizelyJSON(variableMap, ErrorHandlerMock.Object, LoggerMock.Object); + var expectedStringObj = + "{\"strField\":\"john doe\",\"intField\":12,\"objectField\":{\"inner_field_int\":3}}"; var optimizelyDecision = new OptimizelyDecision("var_key", true, @@ -86,25 +94,41 @@ public void TestNewDecision() public void TestNewDecisionReasonWithIncludeReasons() { var decisionReasons = new DecisionReasons(); - var decideOptions = new OptimizelyDecideOption[] { OptimizelyDecideOption.INCLUDE_REASONS }; - decisionReasons.AddError(DecisionMessage.Reason(DecisionMessage.FLAG_KEY_INVALID, "invalid_key")); - - Assert.AreEqual(decisionReasons.ToReport(decideOptions.Contains(OptimizelyDecideOption.INCLUDE_REASONS))[0], "No flag was found for key \"invalid_key\"."); - decisionReasons.AddError(DecisionMessage.Reason(DecisionMessage.VARIABLE_VALUE_INVALID, "invalid_key")); - Assert.AreEqual(decisionReasons.ToReport(decideOptions.Contains(OptimizelyDecideOption.INCLUDE_REASONS))[1], "Variable value for key \"invalid_key\" is invalid or wrong type."); + var decideOptions = new OptimizelyDecideOption[] + { OptimizelyDecideOption.INCLUDE_REASONS }; + decisionReasons.AddError(DecisionMessage.Reason(DecisionMessage.FLAG_KEY_INVALID, + "invalid_key")); + + Assert.AreEqual( + decisionReasons.ToReport( + decideOptions.Contains(OptimizelyDecideOption.INCLUDE_REASONS))[0], + "No flag was found for key \"invalid_key\"."); + decisionReasons.AddError(DecisionMessage.Reason(DecisionMessage.VARIABLE_VALUE_INVALID, + "invalid_key")); + Assert.AreEqual( + decisionReasons.ToReport( + decideOptions.Contains(OptimizelyDecideOption.INCLUDE_REASONS))[1], + "Variable value for key \"invalid_key\" is invalid or wrong type."); decisionReasons.AddInfo("Some info message."); - Assert.AreEqual(decisionReasons.ToReport(decideOptions.Contains(OptimizelyDecideOption.INCLUDE_REASONS))[2], "Some info message."); + Assert.AreEqual( + decisionReasons.ToReport( + decideOptions.Contains(OptimizelyDecideOption.INCLUDE_REASONS))[2], + "Some info message."); } [Test] public void TestNewDecisionReasonWithoutIncludeReasons() { var decisionReasons = new DecisionReasons(); - decisionReasons.AddError(DecisionMessage.Reason(DecisionMessage.FLAG_KEY_INVALID, "invalid_key")); + decisionReasons.AddError(DecisionMessage.Reason(DecisionMessage.FLAG_KEY_INVALID, + "invalid_key")); - Assert.AreEqual(decisionReasons.ToReport()[0], "No flag was found for key \"invalid_key\"."); - decisionReasons.AddError(DecisionMessage.Reason(DecisionMessage.VARIABLE_VALUE_INVALID, "invalid_key")); - Assert.AreEqual(decisionReasons.ToReport()[1], "Variable value for key \"invalid_key\" is invalid or wrong type."); + Assert.AreEqual(decisionReasons.ToReport()[0], + "No flag was found for key \"invalid_key\"."); + decisionReasons.AddError(DecisionMessage.Reason(DecisionMessage.VARIABLE_VALUE_INVALID, + "invalid_key")); + Assert.AreEqual(decisionReasons.ToReport()[1], + "Variable value for key \"invalid_key\" is invalid or wrong type."); decisionReasons.AddInfo("Some info message."); Assert.AreEqual(decisionReasons.ToReport().Count, 2); } diff --git a/OptimizelySDK.Tests/OptimizelyFactoryTest.cs b/OptimizelySDK.Tests/OptimizelyFactoryTest.cs index 92d2a23b2..e1cc7ebff 100644 --- a/OptimizelySDK.Tests/OptimizelyFactoryTest.cs +++ b/OptimizelySDK.Tests/OptimizelyFactoryTest.cs @@ -15,6 +15,7 @@ * limitations under the License. */ +using System; using Moq; using NUnit.Framework; using OptimizelySDK.Config; @@ -25,13 +26,14 @@ using OptimizelySDK.Tests.ConfigTest; using OptimizelySDK.Tests.EventTest; using OptimizelySDK.Tests.Utils; -using System; + namespace OptimizelySDK.Tests { [TestFixture] public class OptimizelyFactoryTest { private Mock LoggerMock; + [SetUp] public void Initialize() { @@ -55,7 +57,7 @@ public void TestOptimizelyInstanceUsingConfigFile() AutoUpdate = true, DatafileAccessToken = "testingtoken123", BlockingTimeout = TimeSpan.FromSeconds(10), - PollingInterval = TimeSpan.FromSeconds(2) + PollingInterval = TimeSpan.FromSeconds(2), }; Assert.AreEqual(actualConfigManagerProps, expectedConfigManagerProps); @@ -78,7 +80,7 @@ public void TestProjectConfigManagerUsingSDKKey() LastModified = "", AutoUpdate = true, BlockingTimeout = TimeSpan.FromSeconds(30), - PollingInterval = TimeSpan.FromMilliseconds(2023) + PollingInterval = TimeSpan.FromMilliseconds(2023), }; Assert.AreEqual(actualConfigManagerProps, expectedConfigManagerProps); @@ -88,7 +90,8 @@ public void TestProjectConfigManagerUsingSDKKey() [Test] public void TestProjectConfigManagerWithDatafileAccessToken() { - var optimizely = OptimizelyFactory.NewDefaultInstance("my-sdk-key", null, "access-token"); + var optimizely = + OptimizelyFactory.NewDefaultInstance("my-sdk-key", null, "access-token"); // Check values are loaded from app.config or not. var projectConfigManager = optimizely.ProjectConfigManager as HttpProjectConfigManager; @@ -102,7 +105,7 @@ public void TestProjectConfigManagerWithDatafileAccessToken() DatafileAccessToken = "access-token", AutoUpdate = true, BlockingTimeout = TimeSpan.FromSeconds(30), - PollingInterval = TimeSpan.FromMilliseconds(2023) + PollingInterval = TimeSpan.FromMilliseconds(2023), }; Assert.AreEqual(actualConfigManagerProps, expectedConfigManagerProps); @@ -111,7 +114,8 @@ public void TestProjectConfigManagerWithDatafileAccessToken() } [Test] - public void TestOptimizelyInstanceUsingConfigNotUseFactoryClassBlockingTimeoutAndPollingInterval() + public void + TestOptimizelyInstanceUsingConfigNotUseFactoryClassBlockingTimeoutAndPollingInterval() { OptimizelyFactory.SetBlockingTimeOutPeriod(TimeSpan.FromSeconds(30)); OptimizelyFactory.SetPollingInterval(TimeSpan.FromMilliseconds(2023)); @@ -128,7 +132,7 @@ public void TestOptimizelyInstanceUsingConfigNotUseFactoryClassBlockingTimeoutAn AutoUpdate = true, DatafileAccessToken = "testingtoken123", BlockingTimeout = TimeSpan.FromMilliseconds(10000), - PollingInterval = TimeSpan.FromMilliseconds(2000) + PollingInterval = TimeSpan.FromMilliseconds(2000), }; Assert.AreEqual(actualConfigManagerProps, expectedConfigManagerProps); @@ -138,18 +142,20 @@ public void TestOptimizelyInstanceUsingConfigNotUseFactoryClassBlockingTimeoutAn [Test] public void TestProjectConfigManagerWithCustomProjectConfigManager() { - var projectConfigManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("10192104166") - .WithFormat("https://optimizely.com/json/{0}.json") - .WithPollingInterval(TimeSpan.FromMilliseconds(3000)) - .WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(4500)) - .WithStartByDefault() - .WithAccessToken("access-token") - .Build(true); + var projectConfigManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("10192104166"). + WithFormat("https://optimizely.com/json/{0}.json"). + WithPollingInterval(TimeSpan.FromMilliseconds(3000)). + WithBlockingTimeoutPeriod(TimeSpan.FromMilliseconds(4500)). + WithStartByDefault(). + WithAccessToken("access-token"). + Build(true); var optimizely = OptimizelyFactory.NewDefaultInstance(projectConfigManager); - var actualProjectConfigManager = optimizely.ProjectConfigManager as HttpProjectConfigManager; - var actualConfigManagerProps = new ProjectConfigManagerProps(actualProjectConfigManager); + var actualProjectConfigManager = + optimizely.ProjectConfigManager as HttpProjectConfigManager; + var actualConfigManagerProps = + new ProjectConfigManagerProps(actualProjectConfigManager); var expectedConfigManagerProps = new ProjectConfigManagerProps(projectConfigManager); Assert.AreEqual(actualConfigManagerProps, expectedConfigManagerProps); optimizely.Dispose(); @@ -160,13 +166,15 @@ public void TestEventProcessorWithDefaultEventBatching() { var optimizely = OptimizelyFactory.NewDefaultInstance(); - var batchEventProcessor = Reflection.GetFieldValue(optimizely, "EventProcessor"); + var batchEventProcessor = + Reflection.GetFieldValue(optimizely, + "EventProcessor"); var actualEventProcessorProps = new EventProcessorProps(batchEventProcessor); var expectedEventProcessorProps = new EventProcessorProps { BatchSize = 10, FlushInterval = TimeSpan.FromSeconds(2), - TimeoutInterval = TimeSpan.FromSeconds(10) + TimeoutInterval = TimeSpan.FromSeconds(10), }; Assert.AreEqual(actualEventProcessorProps, expectedEventProcessorProps); optimizely.Dispose(); @@ -180,13 +188,15 @@ public void TestEventProcessorWithEventBatchingBatchSizeAndInterval() var optimizely = OptimizelyFactory.NewDefaultInstance("sdk-Key"); - var batchEventProcessor = Reflection.GetFieldValue(optimizely, "EventProcessor"); + var batchEventProcessor = + Reflection.GetFieldValue(optimizely, + "EventProcessor"); var actualEventProcessorProps = new EventProcessorProps(batchEventProcessor); var expectedEventProcessorProps = new EventProcessorProps { BatchSize = 2, FlushInterval = TimeSpan.FromSeconds(4), - TimeoutInterval = TimeSpan.FromMinutes(5) + TimeoutInterval = TimeSpan.FromMinutes(5), }; Assert.AreEqual(actualEventProcessorProps, expectedEventProcessorProps); optimizely.Dispose(); @@ -197,21 +207,24 @@ public void TestEventProcessorWithBatchEventProcessorObj() { var eventDispatcher = new DefaultEventDispatcher(LoggerMock.Object); var notificationCenter = new NotificationCenter(); - var projectConfigManager = new HttpProjectConfigManager.Builder() - .WithSdkKey("10192104166") - .Build(true); - - var batchEventProcessor = new BatchEventProcessor.Builder() - .WithLogger(LoggerMock.Object) - .WithMaxBatchSize(20) - .WithFlushInterval(TimeSpan.FromSeconds(3)) - .WithEventDispatcher(eventDispatcher) - .WithNotificationCenter(notificationCenter) - .Build(); - - var optimizely = OptimizelyFactory.NewDefaultInstance(projectConfigManager, notificationCenter, eventProcessor: batchEventProcessor); - - var actualbatchEventProcessor = Reflection.GetFieldValue(optimizely, "EventProcessor"); + var projectConfigManager = new HttpProjectConfigManager.Builder(). + WithSdkKey("10192104166"). + Build(true); + + var batchEventProcessor = new BatchEventProcessor.Builder(). + WithLogger(LoggerMock.Object). + WithMaxBatchSize(20). + WithFlushInterval(TimeSpan.FromSeconds(3)). + WithEventDispatcher(eventDispatcher). + WithNotificationCenter(notificationCenter). + Build(); + + var optimizely = OptimizelyFactory.NewDefaultInstance(projectConfigManager, + notificationCenter, eventProcessor: batchEventProcessor); + + var actualbatchEventProcessor = + Reflection.GetFieldValue(optimizely, + "EventProcessor"); var actualEventProcessorProps = new EventProcessorProps(actualbatchEventProcessor); var expectedEventProcessorProps = new EventProcessorProps(batchEventProcessor); Assert.AreEqual(actualEventProcessorProps, expectedEventProcessorProps); @@ -222,11 +235,13 @@ public void TestEventProcessorWithBatchEventProcessorObj() public void TestGetFeatureVariableJSONEmptyDatafileTest() { var httpClientMock = new Mock(); - var task = TestHttpProjectConfigManagerUtil.MockSendAsync(httpClientMock, TestData.EmptyDatafile, TimeSpan.Zero, System.Net.HttpStatusCode.OK); + var task = TestHttpProjectConfigManagerUtil.MockSendAsync(httpClientMock, + TestData.EmptyDatafile, TimeSpan.Zero, System.Net.HttpStatusCode.OK); TestHttpProjectConfigManagerUtil.SetClientFieldValue(httpClientMock.Object); var optimizely = OptimizelyFactory.NewDefaultInstance("sdk-key"); - Assert.Null(optimizely.GetFeatureVariableJSON("no-feature-variable", "no-variable-key", "userId")); + Assert.Null(optimizely.GetFeatureVariableJSON("no-feature-variable", "no-variable-key", + "userId")); optimizely.Dispose(); } } diff --git a/OptimizelySDK.Tests/OptimizelyJSONTest.cs b/OptimizelySDK.Tests/OptimizelyJSONTest.cs index c07bb137d..e60b458be 100644 --- a/OptimizelySDK.Tests/OptimizelyJSONTest.cs +++ b/OptimizelySDK.Tests/OptimizelyJSONTest.cs @@ -15,39 +15,40 @@ * limitations under the License. */ +using System; +using System.Collections.Generic; using Moq; using NUnit.Framework; using OptimizelySDK.ErrorHandler; using OptimizelySDK.Exceptions; using OptimizelySDK.Logger; -using System; -using System.Collections.Generic; namespace OptimizelySDK.Tests { - class ParentJson + internal class ParentJson { public string strField { get; set; } public int intField { get; set; } public double doubleField { get; set; } public bool boolField { get; set; } public ObjectJson objectField { get; set; } - } - class ObjectJson + + internal class ObjectJson { public int inner_field_int { get; set; } public double inner_field_double { get; set; } - public string inner_field_string {get;set;} + public string inner_field_string { get; set; } public bool inner_field_boolean { get; set; } } - class Field4 + internal class Field4 { public long inner_field1 { get; set; } public InnerField2 inner_field2 { get; set; } } - class InnerField2 : List { } + + internal class InnerField2 : List { } [TestFixture] @@ -67,88 +68,114 @@ public void Initialize() LoggerMock = new Mock(); LoggerMock.Setup(i => i.Log(It.IsAny(), It.IsAny())); - Payload = "{ \"field1\": 1, \"field2\": 2.5, \"field3\": \"three\", \"field4\": {\"inner_field1\":3,\"inner_field2\":[\"1\",\"2\", 3, 4.23, true]}, \"field5\": true, }"; - Map = new Dictionary() { + Payload = + "{ \"field1\": 1, \"field2\": 2.5, \"field3\": \"three\", \"field4\": {\"inner_field1\":3,\"inner_field2\":[\"1\",\"2\", 3, 4.23, true]}, \"field5\": true, }"; + Map = new Dictionary() + { { "strField", "john doe" }, { "intField", 12 }, { "doubleField", 2.23 }, - { "boolField", true}, - { "objectField", new Dictionary () { + { "boolField", true }, + { + "objectField", new Dictionary() + { { "inner_field_int", 3 }, { "inner_field_double", 13.21 }, { "inner_field_string", "john" }, - { "inner_field_boolean", true } + { "inner_field_boolean", true }, } - } + }, }; } [Test] public void TestOptimizelyJsonObjectIsValid() { - var optimizelyJSONUsingMap = new OptimizelyJSON(Map, ErrorHandlerMock.Object, LoggerMock.Object); - var optimizelyJSONUsingString = new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJSONUsingMap = + new OptimizelyJSON(Map, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJSONUsingString = + new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); Assert.IsNotNull(optimizelyJSONUsingMap); Assert.IsNotNull(optimizelyJSONUsingString); } + [Test] public void TestToStringReturnValidString() { - var map = new Dictionary() { + var map = new Dictionary() + { { "strField", "john doe" }, { "intField", 12 }, - { "objectField", new Dictionary () { - { "inner_field_int", 3 } + { + "objectField", new Dictionary() + { + { "inner_field_int", 3 }, } - } + }, }; - var optimizelyJSONUsingMap = new OptimizelyJSON(map, ErrorHandlerMock.Object, LoggerMock.Object); - string str = optimizelyJSONUsingMap.ToString(); - string expectedStringObj = "{\"strField\":\"john doe\",\"intField\":12,\"objectField\":{\"inner_field_int\":3}}"; + var optimizelyJSONUsingMap = + new OptimizelyJSON(map, ErrorHandlerMock.Object, LoggerMock.Object); + var str = optimizelyJSONUsingMap.ToString(); + var expectedStringObj = + "{\"strField\":\"john doe\",\"intField\":12,\"objectField\":{\"inner_field_int\":3}}"; Assert.AreEqual(expectedStringObj, str); } [Test] public void TestGettingErrorUponInvalidJsonString() { - var optimizelyJSONUsingString = new OptimizelyJSON("{\"invalid\":}", ErrorHandlerMock.Object, LoggerMock.Object); - LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Provided string could not be converted to map."), Times.Once); - ErrorHandlerMock.Verify(er => er.HandleError(It.IsAny()), Times.Once); + var optimizelyJSONUsingString = new OptimizelyJSON("{\"invalid\":}", + ErrorHandlerMock.Object, LoggerMock.Object); + LoggerMock.Verify( + log => log.Log(LogLevel.ERROR, "Provided string could not be converted to map."), + Times.Once); + ErrorHandlerMock.Verify(er => er.HandleError(It.IsAny()), + Times.Once); } [Test] public void TestOptimizelyJsonGetVariablesWhenSetUsingMap() { - var optimizelyJSONUsingMap = new OptimizelyJSON(Map, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJSONUsingMap = + new OptimizelyJSON(Map, ErrorHandlerMock.Object, LoggerMock.Object); Assert.AreEqual(optimizelyJSONUsingMap.GetValue("strField"), "john doe"); Assert.AreEqual(optimizelyJSONUsingMap.GetValue("intField"), 12); Assert.AreEqual(optimizelyJSONUsingMap.GetValue("doubleField"), 2.23); Assert.AreEqual(optimizelyJSONUsingMap.GetValue("boolField"), true); Assert.AreEqual(optimizelyJSONUsingMap.GetValue("objectField.inner_field_int"), 3); - Assert.AreEqual(optimizelyJSONUsingMap.GetValue("objectField.inner_field_double"), 13.21); - Assert.AreEqual(optimizelyJSONUsingMap.GetValue("objectField.inner_field_string"), "john"); - Assert.AreEqual(optimizelyJSONUsingMap.GetValue("objectField.inner_field_boolean"), true); - Assert.IsTrue(optimizelyJSONUsingMap.GetValue>("objectField") is Dictionary); + Assert.AreEqual( + optimizelyJSONUsingMap.GetValue("objectField.inner_field_double"), 13.21); + Assert.AreEqual( + optimizelyJSONUsingMap.GetValue("objectField.inner_field_string"), "john"); + Assert.AreEqual( + optimizelyJSONUsingMap.GetValue("objectField.inner_field_boolean"), true); + Assert.IsTrue( + optimizelyJSONUsingMap.GetValue>("objectField") is + Dictionary); } [Test] public void TestOptimizelyJsonGetVariablesWhenSetUsingString() { - var optimizelyJSONUsingString = new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJSONUsingString = + new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); Assert.AreEqual(optimizelyJSONUsingString.GetValue("field1"), 1); Assert.AreEqual(optimizelyJSONUsingString.GetValue("field2"), 2.5); Assert.AreEqual(optimizelyJSONUsingString.GetValue("field3"), "three"); Assert.AreEqual(optimizelyJSONUsingString.GetValue("field4.inner_field1"), 3); - Assert.True(TestData.CompareObjects(optimizelyJSONUsingString.GetValue>("field4.inner_field2"), new List() { "1", "2", 3, 4.23, true })); + Assert.True(TestData.CompareObjects( + optimizelyJSONUsingString.GetValue>("field4.inner_field2"), + new List() { "1", "2", 3, 4.23, true })); } [Test] public void TestGetValueReturnsEntireDictWhenJsonPathIsEmptyAndTypeIsValid() { - var optimizelyJSONUsingString = new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJSONUsingString = + new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); var actualDict = optimizelyJSONUsingString.ToDictionary(); var expectedValue = optimizelyJSONUsingString.GetValue>(""); Assert.NotNull(expectedValue); @@ -159,8 +186,10 @@ public void TestGetValueReturnsEntireDictWhenJsonPathIsEmptyAndTypeIsValid() public void TestGetValueReturnsDefaultValueWhenJsonIsInvalid() { var payload = "{ \"field1\" : {1:\"Csharp\", 2:\"Java\"} }"; - var optimizelyJSONUsingString = new OptimizelyJSON(payload, ErrorHandlerMock.Object, LoggerMock.Object); - var expectedValue = optimizelyJSONUsingString.GetValue>("field1"); + var optimizelyJSONUsingString = + new OptimizelyJSON(payload, ErrorHandlerMock.Object, LoggerMock.Object); + var expectedValue = + optimizelyJSONUsingString.GetValue>("field1"); // Even though above given JSON is not valid, newtonsoft is parsing it so Assert.IsNotNull(expectedValue); } @@ -169,15 +198,18 @@ public void TestGetValueReturnsDefaultValueWhenJsonIsInvalid() public void TestGetValueReturnsDefaultValueWhenTypeIsInvalid() { var payload = "{ \"field1\" : {\"1\":\"Csharp\",\"2\":\"Java\"} }"; - var optimizelyJSONUsingString = new OptimizelyJSON(payload, ErrorHandlerMock.Object, LoggerMock.Object); - var expectedValue = optimizelyJSONUsingString.GetValue>("field1"); + var optimizelyJSONUsingString = + new OptimizelyJSON(payload, ErrorHandlerMock.Object, LoggerMock.Object); + var expectedValue = + optimizelyJSONUsingString.GetValue>("field1"); Assert.IsNotNull(expectedValue); } [Test] public void TestGetValueReturnsNullWhenJsonPathIsEmptyAndTypeIsOfObject() { - var optimizelyJSONUsingString = new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJSONUsingString = + new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); var expectedValue = optimizelyJSONUsingString.GetValue(""); Assert.NotNull(expectedValue); } @@ -185,47 +217,61 @@ public void TestGetValueReturnsNullWhenJsonPathIsEmptyAndTypeIsOfObject() [Test] public void TestGetValueReturnsDefaultValueWhenJsonPathIsEmptyAndTypeIsNotValid() { - var optimizelyJSONUsingString = new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJSONUsingString = + new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); var expectedValue = optimizelyJSONUsingString.GetValue(""); Assert.IsNull(expectedValue); - LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Value for path could not be assigned to provided type."), Times.Once); - ErrorHandlerMock.Verify(er => er.HandleError(It.IsAny()), Times.Once); + LoggerMock.Verify( + log => log.Log(LogLevel.ERROR, + "Value for path could not be assigned to provided type."), Times.Once); + ErrorHandlerMock.Verify(er => er.HandleError(It.IsAny()), + Times.Once); } [Test] public void TestGetValueReturnsDefaultValueWhenJsonPathIsInvalid() { - var optimizelyJSONUsingString = new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJSONUsingString = + new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); var expectedValue = optimizelyJSONUsingString.GetValue("field11"); Assert.IsNull(expectedValue); - LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Value for JSON key not found."), Times.Once); - ErrorHandlerMock.Verify(er => er.HandleError(It.IsAny()), Times.Once); + LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Value for JSON key not found."), + Times.Once); + ErrorHandlerMock.Verify(er => er.HandleError(It.IsAny()), + Times.Once); } [Test] public void TestGetValueReturnsDefaultValueWhenJsonPath1IsInvalid() { - var optimizelyJSONUsingString = new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJSONUsingString = + new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); var expectedValue = optimizelyJSONUsingString.GetValue("field4."); Assert.IsNull(expectedValue); - LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Value for JSON key not found."), Times.Once); - ErrorHandlerMock.Verify(er => er.HandleError(It.IsAny()), Times.Once); + LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Value for JSON key not found."), + Times.Once); + ErrorHandlerMock.Verify(er => er.HandleError(It.IsAny()), + Times.Once); } [Test] public void TestGetValueReturnsDefaultValueWhenJsonPath2IsInvalid() { - var optimizelyJSONUsingString = new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJSONUsingString = + new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); var expectedValue = optimizelyJSONUsingString.GetValue("field4..inner_field1"); Assert.IsNull(expectedValue); - LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Value for JSON key not found."), Times.Once); - ErrorHandlerMock.Verify(er => er.HandleError(It.IsAny()), Times.Once); - } - + LoggerMock.Verify(log => log.Log(LogLevel.ERROR, "Value for JSON key not found."), + Times.Once); + ErrorHandlerMock.Verify(er => er.HandleError(It.IsAny()), + Times.Once); + } + [Test] public void TestGetValueObjectNotModifiedIfCalledTwice() { - var optimizelyJSONUsingString = new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJSONUsingString = + new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); var expectedValue = optimizelyJSONUsingString.GetValue("field4.inner_field1"); var expectedValue2 = optimizelyJSONUsingString.GetValue("field4.inner_field1"); @@ -235,20 +281,23 @@ public void TestGetValueObjectNotModifiedIfCalledTwice() [Test] public void TestGetValueReturnsUsingGivenClassType() { - var optimizelyJSONUsingString = new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJSONUsingString = + new OptimizelyJSON(Payload, ErrorHandlerMock.Object, LoggerMock.Object); var expectedValue = optimizelyJSONUsingString.GetValue("field4"); - + Assert.AreEqual(expectedValue.inner_field1, 3); - Assert.AreEqual(expectedValue.inner_field2, new List() { "1", "2", 3, 4.23, true }); + Assert.AreEqual(expectedValue.inner_field2, + new List() { "1", "2", 3, 4.23, true }); } [Test] public void TestGetValueReturnsCastedObject() { - var optimizelyJson = new OptimizelyJSON(Map, ErrorHandlerMock.Object, LoggerMock.Object); + var optimizelyJson = + new OptimizelyJSON(Map, ErrorHandlerMock.Object, LoggerMock.Object); var expectedValue = optimizelyJson.ToDictionary(); var actualValue = optimizelyJson.GetValue(null); - + Assert.IsTrue(TestData.CompareObjects(actualValue, expectedValue)); } } diff --git a/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj b/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj index 36a800d7e..0471595dd 100644 --- a/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj +++ b/OptimizelySDK.Tests/OptimizelySDK.Tests.csproj @@ -14,7 +14,7 @@ v4.5 512 - + 1.2.1 @@ -41,7 +41,7 @@ ..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll True - + ..\packages\Moq.4.7.1\lib\net45\Moq.dll True @@ -54,97 +54,97 @@ ..\packages\NUnit.2.6.4\lib\nunit.framework.dll True - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - + + + + + + + + + + @@ -156,14 +156,14 @@ keypair.snk - - - + + + - + - + - - - - - - ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll - True - - - ..\packages\NJsonSchema.8.30.6304.31883\lib\net45\NJsonSchema.dll - True - - - - - - - - - - - ..\packages\murmurhash-signed.1.0.2\lib\net45\MurmurHash.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + Debug + AnyCPU + {4DDE7FAA-110D-441C-AB3B-3F31B593E8BF} + Library + Properties + OptimizelySDK + OptimizelySDK + v4.5 + 512 + + 1.2.1 + ..\keypair.snk + + + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + false + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + NET35 + NET40 + + + + + + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + True + + + ..\packages\NJsonSchema.8.30.6304.31883\lib\net45\NJsonSchema.dll + True + + + + + + + + + + + ..\packages\murmurhash-signed.1.0.2\lib\net45\MurmurHash.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OptimizelySDK/OptimizelyUserContext.cs b/OptimizelySDK/OptimizelyUserContext.cs index 89fc3cac4..c5a6252a7 100644 --- a/OptimizelySDK/OptimizelyUserContext.cs +++ b/OptimizelySDK/OptimizelyUserContext.cs @@ -63,16 +63,14 @@ public class OptimizelyUserContext : IDisposable public OptimizelyUserContext(Optimizely optimizely, string userId, UserAttributes userAttributes, IErrorHandler errorHandler, ILogger logger - ) : this(optimizely, userId, userAttributes, null, null, errorHandler, logger) - { - } + ) : this(optimizely, userId, userAttributes, null, null, errorHandler, logger) { } public OptimizelyUserContext(Optimizely optimizely, string userId, UserAttributes userAttributes, ForcedDecisionsStore forcedDecisionsStore, IErrorHandler errorHandler, ILogger logger - ) : this(optimizely, userId, userAttributes, forcedDecisionsStore, null, errorHandler, logger) - { - } + ) : this(optimizely, userId, userAttributes, forcedDecisionsStore, null, errorHandler, + logger) + { } public OptimizelyUserContext(Optimizely optimizely, string userId, UserAttributes userAttributes, ForcedDecisionsStore forcedDecisionsStore, diff --git a/OptimizelySDK/OptlyConfig/OptimizelyAttribute.cs b/OptimizelySDK/OptlyConfig/OptimizelyAttribute.cs index 5e0fb921f..eacfb57bb 100644 --- a/OptimizelySDK/OptlyConfig/OptimizelyAttribute.cs +++ b/OptimizelySDK/OptlyConfig/OptimizelyAttribute.cs @@ -18,7 +18,5 @@ namespace OptimizelySDK.OptlyConfig { - public class OptimizelyAttribute : IdKeyEntity - { - } + public class OptimizelyAttribute : IdKeyEntity { } } diff --git a/OptimizelySDK/OptlyConfig/OptimizelyConfig.cs b/OptimizelySDK/OptlyConfig/OptimizelyConfig.cs index 7b682898e..4ea8648d0 100644 --- a/OptimizelySDK/OptlyConfig/OptimizelyConfig.cs +++ b/OptimizelySDK/OptlyConfig/OptimizelyConfig.cs @@ -39,7 +39,10 @@ public class OptimizelyConfig private string _datafile; - public OptimizelyConfig(string revision, IDictionary experimentsMap, IDictionary featuresMap, string datafile = null) + public OptimizelyConfig(string revision, + IDictionary experimentsMap, + IDictionary featuresMap, string datafile = null + ) { Revision = revision; ExperimentsMap = experimentsMap; @@ -47,7 +50,11 @@ public OptimizelyConfig(string revision, IDictionary experimentsMap, IDictionary featuresMap, string datafile = null) + public OptimizelyConfig(string revision, string sdkKey, string environmentKey, + OptimizelyAttribute[] attributes, OptimizelyAudience[] audiences, + OptimizelyEvent[] events, IDictionary experimentsMap, + IDictionary featuresMap, string datafile = null + ) { Revision = revision; SDKKey = sdkKey; diff --git a/OptimizelySDK/OptlyConfig/OptimizelyConfigService.cs b/OptimizelySDK/OptlyConfig/OptimizelyConfigService.cs index 3f65afdd1..29e474414 100644 --- a/OptimizelySDK/OptlyConfig/OptimizelyConfigService.cs +++ b/OptimizelySDK/OptlyConfig/OptimizelyConfigService.cs @@ -15,8 +15,8 @@ */ using System; -using System.Collections.Generic; using System.Collections; +using System.Collections.Generic; using System.Linq; using System.Text; using Newtonsoft.Json; @@ -37,6 +37,7 @@ public OptimizelyConfigService(ProjectConfig projectConfig) { return; } + featureIdVariablesMap = GetFeatureVariablesByIdMap(projectConfig); var attributes = GetAttributes(projectConfig); var audiences = GetAudiences(projectConfig); @@ -68,18 +69,22 @@ private OptimizelyEvent[] GetEvents(ProjectConfig projectConfig) optimizelyEvent.ExperimentIds = ev.ExperimentIds; optimizelyEvents.Add(optimizelyEvent); } + return optimizelyEvents.ToArray(); } private OptimizelyAudience[] GetAudiences(ProjectConfig projectConfig) { - var typedAudiences = projectConfig.TypedAudiences?.Select(aud => new OptimizelyAudience(aud.Id, - aud.Name, - JsonConvert.SerializeObject(aud.Conditions))); + var typedAudiences = projectConfig.TypedAudiences?.Select(aud => + new OptimizelyAudience(aud.Id, + aud.Name, + JsonConvert.SerializeObject(aud.Conditions))); var typedAudienceIds = typedAudiences.Select(ta => ta.Id).ToList(); - var filteredAudiencesArr = Array.FindAll(projectConfig.Audiences, aud => !aud.Id.Equals("$opt_dummy_audience") + var filteredAudiencesArr = Array.FindAll(projectConfig.Audiences, aud => + !aud.Id.Equals("$opt_dummy_audience") && !typedAudienceIds.Contains(aud.Id)); - var optimizelyAudience = filteredAudiencesArr.Select(aud => new OptimizelyAudience(aud.Id, aud.Name, aud.Conditions)); + var optimizelyAudience = filteredAudiencesArr.Select(aud => + new OptimizelyAudience(aud.Id, aud.Name, aud.Conditions)); optimizelyAudience = optimizelyAudience.Concat(typedAudiences).OrderBy(aud => aud.Name); @@ -96,6 +101,7 @@ private OptimizelyAttribute[] GetAttributes(ProjectConfig projectConfig) attribute.Key = attr.Key; attributes.Add(attribute); } + return attributes.ToArray(); } @@ -104,8 +110,9 @@ private OptimizelyAttribute[] GetAttributes(ProjectConfig projectConfig) /// /// /// Map of experiment key. - - private IDictionary GetExperimentsKeyMap(IDictionary experimentsMapById) + private IDictionary GetExperimentsKeyMap( + IDictionary experimentsMapById + ) { var experimentKeyMaps = new Dictionary(); @@ -113,6 +120,7 @@ private IDictionary GetExperimentsKeyMap(IDictiona { experimentKeyMaps[experiment.Key] = experiment; } + return experimentKeyMaps; } @@ -121,17 +129,23 @@ private IDictionary GetExperimentsKeyMap(IDictiona /// /// The project config /// Dictionary | Dictionary of experiment key and value as experiment object - private IDictionary GetExperimentsMapById(ProjectConfig projectConfig) + private IDictionary GetExperimentsMapById( + ProjectConfig projectConfig + ) { var experimentsMap = new Dictionary(); var featureVariableIdMap = GetVariableIdMap(projectConfig); var experiments = projectConfig?.Experiments?.ToList(); - experiments = projectConfig?.Groups?.SelectMany(g => g.Experiments).Concat(experiments)?.ToList(); + experiments = projectConfig?.Groups?.SelectMany(g => g.Experiments). + Concat(experiments)?. + ToList(); - foreach (Experiment experiment in experiments) + foreach (var experiment in experiments) { - var featureId = projectConfig.GetExperimentFeatureList(experiment.Id)?.FirstOrDefault(); - var variationsMap = GetVariationsMap(experiment.Variations, featureVariableIdMap, featureId); + var featureId = projectConfig.GetExperimentFeatureList(experiment.Id)?. + FirstOrDefault(); + var variationsMap = GetVariationsMap(experiment.Variations, featureVariableIdMap, + featureId); var experimentAudience = GetExperimentAudiences(experiment, projectConfig); var optimizelyExperiment = new OptimizelyExperiment(experiment.Id, experiment.Key, @@ -151,12 +165,14 @@ private IDictionary GetExperimentsMapById(ProjectC /// The map of feature variables and id /// feature Id of the feature /// Dictionary | Dictionary of experiment key and value as experiment object - private IDictionary GetVariationsMap(IEnumerable variations, + private IDictionary GetVariationsMap( + IEnumerable variations, IDictionary featureVariableIdMap, - string featureId) + string featureId + ) { var variationsMap = new Dictionary(); - foreach (Variation variation in variations) + foreach (var variation in variations) { var variablesMap = MergeFeatureVariables( featureVariableIdMap, @@ -184,20 +200,23 @@ private IDictionary GetVariationsMap(IEnumerableisFeatureEnabled of variation /// Dictionary | Dictionary of FeatureVariable key and value as FeatureVariable object private IDictionary MergeFeatureVariables( - IDictionary variableIdMap, - string featureId, - IEnumerable featureVariableUsages, - bool isFeatureEnabled) + IDictionary variableIdMap, + string featureId, + IEnumerable featureVariableUsages, + bool isFeatureEnabled + ) { var variablesMap = new Dictionary(); if (!string.IsNullOrEmpty(featureId)) { - variablesMap = featureIdVariablesMap[featureId]?.Select(f => new OptimizelyVariable(f.Id, + variablesMap = featureIdVariablesMap[featureId]?. + Select(f => new OptimizelyVariable(f.Id, f.Key, f.Type.ToString().ToLower(), f.DefaultValue) - ).ToDictionary(k => k.Key, v => v); + ). + ToDictionary(k => k.Key, v => v); foreach (var featureVariableUsage in featureVariableUsages) { @@ -205,7 +224,9 @@ private IDictionary MergeFeatureVariables( var optimizelyVariable = new OptimizelyVariable(featureVariableUsage.Id, defaultVariable.Key, defaultVariable.Type.ToString().ToLower(), - isFeatureEnabled ? featureVariableUsage.Value : defaultVariable.DefaultValue); + isFeatureEnabled ? + featureVariableUsage.Value : + defaultVariable.DefaultValue); variablesMap[defaultVariable.Key] = optimizelyVariable; } @@ -220,19 +241,29 @@ private IDictionary MergeFeatureVariables( /// The project config /// Dictionary of experiment Id as key and value as experiment object /// Dictionary | Dictionary of FeatureFlag key and value as OptimizelyFeature object - private IDictionary GetFeaturesMap(ProjectConfig projectConfig, IDictionary experimentsMapById) + private IDictionary GetFeaturesMap(ProjectConfig projectConfig, + IDictionary experimentsMapById + ) { var FeaturesMap = new Dictionary(); foreach (var featureFlag in projectConfig.FeatureFlags) { - var experimentRules = featureFlag.ExperimentIds.Select(experimentId => experimentsMapById[experimentId]).ToList(); - - var featureVariableMap = featureFlag.Variables.Select(v => (OptimizelyVariable)v).ToDictionary(k => k.Key, v => v) ?? new Dictionary(); - - var featureExperimentMap = experimentRules.ToDictionary(experiment => experiment.Key, experiment => experiment); + var experimentRules = featureFlag.ExperimentIds. + Select(experimentId => experimentsMapById[experimentId]). + ToList(); + + var featureVariableMap = + featureFlag.Variables.Select(v => (OptimizelyVariable)v). + ToDictionary(k => k.Key, v => v) ?? + new Dictionary(); + + var featureExperimentMap = + experimentRules.ToDictionary(experiment => experiment.Key, + experiment => experiment); var rollout = projectConfig.GetRolloutFromId(featureFlag.RolloutId); - var deliveryRules = GetDeliveryRules(featureFlag.Id, rollout.Experiments, projectConfig); + var deliveryRules = + GetDeliveryRules(featureFlag.Id, rollout.Experiments, projectConfig); var optimizelyFeature = new OptimizelyFeature(featureFlag.Id, featureFlag.Key, @@ -254,9 +285,12 @@ private IDictionary GetFeaturesMap(ProjectConfig proj /// /// The project config /// Dictionary | Dictionary of FeatureFlag key and value as list of all FeatureVariable inside it - private IDictionary> GetFeatureVariablesByIdMap(ProjectConfig projectConfig) + private IDictionary> GetFeatureVariablesByIdMap( + ProjectConfig projectConfig + ) { - var featureIdVariablesMap = projectConfig?.FeatureFlags?.ToDictionary(k => k.Id, v => v.Variables); + var featureIdVariablesMap = + projectConfig?.FeatureFlags?.ToDictionary(k => k.Id, v => v.Variables); return featureIdVariablesMap ?? new Dictionary>(); } @@ -273,7 +307,9 @@ private string GetExperimentAudiences(Experiment experiment, ProjectConfig proje { return ""; } - var s = JsonConvert.DeserializeObject>(experiment.AudienceConditionsString); + + var s = JsonConvert.DeserializeObject>(experiment. + AudienceConditionsString); return GetSerializedAudiences(s, projectConfig.AudienceIdMap); } @@ -294,50 +330,63 @@ private string GetExperimentAudiences(Experiment experiment, ProjectConfig proje /// List of audience conditions in experiment /// The audience Id map /// string | Serialized audience in which IDs are replaced with audience name. - private string GetSerializedAudiences(List audienceConditions, Dictionary audienceIdMap) + private string GetSerializedAudiences(List audienceConditions, + Dictionary audienceIdMap + ) { - StringBuilder sAudience = new StringBuilder(""); + var sAudience = new StringBuilder(""); if (audienceConditions != null) { - string cond = ""; + var cond = ""; foreach (var item in audienceConditions) { var subAudience = ""; // Checks if item is list of conditions means if it is sub audience if (item is JArray) { - subAudience = GetSerializedAudiences(((JArray)item).ToObject>(), audienceIdMap); + subAudience = + GetSerializedAudiences(((JArray)item).ToObject>(), + audienceIdMap); subAudience = "(" + subAudience + ")"; } - else if (AUDIENCE_CONDITIONS.Contains(item.ToString())) // Checks if item is an audience condition + else if + (AUDIENCE_CONDITIONS. + Contains(item.ToString())) // Checks if item is an audience condition { cond = item.ToString().ToUpper(); } else - { // Checks if item is audience id + { + // Checks if item is audience id var itemStr = item.ToString(); - var audienceName = audienceIdMap.ContainsKey(itemStr) ? audienceIdMap[itemStr].Name : itemStr; + var audienceName = audienceIdMap.ContainsKey(itemStr) ? + audienceIdMap[itemStr].Name : + itemStr; // if audience condition is "NOT" then add "NOT" at start. Otherwise check if there is already audience id in sAudience then append condition between saudience and item if (!string.IsNullOrEmpty(sAudience.ToString()) || cond.Equals("NOT")) { cond = string.IsNullOrEmpty(cond) ? "OR" : cond; - sAudience = string.IsNullOrEmpty(sAudience.ToString()) ? new StringBuilder(cond + " \"" + audienceIdMap[itemStr]?.Name + "\"") : - sAudience.Append(" " + cond + " \"" + audienceName + "\""); + sAudience = string.IsNullOrEmpty(sAudience.ToString()) ? + new StringBuilder( + cond + " \"" + audienceIdMap[itemStr]?.Name + "\"") : + sAudience.Append(" " + cond + " \"" + audienceName + "\""); } else { sAudience = new StringBuilder("\"" + audienceName + "\""); } } + // Checks if sub audience is empty or not if (!string.IsNullOrEmpty(subAudience)) { if (!string.IsNullOrEmpty(sAudience.ToString()) || cond == "NOT") { cond = string.IsNullOrEmpty(cond) ? "OR" : cond; - sAudience = string.IsNullOrEmpty(sAudience.ToString()) ? new StringBuilder(cond + " " + subAudience) : - sAudience.Append(" " + cond + " " + subAudience); + sAudience = string.IsNullOrEmpty(sAudience.ToString()) ? + new StringBuilder(cond + " " + subAudience) : + sAudience.Append(" " + cond + " " + subAudience); } else { @@ -346,6 +395,7 @@ private string GetSerializedAudiences(List audienceConditions, Dictionar } } } + return sAudience.ToString(); } @@ -356,8 +406,10 @@ private string GetSerializedAudiences(List audienceConditions, Dictionar /// Experiments /// Project Config /// List | List of Optimizely rollout experiments. - private List GetDeliveryRules(string featureId, IEnumerable experiments, - ProjectConfig projectConfig) + private List GetDeliveryRules(string featureId, + IEnumerable experiments, + ProjectConfig projectConfig + ) { if (experiments == null) { @@ -371,11 +423,11 @@ private List GetDeliveryRules(string featureId, IEnumerabl foreach (var experiment in experiments) { var optimizelyExperiment = new OptimizelyExperiment( - id: experiment.Id, - key: experiment.Key, - audiences: GetExperimentAudiences(experiment, projectConfig), - variationsMap: GetVariationsMap(experiment.Variations, featureVariableIdMap, featureId) - ); + experiment.Id, + experiment.Key, + GetExperimentAudiences(experiment, projectConfig), + GetVariationsMap(experiment.Variations, featureVariableIdMap, featureId) + ); deliveryRules.Add(optimizelyExperiment); } @@ -389,7 +441,8 @@ private List GetDeliveryRules(string featureId, IEnumerabl /// Dictionary | Dictionary of FeatureVariableId as key and value as object of FeatureVariable private IDictionary GetVariableIdMap(ProjectConfig projectConfig) { - var featureVariablesIdMap = projectConfig?.FeatureFlags?.SelectMany(f => f.Variables).ToDictionary(k => k.Id, v => v); + var featureVariablesIdMap = projectConfig?.FeatureFlags?.SelectMany(f => f.Variables). + ToDictionary(k => k.Id, v => v); return featureVariablesIdMap ?? new Dictionary(); } diff --git a/OptimizelySDK/OptlyConfig/OptimizelyExperiment.cs b/OptimizelySDK/OptlyConfig/OptimizelyExperiment.cs index 7b0cb84e4..8b81b5558 100644 --- a/OptimizelySDK/OptlyConfig/OptimizelyExperiment.cs +++ b/OptimizelySDK/OptlyConfig/OptimizelyExperiment.cs @@ -20,11 +20,12 @@ namespace OptimizelySDK.OptlyConfig { public class OptimizelyExperiment : Entity.IdKeyEntity { - public IDictionary VariationsMap { get; private set; } public string Audiences { get; private set; } - public OptimizelyExperiment(string id, string key, string audiences, IDictionary variationsMap) + public OptimizelyExperiment(string id, string key, string audiences, + IDictionary variationsMap + ) { Id = id; Key = key; diff --git a/OptimizelySDK/OptlyConfig/OptimizelyFeature.cs b/OptimizelySDK/OptlyConfig/OptimizelyFeature.cs index b69221e69..c35fff66b 100644 --- a/OptimizelySDK/OptlyConfig/OptimizelyFeature.cs +++ b/OptimizelySDK/OptlyConfig/OptimizelyFeature.cs @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using System; using System.Collections.Generic; @@ -20,15 +21,20 @@ namespace OptimizelySDK.OptlyConfig { public class OptimizelyFeature : Entity.IdKeyEntity { - public List ExperimentRules { get; private set; } public List DeliveryRules { get; private set; } [Obsolete("Use experimentRules and deliveryRules.")] public IDictionary ExperimentsMap { get; private set; } + public IDictionary VariablesMap { get; private set; } - public OptimizelyFeature(string id, string key, List experimentRules, List deliveryRules, IDictionary experimentsMap, IDictionary variablesMap) + [Obsolete] + public OptimizelyFeature(string id, string key, List experimentRules, + List deliveryRules, + IDictionary experimentsMap, + IDictionary variablesMap + ) { Id = id; Key = key; diff --git a/OptimizelySDK/OptlyConfig/OptimizelyVariable.cs b/OptimizelySDK/OptlyConfig/OptimizelyVariable.cs index b17435547..d3315d2ee 100644 --- a/OptimizelySDK/OptlyConfig/OptimizelyVariable.cs +++ b/OptimizelySDK/OptlyConfig/OptimizelyVariable.cs @@ -18,7 +18,7 @@ namespace OptimizelySDK.OptlyConfig { - public class OptimizelyVariable : Entity.IdKeyEntity + public class OptimizelyVariable : IdKeyEntity { public string Type { get; private set; } public string Value { get; private set; } @@ -31,7 +31,9 @@ public OptimizelyVariable(string id, string key, string type, string value) Value = value; } - public OptimizelyVariable(FeatureVariable featureVariable, FeatureVariableUsage featureVariableUsage) + public OptimizelyVariable(FeatureVariable featureVariable, + FeatureVariableUsage featureVariableUsage + ) { Id = featureVariable.Id; Key = featureVariable.Key; @@ -42,7 +44,7 @@ public OptimizelyVariable(FeatureVariable featureVariable, FeatureVariableUsage public static explicit operator OptimizelyVariable(FeatureVariable featureVariable) { - return new OptimizelyVariable(featureVariable, null); + return new OptimizelyVariable(featureVariable, null); } } } diff --git a/OptimizelySDK/OptlyConfig/OptimizelyVariation.cs b/OptimizelySDK/OptlyConfig/OptimizelyVariation.cs index 19b66482d..406e44f76 100644 --- a/OptimizelySDK/OptlyConfig/OptimizelyVariation.cs +++ b/OptimizelySDK/OptlyConfig/OptimizelyVariation.cs @@ -14,8 +14,8 @@ * limitations under the License. */ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace OptimizelySDK.OptlyConfig { @@ -23,9 +23,12 @@ public class OptimizelyVariation : Entity.IdKeyEntity { [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public bool? FeatureEnabled { get; private set; } + public IDictionary VariablesMap { get; private set; } - public OptimizelyVariation(string id, string key, bool? featureEnabled, IDictionary variablesMap) + public OptimizelyVariation(string id, string key, bool? featureEnabled, + IDictionary variablesMap + ) { Id = id; Key = key; diff --git a/OptimizelySDK/ProjectConfig.cs b/OptimizelySDK/ProjectConfig.cs index a84c46173..3e0363e8c 100644 --- a/OptimizelySDK/ProjectConfig.cs +++ b/OptimizelySDK/ProjectConfig.cs @@ -14,8 +14,8 @@ * limitations under the License. */ -using OptimizelySDK.Entity; using System.Collections.Generic; +using OptimizelySDK.Entity; namespace OptimizelySDK { diff --git a/OptimizelySDK/Utils/CollectionExtensions.cs b/OptimizelySDK/Utils/CollectionExtensions.cs index 5c2cad153..9a8771bd8 100644 --- a/OptimizelySDK/Utils/CollectionExtensions.cs +++ b/OptimizelySDK/Utils/CollectionExtensions.cs @@ -46,7 +46,7 @@ this Dictionary left, Dictionary right return left; } - foreach (KeyValuePair kvp in right.Where( + foreach (var kvp in right.Where( kvp => !left.ContainsKey(kvp.Key))) { left.Add(kvp.Key, kvp.Value); diff --git a/OptimizelySDK/Utils/ConditionParser.cs b/OptimizelySDK/Utils/ConditionParser.cs index d9a147ef0..6c55ffeb0 100644 --- a/OptimizelySDK/Utils/ConditionParser.cs +++ b/OptimizelySDK/Utils/ConditionParser.cs @@ -14,9 +14,9 @@ * limitations under the License. */ +using System.Collections.Generic; using Newtonsoft.Json.Linq; using OptimizelySDK.AudienceConditions; -using System.Collections.Generic; namespace OptimizelySDK.Utils { @@ -28,38 +28,48 @@ public static class ConditionParser /// /// const string Representing AND operator. /// - const string AND_OPERATOR = "and"; + private const string AND_OPERATOR = "and"; /// /// const string Representing OR operator. /// - const string OR_OPERATOR = "or"; + private const string OR_OPERATOR = "or"; /// /// const string Representing NOT operator. /// - const string NOT_OPERATOR = "not"; + private const string NOT_OPERATOR = "not"; public static ICondition ParseAudienceConditions(JToken audienceConditions) { if (audienceConditions.Type != JTokenType.Array) + { return new AudienceIdCondition { AudienceId = (string)audienceConditions }; + } var conditionsArray = audienceConditions as JArray; if (conditionsArray.Count == 0) + { return new EmptyCondition(); + } var startIndex = 0; var conditionOperator = GetOperator(conditionsArray.First.ToString()); if (conditionOperator != null) + { startIndex = 1; + } else + { conditionOperator = OR_OPERATOR; + } - List conditions = new List(); - for (int i = startIndex; i < conditionsArray.Count; ++i) + var conditions = new List(); + for (var i = startIndex; i < conditionsArray.Count; ++i) + { conditions.Add(ParseAudienceConditions(conditionsArray[i])); + } return GetConditions(conditions, conditionOperator); } @@ -67,6 +77,7 @@ public static ICondition ParseAudienceConditions(JToken audienceConditions) public static ICondition ParseConditions(JToken conditionObj) { if (conditionObj.Type != JTokenType.Array) + { return new BaseCondition { Match = conditionObj["match"]?.ToString(), @@ -74,18 +85,23 @@ public static ICondition ParseConditions(JToken conditionObj) Name = conditionObj["name"].ToString(), Value = conditionObj["value"]?.ToObject(), }; + } var startIndex = 0; var conditionsArray = conditionObj as JArray; var conditionOperator = GetOperator(conditionsArray.First.ToString()); if (conditionOperator != null) + { startIndex = 1; + } else + { conditionOperator = OR_OPERATOR; + } - List conditions = new List(); - for (int i = startIndex; i < conditionsArray.Count; ++i) + var conditions = new List(); + for (var i = startIndex; i < conditionsArray.Count; ++i) { conditions.Add(ParseConditions(conditionsArray[i])); } @@ -95,7 +111,7 @@ public static ICondition ParseConditions(JToken conditionObj) public static string GetOperator(object condition) { - string conditionOperator = (string)condition; + var conditionOperator = (string)condition; switch (conditionOperator) { case OR_OPERATOR: @@ -107,7 +123,8 @@ public static string GetOperator(object condition) } } - public static ICondition GetConditions(List conditions, string conditionOperator) + public static ICondition GetConditions(List conditions, string conditionOperator + ) { ICondition condition = null; switch (conditionOperator) @@ -119,7 +136,8 @@ public static ICondition GetConditions(List conditions, string condi condition = new OrCondition() { Conditions = conditions.ToArray() }; break; case NOT_OPERATOR: - condition = new NotCondition() { Condition = conditions.Count == 0 ? null : conditions[0] }; + condition = new NotCondition() + { Condition = conditions.Count == 0 ? null : conditions[0] }; break; default: break; diff --git a/OptimizelySDK/Utils/ConfigParser.cs b/OptimizelySDK/Utils/ConfigParser.cs index 1d1b73c04..318ff1b6e 100644 --- a/OptimizelySDK/Utils/ConfigParser.cs +++ b/OptimizelySDK/Utils/ConfigParser.cs @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using System; using System.Collections.Generic; using System.Linq; @@ -28,9 +29,11 @@ public static class ConfigParser where T : ICloneable /// A function to return the key value from the entity /// Whether or not to clone the original entity /// associative array of key => entity - public static Dictionary GenerateMap(IEnumerable entities, Func getKey, bool clone) + public static Dictionary GenerateMap(IEnumerable entities, + Func getKey, bool clone + ) { return entities.ToDictionary(e => getKey(e), e => clone ? (T)e.Clone() : e); } } -} \ No newline at end of file +} diff --git a/OptimizelySDK/Utils/ControlAttributes.cs b/OptimizelySDK/Utils/ControlAttributes.cs index 9fc7a5baf..327e9ef21 100644 --- a/OptimizelySDK/Utils/ControlAttributes.cs +++ b/OptimizelySDK/Utils/ControlAttributes.cs @@ -19,7 +19,7 @@ namespace OptimizelySDK.Utils public class ControlAttributes { public const string BOT_FILTERING_ATTRIBUTE = "$opt_bot_filtering"; - public const string BUCKETING_ID_ATTRIBUTE = "$opt_bucketing_id"; - public const string USER_AGENT_ATTRIBUTE = "$opt_user_agent"; + public const string BUCKETING_ID_ATTRIBUTE = "$opt_bucketing_id"; + public const string USER_AGENT_ATTRIBUTE = "$opt_user_agent"; } } diff --git a/OptimizelySDK/Utils/DateTimeUtils.cs b/OptimizelySDK/Utils/DateTimeUtils.cs index 305c16e36..4a217c3d6 100644 --- a/OptimizelySDK/Utils/DateTimeUtils.cs +++ b/OptimizelySDK/Utils/DateTimeUtils.cs @@ -7,13 +7,8 @@ public static class DateTimeUtils /// /// Helper to compute Unix time (i.e. since Jan 1, 1970) /// - public static long SecondsSince1970 - { - get - { - return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; - } - } + public static long SecondsSince1970 => + (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; public static long MillisecondsSince1970(this DateTime dateTime) { diff --git a/OptimizelySDK/Utils/EventTagUtils.cs b/OptimizelySDK/Utils/EventTagUtils.cs index 64482d338..a2a094a81 100644 --- a/OptimizelySDK/Utils/EventTagUtils.cs +++ b/OptimizelySDK/Utils/EventTagUtils.cs @@ -26,10 +26,10 @@ public class EventTagUtils public static object GetRevenueValue(Dictionary eventTags, ILogger logger) { - int result = 0; - bool isCasted = false; - string logMessage = string.Empty; - LogLevel logLevel = LogLevel.INFO; + var result = 0; + var isCasted = false; + var logMessage = string.Empty; + var logLevel = LogLevel.INFO; if (eventTags == null) { @@ -58,20 +58,26 @@ public static object GetRevenueValue(Dictionary eventTags, ILogg } if (logger != null) + { logger.Log(logLevel, logMessage); + } if (isCasted) + { return result; + } return null; } - public static object GetNumericValue(Dictionary eventTags, ILogger logger = null) + public static object GetNumericValue(Dictionary eventTags, + ILogger logger = null + ) { float refVar = 0; - bool isCasted = false; - string logMessage = string.Empty; - LogLevel logLevel = LogLevel.INFO; + var isCasted = false; + var logMessage = string.Empty; + var logLevel = LogLevel.INFO; if (eventTags == null) { @@ -92,10 +98,16 @@ public static object GetNumericValue(Dictionary eventTags, ILogg { logMessage = "Provided numeric value is boolean which is an invalid format."; logLevel = LogLevel.ERROR; - } else if (!(eventTags[VALUE_EVENT_METRIC_NAME] is int) && !(eventTags[VALUE_EVENT_METRIC_NAME] is string) && !(eventTags[VALUE_EVENT_METRIC_NAME] is float) - && !(eventTags[VALUE_EVENT_METRIC_NAME] is decimal) && !(eventTags[VALUE_EVENT_METRIC_NAME] is double) && !(eventTags[VALUE_EVENT_METRIC_NAME] is long) - && !(eventTags[VALUE_EVENT_METRIC_NAME] is short) && !(eventTags[VALUE_EVENT_METRIC_NAME] is uint)) - { + } + else if (!(eventTags[VALUE_EVENT_METRIC_NAME] is int) && + !(eventTags[VALUE_EVENT_METRIC_NAME] is string) && + !(eventTags[VALUE_EVENT_METRIC_NAME] is float) + && !(eventTags[VALUE_EVENT_METRIC_NAME] is decimal) && + !(eventTags[VALUE_EVENT_METRIC_NAME] is double) && + !(eventTags[VALUE_EVENT_METRIC_NAME] is long) + && !(eventTags[VALUE_EVENT_METRIC_NAME] is short) && + !(eventTags[VALUE_EVENT_METRIC_NAME] is uint)) + { logMessage = "Numeric metric value is not in integer, float, or string form."; logLevel = LogLevel.ERROR; } @@ -108,14 +120,16 @@ public static object GetNumericValue(Dictionary eventTags, ILogg { if (!float.TryParse(eventTags[VALUE_EVENT_METRIC_NAME].ToString(), out refVar)) { - logMessage = $"Provided numeric value {eventTags[VALUE_EVENT_METRIC_NAME]} is in an invalid format."; + logMessage = + $"Provided numeric value {eventTags[VALUE_EVENT_METRIC_NAME]} is in an invalid format."; logLevel = LogLevel.ERROR; } else { if (float.IsInfinity(refVar)) { - logMessage = $"Provided numeric value {eventTags[VALUE_EVENT_METRIC_NAME]} is in an invalid format."; + logMessage = + $"Provided numeric value {eventTags[VALUE_EVENT_METRIC_NAME]} is in an invalid format."; logLevel = LogLevel.ERROR; } else @@ -127,10 +141,12 @@ public static object GetNumericValue(Dictionary eventTags, ILogg } if (logger != null) + { logger.Log(logLevel, logMessage); + } object o = refVar; - if(isCasted && eventTags[VALUE_EVENT_METRIC_NAME] is float) + if (isCasted && eventTags[VALUE_EVENT_METRIC_NAME] is float) { // Special case, maximum value when passed and gone through tryparse, it loses precision. o = eventTags[VALUE_EVENT_METRIC_NAME]; @@ -140,4 +156,3 @@ public static object GetNumericValue(Dictionary eventTags, ILogg } } } - \ No newline at end of file diff --git a/OptimizelySDK/Utils/ExceptionExtensions.cs b/OptimizelySDK/Utils/ExceptionExtensions.cs index 8b08cb93f..f6f3f7256 100644 --- a/OptimizelySDK/Utils/ExceptionExtensions.cs +++ b/OptimizelySDK/Utils/ExceptionExtensions.cs @@ -23,9 +23,13 @@ public static class ExceptionExtensions public static string GetAllMessages(this Exception exception, string separator = "\n") { if (exception.InnerException == null) + { return exception.Message; + } - return (string.IsNullOrEmpty(exception.Message) ? "" : $"{exception.Message}{separator}{GetAllMessages(exception.InnerException, separator)}"); + return string.IsNullOrEmpty(exception.Message) ? + "" : + $"{exception.Message}{separator}{GetAllMessages(exception.InnerException, separator)}"; } } } diff --git a/OptimizelySDK/Utils/ExperimentUtils.cs b/OptimizelySDK/Utils/ExperimentUtils.cs index cffd0721f..c87cebbf6 100644 --- a/OptimizelySDK/Utils/ExperimentUtils.cs +++ b/OptimizelySDK/Utils/ExperimentUtils.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright 2017-2022, Optimizely * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,7 +25,6 @@ public class ExperimentUtils { public static bool IsExperimentActive(Experiment experiment, ILogger logger) { - if (!experiment.IsExperimentRunning) { logger.Log(LogLevel.INFO, $"Experiment \"{experiment.Key}\" is not running."); @@ -51,7 +50,8 @@ public static Result DoesUserMeetAudienceConditions(ProjectConfig config, OptimizelyUserContext user, string loggingKeyType, string loggingKey, - ILogger logger) + ILogger logger + ) { var reasons = new DecisionReasons(); if (user == null) @@ -63,21 +63,29 @@ public static Result DoesUserMeetAudienceConditions(ProjectConfig config, if (experiment.AudienceConditionsList != null) { expConditions = experiment.AudienceConditionsList; - logger.Log(LogLevel.DEBUG, $@"Evaluating audiences for {loggingKeyType} ""{loggingKey}"": {experiment.AudienceConditionsString}."); + logger.Log(LogLevel.DEBUG, + $@"Evaluating audiences for {loggingKeyType} ""{loggingKey}"": { + experiment.AudienceConditionsString}."); } else { expConditions = experiment.AudienceIdsList; - logger.Log(LogLevel.DEBUG, $@"Evaluating audiences for {loggingKeyType} ""{loggingKey}"": {experiment.AudienceIdsString}."); + logger.Log(LogLevel.DEBUG, + $@"Evaluating audiences for {loggingKeyType} ""{loggingKey}"": { + experiment.AudienceIdsString}."); } // If there are no audiences, return true because that means ALL users are included in the experiment. if (expConditions == null) + { return Result.NewResult(true, reasons); + } var result = expConditions.Evaluate(config, user, logger).GetValueOrDefault(); var resultText = result.ToString().ToUpper(); - logger.Log(LogLevel.INFO, reasons.AddInfo($@"Audiences for {loggingKeyType} ""{loggingKey}"" collectively evaluated to {resultText}")); + logger.Log(LogLevel.INFO, + reasons.AddInfo($@"Audiences for {loggingKeyType} ""{loggingKey + }"" collectively evaluated to {resultText}")); return Result.NewResult(result, reasons); } } diff --git a/OptimizelySDK/Utils/Schema.cs b/OptimizelySDK/Utils/Schema.cs index 6a854bf36..2ee82c500 100644 --- a/OptimizelySDK/Utils/Schema.cs +++ b/OptimizelySDK/Utils/Schema.cs @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + using System.IO; using System.Reflection; @@ -25,7 +26,9 @@ internal class Schema public static string GetSchemaJson() { if (cache != null) + { return cache; + } #if NET35 || NET40 var assembly = Assembly.GetExecutingAssembly(); #else @@ -33,9 +36,11 @@ public static string GetSchemaJson() #endif const string resourceName = "OptimizelySDK.Utils.schema.json"; - using (Stream stream = assembly.GetManifestResourceStream(resourceName)) - using (StreamReader reader = new StreamReader(stream)) + using (var stream = assembly.GetManifestResourceStream(resourceName)) + using (var reader = new StreamReader(stream)) + { return cache = reader.ReadToEnd(); + } } } -} \ No newline at end of file +} diff --git a/OptimizelySDK/Utils/Validator.cs b/OptimizelySDK/Utils/Validator.cs index fd79ca167..3cae16cd1 100644 --- a/OptimizelySDK/Utils/Validator.cs +++ b/OptimizelySDK/Utils/Validator.cs @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -using OptimizelySDK.Entity; + using System; using System.Collections.Generic; using System.Linq; +using OptimizelySDK.Entity; using Attribute = OptimizelySDK.Entity.Attribute; namespace OptimizelySDK.Utils @@ -37,11 +38,9 @@ public static bool ValidateJSONSchema(string configJson, string schemaJson = nul { try { - return !NJsonSchema.JsonSchema4 - .FromJsonAsync(schemaJson ?? Schema.GetSchemaJson()) - .Result - .Validate(configJson) - .Any(); + return !NJsonSchema.JsonSchema4.FromJsonAsync(schemaJson ?? Schema.GetSchemaJson()). + Result.Validate(configJson). + Any(); } catch (Newtonsoft.Json.JsonReaderException) { @@ -75,10 +74,10 @@ public static bool IsAttributeValid(Attribute attribute) return !int.TryParse(attribute.Key, out key); } - public static bool AreEventTagsValid(Dictionary eventTags) { + public static bool AreEventTagsValid(Dictionary eventTags) + { int key; return eventTags.All(tag => !int.TryParse(tag.Key, out key)); - } /// @@ -93,15 +92,19 @@ public static bool IsFeatureFlagValid(ProjectConfig projectConfig, FeatureFlag f var experimentIds = featureFlag.ExperimentIds; if (experimentIds == null || experimentIds.Count <= 1) + { return true; + } var groupId = projectConfig.GetExperimentFromId(experimentIds[0]).GroupId; - for (int i = 1; i < experimentIds.Count; i++) + for (var i = 1; i < experimentIds.Count; i++) { // Every experiment should have the same group Id. if (projectConfig.GetExperimentFromId(experimentIds[i]).GroupId != groupId) + { return false; + } } return true; @@ -114,8 +117,9 @@ public static bool IsFeatureFlagValid(ProjectConfig projectConfig, FeatureFlag f /// true if attribute key is not null and value is one of the supported type, false otherwise public static bool IsUserAttributeValid(KeyValuePair attribute) { - return (attribute.Key != null) && - (attribute.Value is string || attribute.Value is bool || IsValidNumericValue(attribute.Value)); + return attribute.Key != null && + (attribute.Value is string || attribute.Value is bool || + IsValidNumericValue(attribute.Value)); } /// @@ -125,9 +129,11 @@ public static bool IsUserAttributeValid(KeyValuePair attribute) /// public static bool IsNumericType(object value) { - return value is byte || value is sbyte || value is char || value is short || value is ushort - || value is int || value is uint || value is long || value is ulong || value is float - || value is double || value is decimal; + return value is byte || value is sbyte || value is char || value is short || + value is ushort + || value is int || value is uint || value is long || value is ulong || + value is float + || value is double || value is decimal; } /// @@ -140,8 +146,11 @@ public static bool IsValidNumericValue(object value) if (IsNumericType(value)) { var doubleValue = Convert.ToDouble(value); - if (double.IsInfinity(doubleValue) || double.IsNaN(doubleValue) || Math.Abs(doubleValue) > OPT_NUMBER_LIMIT) + if (double.IsInfinity(doubleValue) || double.IsNaN(doubleValue) || + Math.Abs(doubleValue) > OPT_NUMBER_LIMIT) + { return false; + } return true; } @@ -150,4 +159,3 @@ public static bool IsValidNumericValue(object value) } } } - diff --git a/OptimizelySDK/packages.config b/OptimizelySDK/packages.config index c87329134..d5dd6846e 100644 --- a/OptimizelySDK/packages.config +++ b/OptimizelySDK/packages.config @@ -1,6 +1,6 @@  - - - - \ No newline at end of file + + + +