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/event_model_impl.h"
6 
7 #include <memory>
8 
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/feature_list.h"
12 #include "base/test/test_simple_task_runner.h"
13 #include "base/threading/thread_task_runner_handle.h"
14 #include "components/feature_engagement/internal/editable_configuration.h"
15 #include "components/feature_engagement/internal/in_memory_event_store.h"
16 #include "components/feature_engagement/internal/never_event_storage_validator.h"
17 #include "components/feature_engagement/internal/proto/feature_event.pb.h"
18 #include "components/feature_engagement/internal/test/event_util.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 namespace feature_engagement {
22 
23 namespace {
24 
25 // A test-only implementation of InMemoryEventStore that tracks calls to
26 // WriteEvent(...).
27 class TestInMemoryEventStore : public InMemoryEventStore {
28  public:
TestInMemoryEventStore(std::unique_ptr<std::vector<Event>> events,bool load_should_succeed)29   TestInMemoryEventStore(std::unique_ptr<std::vector<Event>> events,
30                          bool load_should_succeed)
31       : InMemoryEventStore(std::move(events)),
32         store_operation_count_(0),
33         load_should_succeed_(load_should_succeed) {}
34 
Load(const OnLoadedCallback & callback)35   void Load(const OnLoadedCallback& callback) override {
36     HandleLoadResult(callback, load_should_succeed_);
37   }
38 
WriteEvent(const Event & event)39   void WriteEvent(const Event& event) override {
40     ++store_operation_count_;
41     last_written_event_.reset(new Event(event));
42   }
43 
DeleteEvent(const std::string & event_name)44   void DeleteEvent(const std::string& event_name) override {
45     ++store_operation_count_;
46     last_deleted_event_ = event_name;
47   }
48 
GetLastWrittenEvent()49   const Event* GetLastWrittenEvent() { return last_written_event_.get(); }
50 
GetLastDeletedEvent()51   const std::string GetLastDeletedEvent() { return last_deleted_event_; }
52 
GetStoreOperationCount()53   uint32_t GetStoreOperationCount() { return store_operation_count_; }
54 
55  private:
56   // Temporary store the last written event.
57   std::unique_ptr<Event> last_written_event_;
58 
59   // Temporary store the last deleted event.
60   std::string last_deleted_event_;
61 
62   // Tracks the number of operations performed on the store.
63   uint32_t store_operation_count_;
64 
65   // Denotes whether the call to Load(...) should succeed or not. This impacts
66   // both the ready-state and the result for the OnLoadedCallback.
67   bool load_should_succeed_;
68 };
69 
70 class TestEventStorageValidator : public EventStorageValidator {
71  public:
TestEventStorageValidator()72   TestEventStorageValidator() : should_store_(true) {}
73 
ShouldStore(const std::string & event_name) const74   bool ShouldStore(const std::string& event_name) const override {
75     return should_store_;
76   }
77 
ShouldKeep(const std::string & event_name,uint32_t event_day,uint32_t current_day) const78   bool ShouldKeep(const std::string& event_name,
79                   uint32_t event_day,
80                   uint32_t current_day) const override {
81     auto search = max_keep_ages_.find(event_name);
82     if (search == max_keep_ages_.end())
83       return false;
84 
85     return (current_day - event_day) < search->second;
86   }
87 
SetShouldStore(bool should_store)88   void SetShouldStore(bool should_store) { should_store_ = should_store; }
89 
SetMaxKeepAge(const std::string & event_name,uint32_t age)90   void SetMaxKeepAge(const std::string& event_name, uint32_t age) {
91     max_keep_ages_[event_name] = age;
92   }
93 
94  private:
95   bool should_store_;
96   std::map<std::string, uint32_t> max_keep_ages_;
97 
98   DISALLOW_COPY_AND_ASSIGN(TestEventStorageValidator);
99 };
100 
101 // Creates a TestInMemoryEventStore containing three hard coded events.
CreatePrefilledStore()102 std::unique_ptr<TestInMemoryEventStore> CreatePrefilledStore() {
103   std::unique_ptr<std::vector<Event>> events =
104       std::make_unique<std::vector<Event>>();
105 
106   Event foo;
107   foo.set_name("foo");
108   test::SetEventCountForDay(&foo, 1, 1);
109   events->push_back(foo);
110 
111   Event bar;
112   bar.set_name("bar");
113   test::SetEventCountForDay(&bar, 1, 3);
114   test::SetEventCountForDay(&bar, 2, 3);
115   test::SetEventCountForDay(&bar, 5, 5);
116   events->push_back(bar);
117 
118   Event qux;
119   qux.set_name("qux");
120   test::SetEventCountForDay(&qux, 1, 5);
121   test::SetEventCountForDay(&qux, 2, 1);
122   test::SetEventCountForDay(&qux, 3, 2);
123   events->push_back(qux);
124 
125   return std::make_unique<TestInMemoryEventStore>(std::move(events), true);
126 }
127 
128 class EventModelImplTest : public ::testing::Test {
129  public:
EventModelImplTest()130   EventModelImplTest()
131       : task_runner_(new base::TestSimpleTaskRunner),
132         handle_(task_runner_),
133         got_initialize_callback_(false),
134         initialize_callback_result_(false) {}
135 
SetUp()136   void SetUp() override {
137     std::unique_ptr<TestInMemoryEventStore> store = CreateStore();
138     store_ = store.get();
139 
140     auto storage_validator = std::make_unique<TestEventStorageValidator>();
141     storage_validator_ = storage_validator.get();
142 
143     model_.reset(
144         new EventModelImpl(std::move(store), std::move(storage_validator)));
145 
146     // By default store all events for a very long time.
147     storage_validator_->SetMaxKeepAge("foo", 10000u);
148     storage_validator_->SetMaxKeepAge("bar", 10000u);
149     storage_validator_->SetMaxKeepAge("qux", 10000u);
150   }
151 
CreateStore()152   virtual std::unique_ptr<TestInMemoryEventStore> CreateStore() {
153     return CreatePrefilledStore();
154   }
155 
OnModelInitializationFinished(bool success)156   void OnModelInitializationFinished(bool success) {
157     got_initialize_callback_ = true;
158     initialize_callback_result_ = success;
159   }
160 
161  protected:
162   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
163   base::ThreadTaskRunnerHandle handle_;
164 
165   std::unique_ptr<EventModelImpl> model_;
166   TestInMemoryEventStore* store_;
167   TestEventStorageValidator* storage_validator_;
168   bool got_initialize_callback_;
169   bool initialize_callback_result_;
170 };
171 
172 class LoadFailingEventModelImplTest : public EventModelImplTest {
173  public:
LoadFailingEventModelImplTest()174   LoadFailingEventModelImplTest() {}
175 
CreateStore()176   std::unique_ptr<TestInMemoryEventStore> CreateStore() override {
177     return std::make_unique<TestInMemoryEventStore>(
178         std::make_unique<std::vector<Event>>(), false);
179   }
180 };
181 
182 }  // namespace
183 
TEST_F(EventModelImplTest,InitializeShouldBeReadyImmediatelyAfterCallback)184 TEST_F(EventModelImplTest, InitializeShouldBeReadyImmediatelyAfterCallback) {
185   model_->Initialize(
186       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
187                  base::Unretained(this)),
188       1000u);
189 
190   // Only run pending tasks on the queue.  Do not run any subsequently queued
191   // tasks that result from running the current pending tasks.
192   task_runner_->RunPendingTasks();
193 
194   EXPECT_TRUE(got_initialize_callback_);
195   EXPECT_TRUE(model_->IsReady());
196 }
197 
TEST_F(EventModelImplTest,InitializeShouldLoadEntries)198 TEST_F(EventModelImplTest, InitializeShouldLoadEntries) {
199   model_->Initialize(
200       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
201                  base::Unretained(this)),
202       1000u);
203   task_runner_->RunUntilIdle();
204   EXPECT_TRUE(model_->IsReady());
205   EXPECT_TRUE(got_initialize_callback_);
206   EXPECT_TRUE(initialize_callback_result_);
207 
208   // Verify that all the data matches what was put into the store in
209   // CreateStore().
210   const Event* foo_event = model_->GetEvent("foo");
211   EXPECT_EQ("foo", foo_event->name());
212   EXPECT_EQ(1, foo_event->events_size());
213   test::VerifyEventCount(foo_event, 1u, 1u);
214 
215   const Event* bar_event = model_->GetEvent("bar");
216   EXPECT_EQ("bar", bar_event->name());
217   EXPECT_EQ(3, bar_event->events_size());
218   test::VerifyEventCount(bar_event, 1u, 3u);
219   test::VerifyEventCount(bar_event, 2u, 3u);
220   test::VerifyEventCount(bar_event, 5u, 5u);
221 
222   const Event* qux_event = model_->GetEvent("qux");
223   EXPECT_EQ("qux", qux_event->name());
224   EXPECT_EQ(3, qux_event->events_size());
225   test::VerifyEventCount(qux_event, 1u, 5u);
226   test::VerifyEventCount(qux_event, 2u, 1u);
227   test::VerifyEventCount(qux_event, 3u, 2u);
228 }
229 
TEST_F(EventModelImplTest,InitializeShouldOnlyLoadEntriesThatShouldBeKept)230 TEST_F(EventModelImplTest, InitializeShouldOnlyLoadEntriesThatShouldBeKept) {
231   // Back to day 5, i.e. no entries.
232   storage_validator_->SetMaxKeepAge("foo", 1u);
233 
234   // Back to day 2, i.e. 2 events.
235   storage_validator_->SetMaxKeepAge("bar", 4u);
236 
237   // Back to day epoch, i.e. all events.
238   storage_validator_->SetMaxKeepAge("qux", 10u);
239 
240   model_->Initialize(
241       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
242                  base::Unretained(this)),
243       5u);
244   task_runner_->RunUntilIdle();
245   EXPECT_TRUE(model_->IsReady());
246   EXPECT_TRUE(got_initialize_callback_);
247   EXPECT_TRUE(initialize_callback_result_);
248 
249   // Verify that all the data matches what was put into the store in
250   // CreateStore(), minus the events that should no longer exist.
251   const Event* foo_event = model_->GetEvent("foo");
252   EXPECT_EQ(nullptr, foo_event);
253   EXPECT_EQ("foo", store_->GetLastDeletedEvent());
254 
255   const Event* bar_event = model_->GetEvent("bar");
256   EXPECT_EQ("bar", bar_event->name());
257   EXPECT_EQ(2, bar_event->events_size());
258   test::VerifyEventCount(bar_event, 2u, 3u);
259   test::VerifyEventCount(bar_event, 5u, 5u);
260   test::VerifyEventsEqual(bar_event, store_->GetLastWrittenEvent());
261 
262   // Nothing has changed for 'qux', so nothing will be written to EventStore.
263   const Event* qux_event = model_->GetEvent("qux");
264   EXPECT_EQ("qux", qux_event->name());
265   EXPECT_EQ(3, qux_event->events_size());
266   test::VerifyEventCount(qux_event, 1u, 5u);
267   test::VerifyEventCount(qux_event, 2u, 1u);
268   test::VerifyEventCount(qux_event, 3u, 2u);
269 
270   // In total, only two operations should have happened, the update of "bar",
271   // and the delete of "foo".
272   EXPECT_EQ(2u, store_->GetStoreOperationCount());
273 }
274 
TEST_F(EventModelImplTest,RetrievingNewEventsShouldYieldNullptr)275 TEST_F(EventModelImplTest, RetrievingNewEventsShouldYieldNullptr) {
276   model_->Initialize(
277       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
278                  base::Unretained(this)),
279       1000u);
280   task_runner_->RunUntilIdle();
281   EXPECT_TRUE(model_->IsReady());
282 
283   const Event* no_event = model_->GetEvent("no");
284   EXPECT_EQ(nullptr, no_event);
285   test::VerifyEventsEqual(nullptr, store_->GetLastWrittenEvent());
286 }
287 
TEST_F(EventModelImplTest,IncrementingNonExistingEvent)288 TEST_F(EventModelImplTest, IncrementingNonExistingEvent) {
289   model_->Initialize(
290       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
291                  base::Unretained(this)),
292       1000u);
293   task_runner_->RunUntilIdle();
294   EXPECT_TRUE(model_->IsReady());
295 
296   // Incrementing the event should work even if it does not exist.
297   model_->IncrementEvent("nonexisting", 1u);
298   const Event* event1 = model_->GetEvent("nonexisting");
299   ASSERT_NE(nullptr, event1);
300   EXPECT_EQ("nonexisting", event1->name());
301   EXPECT_EQ(1, event1->events_size());
302   test::VerifyEventCount(event1, 1u, 1u);
303   test::VerifyEventsEqual(event1, store_->GetLastWrittenEvent());
304 
305   // Incrementing the event after it has been initialized to 1, it should now
306   // have a count of 2 for the given day.
307   model_->IncrementEvent("nonexisting", 1u);
308   const Event* event2 = model_->GetEvent("nonexisting");
309   ASSERT_NE(nullptr, event2);
310   Event_Count event2_count = event2->events(0);
311   EXPECT_EQ(1, event2->events_size());
312   test::VerifyEventCount(event2, 1u, 2u);
313   test::VerifyEventsEqual(event2, store_->GetLastWrittenEvent());
314 }
315 
TEST_F(EventModelImplTest,IncrementingNonExistingEventMultipleDays)316 TEST_F(EventModelImplTest, IncrementingNonExistingEventMultipleDays) {
317   model_->Initialize(
318       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
319                  base::Unretained(this)),
320       1000u);
321   task_runner_->RunUntilIdle();
322   EXPECT_TRUE(model_->IsReady());
323 
324   model_->IncrementEvent("nonexisting", 1u);
325   model_->IncrementEvent("nonexisting", 2u);
326   model_->IncrementEvent("nonexisting", 2u);
327   model_->IncrementEvent("nonexisting", 3u);
328   const Event* event = model_->GetEvent("nonexisting");
329   ASSERT_NE(nullptr, event);
330   EXPECT_EQ(3, event->events_size());
331   test::VerifyEventCount(event, 1u, 1u);
332   test::VerifyEventCount(event, 2u, 2u);
333   test::VerifyEventCount(event, 3u, 1u);
334   test::VerifyEventsEqual(event, store_->GetLastWrittenEvent());
335 }
336 
TEST_F(EventModelImplTest,IncrementingNonExistingEventWithoutStoring)337 TEST_F(EventModelImplTest, IncrementingNonExistingEventWithoutStoring) {
338   model_->Initialize(
339       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
340                  base::Unretained(this)),
341       1000u);
342   task_runner_->RunUntilIdle();
343   EXPECT_TRUE(model_->IsReady());
344 
345   storage_validator_->SetShouldStore(false);
346 
347   // Incrementing the event should not be written or stored in-memory.
348   model_->IncrementEvent("nonexisting", 1u);
349   const Event* event1 = model_->GetEvent("nonexisting");
350   EXPECT_EQ(nullptr, event1);
351   test::VerifyEventsEqual(nullptr, store_->GetLastWrittenEvent());
352 }
353 
TEST_F(EventModelImplTest,IncrementingExistingEventWithoutStoring)354 TEST_F(EventModelImplTest, IncrementingExistingEventWithoutStoring) {
355   model_->Initialize(
356       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
357                  base::Unretained(this)),
358       1000u);
359   task_runner_->RunUntilIdle();
360   EXPECT_TRUE(model_->IsReady());
361 
362   // Write one event before turning off storage.
363   model_->IncrementEvent("nonexisting", 1u);
364   const Event* first_event = model_->GetEvent("nonexisting");
365   ASSERT_NE(nullptr, first_event);
366   test::VerifyEventsEqual(first_event, store_->GetLastWrittenEvent());
367 
368   storage_validator_->SetShouldStore(false);
369 
370   // Incrementing the event should no longer be written or stored in-memory.
371   model_->IncrementEvent("nonexisting", 1u);
372   const Event* second_event = model_->GetEvent("nonexisting");
373   EXPECT_EQ(first_event, second_event);
374   test::VerifyEventsEqual(first_event, store_->GetLastWrittenEvent());
375 }
376 
TEST_F(EventModelImplTest,IncrementingSingleDayExistingEvent)377 TEST_F(EventModelImplTest, IncrementingSingleDayExistingEvent) {
378   model_->Initialize(
379       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
380                  base::Unretained(this)),
381       1000u);
382   task_runner_->RunUntilIdle();
383   EXPECT_TRUE(model_->IsReady());
384 
385   // |foo| is inserted into the store with a count of 1 at day 1.
386   const Event* foo_event = model_->GetEvent("foo");
387   EXPECT_EQ("foo", foo_event->name());
388   EXPECT_EQ(1, foo_event->events_size());
389   test::VerifyEventCount(foo_event, 1u, 1u);
390 
391   // Incrementing |foo| should change count to 2.
392   model_->IncrementEvent("foo", 1u);
393   const Event* foo_event2 = model_->GetEvent("foo");
394   EXPECT_EQ(1, foo_event2->events_size());
395   test::VerifyEventCount(foo_event2, 1u, 2u);
396   test::VerifyEventsEqual(foo_event2, store_->GetLastWrittenEvent());
397 }
398 
TEST_F(EventModelImplTest,IncrementingSingleDayExistingEventTwice)399 TEST_F(EventModelImplTest, IncrementingSingleDayExistingEventTwice) {
400   model_->Initialize(
401       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
402                  base::Unretained(this)),
403       1000u);
404   task_runner_->RunUntilIdle();
405   EXPECT_TRUE(model_->IsReady());
406 
407   // |foo| is inserted into the store with a count of 1 at day 1, so
408   // incrementing twice should lead to 3.
409   model_->IncrementEvent("foo", 1u);
410   model_->IncrementEvent("foo", 1u);
411   const Event* foo_event = model_->GetEvent("foo");
412   EXPECT_EQ(1, foo_event->events_size());
413   test::VerifyEventCount(foo_event, 1u, 3u);
414   test::VerifyEventsEqual(foo_event, store_->GetLastWrittenEvent());
415 }
416 
TEST_F(EventModelImplTest,IncrementingExistingMultiDayEvent)417 TEST_F(EventModelImplTest, IncrementingExistingMultiDayEvent) {
418   model_->Initialize(
419       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
420                  base::Unretained(this)),
421       1000u);
422   task_runner_->RunUntilIdle();
423   EXPECT_TRUE(model_->IsReady());
424 
425   // |bar| is inserted into the store with a count of 3 at day 2. Incrementing
426   // that day should lead to a count of 4.
427   const Event* bar_event = model_->GetEvent("bar");
428   test::VerifyEventCount(bar_event, 2u, 3u);
429   model_->IncrementEvent("bar", 2u);
430   const Event* bar_event2 = model_->GetEvent("bar");
431   test::VerifyEventCount(bar_event2, 2u, 4u);
432   test::VerifyEventsEqual(bar_event2, store_->GetLastWrittenEvent());
433 }
434 
TEST_F(EventModelImplTest,IncrementingExistingMultiDayEventNewDay)435 TEST_F(EventModelImplTest, IncrementingExistingMultiDayEventNewDay) {
436   model_->Initialize(
437       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
438                  base::Unretained(this)),
439       1000u);
440   task_runner_->RunUntilIdle();
441   EXPECT_TRUE(model_->IsReady());
442 
443   // |bar| does not contain entries for day 10, so incrementing should create
444   // the day.
445   model_->IncrementEvent("bar", 10u);
446   const Event* bar_event = model_->GetEvent("bar");
447   test::VerifyEventCount(bar_event, 10u, 1u);
448   test::VerifyEventsEqual(bar_event, store_->GetLastWrittenEvent());
449   model_->IncrementEvent("bar", 10u);
450   const Event* bar_event2 = model_->GetEvent("bar");
451   test::VerifyEventCount(bar_event2, 10u, 2u);
452   test::VerifyEventsEqual(bar_event2, store_->GetLastWrittenEvent());
453 }
454 
TEST_F(LoadFailingEventModelImplTest,FailedInitializeInformsCaller)455 TEST_F(LoadFailingEventModelImplTest, FailedInitializeInformsCaller) {
456   model_->Initialize(
457       base::Bind(&EventModelImplTest::OnModelInitializationFinished,
458                  base::Unretained(this)),
459       1000u);
460   task_runner_->RunUntilIdle();
461   EXPECT_FALSE(model_->IsReady());
462   EXPECT_TRUE(got_initialize_callback_);
463   EXPECT_FALSE(initialize_callback_result_);
464 }
465 
466 }  // namespace feature_engagement
467