1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/path_service.h"
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/image_loading_tracker.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/extensions/extension_icon_set.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_resource.h"
12dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/json_value_serializer.h"
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "testing/gtest/include/gtest/gtest.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/skia/include/core/SkBitmap.h"
1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/size.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass ImageLoadingTrackerTest : public testing::Test,
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                public ImageLoadingTracker::Observer {
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ImageLoadingTrackerTest()
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : image_loaded_count_(0),
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        quit_in_image_loaded_(false),
26731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        ui_thread_(BrowserThread::UI, &ui_loop_),
27731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        file_thread_(BrowserThread::FILE),
28731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        io_thread_(BrowserThread::IO) {
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void OnImageLoaded(SkBitmap* image, const ExtensionResource& resource,
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             int index) {
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    image_loaded_count_++;
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (quit_in_image_loaded_)
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      MessageLoop::current()->Quit();
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (image)
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      image_ = *image;
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      image_.reset();
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void WaitForImageLoad() {
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    quit_in_image_loaded_ = true;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->Run();
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    quit_in_image_loaded_ = false;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int image_loaded_count() {
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int result = image_loaded_count_;
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    image_loaded_count_ = 0;
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
54513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<Extension> CreateExtension() {
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Create and load an extension.
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FilePath test_file;
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!PathService::Get(chrome::DIR_TEST_DATA, &test_file)) {
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXPECT_FALSE(true);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return NULL;
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    test_file = test_file.AppendASCII("extensions")
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         .AppendASCII("image_loading_tracker");
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int error_code = 0;
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string error;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    JSONFileValueSerializer serializer(test_file.AppendASCII("app.json"));
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<DictionaryValue> valid_value(
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        static_cast<DictionaryValue*>(serializer.Deserialize(&error_code,
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                             &error)));
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_EQ(0, error_code) << error;
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (error_code != 0)
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return NULL;
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_TRUE(valid_value.get());
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!valid_value.get())
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return NULL;
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return Extension::Create(test_file, Extension::INVALID, *valid_value,
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        Extension::STRICT_ERROR_CHECKS, &error);
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkBitmap image_;
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void SetUp() {
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    file_thread_.Start();
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    io_thread_.Start();
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int image_loaded_count_;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool quit_in_image_loaded_;
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop ui_loop_;
92731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread ui_thread_;
93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread file_thread_;
94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread io_thread_;
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Tests asking ImageLoadingTracker to cache pushes the result to the Extension.
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ImageLoadingTrackerTest, Cache) {
99513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<Extension> extension(CreateExtension());
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(extension.get() != NULL);
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionResource image_resource =
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      extension->GetIconResource(Extension::EXTENSION_ICON_SMALLISH,
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                 ExtensionIconSet::MATCH_EXACTLY);
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Size max_size(Extension::EXTENSION_ICON_SMALLISH,
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     Extension::EXTENSION_ICON_SMALLISH);
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ImageLoadingTracker loader(static_cast<ImageLoadingTracker::Observer*>(this));
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  loader.LoadImage(extension.get(),
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   image_resource,
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   max_size,
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   ImageLoadingTracker::CACHE);
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The image isn't cached, so we should not have received notification.
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, image_loaded_count());
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WaitForImageLoad();
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We should have gotten the image.
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, image_loaded_count());
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check that the image was loaded.
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(Extension::EXTENSION_ICON_SMALLISH, image_.width());
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The image should be cached in the Extension.
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(extension->HasCachedImage(image_resource, max_size));
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure the image is in the extension.
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(Extension::EXTENSION_ICON_SMALLISH,
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            extension->GetCachedImage(image_resource, max_size).width());
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Ask the tracker for the image again, this should call us back immediately.
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  loader.LoadImage(extension.get(),
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   image_resource,
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   max_size,
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   ImageLoadingTracker::CACHE);
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We should have gotten the image.
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, image_loaded_count());
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check that the image was loaded.
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(Extension::EXTENSION_ICON_SMALLISH, image_.width());
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Tests deleting an extension while waiting for the image to load doesn't cause
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// problems.
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ImageLoadingTrackerTest, DeleteExtensionWhileWaitingForCache) {
146513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<Extension> extension(CreateExtension());
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(extension.get() != NULL);
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionResource image_resource =
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      extension->GetIconResource(Extension::EXTENSION_ICON_SMALLISH,
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                 ExtensionIconSet::MATCH_EXACTLY);
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ImageLoadingTracker loader(static_cast<ImageLoadingTracker::Observer*>(this));
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  loader.LoadImage(extension.get(),
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   image_resource,
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   gfx::Size(Extension::EXTENSION_ICON_SMALLISH,
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             Extension::EXTENSION_ICON_SMALLISH),
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   ImageLoadingTracker::CACHE);
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The image isn't cached, so we should not have received notification.
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, image_loaded_count());
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Send out notification the extension was uninstalled.
16321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  UnloadedExtensionInfo details(extension.get(),
16421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                UnloadedExtensionInfo::UNINSTALL);
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationService::current()->Notify(
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationType::EXTENSION_UNLOADED,
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationService::AllSources(),
16821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      Details<UnloadedExtensionInfo>(&details));
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Chuck the extension, that way if anyone tries to access it we should crash
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // or get valgrind errors.
172513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  extension = NULL;
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WaitForImageLoad();
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Even though we deleted the extension, we should still get the image.
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We should still have gotten the image.
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, image_loaded_count());
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check that the image was loaded.
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(Extension::EXTENSION_ICON_SMALLISH, image_.width());
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
183