Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / apps / app_shim / extension_app_shim_handler_mac_unittest.cc
blob31fe992b34870c303d3f03ea61add0751d26e37c
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*)>));
38 MOCK_METHOD1(IsProfileLockedForPath, bool(const base::FilePath&));
40 MOCK_METHOD2(GetWindows, AppWindowList(Profile*, const std::string&));
42 MOCK_METHOD2(MaybeGetAppExtension,
43 const Extension*(Profile*, const std::string&));
44 MOCK_METHOD3(EnableExtension, void(Profile*,
45 const std::string&,
46 const base::Callback<void()>&));
47 MOCK_METHOD3(LaunchApp,
48 void(Profile*,
49 const Extension*,
50 const std::vector<base::FilePath>&));
51 MOCK_METHOD2(LaunchShim, void(Profile*, const Extension*));
52 MOCK_METHOD0(LaunchUserManager, void());
54 MOCK_METHOD0(MaybeTerminate, void());
56 void CaptureLoadProfileCallback(
57 const base::FilePath& path,
58 base::Callback<void(Profile*)> callback) {
59 callbacks_[path] = callback;
62 bool RunLoadProfileCallback(
63 const base::FilePath& path,
64 Profile* profile) {
65 callbacks_[path].Run(profile);
66 return callbacks_.erase(path);
69 void RunCallback(const base::Callback<void()>& callback) {
70 callback.Run();
73 private:
74 std::map<base::FilePath,
75 base::Callback<void(Profile*)> > callbacks_;
78 class TestingExtensionAppShimHandler : public ExtensionAppShimHandler {
79 public:
80 TestingExtensionAppShimHandler(Delegate* delegate) {
81 set_delegate(delegate);
83 virtual ~TestingExtensionAppShimHandler() {}
85 MOCK_METHOD3(OnShimFocus,
86 void(Host* host,
87 AppShimFocusType,
88 const std::vector<base::FilePath>& files));
90 void RealOnShimFocus(Host* host,
91 AppShimFocusType focus_type,
92 const std::vector<base::FilePath>& files) {
93 ExtensionAppShimHandler::OnShimFocus(host, focus_type, files);
96 AppShimHandler::Host* FindHost(Profile* profile,
97 const std::string& app_id) {
98 HostMap::const_iterator it = hosts().find(make_pair(profile, app_id));
99 return it == hosts().end() ? NULL : it->second;
102 content::NotificationRegistrar& GetRegistrar() { return registrar(); }
104 private:
105 DISALLOW_COPY_AND_ASSIGN(TestingExtensionAppShimHandler);
108 const char kTestAppIdA[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
109 const char kTestAppIdB[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
111 class FakeHost : public apps::AppShimHandler::Host {
112 public:
113 FakeHost(const base::FilePath& profile_path,
114 const std::string& app_id,
115 TestingExtensionAppShimHandler* handler)
116 : profile_path_(profile_path),
117 app_id_(app_id),
118 handler_(handler),
119 close_count_(0) {}
121 MOCK_METHOD1(OnAppLaunchComplete, void(AppShimLaunchResult));
123 void OnAppClosed() override {
124 handler_->OnShimClose(this);
125 ++close_count_;
127 void OnAppHide() override {}
128 void OnAppUnhideWithoutActivation() override {}
129 void OnAppRequestUserAttention(AppShimAttentionType type) override {}
130 base::FilePath GetProfilePath() const override {
131 return profile_path_;
133 std::string GetAppId() const override { return app_id_; }
135 int close_count() { return close_count_; }
137 private:
138 base::FilePath profile_path_;
139 std::string app_id_;
140 TestingExtensionAppShimHandler* handler_;
141 int close_count_;
143 DISALLOW_COPY_AND_ASSIGN(FakeHost);
146 class ExtensionAppShimHandlerTest : public testing::Test {
147 protected:
148 ExtensionAppShimHandlerTest()
149 : delegate_(new MockDelegate),
150 handler_(new TestingExtensionAppShimHandler(delegate_)),
151 profile_path_a_("Profile A"),
152 profile_path_b_("Profile B"),
153 host_aa_(profile_path_a_, kTestAppIdA, handler_.get()),
154 host_ab_(profile_path_a_, kTestAppIdB, handler_.get()),
155 host_bb_(profile_path_b_, kTestAppIdB, handler_.get()),
156 host_aa_duplicate_(profile_path_a_, kTestAppIdA, handler_.get()) {
157 base::FilePath extension_path("/fake/path");
158 base::DictionaryValue manifest;
159 manifest.SetString("name", "Fake Name");
160 manifest.SetString("version", "1");
161 std::string error;
162 extension_a_ = Extension::Create(
163 extension_path, extensions::Manifest::INTERNAL, manifest,
164 Extension::NO_FLAGS, kTestAppIdA, &error);
165 EXPECT_TRUE(extension_a_.get()) << error;
167 extension_b_ = Extension::Create(
168 extension_path, extensions::Manifest::INTERNAL, manifest,
169 Extension::NO_FLAGS, kTestAppIdB, &error);
170 EXPECT_TRUE(extension_b_.get()) << error;
172 EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_a_))
173 .WillRepeatedly(Return(true));
174 EXPECT_CALL(*delegate_, IsProfileLockedForPath(profile_path_a_))
175 .WillRepeatedly(Return(false));
176 EXPECT_CALL(*delegate_, ProfileForPath(profile_path_a_))
177 .WillRepeatedly(Return(&profile_a_));
178 EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_b_))
179 .WillRepeatedly(Return(true));
180 EXPECT_CALL(*delegate_, IsProfileLockedForPath(profile_path_b_))
181 .WillRepeatedly(Return(false));
182 EXPECT_CALL(*delegate_, ProfileForPath(profile_path_b_))
183 .WillRepeatedly(Return(&profile_b_));
185 // In most tests, we don't care about the result of GetWindows, it just
186 // needs to be non-empty.
187 AppWindowList app_window_list;
188 app_window_list.push_back(static_cast<extensions::AppWindow*>(NULL));
189 EXPECT_CALL(*delegate_, GetWindows(_, _))
190 .WillRepeatedly(Return(app_window_list));
192 EXPECT_CALL(*delegate_, MaybeGetAppExtension(_, kTestAppIdA))
193 .WillRepeatedly(Return(extension_a_.get()));
194 EXPECT_CALL(*delegate_, MaybeGetAppExtension(_, kTestAppIdB))
195 .WillRepeatedly(Return(extension_b_.get()));
196 EXPECT_CALL(*delegate_, LaunchApp(_, _, _))
197 .WillRepeatedly(Return());
200 void NormalLaunch(AppShimHandler::Host* host) {
201 handler_->OnShimLaunch(host,
202 APP_SHIM_LAUNCH_NORMAL,
203 std::vector<base::FilePath>());
206 void RegisterOnlyLaunch(AppShimHandler::Host* host) {
207 handler_->OnShimLaunch(host,
208 APP_SHIM_LAUNCH_REGISTER_ONLY,
209 std::vector<base::FilePath>());
212 // Completely launch a shim host and leave it running.
213 void LaunchAndActivate(FakeHost* host, Profile* profile) {
214 NormalLaunch(host);
215 EXPECT_EQ(host, handler_->FindHost(profile, host->GetAppId()));
216 EXPECT_CALL(*host, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
217 EXPECT_CALL(*handler_, OnShimFocus(host, APP_SHIM_FOCUS_NORMAL, _));
218 handler_->OnAppActivated(profile, host->GetAppId());
221 // Simulates a focus request coming from a running app shim.
222 void ShimNormalFocus(FakeHost* host) {
223 EXPECT_CALL(*handler_, OnShimFocus(host, APP_SHIM_FOCUS_NORMAL, _))
224 .WillOnce(Invoke(handler_.get(),
225 &TestingExtensionAppShimHandler::RealOnShimFocus));
227 const std::vector<base::FilePath> no_files;
228 handler_->OnShimFocus(host, APP_SHIM_FOCUS_NORMAL, no_files);
231 // Simulates a hide (or unhide) request coming from a running app shim.
232 void ShimSetHidden(FakeHost* host, bool hidden) {
233 handler_->OnShimSetHidden(host, hidden);
236 content::TestBrowserThreadBundle thread_bundle_;
237 MockDelegate* delegate_;
238 scoped_ptr<TestingExtensionAppShimHandler> handler_;
239 base::FilePath profile_path_a_;
240 base::FilePath profile_path_b_;
241 TestingProfile profile_a_;
242 TestingProfile profile_b_;
243 FakeHost host_aa_;
244 FakeHost host_ab_;
245 FakeHost host_bb_;
246 FakeHost host_aa_duplicate_;
247 scoped_refptr<Extension> extension_a_;
248 scoped_refptr<Extension> extension_b_;
250 private:
251 DISALLOW_COPY_AND_ASSIGN(ExtensionAppShimHandlerTest);
254 TEST_F(ExtensionAppShimHandlerTest, LaunchProfileNotFound) {
255 // Bad profile path.
256 EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_a_))
257 .WillOnce(Return(false))
258 .WillRepeatedly(Return(true));
259 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND));
260 NormalLaunch(&host_aa_);
263 TEST_F(ExtensionAppShimHandlerTest, LaunchProfileIsLocked) {
264 // Profile is locked.
265 EXPECT_CALL(*delegate_, IsProfileLockedForPath(profile_path_a_))
266 .WillOnce(Return(true));
267 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_PROFILE_LOCKED));
268 EXPECT_CALL(*delegate_, LaunchUserManager());
269 NormalLaunch(&host_aa_);
272 TEST_F(ExtensionAppShimHandlerTest, LaunchAppNotFound) {
273 // App not found.
274 EXPECT_CALL(*delegate_, MaybeGetAppExtension(&profile_a_, kTestAppIdA))
275 .WillRepeatedly(Return(static_cast<const Extension*>(NULL)));
276 EXPECT_CALL(*delegate_, EnableExtension(&profile_a_, kTestAppIdA, _))
277 .WillOnce(WithArgs<2>(Invoke(delegate_, &MockDelegate::RunCallback)));
278 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_APP_NOT_FOUND));
279 NormalLaunch(&host_aa_);
282 TEST_F(ExtensionAppShimHandlerTest, LaunchAppNotEnabled) {
283 // App not found.
284 EXPECT_CALL(*delegate_, MaybeGetAppExtension(&profile_a_, kTestAppIdA))
285 .WillOnce(Return(static_cast<const Extension*>(NULL)))
286 .WillRepeatedly(Return(extension_a_.get()));
287 EXPECT_CALL(*delegate_, EnableExtension(&profile_a_, kTestAppIdA, _))
288 .WillOnce(WithArgs<2>(Invoke(delegate_, &MockDelegate::RunCallback)));
289 NormalLaunch(&host_aa_);
292 TEST_F(ExtensionAppShimHandlerTest, LaunchAndCloseShim) {
293 // Normal startup.
294 NormalLaunch(&host_aa_);
295 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
297 NormalLaunch(&host_ab_);
298 EXPECT_EQ(&host_ab_, handler_->FindHost(&profile_a_, kTestAppIdB));
300 std::vector<base::FilePath> some_file(1, base::FilePath("some_file"));
301 EXPECT_CALL(*delegate_,
302 LaunchApp(&profile_b_, extension_b_.get(), some_file));
303 handler_->OnShimLaunch(&host_bb_, APP_SHIM_LAUNCH_NORMAL, some_file);
304 EXPECT_EQ(&host_bb_, handler_->FindHost(&profile_b_, kTestAppIdB));
306 // Activation when there is a registered shim finishes launch with success and
307 // focuses the app.
308 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
309 EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_NORMAL, _));
310 handler_->OnAppActivated(&profile_a_, kTestAppIdA);
312 // Starting and closing a second host just focuses the app.
313 EXPECT_CALL(*handler_, OnShimFocus(&host_aa_duplicate_,
314 APP_SHIM_FOCUS_REOPEN,
315 some_file));
316 EXPECT_CALL(host_aa_duplicate_,
317 OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST));
318 handler_->OnShimLaunch(&host_aa_duplicate_,
319 APP_SHIM_LAUNCH_NORMAL,
320 some_file);
321 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
322 handler_->OnShimClose(&host_aa_duplicate_);
323 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
325 // Normal close.
326 handler_->OnShimClose(&host_aa_);
327 EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
329 // Closing the second host afterward does nothing.
330 handler_->OnShimClose(&host_aa_duplicate_);
331 EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
334 TEST_F(ExtensionAppShimHandlerTest, AppLifetime) {
335 // When the app activates, if there is no shim, start one.
336 EXPECT_CALL(*delegate_, LaunchShim(&profile_a_, extension_a_.get()));
337 handler_->OnAppActivated(&profile_a_, kTestAppIdA);
339 // Normal shim launch adds an entry in the map.
340 // App should not be launched here, but return success to the shim.
341 EXPECT_CALL(*delegate_,
342 LaunchApp(&profile_a_, extension_a_.get(), _))
343 .Times(0);
344 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
345 RegisterOnlyLaunch(&host_aa_);
346 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
348 // Return no app windows for OnShimFocus and OnShimQuit.
349 AppWindowList app_window_list;
350 EXPECT_CALL(*delegate_, GetWindows(&profile_a_, kTestAppIdA))
351 .WillRepeatedly(Return(app_window_list));
353 // Non-reopen focus does nothing.
354 EXPECT_CALL(*delegate_,
355 LaunchApp(&profile_a_, extension_a_.get(), _))
356 .Times(0);
357 ShimNormalFocus(&host_aa_);
359 // Reopen focus launches the app.
360 EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_REOPEN, _))
361 .WillOnce(Invoke(handler_.get(),
362 &TestingExtensionAppShimHandler::RealOnShimFocus));
363 std::vector<base::FilePath> some_file(1, base::FilePath("some_file"));
364 EXPECT_CALL(*delegate_,
365 LaunchApp(&profile_a_, extension_a_.get(), some_file));
366 handler_->OnShimFocus(&host_aa_, APP_SHIM_FOCUS_REOPEN, some_file);
368 // Quit just closes all the windows. This tests that it doesn't terminate,
369 // but we expect closing all windows triggers a OnAppDeactivated from
370 // AppLifetimeMonitor.
371 handler_->OnShimQuit(&host_aa_);
373 // Closing all windows closes the shim and checks if Chrome should be
374 // terminated.
375 EXPECT_CALL(*delegate_, MaybeTerminate())
376 .WillOnce(Return());
377 handler_->OnAppDeactivated(&profile_a_, kTestAppIdA);
378 EXPECT_EQ(1, host_aa_.close_count());
381 TEST_F(ExtensionAppShimHandlerTest, MaybeTerminate) {
382 // Launch shims, adding entries in the map.
383 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
384 RegisterOnlyLaunch(&host_aa_);
385 EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
387 EXPECT_CALL(host_ab_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
388 RegisterOnlyLaunch(&host_ab_);
389 EXPECT_EQ(&host_ab_, handler_->FindHost(&profile_a_, kTestAppIdB));
391 // Return empty window list.
392 AppWindowList app_window_list;
393 EXPECT_CALL(*delegate_, GetWindows(_, _))
394 .WillRepeatedly(Return(app_window_list));
396 // Quitting when there's another shim should not terminate.
397 EXPECT_CALL(*delegate_, MaybeTerminate())
398 .Times(0);
399 handler_->OnAppDeactivated(&profile_a_, kTestAppIdA);
401 // Quitting when it's the last shim should terminate.
402 EXPECT_CALL(*delegate_, MaybeTerminate());
403 handler_->OnAppDeactivated(&profile_a_, kTestAppIdB);
406 TEST_F(ExtensionAppShimHandlerTest, RegisterOnly) {
407 // For an APP_SHIM_LAUNCH_REGISTER_ONLY, don't launch the app.
408 EXPECT_CALL(*delegate_, LaunchApp(_, _, _))
409 .Times(0);
410 EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
411 RegisterOnlyLaunch(&host_aa_);
412 EXPECT_TRUE(handler_->FindHost(&profile_a_, kTestAppIdA));
414 // Close the shim, removing the entry in the map.
415 handler_->OnShimClose(&host_aa_);
416 EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
419 TEST_F(ExtensionAppShimHandlerTest, LoadProfile) {
420 // If the profile is not loaded when an OnShimLaunch arrives, return false
421 // and load the profile asynchronously. Launch the app when the profile is
422 // ready.
423 EXPECT_CALL(*delegate_, ProfileForPath(profile_path_a_))
424 .WillOnce(Return(static_cast<Profile*>(NULL)))
425 .WillRepeatedly(Return(&profile_a_));
426 EXPECT_CALL(*delegate_, LoadProfileAsync(profile_path_a_, _))
427 .WillOnce(Invoke(delegate_, &MockDelegate::CaptureLoadProfileCallback));
428 NormalLaunch(&host_aa_);
429 EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
430 delegate_->RunLoadProfileCallback(profile_path_a_, &profile_a_);
431 EXPECT_TRUE(handler_->FindHost(&profile_a_, kTestAppIdA));
434 // Tests that calls to OnShimFocus, OnShimHide correctly handle a null extension
435 // being provided by the extension system.
436 TEST_F(ExtensionAppShimHandlerTest, ExtensionUninstalled) {
437 LaunchAndActivate(&host_aa_, &profile_a_);
439 // Have GetWindows() return an empty window list for focus (otherwise, it
440 // will contain a single nullptr, which can't be focused). Expect 1 call only.
441 AppWindowList empty_window_list;
442 EXPECT_CALL(*delegate_, GetWindows(_, _)).WillOnce(Return(empty_window_list));
444 ShimNormalFocus(&host_aa_);
445 EXPECT_EQ(0, host_aa_.close_count());
447 // Set up the mock to return a null extension, as if it were uninstalled.
448 EXPECT_CALL(*delegate_, MaybeGetAppExtension(&profile_a_, kTestAppIdA))
449 .WillRepeatedly(Return(nullptr));
451 // Now trying to focus should automatically close the shim, and not try to
452 // get the window list.
453 ShimNormalFocus(&host_aa_);
454 EXPECT_EQ(1, host_aa_.close_count());
456 // Do the same for SetHidden on host_bb.
457 LaunchAndActivate(&host_bb_, &profile_b_);
458 ShimSetHidden(&host_bb_, true);
459 EXPECT_EQ(0, host_bb_.close_count());
461 EXPECT_CALL(*delegate_, MaybeGetAppExtension(&profile_b_, kTestAppIdB))
462 .WillRepeatedly(Return(nullptr));
463 ShimSetHidden(&host_bb_, true);
464 EXPECT_EQ(1, host_bb_.close_count());
467 } // namespace apps