- add sources.
[platform/framework/web/crosswalk.git] / src / apps / app_shim / app_shim_host_manager_browsertest_mac.mm
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/app_shim_host_manager_mac.h"
6
7 #include <unistd.h>
8
9 #include "apps/app_shim/app_shim_messages.h"
10 #include "apps/app_shim/test/app_shim_host_manager_test_api_mac.h"
11 #include "base/files/file_path.h"
12 #include "base/logging.h"
13 #include "base/path_service.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/common/chrome_paths.h"
18 #include "chrome/common/mac/app_mode_common.h"
19 #include "chrome/test/base/in_process_browser_test.h"
20 #include "content/public/test/test_utils.h"
21 #include "ipc/ipc_channel_proxy.h"
22 #include "ipc/ipc_listener.h"
23 #include "ipc/ipc_message.h"
24
25 namespace {
26
27 const char kTestAppMode[] = "test_app";
28
29 // A test version of the AppShimController IPC client in chrome_main_app_mode.
30 class TestShimClient : public IPC::Listener {
31  public:
32   TestShimClient(const base::FilePath& socket_path);
33   virtual ~TestShimClient();
34
35   template <class T>
36   void Send(const T& message) {
37     channel_->Send(message);
38   }
39
40  private:
41   // IPC::Listener overrides:
42   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
43   virtual void OnChannelError() OVERRIDE;
44
45   base::Thread io_thread_;
46   scoped_ptr<IPC::ChannelProxy> channel_;
47
48   DISALLOW_COPY_AND_ASSIGN(TestShimClient);
49 };
50
51 TestShimClient::TestShimClient(const base::FilePath& socket_path)
52     : io_thread_("TestShimClientIO") {
53   base::Thread::Options io_thread_options;
54   io_thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
55   io_thread_.StartWithOptions(io_thread_options);
56
57   IPC::ChannelHandle handle(socket_path.value());
58   channel_.reset(new IPC::ChannelProxy(handle, IPC::Channel::MODE_NAMED_CLIENT,
59       this, io_thread_.message_loop_proxy().get()));
60 }
61
62 TestShimClient::~TestShimClient() {}
63
64 bool TestShimClient::OnMessageReceived(const IPC::Message& message) {
65   return true;
66 }
67
68 void TestShimClient::OnChannelError() {
69   // Client should not get any channel errors for the current set of tests.
70   PLOG(FATAL) << "ChannelError";
71 }
72
73 // Browser Test for AppShimHostManager to test IPC interactions across the
74 // UNIX domain socket.
75 class AppShimHostManagerBrowserTest : public InProcessBrowserTest,
76                                       public apps::AppShimHandler {
77  public:
78   AppShimHostManagerBrowserTest();
79   virtual ~AppShimHostManagerBrowserTest();
80
81  protected:
82   // Wait for OnShimLaunch, then send a quit, and wait for the response. Used to
83   // test launch behavior.
84   void RunAndExitGracefully();
85
86   // InProcessBrowserTest overrides:
87   virtual bool SetUpUserDataDirectory() OVERRIDE;
88
89   // AppShimHandler overrides:
90   virtual void OnShimLaunch(apps::AppShimHandler::Host* host,
91                             apps::AppShimLaunchType launch_type,
92                             const std::vector<base::FilePath>& files) OVERRIDE;
93   virtual void OnShimClose(apps::AppShimHandler::Host* host) OVERRIDE {}
94   virtual void OnShimFocus(apps::AppShimHandler::Host* host,
95                            apps::AppShimFocusType focus_type,
96                            const std::vector<base::FilePath>& files) OVERRIDE {}
97   virtual void OnShimSetHidden(apps::AppShimHandler::Host* host,
98                                bool hidden) OVERRIDE {}
99   virtual void OnShimQuit(apps::AppShimHandler::Host* host) OVERRIDE;
100
101   scoped_ptr<TestShimClient> test_client_;
102   base::FilePath short_socket_path_;
103   std::vector<base::FilePath> last_launch_files_;
104   apps::AppShimLaunchType last_launch_type_;
105
106 private:
107   scoped_refptr<content::MessageLoopRunner> runner_;
108   base::ScopedTempDir short_temp_dir_;
109
110   int launch_count_;
111   int quit_count_;
112
113   DISALLOW_COPY_AND_ASSIGN(AppShimHostManagerBrowserTest);
114 };
115
116 AppShimHostManagerBrowserTest::AppShimHostManagerBrowserTest()
117     : last_launch_type_(apps::APP_SHIM_LAUNCH_NUM_TYPES),
118       launch_count_(0),
119       quit_count_(0) {
120   apps::AppShimHandler::RegisterHandler(kTestAppMode, this);
121 }
122
123 AppShimHostManagerBrowserTest::~AppShimHostManagerBrowserTest() {
124   apps::AppShimHandler::RemoveHandler(kTestAppMode);
125 }
126
127 void AppShimHostManagerBrowserTest::RunAndExitGracefully() {
128   runner_ = new content::MessageLoopRunner();
129   EXPECT_EQ(0, launch_count_);
130   runner_->Run();  // Will stop in OnShimLaunch().
131   EXPECT_EQ(1, launch_count_);
132
133   runner_ = new content::MessageLoopRunner();
134   test_client_->Send(new AppShimHostMsg_QuitApp);
135   EXPECT_EQ(0, quit_count_);
136   runner_->Run();  // Will stop in OnShimQuit().
137   EXPECT_EQ(1, quit_count_);
138
139   test_client_.reset();
140 }
141
142 bool AppShimHostManagerBrowserTest::SetUpUserDataDirectory() {
143   // Create a symlink at /tmp/scoped_dir_XXXXXX/udd that points to the real user
144   // data dir, and use this as the domain socket path. This is required because
145   // there is a path length limit for named sockets that is exceeded in
146   // multi-process test spawning.
147   base::FilePath real_user_data_dir;
148   EXPECT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &real_user_data_dir));
149   EXPECT_TRUE(
150       short_temp_dir_.CreateUniqueTempDirUnderPath(base::FilePath("/tmp")));
151   base::FilePath shortened_user_data_dir = short_temp_dir_.path().Append("udd");
152   EXPECT_EQ(0, ::symlink(real_user_data_dir.AsUTF8Unsafe().c_str(),
153                          shortened_user_data_dir.AsUTF8Unsafe().c_str()));
154
155   test::AppShimHostManagerTestApi::OverrideUserDataDir(shortened_user_data_dir);
156   short_socket_path_ =
157       shortened_user_data_dir.Append(app_mode::kAppShimSocketName);
158
159   return InProcessBrowserTest::SetUpUserDataDirectory();
160 }
161
162 void AppShimHostManagerBrowserTest::OnShimLaunch(
163     apps::AppShimHandler::Host* host,
164     apps::AppShimLaunchType launch_type,
165     const std::vector<base::FilePath>& files) {
166   host->OnAppLaunchComplete(apps::APP_SHIM_LAUNCH_SUCCESS);
167   ++launch_count_;
168   last_launch_type_ = launch_type;
169   last_launch_files_ = files;
170   runner_->Quit();
171 }
172
173 void AppShimHostManagerBrowserTest::OnShimQuit(
174     apps::AppShimHandler::Host* host) {
175   ++quit_count_;
176   runner_->Quit();
177 }
178
179 // Test regular launch, which would ask Chrome to launch the app.
180 IN_PROC_BROWSER_TEST_F(AppShimHostManagerBrowserTest, LaunchNormal) {
181   test_client_.reset(new TestShimClient(short_socket_path_));
182   test_client_->Send(new AppShimHostMsg_LaunchApp(
183       browser()->profile()->GetPath(),
184       kTestAppMode,
185       apps::APP_SHIM_LAUNCH_NORMAL,
186       std::vector<base::FilePath>()));
187
188   RunAndExitGracefully();
189   EXPECT_EQ(apps::APP_SHIM_LAUNCH_NORMAL, last_launch_type_);
190   EXPECT_TRUE(last_launch_files_.empty());
191 }
192
193 // Test register-only launch, used when Chrome has already launched the app.
194 IN_PROC_BROWSER_TEST_F(AppShimHostManagerBrowserTest, LaunchRegisterOnly) {
195   test_client_.reset(new TestShimClient(short_socket_path_));
196   test_client_->Send(new AppShimHostMsg_LaunchApp(
197       browser()->profile()->GetPath(),
198       kTestAppMode,
199       apps::APP_SHIM_LAUNCH_REGISTER_ONLY,
200       std::vector<base::FilePath>()));
201
202   RunAndExitGracefully();
203   EXPECT_EQ(apps::APP_SHIM_LAUNCH_REGISTER_ONLY, last_launch_type_);
204   EXPECT_TRUE(last_launch_files_.empty());
205 }
206
207 // Ensure the domain socket can be created in a fresh user data dir.
208 IN_PROC_BROWSER_TEST_F(AppShimHostManagerBrowserTest,
209                        PRE_ReCreate) {
210   test::AppShimHostManagerTestApi test_api(
211       g_browser_process->platform_part()->app_shim_host_manager());
212   EXPECT_TRUE(test_api.factory());
213 }
214
215 // Ensure the domain socket can be re-created after a prior browser process has
216 // quit.
217 IN_PROC_BROWSER_TEST_F(AppShimHostManagerBrowserTest,
218                        ReCreate) {
219   test::AppShimHostManagerTestApi test_api(
220       g_browser_process->platform_part()->app_shim_host_manager());
221   EXPECT_TRUE(test_api.factory());
222 }
223
224 // Test for AppShimHostManager that fails to create the socket.
225 class AppShimHostManagerBrowserTestFailsCreate :
226     public AppShimHostManagerBrowserTest {
227  public:
228   AppShimHostManagerBrowserTestFailsCreate() {}
229
230  private:
231   virtual bool SetUpUserDataDirectory() OVERRIDE;
232
233   base::ScopedTempDir barrier_dir_;
234
235   DISALLOW_COPY_AND_ASSIGN(AppShimHostManagerBrowserTestFailsCreate);
236 };
237
238 bool AppShimHostManagerBrowserTestFailsCreate::SetUpUserDataDirectory() {
239   base::FilePath user_data_dir;
240   // Start in the "real" user data dir for this test. This is a meta-test for
241   // the symlinking steps used in the superclass. That is, by putting the
242   // clobber in the actual user data dir, the test will fail if the symlink
243   // does not actually point to the user data dir, since it won't be clobbered.
244   EXPECT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
245   base::FilePath socket_path =
246       user_data_dir.Append(app_mode::kAppShimSocketName);
247   // Create a "barrier" to forming the UNIX domain socket. This is just a
248   // pre-existing directory which can not be unlink()ed, in order to place a
249   // named socked there instead.
250   EXPECT_TRUE(barrier_dir_.Set(socket_path));
251   return AppShimHostManagerBrowserTest::SetUpUserDataDirectory();
252 }
253
254 // Test error handling. This is essentially testing for lifetime correctness
255 // during startup for unexpected failures.
256 IN_PROC_BROWSER_TEST_F(AppShimHostManagerBrowserTestFailsCreate,
257                        SocketFailure) {
258   test::AppShimHostManagerTestApi test_api(
259       g_browser_process->platform_part()->app_shim_host_manager());
260   EXPECT_FALSE(test_api.factory());
261 }
262
263 }  // namespace