Ensure tests have an active task runner
[chromium-blink-merge.git] / chrome / browser / apps / app_shim / extension_app_shim_handler_mac_unittest.cc
blobf361b7a69891f32c00a09365d3766c85d556ca8a
1 // Copyright 2013 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.
5 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
7 #include <vector>
9 #include "base/memory/scoped_ptr.h"
10 #include "chrome/browser/apps/app_shim/app_shim_host_mac.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/test/base/testing_profile.h"
13 #include "content/public/browser/notification_service.h"
14 #include "content/public/test/test_browser_thread_bundle.h"
15 #include "extensions/common/extension.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 namespace apps {
21 using extensions::Extension;
22 typedef extensions::AppWindowRegistry::AppWindowList AppWindowList;
24 using ::testing::_;
25 using ::testing::Invoke;
26 using ::testing::Return;
27 using ::testing::WithArgs;
29 class MockDelegate : public ExtensionAppShimHandler::Delegate {
30 public:
31 virtual ~MockDelegate() {}
33 MOCK_METHOD1(ProfileExistsForPath, bool(const base::FilePath&));
34 MOCK_METHOD1(ProfileForPath, Profile*(const base::FilePath&));
35 MOCK_METHOD2(LoadProfileAsync,
36 void(const base::FilePath&,
37 base::Callback<void(Profile*)>));
39 MOCK_METHOD2(GetWindows, AppWindowList(Profile*, const std::string&));
41 MOCK_METHOD2(GetAppExtension, const Extension*(Profile*, const std::string&));
42 MOCK_METHOD3(EnableExtension, void(Profile*,
43 const std::string&,
44 const base::Callback<void()>&));
45 MOCK_METHOD3(LaunchApp,
46 void(Profile*,
47 const Extension*,
48 const std::vector<base::FilePath>&));
49 MOCK_METHOD2(LaunchShim, void(Profile*, const Extension*));
51 MOCK_METHOD0(MaybeTerminate, void());
53 void CaptureLoadProfileCallback(
54 const base::FilePath& path,
55 base::Callback<void(Profile*)> callback) {
56 callbacks_[path] = callback;
59 bool RunLoadProfileCallback(
60 const base::FilePath& path,
61 Profile* profile) {
62 callbacks_[path].Run(profile);
63 return callbacks_.erase(path);
66 void RunCallback(const base::Callback<void()>& callback) {
67 callback.Run();
70 private:
71 std::map<base::FilePath,
72 base::Callback<void(Profile*)> > callbacks_;
75 class TestingExtensionAppShimHandler : public ExtensionAppShimHandler {
76 public:
77 TestingExtensionAppShimHandler(Delegate* delegate) {
78 set_delegate(delegate);
80 virtual ~TestingExtensionAppShimHandler() {}
82 MOCK_METHOD3(OnShimFocus,
83 void(Host* host,
84 AppShimFocusType,
85 const std::vector<base::FilePath>& files));
87 void RealOnShimFocus(Host* host,
88 AppShimFocusType focus_type,
89 const std::vector<base::FilePath>& files) {
90 ExtensionAppShimHandler::OnShimFocus(host, focus_type, files);
93 AppShimHandler::Host* FindHost(Profile* profile,
94 const std::string& app_id) {
95 HostMap::const_iterator it = hosts().find(make_pair(profile, app_id));
96 return it == hosts().end() ? NULL : it->second;
99 content::NotificationRegistrar& GetRegistrar() { return registrar(); }
101 private:
102 DISALLOW_COPY_AND_ASSIGN(TestingExtensionAppShimHandler);
105 const char kTestAppIdA[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
106 const char kTestAppIdB[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
108 class FakeHost : public apps::AppShimHandler::Host {
109 public:
110 FakeHost(const base::FilePath& profile_path,
111 const std::string& app_id,
112 TestingExtensionAppShimHandler* handler)
113 : profile_path_(profile_path),
114 app_id_(app_id),
115 handler_(handler),
116 close_count_(0) {}
118 MOCK_METHOD1(OnAppLaunchComplete, void(AppShimLaunchResult));
120 void OnAppClosed() override {
121 handler_->OnShimClose(this);
122 ++close_count_;
124 void OnAppHide() override {}
125 void OnAppRequestUserAttention(AppShimAttentionType type) override {}
126 base::FilePath GetProfilePath() const override {
127 return profile_path_;
129 std::string GetAppId() const override { return app_id_; }
131 int close_count() { return close_count_; }
133 private:
134 base::FilePath profile_path_;
135 std::string app_id_;
136 TestingExtensionAppShimHandler* handler_;
137 int close_count_;
139 DISALLOW_COPY_AND_ASSIGN(FakeHost);
142 class ExtensionAppShimHandlerTest : public testing::Test {
143 protected:
144 ExtensionAppShimHandlerTest()
145 : delegate_(new MockDelegate),
146 handler_(new TestingExtensionAppShimHandler(delegate_)),
147 profile_path_a_("Profile A"),
148 profile_path_b_("Profile B"),
149 host_aa_(profile_path_a_, kTestAppIdA, handler_.get()),
150 host_ab_(profile_path_a_, kTestAppIdB, handler_.get()),
151 host_bb_(profile_path_b_, kTestAppIdB, handler_.get()),
152 host_aa_duplicate_(profile_path_a_, kTestAppIdA, handler_.get()) {
153 base::FilePath extension_path("/fake/path");
154 base::DictionaryValue manifest;
155 manifest.SetString("name", "Fake Name");
156 manifest.SetString("version", "1");
157 std::string error;
158 extension_a_ = Extension::Create(
159 extension_path, extensions::Manifest::INTERNAL, manifest,
160 Extension::NO_FLAGS, kTestAppIdA, &error);
161 EXPECT_TRUE(extension_a_.get()) << error;
163 extension_b_ = Extension::Create(
164 extension_path, extensions::Manifest::INTERNAL, manifest,
165 Extension::NO_FLAGS, kTestAppIdB, &error);
166 EXPECT_TRUE(extension_b_.get()) << error;
168 EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_a_))
169 .WillRepeatedly(Return(true));
170 EXPECT_CALL(*delegate_, ProfileForPath(profile_path_a_))
171 .WillRepeatedly(Return(&profile_a_));
172 EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_b_))
173 .WillRepeatedly(Return(true));
174 EXPECT_CALL(*delegate_, ProfileForPath(profile_path_b_))
175 .WillRepeatedly(Return(&profile_b_));
177 // In most tests, we don't care about the result of GetWindows, it just
178 // needs to be non-empty.
179 AppWindowList app_window_list;
180 app_window_list.push_back(static_cast<extensions::AppWindow*>(NULL));
181 EXPECT_CALL(*delegate_, GetWindows(_, _))
182 .WillRepeatedly(Return(app_window_list));
184 EXPECT_CALL(*delegate_, GetAppExtension(_, kTestAppIdA))
185 .WillRepeatedly(Return(extension_a_.get()));
186 EXPECT_CALL(*delegate_, GetAppExtension(_, kTestAppIdB))
187 .WillRepeatedly(Return(extension_b_.get()));
188 EXPECT_CALL(*delegate_, LaunchApp(_, _, _))
189 .WillRepeatedly(Return());
192 void NormalLaunch(AppShimHandler::Host* host) {
193 handler_->OnShimLaunch(host,
194 APP_SHIM_LAUNCH_NORMAL,
195 std::vector<base::FilePath>());
198 void RegisterOnlyLaunch(AppShimHandler::Host* host) {
199 handler_->OnShimLaunch(host,
200 APP_SHIM_LAUNCH_REGISTER_ONLY,
201 std::vector<base::FilePath>());
204 content::TestBrowserThreadBundle thread_bundle_;
205 MockDelegate* delegate_;
206 scoped_ptr<TestingExtensionAppShimHandler> handler_;
207 base::FilePath profile_path_a_;
208 base::FilePath profile_path_b_;
209 TestingProfile profile_a_;
210 TestingProfile profile_b_;
211 FakeHost host_aa_;
212 FakeHost host_ab_;
213 FakeHost host_bb_;
214 FakeHost host_aa_duplicate_;
215 scoped_refptr<Extension> extension_a_;
216 scoped_refptr<Extension> extension_b_;
218 private:
219 DISALLOW_COPY_AND_ASSIGN(ExtensionAppShimHandlerTest);
222 TEST_F(ExtensionAppShimHandlerTest, LaunchProfileNotFound) {
223 // Bad profile path.
224 EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_a_))
225 .WillOnce(Return(false))
226 .WillRepeatedly(Return(true));
227 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND));
228 NormalLaunch(&host_aa_);
231 TEST_F(ExtensionAppShimHandlerTest, LaunchAppNotFound) {
232 // App not found.
233 EXPECT_CALL(*delegate_, GetAppExtension(&profile_a_, kTestAppIdA))
234 .WillRepeatedly(Return(static_cast<const Extension*>(NULL)));
235 EXPECT_CALL(*delegate_, EnableExtension(&profile_a_, kTestAppIdA, _))
236 .WillOnce(WithArgs<2>(Invoke(delegate_, &MockDelegate::RunCallback)));
237 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_APP_NOT_FOUND));
238 NormalLaunch(&host_aa_);
241 TEST_F(ExtensionAppShimHandlerTest, LaunchAppNotEnabled) {
242 // App not found.
243 EXPECT_CALL(*delegate_, GetAppExtension(&profile_a_, kTestAppIdA))
244 .WillOnce(Return(static_cast<const Extension*>(NULL)))
245 .WillRepeatedly(Return(extension_a_.get()));
246 EXPECT_CALL(*delegate_, EnableExtension(&profile_a_, kTestAppIdA, _))
247 .WillOnce(WithArgs<2>(Invoke(delegate_, &MockDelegate::RunCallback)));
248 NormalLaunch(&host_aa_);
251 TEST_F(ExtensionAppShimHandlerTest, LaunchAndCloseShim) {
252 // Normal startup.
253 NormalLaunch(&host_aa_);
254 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
256 NormalLaunch(&host_ab_);
257 EXPECT_EQ(&host_ab_, handler_->FindHost(&profile_a_, kTestAppIdB));
259 std::vector<base::FilePath> some_file(1, base::FilePath("some_file"));
260 EXPECT_CALL(*delegate_,
261 LaunchApp(&profile_b_, extension_b_.get(), some_file));
262 handler_->OnShimLaunch(&host_bb_, APP_SHIM_LAUNCH_NORMAL, some_file);
263 EXPECT_EQ(&host_bb_, handler_->FindHost(&profile_b_, kTestAppIdB));
265 // Activation when there is a registered shim finishes launch with success and
266 // focuses the app.
267 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
268 EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_NORMAL, _));
269 handler_->OnAppActivated(&profile_a_, kTestAppIdA);
271 // Starting and closing a second host just focuses the app.
272 EXPECT_CALL(*handler_, OnShimFocus(&host_aa_duplicate_,
273 APP_SHIM_FOCUS_REOPEN,
274 some_file));
275 EXPECT_CALL(host_aa_duplicate_,
276 OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST));
277 handler_->OnShimLaunch(&host_aa_duplicate_,
278 APP_SHIM_LAUNCH_NORMAL,
279 some_file);
280 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
281 handler_->OnShimClose(&host_aa_duplicate_);
282 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
284 // Normal close.
285 handler_->OnShimClose(&host_aa_);
286 EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
288 // Closing the second host afterward does nothing.
289 handler_->OnShimClose(&host_aa_duplicate_);
290 EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
293 TEST_F(ExtensionAppShimHandlerTest, AppLifetime) {
294 // When the app activates, if there is no shim, start one.
295 EXPECT_CALL(*delegate_, LaunchShim(&profile_a_, extension_a_.get()));
296 handler_->OnAppActivated(&profile_a_, kTestAppIdA);
298 // Normal shim launch adds an entry in the map.
299 // App should not be launched here, but return success to the shim.
300 EXPECT_CALL(*delegate_,
301 LaunchApp(&profile_a_, extension_a_.get(), _))
302 .Times(0);
303 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
304 RegisterOnlyLaunch(&host_aa_);
305 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
307 // Return no app windows for OnShimFocus and OnShimQuit.
308 AppWindowList app_window_list;
309 EXPECT_CALL(*delegate_, GetWindows(&profile_a_, kTestAppIdA))
310 .WillRepeatedly(Return(app_window_list));
312 // Non-reopen focus does nothing.
313 EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_NORMAL, _))
314 .WillOnce(Invoke(handler_.get(),
315 &TestingExtensionAppShimHandler::RealOnShimFocus));
316 EXPECT_CALL(*delegate_,
317 LaunchApp(&profile_a_, extension_a_.get(), _))
318 .Times(0);
319 handler_->OnShimFocus(&host_aa_,
320 APP_SHIM_FOCUS_NORMAL,
321 std::vector<base::FilePath>());
323 // Reopen focus launches the app.
324 EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_REOPEN, _))
325 .WillOnce(Invoke(handler_.get(),
326 &TestingExtensionAppShimHandler::RealOnShimFocus));
327 std::vector<base::FilePath> some_file(1, base::FilePath("some_file"));
328 EXPECT_CALL(*delegate_,
329 LaunchApp(&profile_a_, extension_a_.get(), some_file));
330 handler_->OnShimFocus(&host_aa_, APP_SHIM_FOCUS_REOPEN, some_file);
332 // Quit just closes all the windows. This tests that it doesn't terminate,
333 // but we expect closing all windows triggers a OnAppDeactivated from
334 // AppLifetimeMonitor.
335 handler_->OnShimQuit(&host_aa_);
337 // Closing all windows closes the shim and checks if Chrome should be
338 // terminated.
339 EXPECT_CALL(*delegate_, MaybeTerminate())
340 .WillOnce(Return());
341 handler_->OnAppDeactivated(&profile_a_, kTestAppIdA);
342 EXPECT_EQ(1, host_aa_.close_count());
345 TEST_F(ExtensionAppShimHandlerTest, MaybeTerminate) {
346 // Launch shims, adding entries in the map.
347 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
348 RegisterOnlyLaunch(&host_aa_);
349 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
351 EXPECT_CALL(host_ab_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
352 RegisterOnlyLaunch(&host_ab_);
353 EXPECT_EQ(&host_ab_, handler_->FindHost(&profile_a_, kTestAppIdB));
355 // Return empty window list.
356 AppWindowList app_window_list;
357 EXPECT_CALL(*delegate_, GetWindows(_, _))
358 .WillRepeatedly(Return(app_window_list));
360 // Quitting when there's another shim should not terminate.
361 EXPECT_CALL(*delegate_, MaybeTerminate())
362 .Times(0);
363 handler_->OnAppDeactivated(&profile_a_, kTestAppIdA);
365 // Quitting when it's the last shim should terminate.
366 EXPECT_CALL(*delegate_, MaybeTerminate());
367 handler_->OnAppDeactivated(&profile_a_, kTestAppIdB);
370 TEST_F(ExtensionAppShimHandlerTest, RegisterOnly) {
371 // For an APP_SHIM_LAUNCH_REGISTER_ONLY, don't launch the app.
372 EXPECT_CALL(*delegate_, LaunchApp(_, _, _))
373 .Times(0);
374 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
375 RegisterOnlyLaunch(&host_aa_);
376 EXPECT_TRUE(handler_->FindHost(&profile_a_, kTestAppIdA));
378 // Close the shim, removing the entry in the map.
379 handler_->OnShimClose(&host_aa_);
380 EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
383 TEST_F(ExtensionAppShimHandlerTest, LoadProfile) {
384 // If the profile is not loaded when an OnShimLaunch arrives, return false
385 // and load the profile asynchronously. Launch the app when the profile is
386 // ready.
387 EXPECT_CALL(*delegate_, ProfileForPath(profile_path_a_))
388 .WillOnce(Return(static_cast<Profile*>(NULL)))
389 .WillRepeatedly(Return(&profile_a_));
390 EXPECT_CALL(*delegate_, LoadProfileAsync(profile_path_a_, _))
391 .WillOnce(Invoke(delegate_, &MockDelegate::CaptureLoadProfileCallback));
392 NormalLaunch(&host_aa_);
393 EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
394 delegate_->RunLoadProfileCallback(profile_path_a_, &profile_a_);
395 EXPECT_TRUE(handler_->FindHost(&profile_a_, kTestAppIdA));
398 } // namespace apps