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/feature_config_condition_validator.h"
6 
7 #include <map>
8 #include <memory>
9 #include <string>
10 
11 #include "base/feature_list.h"
12 #include "base/metrics/field_trial.h"
13 #include "base/test/scoped_feature_list.h"
14 #include "components/feature_engagement/internal/availability_model.h"
15 #include "components/feature_engagement/internal/event_model.h"
16 #include "components/feature_engagement/internal/noop_display_lock_controller.h"
17 #include "components/feature_engagement/internal/proto/feature_event.pb.h"
18 #include "components/feature_engagement/internal/test/event_util.h"
19 #include "components/feature_engagement/public/configuration.h"
20 #include "components/feature_engagement/public/tracker.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 namespace feature_engagement {
24 
25 namespace {
26 
27 const base::Feature kFeatureConfigTestFeatureFoo{
28     "test_foo", base::FEATURE_DISABLED_BY_DEFAULT};
29 const base::Feature kFeatureConfigTestFeatureBar{
30     "test_bar", base::FEATURE_DISABLED_BY_DEFAULT};
31 const base::Feature kFeatureConfigTestFeatureQux{
32     "test_qux", base::FEATURE_DISABLED_BY_DEFAULT};
33 const base::Feature kFeatureConfigTestFeatureXyz{
34     "test_xyz", base::FEATURE_DISABLED_BY_DEFAULT};
35 
GetValidFeatureConfig()36 FeatureConfig GetValidFeatureConfig() {
37   FeatureConfig config;
38   config.valid = true;
39   return config;
40 }
41 
GetAcceptingFeatureConfig()42 FeatureConfig GetAcceptingFeatureConfig() {
43   FeatureConfig config;
44   config.valid = true;
45   config.used = EventConfig("used", Comparator(ANY, 0), 0, 0);
46   config.trigger = EventConfig("trigger", Comparator(ANY, 0), 0, 0);
47   config.session_rate = Comparator(ANY, 0);
48   config.availability = Comparator(ANY, 0);
49   return config;
50 }
51 
CreateSessionRateImpactTypeExplicit(std::vector<std::string> affected_features)52 SessionRateImpact CreateSessionRateImpactTypeExplicit(
53     std::vector<std::string> affected_features) {
54   SessionRateImpact impact;
55   impact.type = SessionRateImpact::Type::EXPLICIT;
56   impact.affected_features = affected_features;
57   return impact;
58 }
59 
60 class TestEventModel : public EventModel {
61  public:
TestEventModel()62   TestEventModel() : ready_(true) {}
63 
Initialize(const OnModelInitializationFinished & callback,uint32_t current_day)64   void Initialize(const OnModelInitializationFinished& callback,
65                   uint32_t current_day) override {}
66 
IsReady() const67   bool IsReady() const override { return ready_; }
68 
SetIsReady(bool ready)69   void SetIsReady(bool ready) { ready_ = ready; }
70 
GetEvent(const std::string & event_name) const71   const Event* GetEvent(const std::string& event_name) const override {
72     auto search = events_.find(event_name);
73     if (search == events_.end())
74       return nullptr;
75 
76     return &search->second;
77   }
78 
SetEvent(const Event & event)79   void SetEvent(const Event& event) { events_[event.name()] = event; }
80 
IncrementEvent(const std::string & event_name,uint32_t day)81   void IncrementEvent(const std::string& event_name, uint32_t day) override {}
82 
83  private:
84   std::map<std::string, Event> events_;
85   bool ready_;
86 };
87 
88 class TestAvailabilityModel : public AvailabilityModel {
89  public:
TestAvailabilityModel()90   TestAvailabilityModel() : ready_(true) {}
91   ~TestAvailabilityModel() override = default;
92 
Initialize(AvailabilityModel::OnInitializedCallback callback,uint32_t current_day)93   void Initialize(AvailabilityModel::OnInitializedCallback callback,
94                   uint32_t current_day) override {}
95 
IsReady() const96   bool IsReady() const override { return ready_; }
97 
SetIsReady(bool ready)98   void SetIsReady(bool ready) { ready_ = ready; }
99 
GetAvailability(const base::Feature & feature) const100   base::Optional<uint32_t> GetAvailability(
101       const base::Feature& feature) const override {
102     auto search = availabilities_.find(feature.name);
103     if (search == availabilities_.end())
104       return base::nullopt;
105 
106     return search->second;
107   }
108 
SetAvailability(const base::Feature * feature,base::Optional<uint32_t> availability)109   void SetAvailability(const base::Feature* feature,
110                        base::Optional<uint32_t> availability) {
111     availabilities_[feature->name] = availability;
112   }
113 
114  private:
115   bool ready_;
116 
117   std::map<std::string, base::Optional<uint32_t>> availabilities_;
118 
119   DISALLOW_COPY_AND_ASSIGN(TestAvailabilityModel);
120 };
121 
122 class TestDisplayLockController : public DisplayLockController {
123  public:
124   TestDisplayLockController() = default;
125   ~TestDisplayLockController() override = default;
126 
AcquireDisplayLock()127   std::unique_ptr<DisplayLockHandle> AcquireDisplayLock() override {
128     return nullptr;
129   }
130 
IsDisplayLocked() const131   bool IsDisplayLocked() const override { return next_display_locked_result_; }
132 
SetNextIsDisplayLockedResult(bool result)133   void SetNextIsDisplayLockedResult(bool result) {
134     next_display_locked_result_ = result;
135   }
136 
137  private:
138   // The next result to return from IsDisplayLocked().
139   bool next_display_locked_result_ = false;
140 
141   DISALLOW_COPY_AND_ASSIGN(TestDisplayLockController);
142 };
143 
144 class FeatureConfigConditionValidatorTest : public ::testing::Test {
145  public:
146   FeatureConfigConditionValidatorTest() = default;
147 
148  protected:
GetResultForDayAndEventWindow(Comparator comparator,uint32_t window,uint32_t current_day)149   ConditionValidator::Result GetResultForDayAndEventWindow(
150       Comparator comparator,
151       uint32_t window,
152       uint32_t current_day) {
153     FeatureConfig config = GetAcceptingFeatureConfig();
154     config.event_configs.insert(EventConfig("event1", comparator, window, 0));
155     return validator_.MeetsConditions(kFeatureConfigTestFeatureFoo, config,
156                                       event_model_, availability_model_,
157                                       display_lock_controller_, current_day);
158   }
159 
GetResultForDay(const FeatureConfig & config,uint32_t current_day)160   ConditionValidator::Result GetResultForDay(const FeatureConfig& config,
161                                              uint32_t current_day) {
162     return validator_.MeetsConditions(kFeatureConfigTestFeatureFoo, config,
163                                       event_model_, availability_model_,
164                                       display_lock_controller_, current_day);
165   }
166 
GetResultForDayZero(const FeatureConfig & config)167   ConditionValidator::Result GetResultForDayZero(const FeatureConfig& config) {
168     return validator_.MeetsConditions(kFeatureConfigTestFeatureFoo, config,
169                                       event_model_, availability_model_,
170                                       display_lock_controller_, 0);
171   }
172 
GetResultForDayZeroForFeature(const base::Feature & feature,const FeatureConfig & config)173   ConditionValidator::Result GetResultForDayZeroForFeature(
174       const base::Feature& feature,
175       const FeatureConfig& config) {
176     return validator_.MeetsConditions(feature, config, event_model_,
177                                       availability_model_,
178                                       display_lock_controller_, 0);
179   }
180 
181   TestEventModel event_model_;
182   TestAvailabilityModel availability_model_;
183   TestDisplayLockController display_lock_controller_;
184   FeatureConfigConditionValidator validator_;
185   uint32_t current_day_;
186 
187  private:
188   DISALLOW_COPY_AND_ASSIGN(FeatureConfigConditionValidatorTest);
189 };
190 
191 }  // namespace
192 
TEST_F(FeatureConfigConditionValidatorTest,ModelNotReadyShouldFail)193 TEST_F(FeatureConfigConditionValidatorTest, ModelNotReadyShouldFail) {
194   base::test::ScopedFeatureList scoped_feature_list;
195   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
196 
197   event_model_.SetIsReady(false);
198 
199   ConditionValidator::Result result =
200       GetResultForDayZero(GetValidFeatureConfig());
201   EXPECT_FALSE(result.NoErrors());
202   EXPECT_FALSE(result.event_model_ready_ok);
203 }
204 
TEST_F(FeatureConfigConditionValidatorTest,ConfigInvalidShouldFail)205 TEST_F(FeatureConfigConditionValidatorTest, ConfigInvalidShouldFail) {
206   base::test::ScopedFeatureList scoped_feature_list;
207   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
208 
209   ConditionValidator::Result result = GetResultForDayZero(FeatureConfig());
210   EXPECT_FALSE(result.NoErrors());
211   EXPECT_FALSE(result.config_ok);
212 }
213 
TEST_F(FeatureConfigConditionValidatorTest,MultipleErrorsShouldBeSet)214 TEST_F(FeatureConfigConditionValidatorTest, MultipleErrorsShouldBeSet) {
215   base::test::ScopedFeatureList scoped_feature_list;
216   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
217 
218   event_model_.SetIsReady(false);
219 
220   ConditionValidator::Result result = GetResultForDayZero(FeatureConfig());
221   EXPECT_FALSE(result.NoErrors());
222   EXPECT_FALSE(result.event_model_ready_ok);
223   EXPECT_FALSE(result.config_ok);
224 }
225 
TEST_F(FeatureConfigConditionValidatorTest,ReadyModelEmptyConfig)226 TEST_F(FeatureConfigConditionValidatorTest, ReadyModelEmptyConfig) {
227   base::test::ScopedFeatureList scoped_feature_list;
228   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
229 
230   EXPECT_TRUE(GetResultForDayZero(GetValidFeatureConfig()).NoErrors());
231 }
232 
TEST_F(FeatureConfigConditionValidatorTest,ReadyModelAcceptingConfig)233 TEST_F(FeatureConfigConditionValidatorTest, ReadyModelAcceptingConfig) {
234   base::test::ScopedFeatureList scoped_feature_list;
235   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
236 
237   EXPECT_TRUE(GetResultForDayZero(GetAcceptingFeatureConfig()).NoErrors());
238 }
239 
TEST_F(FeatureConfigConditionValidatorTest,CurrentlyShowing)240 TEST_F(FeatureConfigConditionValidatorTest, CurrentlyShowing) {
241   base::test::ScopedFeatureList scoped_feature_list;
242   scoped_feature_list.InitWithFeatures(
243       {kFeatureConfigTestFeatureFoo, kFeatureConfigTestFeatureBar}, {});
244 
245   validator_.NotifyIsShowing(
246       kFeatureConfigTestFeatureBar, FeatureConfig(),
247       {kFeatureConfigTestFeatureFoo.name, kFeatureConfigTestFeatureBar.name});
248   ConditionValidator::Result result =
249       GetResultForDayZero(GetAcceptingFeatureConfig());
250   EXPECT_FALSE(result.NoErrors());
251   EXPECT_FALSE(result.currently_showing_ok);
252 }
253 
TEST_F(FeatureConfigConditionValidatorTest,Used)254 TEST_F(FeatureConfigConditionValidatorTest, Used) {
255   base::test::ScopedFeatureList scoped_feature_list;
256   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
257 
258   FeatureConfig config = GetAcceptingFeatureConfig();
259   config.used = EventConfig("used", Comparator(LESS_THAN, 0), 0, 0);
260 
261   ConditionValidator::Result result = GetResultForDayZero(config);
262   EXPECT_FALSE(result.NoErrors());
263   EXPECT_FALSE(result.used_ok);
264 }
265 
TEST_F(FeatureConfigConditionValidatorTest,Trigger)266 TEST_F(FeatureConfigConditionValidatorTest, Trigger) {
267   base::test::ScopedFeatureList scoped_feature_list;
268   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
269 
270   FeatureConfig config = GetAcceptingFeatureConfig();
271   config.trigger = EventConfig("trigger", Comparator(LESS_THAN, 0), 0, 0);
272 
273   ConditionValidator::Result result = GetResultForDayZero(config);
274   EXPECT_FALSE(result.NoErrors());
275   EXPECT_FALSE(result.trigger_ok);
276 }
277 
TEST_F(FeatureConfigConditionValidatorTest,SingleOKPrecondition)278 TEST_F(FeatureConfigConditionValidatorTest, SingleOKPrecondition) {
279   base::test::ScopedFeatureList scoped_feature_list;
280   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
281 
282   FeatureConfig config = GetAcceptingFeatureConfig();
283   config.event_configs.insert(EventConfig("event1", Comparator(ANY, 0), 0, 0));
284 
285   EXPECT_TRUE(GetResultForDayZero(config).NoErrors());
286 }
287 
TEST_F(FeatureConfigConditionValidatorTest,MultipleOKPreconditions)288 TEST_F(FeatureConfigConditionValidatorTest, MultipleOKPreconditions) {
289   base::test::ScopedFeatureList scoped_feature_list;
290   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
291 
292   FeatureConfig config = GetAcceptingFeatureConfig();
293   config.event_configs.insert(EventConfig("event1", Comparator(ANY, 0), 0, 0));
294   config.event_configs.insert(EventConfig("event2", Comparator(ANY, 0), 0, 0));
295 
296   EXPECT_TRUE(GetResultForDayZero(config).NoErrors());
297 }
298 
TEST_F(FeatureConfigConditionValidatorTest,OneOKThenOneFailingPrecondition)299 TEST_F(FeatureConfigConditionValidatorTest, OneOKThenOneFailingPrecondition) {
300   base::test::ScopedFeatureList scoped_feature_list;
301   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
302 
303   FeatureConfig config = GetAcceptingFeatureConfig();
304   config.event_configs.insert(EventConfig("event1", Comparator(ANY, 0), 0, 0));
305   config.event_configs.insert(
306       EventConfig("event2", Comparator(LESS_THAN, 0), 0, 0));
307 
308   ConditionValidator::Result result = GetResultForDayZero(config);
309   EXPECT_FALSE(result.NoErrors());
310   EXPECT_FALSE(result.preconditions_ok);
311 }
312 
TEST_F(FeatureConfigConditionValidatorTest,OneFailingThenOneOKPrecondition)313 TEST_F(FeatureConfigConditionValidatorTest, OneFailingThenOneOKPrecondition) {
314   base::test::ScopedFeatureList scoped_feature_list;
315   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
316 
317   FeatureConfig config = GetAcceptingFeatureConfig();
318   config.event_configs.insert(EventConfig("event1", Comparator(ANY, 0), 0, 0));
319   config.event_configs.insert(
320       EventConfig("event2", Comparator(LESS_THAN, 0), 0, 0));
321 
322   ConditionValidator::Result result = GetResultForDayZero(config);
323   EXPECT_FALSE(result.NoErrors());
324   EXPECT_FALSE(result.preconditions_ok);
325 }
326 
TEST_F(FeatureConfigConditionValidatorTest,TwoFailingPreconditions)327 TEST_F(FeatureConfigConditionValidatorTest, TwoFailingPreconditions) {
328   base::test::ScopedFeatureList scoped_feature_list;
329   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
330 
331   FeatureConfig config = GetAcceptingFeatureConfig();
332   config.event_configs.insert(
333       EventConfig("event1", Comparator(LESS_THAN, 0), 0, 0));
334   config.event_configs.insert(
335       EventConfig("event2", Comparator(LESS_THAN, 0), 0, 0));
336 
337   ConditionValidator::Result result = GetResultForDayZero(config);
338   EXPECT_FALSE(result.NoErrors());
339   EXPECT_FALSE(result.preconditions_ok);
340 }
341 
TEST_F(FeatureConfigConditionValidatorTest,SessionRate)342 TEST_F(FeatureConfigConditionValidatorTest, SessionRate) {
343   base::test::ScopedFeatureList scoped_feature_list;
344   scoped_feature_list.InitWithFeatures(
345       {kFeatureConfigTestFeatureFoo, kFeatureConfigTestFeatureBar}, {});
346   std::vector<std::string> all_feature_names = {
347       kFeatureConfigTestFeatureFoo.name, kFeatureConfigTestFeatureBar.name};
348 
349   FeatureConfig foo_config = GetAcceptingFeatureConfig();
350   foo_config.session_rate = Comparator(LESS_THAN, 2u);
351   FeatureConfig bar_config = GetAcceptingFeatureConfig();
352 
353   EXPECT_TRUE(GetResultForDayZero(foo_config).NoErrors());
354 
355   validator_.NotifyIsShowing(kFeatureConfigTestFeatureBar, bar_config,
356                              all_feature_names);
357   validator_.NotifyDismissed(kFeatureConfigTestFeatureBar);
358   EXPECT_TRUE(GetResultForDayZero(foo_config).NoErrors());
359 
360   validator_.NotifyIsShowing(kFeatureConfigTestFeatureBar, bar_config,
361                              all_feature_names);
362   validator_.NotifyDismissed(kFeatureConfigTestFeatureBar);
363   ConditionValidator::Result result = GetResultForDayZero(foo_config);
364   EXPECT_FALSE(result.NoErrors());
365   EXPECT_FALSE(result.session_rate_ok);
366 
367   validator_.NotifyIsShowing(kFeatureConfigTestFeatureBar, bar_config,
368                              all_feature_names);
369   validator_.NotifyDismissed(kFeatureConfigTestFeatureBar);
370   result = GetResultForDayZero(foo_config);
371   EXPECT_FALSE(result.NoErrors());
372   EXPECT_FALSE(result.session_rate_ok);
373 }
374 
TEST_F(FeatureConfigConditionValidatorTest,SessionRateImpactAffectsNone)375 TEST_F(FeatureConfigConditionValidatorTest, SessionRateImpactAffectsNone) {
376   base::test::ScopedFeatureList scoped_feature_list;
377   scoped_feature_list.InitWithFeatures(
378       {kFeatureConfigTestFeatureFoo, kFeatureConfigTestFeatureBar}, {});
379   std::vector<std::string> all_feature_names = {
380       kFeatureConfigTestFeatureFoo.name, kFeatureConfigTestFeatureBar.name};
381 
382   FeatureConfig foo_config = GetAcceptingFeatureConfig();
383   foo_config.session_rate = Comparator(LESS_THAN, 2u);
384   FeatureConfig affects_none_config = GetAcceptingFeatureConfig();
385   affects_none_config.session_rate_impact = SessionRateImpact();
386   affects_none_config.session_rate_impact.type = SessionRateImpact::Type::NONE;
387 
388   EXPECT_TRUE(GetResultForDayZero(foo_config).NoErrors());
389 
390   validator_.NotifyIsShowing(kFeatureConfigTestFeatureBar, affects_none_config,
391                              all_feature_names);
392   validator_.NotifyDismissed(kFeatureConfigTestFeatureBar);
393   EXPECT_TRUE(GetResultForDayZero(foo_config).NoErrors());
394 
395   validator_.NotifyIsShowing(kFeatureConfigTestFeatureBar, affects_none_config,
396                              all_feature_names);
397   validator_.NotifyDismissed(kFeatureConfigTestFeatureBar);
398   EXPECT_TRUE(GetResultForDayZero(foo_config).NoErrors());
399 
400   validator_.NotifyIsShowing(kFeatureConfigTestFeatureBar, affects_none_config,
401                              all_feature_names);
402   validator_.NotifyDismissed(kFeatureConfigTestFeatureBar);
403   EXPECT_TRUE(GetResultForDayZero(foo_config).NoErrors());
404 }
405 
TEST_F(FeatureConfigConditionValidatorTest,SessionRateImpactAffectsExplicit)406 TEST_F(FeatureConfigConditionValidatorTest, SessionRateImpactAffectsExplicit) {
407   base::test::ScopedFeatureList scoped_feature_list;
408   scoped_feature_list.InitWithFeatures(
409       {kFeatureConfigTestFeatureFoo, kFeatureConfigTestFeatureBar,
410        kFeatureConfigTestFeatureQux},
411       {});
412   std::vector<std::string> all_feature_names = {
413       kFeatureConfigTestFeatureFoo.name, kFeatureConfigTestFeatureBar.name,
414       kFeatureConfigTestFeatureQux.name};
415 
416   FeatureConfig foo_config = GetAcceptingFeatureConfig();
417   foo_config.session_rate = Comparator(LESS_THAN, 2u);
418   FeatureConfig bar_config = GetAcceptingFeatureConfig();
419   bar_config.session_rate = Comparator(LESS_THAN, 2u);
420 
421   FeatureConfig affects_only_foo_config = GetAcceptingFeatureConfig();
422   affects_only_foo_config.session_rate_impact =
423       CreateSessionRateImpactTypeExplicit({kFeatureConfigTestFeatureFoo.name});
424 
425   EXPECT_TRUE(
426       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config)
427           .NoErrors());
428   EXPECT_TRUE(
429       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureBar, bar_config)
430           .NoErrors());
431 
432   validator_.NotifyIsShowing(kFeatureConfigTestFeatureQux,
433                              affects_only_foo_config, all_feature_names);
434   validator_.NotifyDismissed(kFeatureConfigTestFeatureQux);
435   EXPECT_TRUE(
436       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config)
437           .NoErrors());
438   EXPECT_TRUE(
439       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureBar, bar_config)
440           .NoErrors());
441 
442   validator_.NotifyIsShowing(kFeatureConfigTestFeatureQux,
443                              affects_only_foo_config, all_feature_names);
444   validator_.NotifyDismissed(kFeatureConfigTestFeatureQux);
445   ConditionValidator::Result result =
446       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config);
447   EXPECT_FALSE(result.NoErrors());
448   EXPECT_FALSE(result.session_rate_ok);
449   EXPECT_TRUE(
450       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureBar, bar_config)
451           .NoErrors());
452 }
453 
TEST_F(FeatureConfigConditionValidatorTest,SessionRateImpactAffectsSelf)454 TEST_F(FeatureConfigConditionValidatorTest, SessionRateImpactAffectsSelf) {
455   base::test::ScopedFeatureList scoped_feature_list;
456   scoped_feature_list.InitWithFeatures(
457       {kFeatureConfigTestFeatureFoo, kFeatureConfigTestFeatureBar,
458        kFeatureConfigTestFeatureQux},
459       {});
460   std::vector<std::string> all_feature_names = {
461       kFeatureConfigTestFeatureFoo.name, kFeatureConfigTestFeatureBar.name};
462 
463   FeatureConfig foo_config = GetAcceptingFeatureConfig();
464   foo_config.session_rate = Comparator(LESS_THAN, 2u);
465   FeatureConfig bar_config = GetAcceptingFeatureConfig();
466   bar_config.session_rate = Comparator(LESS_THAN, 2u);
467 
468   FeatureConfig affects_only_foo_config = GetAcceptingFeatureConfig();
469   affects_only_foo_config.session_rate_impact =
470       CreateSessionRateImpactTypeExplicit({kFeatureConfigTestFeatureFoo.name});
471 
472   EXPECT_TRUE(
473       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config)
474           .NoErrors());
475   EXPECT_TRUE(
476       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureBar, bar_config)
477           .NoErrors());
478 
479   validator_.NotifyIsShowing(kFeatureConfigTestFeatureFoo,
480                              affects_only_foo_config, all_feature_names);
481   validator_.NotifyDismissed(kFeatureConfigTestFeatureFoo);
482   EXPECT_TRUE(
483       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config)
484           .NoErrors());
485   EXPECT_TRUE(
486       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureBar, bar_config)
487           .NoErrors());
488 
489   validator_.NotifyIsShowing(kFeatureConfigTestFeatureFoo,
490                              affects_only_foo_config, all_feature_names);
491   validator_.NotifyDismissed(kFeatureConfigTestFeatureFoo);
492   ConditionValidator::Result result =
493       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config);
494   EXPECT_FALSE(result.NoErrors());
495   EXPECT_FALSE(result.session_rate_ok);
496   EXPECT_TRUE(
497       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureBar, bar_config)
498           .NoErrors());
499 }
500 
TEST_F(FeatureConfigConditionValidatorTest,SessionRateImpactAffectsExplicitMultipleFeatures)501 TEST_F(FeatureConfigConditionValidatorTest,
502        SessionRateImpactAffectsExplicitMultipleFeatures) {
503   base::test::ScopedFeatureList scoped_feature_list;
504   scoped_feature_list.InitWithFeatures(
505       {kFeatureConfigTestFeatureFoo, kFeatureConfigTestFeatureBar,
506        kFeatureConfigTestFeatureQux, kFeatureConfigTestFeatureXyz},
507       {});
508   std::vector<std::string> all_feature_names = {
509       kFeatureConfigTestFeatureFoo.name, kFeatureConfigTestFeatureBar.name,
510       kFeatureConfigTestFeatureQux.name, kFeatureConfigTestFeatureXyz.name};
511 
512   FeatureConfig foo_config = GetAcceptingFeatureConfig();
513   foo_config.session_rate = Comparator(LESS_THAN, 2u);
514   FeatureConfig bar_config = GetAcceptingFeatureConfig();
515   bar_config.session_rate = Comparator(LESS_THAN, 2u);
516   FeatureConfig xyz_config = GetAcceptingFeatureConfig();
517   xyz_config.session_rate = Comparator(LESS_THAN, 2u);
518 
519   FeatureConfig affects_foo_and_bar_config = GetAcceptingFeatureConfig();
520   affects_foo_and_bar_config.session_rate_impact =
521       CreateSessionRateImpactTypeExplicit({kFeatureConfigTestFeatureFoo.name,
522                                            kFeatureConfigTestFeatureBar.name});
523 
524   EXPECT_TRUE(
525       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config)
526           .NoErrors());
527   EXPECT_TRUE(
528       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureBar, bar_config)
529           .NoErrors());
530   EXPECT_TRUE(
531       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureXyz, xyz_config)
532           .NoErrors());
533 
534   validator_.NotifyIsShowing(kFeatureConfigTestFeatureQux,
535                              affects_foo_and_bar_config, all_feature_names);
536   validator_.NotifyDismissed(kFeatureConfigTestFeatureQux);
537   EXPECT_TRUE(
538       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config)
539           .NoErrors());
540   EXPECT_TRUE(
541       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureBar, bar_config)
542           .NoErrors());
543   EXPECT_TRUE(
544       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureXyz, xyz_config)
545           .NoErrors());
546 
547   validator_.NotifyIsShowing(kFeatureConfigTestFeatureQux,
548                              affects_foo_and_bar_config, all_feature_names);
549   validator_.NotifyDismissed(kFeatureConfigTestFeatureQux);
550   ConditionValidator::Result foo_result =
551       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config);
552   EXPECT_FALSE(foo_result.NoErrors());
553   EXPECT_FALSE(foo_result.session_rate_ok);
554   ConditionValidator::Result bar_result =
555       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, bar_config);
556   EXPECT_FALSE(bar_result.NoErrors());
557   EXPECT_FALSE(bar_result.session_rate_ok);
558   EXPECT_TRUE(
559       GetResultForDayZeroForFeature(kFeatureConfigTestFeatureXyz, xyz_config)
560           .NoErrors());
561 }
562 
TEST_F(FeatureConfigConditionValidatorTest,Availability)563 TEST_F(FeatureConfigConditionValidatorTest, Availability) {
564   base::test::ScopedFeatureList scoped_feature_list;
565   scoped_feature_list.InitWithFeatures(
566       {kFeatureConfigTestFeatureFoo, kFeatureConfigTestFeatureBar}, {});
567 
568   FeatureConfig config = GetAcceptingFeatureConfig();
569   EXPECT_TRUE(GetResultForDayZero(config).NoErrors());
570   EXPECT_TRUE(GetResultForDay(config, 100u).NoErrors());
571 
572   // When the AvailabilityModel is not ready, it should fail.
573   availability_model_.SetIsReady(false);
574   ConditionValidator::Result result = GetResultForDayZero(config);
575   EXPECT_FALSE(result.NoErrors());
576   EXPECT_FALSE(result.availability_model_ready_ok);
577   result = GetResultForDay(config, 100u);
578   EXPECT_FALSE(result.NoErrors());
579   EXPECT_FALSE(result.availability_model_ready_ok);
580 
581   // Reset state back to ready.
582   availability_model_.SetIsReady(true);
583 
584   // For a feature that became available on day 2 that has to have been
585   // available for at least 1 day, it should start being accepted on day 3.
586   availability_model_.SetAvailability(&kFeatureConfigTestFeatureFoo, 2u);
587   config.availability = Comparator(GREATER_THAN_OR_EQUAL, 1u);
588   result = GetResultForDay(config, 1u);
589   EXPECT_FALSE(result.NoErrors());
590   EXPECT_FALSE(result.availability_ok);
591   result = GetResultForDay(config, 2u);
592   EXPECT_FALSE(result.NoErrors());
593   EXPECT_FALSE(result.availability_ok);
594   EXPECT_TRUE(GetResultForDay(config, 3u).NoErrors());
595   EXPECT_TRUE(GetResultForDay(config, 4u).NoErrors());
596 
597   // For a feature that became available on day 10 that has to have been
598   // available for at least 3 days, it should start being accepted on day 13.
599   availability_model_.SetAvailability(&kFeatureConfigTestFeatureFoo, 10u);
600   config.availability = Comparator(GREATER_THAN_OR_EQUAL, 3u);
601   result = GetResultForDay(config, 11u);
602   EXPECT_FALSE(result.NoErrors());
603   EXPECT_FALSE(result.availability_ok);
604   result = GetResultForDay(config, 12u);
605   EXPECT_FALSE(result.NoErrors());
606   EXPECT_FALSE(result.availability_ok);
607   EXPECT_TRUE(GetResultForDay(config, 13u).NoErrors());
608   EXPECT_TRUE(GetResultForDay(config, 14u).NoErrors());
609 }
610 
TEST_F(FeatureConfigConditionValidatorTest,SingleEventChangingComparator)611 TEST_F(FeatureConfigConditionValidatorTest, SingleEventChangingComparator) {
612   base::test::ScopedFeatureList scoped_feature_list;
613   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
614 
615   uint32_t current_day = 102u;
616   uint32_t window = 10u;
617 
618   // Create event with 10 events per day for three days.
619   Event event1;
620   event1.set_name("event1");
621   test::SetEventCountForDay(&event1, 100u, 10u);
622   test::SetEventCountForDay(&event1, 101u, 10u);
623   test::SetEventCountForDay(&event1, 102u, 10u);
624   event_model_.SetEvent(event1);
625 
626   EXPECT_TRUE(GetResultForDayAndEventWindow(Comparator(LESS_THAN, 50u), window,
627                                             current_day)
628                   .NoErrors());
629   EXPECT_TRUE(
630       GetResultForDayAndEventWindow(Comparator(EQUAL, 30u), window, current_day)
631           .NoErrors());
632   EXPECT_FALSE(GetResultForDayAndEventWindow(Comparator(LESS_THAN, 30u), window,
633                                              current_day)
634                    .NoErrors());
635 }
636 
TEST_F(FeatureConfigConditionValidatorTest,SingleEventChangingWindow)637 TEST_F(FeatureConfigConditionValidatorTest, SingleEventChangingWindow) {
638   base::test::ScopedFeatureList scoped_feature_list;
639   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
640 
641   Event event1;
642   event1.set_name("event1");
643   test::SetEventCountForDay(&event1, 100u, 10u);
644   test::SetEventCountForDay(&event1, 101u, 10u);
645   test::SetEventCountForDay(&event1, 102u, 10u);
646   test::SetEventCountForDay(&event1, 103u, 10u);
647   test::SetEventCountForDay(&event1, 104u, 10u);
648   event_model_.SetEvent(event1);
649 
650   uint32_t current_day = 104u;
651 
652   EXPECT_FALSE(GetResultForDayAndEventWindow(Comparator(GREATER_THAN, 30u), 0,
653                                              current_day)
654                    .NoErrors());
655   EXPECT_FALSE(GetResultForDayAndEventWindow(Comparator(GREATER_THAN, 30u), 1u,
656                                              current_day)
657                    .NoErrors());
658   EXPECT_FALSE(GetResultForDayAndEventWindow(Comparator(GREATER_THAN, 30u), 2u,
659                                              current_day)
660                    .NoErrors());
661   EXPECT_FALSE(GetResultForDayAndEventWindow(Comparator(GREATER_THAN, 30u), 3u,
662                                              current_day)
663                    .NoErrors());
664   EXPECT_TRUE(GetResultForDayAndEventWindow(Comparator(GREATER_THAN, 30u), 4u,
665                                             current_day)
666                   .NoErrors());
667   EXPECT_TRUE(GetResultForDayAndEventWindow(Comparator(GREATER_THAN, 30u), 5u,
668                                             current_day)
669                   .NoErrors());
670 }
671 
TEST_F(FeatureConfigConditionValidatorTest,CapEarliestAcceptedDayAtEpoch)672 TEST_F(FeatureConfigConditionValidatorTest, CapEarliestAcceptedDayAtEpoch) {
673   base::test::ScopedFeatureList scoped_feature_list;
674   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
675 
676   Event event1;
677   event1.set_name("event1");
678   test::SetEventCountForDay(&event1, 0, 10u);
679   test::SetEventCountForDay(&event1, 1u, 10u);
680   test::SetEventCountForDay(&event1, 2u, 10u);
681   event_model_.SetEvent(event1);
682 
683   uint32_t current_day = 100u;
684 
685   EXPECT_TRUE(
686       GetResultForDayAndEventWindow(Comparator(EQUAL, 10u), 99u, current_day)
687           .NoErrors());
688   EXPECT_TRUE(
689       GetResultForDayAndEventWindow(Comparator(EQUAL, 20u), 100u, current_day)
690           .NoErrors());
691   EXPECT_TRUE(
692       GetResultForDayAndEventWindow(Comparator(EQUAL, 30u), 101u, current_day)
693           .NoErrors());
694   EXPECT_TRUE(
695       GetResultForDayAndEventWindow(Comparator(EQUAL, 30u), 1000u, current_day)
696           .NoErrors());
697 }
698 
TEST_F(FeatureConfigConditionValidatorTest,TestMultipleEvents)699 TEST_F(FeatureConfigConditionValidatorTest, TestMultipleEvents) {
700   base::test::ScopedFeatureList scoped_feature_list;
701   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
702 
703   Event event1;
704   event1.set_name("event1");
705   test::SetEventCountForDay(&event1, 0, 10u);
706   test::SetEventCountForDay(&event1, 1u, 10u);
707   test::SetEventCountForDay(&event1, 2u, 10u);
708   event_model_.SetEvent(event1);
709 
710   Event event2;
711   event2.set_name("event2");
712   test::SetEventCountForDay(&event2, 0, 5u);
713   test::SetEventCountForDay(&event2, 1u, 5u);
714   test::SetEventCountForDay(&event2, 2u, 5u);
715   event_model_.SetEvent(event2);
716 
717   uint32_t current_day = 100u;
718 
719   // Verify validator counts correctly for two events last 99 days.
720   FeatureConfig config = GetAcceptingFeatureConfig();
721   config.event_configs.insert(
722       EventConfig("event1", Comparator(EQUAL, 10u), 99u, 0));
723   config.event_configs.insert(
724       EventConfig("event2", Comparator(EQUAL, 5u), 99u, 0));
725   ConditionValidator::Result result = validator_.MeetsConditions(
726       kFeatureConfigTestFeatureFoo, config, event_model_, availability_model_,
727       display_lock_controller_, current_day);
728   EXPECT_TRUE(result.NoErrors());
729 
730   // Verify validator counts correctly for two events last 100 days.
731   config = GetAcceptingFeatureConfig();
732   config.event_configs.insert(
733       EventConfig("event1", Comparator(EQUAL, 20u), 100u, 0));
734   config.event_configs.insert(
735       EventConfig("event2", Comparator(EQUAL, 10u), 100u, 0));
736   result = validator_.MeetsConditions(kFeatureConfigTestFeatureFoo, config,
737                                       event_model_, availability_model_,
738                                       display_lock_controller_, current_day);
739   EXPECT_TRUE(result.NoErrors());
740 
741   // Verify validator counts correctly for two events last 101 days.
742   config = GetAcceptingFeatureConfig();
743   config.event_configs.insert(
744       EventConfig("event1", Comparator(EQUAL, 30u), 101u, 0));
745   config.event_configs.insert(
746       EventConfig("event2", Comparator(EQUAL, 15u), 101u, 0));
747   result = validator_.MeetsConditions(kFeatureConfigTestFeatureFoo, config,
748                                       event_model_, availability_model_,
749                                       display_lock_controller_, current_day);
750   EXPECT_TRUE(result.NoErrors());
751 
752   // Verify validator counts correctly for two events last 101 days, and returns
753   // error when first event fails.
754   config = GetAcceptingFeatureConfig();
755   config.event_configs.insert(
756       EventConfig("event1", Comparator(EQUAL, 0), 101u, 0));
757   config.event_configs.insert(
758       EventConfig("event2", Comparator(EQUAL, 15u), 101u, 0));
759   result = validator_.MeetsConditions(kFeatureConfigTestFeatureFoo, config,
760                                       event_model_, availability_model_,
761                                       display_lock_controller_, current_day);
762   EXPECT_FALSE(result.NoErrors());
763   EXPECT_FALSE(result.preconditions_ok);
764 
765   // Verify validator counts correctly for two events last 101 days, and returns
766   // error when second event fails.
767   config = GetAcceptingFeatureConfig();
768   config.event_configs.insert(
769       EventConfig("event1", Comparator(EQUAL, 30u), 101u, 0));
770   config.event_configs.insert(
771       EventConfig("event2", Comparator(EQUAL, 0), 101u, 0));
772   result = validator_.MeetsConditions(kFeatureConfigTestFeatureFoo, config,
773                                       event_model_, availability_model_,
774                                       display_lock_controller_, current_day);
775   EXPECT_FALSE(result.NoErrors());
776   EXPECT_FALSE(result.preconditions_ok);
777 
778   // Verify validator counts correctly for two events last 101 days, and returns
779   // error when both events fail.
780   config = GetAcceptingFeatureConfig();
781   config.event_configs.insert(
782       EventConfig("event1", Comparator(EQUAL, 0), 101u, 0));
783   config.event_configs.insert(
784       EventConfig("event2", Comparator(EQUAL, 0), 101u, 0));
785   result = validator_.MeetsConditions(kFeatureConfigTestFeatureFoo, config,
786                                       event_model_, availability_model_,
787                                       display_lock_controller_, current_day);
788   EXPECT_FALSE(result.NoErrors());
789   EXPECT_FALSE(result.preconditions_ok);
790 }
791 
TEST_F(FeatureConfigConditionValidatorTest,TestStaggeredTriggering)792 TEST_F(FeatureConfigConditionValidatorTest, TestStaggeredTriggering) {
793   base::test::ScopedFeatureList scoped_feature_list;
794   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
795 
796   // Trigger maximum 2 times, and only 1 time last 2 days (today + yesterday).
797   FeatureConfig config;
798   config.valid = true;
799   config.used = EventConfig("used", Comparator(ANY, 0), 0, 0);
800   config.trigger = EventConfig("trigger", Comparator(LESS_THAN, 2), 100u, 100u);
801   config.session_rate = Comparator(ANY, 0);
802   config.availability = Comparator(ANY, 0);
803   config.event_configs.insert(
804       EventConfig("trigger", Comparator(LESS_THAN, 1u), 2u, 100u));
805 
806   // Should be OK to trigger initially on day 0.
807   EXPECT_TRUE(GetResultForDay(config, 0u).NoErrors());
808 
809   // Set that we triggered on day 0. We should then only trigger on day 2+.
810   Event trigger_event;
811   trigger_event.set_name("trigger");
812   test::SetEventCountForDay(&trigger_event, 0u, 1u);
813   event_model_.SetEvent(trigger_event);
814   EXPECT_FALSE(GetResultForDay(config, 0u).NoErrors());
815   EXPECT_FALSE(GetResultForDay(config, 1u).NoErrors());
816   EXPECT_TRUE(GetResultForDay(config, 2u).NoErrors());
817   EXPECT_TRUE(GetResultForDay(config, 3u).NoErrors());
818 
819   // Set that we triggered again on day 2. We should then not trigger again
820   // until max storage time has passed (100 days), which would expire the
821   // trigger from day 0.
822   test::SetEventCountForDay(&trigger_event, 2u, 1u);
823   event_model_.SetEvent(trigger_event);
824   EXPECT_FALSE(GetResultForDay(config, 2u).NoErrors());
825   EXPECT_FALSE(GetResultForDay(config, 3u).NoErrors());
826   EXPECT_FALSE(GetResultForDay(config, 4u).NoErrors());
827   EXPECT_FALSE(GetResultForDay(config, 5u).NoErrors());
828   EXPECT_FALSE(GetResultForDay(config, 99u).NoErrors());
829   EXPECT_TRUE(GetResultForDay(config, 100u).NoErrors());
830 }
831 
TEST_F(FeatureConfigConditionValidatorTest,TestMultipleEventsWithSameName)832 TEST_F(FeatureConfigConditionValidatorTest, TestMultipleEventsWithSameName) {
833   base::test::ScopedFeatureList scoped_feature_list;
834   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
835 
836   // Trigger maximum 2 times, and only 1 time last 2 days (today + yesterday).
837   FeatureConfig config = GetAcceptingFeatureConfig();
838   config.event_configs.insert(
839       EventConfig("event1", Comparator(LESS_THAN, 1u), 2u, 100u));
840   config.event_configs.insert(
841       EventConfig("event1", Comparator(LESS_THAN, 2u), 100u, 100u));
842 
843   // Should be OK to trigger initially on day 0.
844   EXPECT_TRUE(GetResultForDay(config, 0u).NoErrors());
845 
846   // Set that we had event1 on day 0. We should then only trigger on day 2+.
847   Event event1;
848   event1.set_name("event1");
849   test::SetEventCountForDay(&event1, 0u, 1u);
850   event_model_.SetEvent(event1);
851   EXPECT_FALSE(GetResultForDay(config, 0u).NoErrors());
852   EXPECT_FALSE(GetResultForDay(config, 1u).NoErrors());
853   EXPECT_TRUE(GetResultForDay(config, 2u).NoErrors());
854   EXPECT_TRUE(GetResultForDay(config, 3u).NoErrors());
855 
856   // Set that we had event1 again on day 2. We should then not trigger again
857   // until max storage time has passed (100 days), which would expire the
858   // trigger from day 0.
859   test::SetEventCountForDay(&event1, 2u, 1u);
860   event_model_.SetEvent(event1);
861   EXPECT_FALSE(GetResultForDay(config, 2u).NoErrors());
862   EXPECT_FALSE(GetResultForDay(config, 3u).NoErrors());
863   EXPECT_FALSE(GetResultForDay(config, 4u).NoErrors());
864   EXPECT_FALSE(GetResultForDay(config, 5u).NoErrors());
865   EXPECT_FALSE(GetResultForDay(config, 99u).NoErrors());
866   EXPECT_TRUE(GetResultForDay(config, 100u).NoErrors());
867 }
868 
TEST_F(FeatureConfigConditionValidatorTest,DisplayLockedStatus)869 TEST_F(FeatureConfigConditionValidatorTest, DisplayLockedStatus) {
870   base::test::ScopedFeatureList scoped_feature_list;
871   scoped_feature_list.InitWithFeatures({kFeatureConfigTestFeatureFoo}, {});
872 
873   // When the display is locked, the result should be negative.
874   display_lock_controller_.SetNextIsDisplayLockedResult(true);
875 
876   ConditionValidator::Result result =
877       GetResultForDayZero(GetAcceptingFeatureConfig());
878   EXPECT_FALSE(result.NoErrors());
879   EXPECT_FALSE(result.display_lock_ok);
880 
881   // Setting the display to unlocked should make the result positive.
882   display_lock_controller_.SetNextIsDisplayLockedResult(false);
883 
884   EXPECT_TRUE(GetResultForDayZero(GetAcceptingFeatureConfig()).NoErrors());
885 }
886 
887 }  // namespace feature_engagement
888