Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_storage_monitor_browsertest.cc
1 // Copyright 2014 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 <set>
6
7 #include "base/run_loop.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "chrome/browser/extensions/extension_browsertest.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/extension_storage_monitor.h"
12 #include "chrome/browser/ui/extensions/application_launch.h"
13 #include "content/public/test/test_utils.h"
14 #include "extensions/browser/extension_prefs.h"
15 #include "extensions/browser/extension_registry.h"
16 #include "extensions/browser/extension_system.h"
17 #include "extensions/browser/test_extension_registry_observer.h"
18 #include "extensions/test/extension_test_message_listener.h"
19 #include "ui/message_center/message_center.h"
20 #include "ui/message_center/message_center_observer.h"
21
22 namespace extensions {
23
24 namespace {
25
26 const int kInitialUsageThreshold = 500;
27
28 const char kWriteDataApp[] = "storage_monitor/write_data";
29
30 class NotificationObserver : public message_center::MessageCenterObserver {
31  public:
32   explicit NotificationObserver(const std::string& target_notification)
33       : message_center_(message_center::MessageCenter::Get()),
34         target_notification_id_(target_notification),
35         waiting_(false) {
36     message_center_->AddObserver(this);
37   }
38
39   ~NotificationObserver() override { message_center_->RemoveObserver(this); }
40
41   bool HasReceivedNotification() const {
42     return received_notifications_.find(target_notification_id_) !=
43       received_notifications_.end();
44   }
45
46   // Runs the message loop and returns true if a notification is received.
47   // Immediately returns true if a notification has already been received.
48   bool WaitForNotification() {
49     if (HasReceivedNotification())
50       return true;
51
52     waiting_ = true;
53     content::RunMessageLoop();
54     waiting_ = false;
55     return HasReceivedNotification();
56   }
57
58  private:
59   // MessageCenterObserver implementation:
60   void OnNotificationAdded(const std::string& notification_id) override {
61     received_notifications_.insert(notification_id);
62
63     if (waiting_ && HasReceivedNotification())
64       base::MessageLoopForUI::current()->Quit();
65   }
66
67   message_center::MessageCenter* message_center_;
68   std::set<std::string> received_notifications_;
69   std::string target_notification_id_;
70   bool waiting_;
71 };
72
73 }  // namespace
74
75 class ExtensionStorageMonitorTest : public ExtensionBrowserTest {
76  public:
77   ExtensionStorageMonitorTest() : storage_monitor_(NULL) {}
78
79  protected:
80   // ExtensionBrowserTest overrides:
81   void SetUpOnMainThread() override {
82     ExtensionBrowserTest::SetUpOnMainThread();
83
84     InitStorageMonitor();
85   }
86
87   ExtensionStorageMonitor* monitor() {
88     CHECK(storage_monitor_);
89     return storage_monitor_;
90   }
91
92   int64 GetInitialExtensionThreshold() {
93     CHECK(storage_monitor_);
94     return storage_monitor_->initial_extension_threshold_;
95   }
96
97   int64 GetInitialEphemeralThreshold() {
98     CHECK(storage_monitor_);
99     return storage_monitor_->initial_ephemeral_threshold_;
100   }
101
102   void DisableForInstalledExtensions() {
103     CHECK(storage_monitor_);
104     storage_monitor_->enable_for_all_extensions_ = false;
105   }
106
107   const Extension* InitWriteDataApp() {
108     base::FilePath path = test_data_dir_.AppendASCII(kWriteDataApp);
109     const Extension* extension = InstallExtension(path, 1);
110     EXPECT_TRUE(extension);
111     return extension;
112   }
113
114   const Extension* InitWriteDataEphemeralApp() {
115     // The threshold for installed extensions should be higher than ephemeral
116     // apps.
117     storage_monitor_->initial_extension_threshold_ =
118         storage_monitor_->initial_ephemeral_threshold_ * 4;
119
120     base::FilePath path = test_data_dir_.AppendASCII(kWriteDataApp);
121     const Extension* extension = InstallEphemeralAppWithSourceAndFlags(
122         path, 1, Manifest::INTERNAL, Extension::NO_FLAGS);
123     EXPECT_TRUE(extension);
124     return extension;
125   }
126
127   std::string GetNotificationId(const std::string& extension_id) {
128     return monitor()->GetNotificationId(extension_id);
129   }
130
131   bool IsStorageNotificationEnabled(const std::string& extension_id) {
132     return monitor()->IsStorageNotificationEnabled(extension_id);
133   }
134
135   int64 GetNextStorageThreshold(const std::string& extension_id) {
136     return monitor()->GetNextStorageThreshold(extension_id);
137   }
138
139   void WriteBytesExpectingNotification(const Extension* extension,
140                                        int num_bytes) {
141     int64 previous_threshold = GetNextStorageThreshold(extension->id());
142     WriteBytes(extension, num_bytes, true);
143     EXPECT_GT(GetNextStorageThreshold(extension->id()), previous_threshold);
144   }
145
146   void WriteBytesNotExpectingNotification(const Extension* extension,
147                                          int num_bytes) {
148     WriteBytes(extension, num_bytes, false);
149   }
150
151   void SimulateUninstallDialogAccept() {
152     // Ensure the uninstall dialog was shown and fake an accept.
153     ASSERT_TRUE(monitor()->uninstall_dialog_.get());
154     monitor()->ExtensionUninstallAccepted();
155   }
156
157  private:
158   void InitStorageMonitor() {
159     storage_monitor_ = ExtensionStorageMonitor::Get(profile());
160     ASSERT_TRUE(storage_monitor_);
161
162     // Override thresholds so that we don't have to write a huge amount of data
163     // to trigger notifications in these tests.
164     storage_monitor_->enable_for_all_extensions_ = true;
165     storage_monitor_->initial_extension_threshold_ = kInitialUsageThreshold;
166     storage_monitor_->initial_ephemeral_threshold_ = kInitialUsageThreshold;
167
168     // To ensure storage events are dispatched from QuotaManager immediately.
169     storage_monitor_->observer_rate_ = base::TimeDelta();
170   }
171
172   // Write a number of bytes to persistent storage.
173   void WriteBytes(const Extension* extension,
174                   int num_bytes,
175                   bool expected_notification) {
176     ExtensionTestMessageListener launched_listener("launched", true);
177     ExtensionTestMessageListener write_complete_listener(
178         "write_complete", false);
179     NotificationObserver notification_observer(
180         GetNotificationId(extension->id()));
181
182     OpenApplication(AppLaunchParams(
183         profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW));
184     ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
185
186     // Instruct the app to write |num_bytes| of data.
187     launched_listener.Reply(base::IntToString(num_bytes));
188     ASSERT_TRUE(write_complete_listener.WaitUntilSatisfied());
189
190     if (expected_notification) {
191       EXPECT_TRUE(notification_observer.WaitForNotification());
192     } else {
193       base::RunLoop().RunUntilIdle();
194       EXPECT_FALSE(notification_observer.HasReceivedNotification());
195     }
196   }
197
198   ExtensionStorageMonitor* storage_monitor_;
199 };
200
201 // Control - No notifications should be shown if usage remains under the
202 // threshold.
203 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, UnderThreshold) {
204   const Extension* extension = InitWriteDataApp();
205   ASSERT_TRUE(extension);
206   WriteBytesNotExpectingNotification(extension, 1);
207 }
208
209 // Ensure a notification is shown when usage reaches the first threshold.
210 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, ExceedInitialThreshold) {
211   const Extension* extension = InitWriteDataApp();
212   ASSERT_TRUE(extension);
213   WriteBytesExpectingNotification(extension, GetInitialExtensionThreshold());
214 }
215
216 // Ensure a notification is shown when usage immediately exceeds double the
217 // first threshold.
218 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, DoubleInitialThreshold) {
219   const Extension* extension = InitWriteDataApp();
220   ASSERT_TRUE(extension);
221   WriteBytesExpectingNotification(extension,
222                                   GetInitialExtensionThreshold() * 2);
223 }
224
225 // Ensure that notifications are not fired if the next threshold has not been
226 // reached.
227 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, ThrottleNotifications) {
228   const Extension* extension = InitWriteDataApp();
229   ASSERT_TRUE(extension);
230
231   // Exceed the first threshold.
232   WriteBytesExpectingNotification(extension, GetInitialExtensionThreshold());
233
234   // Stay within the next threshold.
235   WriteBytesNotExpectingNotification(extension, 1);
236 }
237
238 // Verify that notifications are disabled when the user clicks the action button
239 // in the notification.
240 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, UserDisabledNotifications) {
241   const Extension* extension = InitWriteDataApp();
242   ASSERT_TRUE(extension);
243   WriteBytesExpectingNotification(extension, GetInitialExtensionThreshold());
244
245   EXPECT_TRUE(IsStorageNotificationEnabled(extension->id()));
246
247   // Fake clicking the notification button to disable notifications.
248   message_center::MessageCenter::Get()->ClickOnNotificationButton(
249       GetNotificationId(extension->id()),
250       ExtensionStorageMonitor::BUTTON_DISABLE_NOTIFICATION);
251
252   EXPECT_FALSE(IsStorageNotificationEnabled(extension->id()));
253
254   // Expect to receive no further notifications when usage continues to
255   // increase.
256   int64 next_threshold = GetNextStorageThreshold(extension->id());
257   int64 next_data_size = next_threshold - GetInitialExtensionThreshold();
258   ASSERT_GT(next_data_size, 0);
259
260   WriteBytesNotExpectingNotification(extension, next_data_size);
261 }
262
263 // Verify that thresholds for ephemeral apps are reset when they are
264 // promoted to regular installed apps.
265 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, EphemeralAppLowUsage) {
266   const Extension* extension = InitWriteDataEphemeralApp();
267   ASSERT_TRUE(extension);
268   WriteBytesExpectingNotification(extension, GetInitialEphemeralThreshold());
269
270   // Store the number of bytes until the next threshold is reached.
271   int64 next_threshold = GetNextStorageThreshold(extension->id());
272   int64 next_data_size = next_threshold - GetInitialEphemeralThreshold();
273   ASSERT_GT(next_data_size, 0);
274   EXPECT_GE(GetInitialExtensionThreshold(), next_threshold);
275
276   // Promote the ephemeral app.
277   ExtensionService* service =
278       ExtensionSystem::Get(profile())->extension_service();
279   service->PromoteEphemeralApp(extension, false);
280
281   // The next threshold should now be equal to the initial threshold for
282   // extensions (which is higher than the initial threshold for ephemeral apps).
283   EXPECT_EQ(GetInitialExtensionThreshold(),
284             GetNextStorageThreshold(extension->id()));
285
286   // Since the threshold was increased, a notification should not be
287   // triggered.
288   WriteBytesNotExpectingNotification(extension, next_data_size);
289 }
290
291 // Verify that thresholds for ephemeral apps are not reset when they are
292 // promoted to regular installed apps if their usage is higher than the initial
293 // threshold for installed extensions.
294 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, EphemeralAppWithHighUsage) {
295   const Extension* extension = InitWriteDataEphemeralApp();
296   ASSERT_TRUE(extension);
297   WriteBytesExpectingNotification(extension, GetInitialExtensionThreshold());
298   int64 saved_next_threshold = GetNextStorageThreshold(extension->id());
299
300   // Promote the ephemeral app.
301   ExtensionService* service =
302       ExtensionSystem::Get(profile())->extension_service();
303   service->PromoteEphemeralApp(extension, false);
304
305   // The next threshold should not have changed.
306   EXPECT_EQ(saved_next_threshold, GetNextStorageThreshold(extension->id()));
307 }
308
309 // Ensure that monitoring is disabled for installed extensions if
310 // |enable_for_all_extensions_| is false. This test can be removed if monitoring
311 // is eventually enabled for all extensions.
312 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest,
313                        DisableForInstalledExtensions) {
314   DisableForInstalledExtensions();
315
316   const Extension* extension = InitWriteDataApp();
317   ASSERT_TRUE(extension);
318   WriteBytesNotExpectingNotification(extension, GetInitialExtensionThreshold());
319 }
320
321 // Verify that notifications are disabled when the user clicks the action button
322 // in the notification.
323 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, UninstallExtension) {
324   const Extension* extension = InitWriteDataApp();
325   ASSERT_TRUE(extension);
326   WriteBytesExpectingNotification(extension, GetInitialExtensionThreshold());
327
328   // Fake clicking the notification button to uninstall.
329   message_center::MessageCenter::Get()->ClickOnNotificationButton(
330       GetNotificationId(extension->id()),
331       ExtensionStorageMonitor::BUTTON_UNINSTALL);
332
333   // Also fake accepting the uninstall.
334   TestExtensionRegistryObserver observer(ExtensionRegistry::Get(profile()),
335                                          extension->id());
336   SimulateUninstallDialogAccept();
337   observer.WaitForExtensionUninstalled();
338 }
339
340 }  // namespace extensions