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