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