1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/feature_engagement/internal/once_condition_validator.h"
6 
7 #include <string>
8 
9 #include "base/feature_list.h"
10 #include "components/feature_engagement/internal/editable_configuration.h"
11 #include "components/feature_engagement/internal/event_model.h"
12 #include "components/feature_engagement/internal/never_availability_model.h"
13 #include "components/feature_engagement/internal/noop_display_lock_controller.h"
14 #include "components/feature_engagement/internal/proto/feature_event.pb.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace feature_engagement {
18 
19 namespace {
20 
21 const base::Feature kOnceTestFeatureFoo{"test_foo",
22                                         base::FEATURE_DISABLED_BY_DEFAULT};
23 const base::Feature kOnceTestFeatureBar{"test_bar",
24                                         base::FEATURE_DISABLED_BY_DEFAULT};
25 
26 FeatureConfig kValidFeatureConfig;
27 FeatureConfig kInvalidFeatureConfig;
28 
29 // A EventModel that is easily configurable at runtime.
30 class OnceTestEventModel : public EventModel {
31  public:
OnceTestEventModel()32   OnceTestEventModel() : ready_(false) { kValidFeatureConfig.valid = true; }
33 
Initialize(const OnModelInitializationFinished & callback,uint32_t current_day)34   void Initialize(const OnModelInitializationFinished& callback,
35                   uint32_t current_day) override {}
36 
IsReady() const37   bool IsReady() const override { return ready_; }
38 
SetIsReady(bool ready)39   void SetIsReady(bool ready) { ready_ = ready; }
40 
GetEvent(const std::string & event_name) const41   const Event* GetEvent(const std::string& event_name) const override {
42     return nullptr;
43   }
44 
IncrementEvent(const std::string & event_name,uint32_t day)45   void IncrementEvent(const std::string& event_name, uint32_t day) override {}
46 
47  private:
48   bool ready_;
49 };
50 
51 class OnceConditionValidatorTest : public ::testing::Test {
52  public:
OnceConditionValidatorTest()53   OnceConditionValidatorTest() {
54     // By default, event model should be ready.
55     event_model_.SetIsReady(true);
56   }
57 
58  protected:
59   EditableConfiguration configuration_;
60   OnceTestEventModel event_model_;
61   NeverAvailabilityModel availability_model_;
62   NoopDisplayLockController display_lock_controller_;
63   OnceConditionValidator validator_;
64 
65  private:
66   DISALLOW_COPY_AND_ASSIGN(OnceConditionValidatorTest);
67 };
68 
69 }  // namespace
70 
TEST_F(OnceConditionValidatorTest,EnabledFeatureShouldTriggerOnce)71 TEST_F(OnceConditionValidatorTest, EnabledFeatureShouldTriggerOnce) {
72   // Only the first call to MeetsConditions() should lead to enlightenment.
73   EXPECT_TRUE(validator_
74                   .MeetsConditions(kOnceTestFeatureFoo, kValidFeatureConfig,
75                                    event_model_, availability_model_,
76                                    display_lock_controller_, 0u)
77                   .NoErrors());
78   validator_.NotifyIsShowing(kOnceTestFeatureFoo, FeatureConfig(), {""});
79   ConditionValidator::Result result = validator_.MeetsConditions(
80       kOnceTestFeatureFoo, kValidFeatureConfig, event_model_,
81       availability_model_, display_lock_controller_, 0u);
82   EXPECT_FALSE(result.NoErrors());
83   EXPECT_FALSE(result.session_rate_ok);
84   EXPECT_FALSE(result.trigger_ok);
85 }
86 
TEST_F(OnceConditionValidatorTest,BothEnabledAndDisabledFeaturesShouldTrigger)87 TEST_F(OnceConditionValidatorTest,
88        BothEnabledAndDisabledFeaturesShouldTrigger) {
89   // Only the kOnceTestFeatureFoo feature should lead to enlightenment, since
90   // kOnceTestFeatureBar is disabled. Ordering disabled feature first to ensure
91   // this captures a different behavior than the
92   // OnlyOneFeatureShouldTriggerPerSession test below.
93   EXPECT_TRUE(validator_
94                   .MeetsConditions(kOnceTestFeatureBar, kValidFeatureConfig,
95                                    event_model_, availability_model_,
96                                    display_lock_controller_, 0u)
97                   .NoErrors());
98   EXPECT_TRUE(validator_
99                   .MeetsConditions(kOnceTestFeatureFoo, kValidFeatureConfig,
100                                    event_model_, availability_model_,
101                                    display_lock_controller_, 0u)
102                   .NoErrors());
103 }
104 
TEST_F(OnceConditionValidatorTest,StillTriggerWhenAllFeaturesDisabled)105 TEST_F(OnceConditionValidatorTest, StillTriggerWhenAllFeaturesDisabled) {
106   // No features should get to show enlightenment.
107   EXPECT_TRUE(validator_
108                   .MeetsConditions(kOnceTestFeatureFoo, kValidFeatureConfig,
109                                    event_model_, availability_model_,
110                                    display_lock_controller_, 0u)
111                   .NoErrors());
112   EXPECT_TRUE(validator_
113                   .MeetsConditions(kOnceTestFeatureBar, kValidFeatureConfig,
114                                    event_model_, availability_model_,
115                                    display_lock_controller_, 0u)
116                   .NoErrors());
117 }
118 
TEST_F(OnceConditionValidatorTest,OnlyTriggerWhenModelIsReady)119 TEST_F(OnceConditionValidatorTest, OnlyTriggerWhenModelIsReady) {
120   event_model_.SetIsReady(false);
121   ConditionValidator::Result result = validator_.MeetsConditions(
122       kOnceTestFeatureFoo, kValidFeatureConfig, event_model_,
123       availability_model_, display_lock_controller_, 0u);
124   EXPECT_FALSE(result.NoErrors());
125   EXPECT_FALSE(result.event_model_ready_ok);
126 
127   event_model_.SetIsReady(true);
128   EXPECT_TRUE(validator_
129                   .MeetsConditions(kOnceTestFeatureFoo, kValidFeatureConfig,
130                                    event_model_, availability_model_,
131                                    display_lock_controller_, 0u)
132                   .NoErrors());
133 }
134 
TEST_F(OnceConditionValidatorTest,OnlyTriggerIfNothingElseIsShowing)135 TEST_F(OnceConditionValidatorTest, OnlyTriggerIfNothingElseIsShowing) {
136   validator_.NotifyIsShowing(kOnceTestFeatureBar, FeatureConfig(), {""});
137   ConditionValidator::Result result = validator_.MeetsConditions(
138       kOnceTestFeatureFoo, kValidFeatureConfig, event_model_,
139       availability_model_, display_lock_controller_, 0u);
140   EXPECT_FALSE(result.NoErrors());
141   EXPECT_FALSE(result.currently_showing_ok);
142 
143   validator_.NotifyDismissed(kOnceTestFeatureBar);
144   EXPECT_TRUE(validator_
145                   .MeetsConditions(kOnceTestFeatureFoo, kValidFeatureConfig,
146                                    event_model_, availability_model_,
147                                    display_lock_controller_, 0u)
148                   .NoErrors());
149 }
150 
TEST_F(OnceConditionValidatorTest,DoNotTriggerForInvalidConfig)151 TEST_F(OnceConditionValidatorTest, DoNotTriggerForInvalidConfig) {
152   ConditionValidator::Result result = validator_.MeetsConditions(
153       kOnceTestFeatureFoo, kInvalidFeatureConfig, event_model_,
154       availability_model_, display_lock_controller_, 0u);
155   EXPECT_FALSE(result.NoErrors());
156   EXPECT_FALSE(result.config_ok);
157 
158   EXPECT_TRUE(validator_
159                   .MeetsConditions(kOnceTestFeatureFoo, kValidFeatureConfig,
160                                    event_model_, availability_model_,
161                                    display_lock_controller_, 0u)
162                   .NoErrors());
163 }
164 
165 }  // namespace feature_engagement
166