- add sources.
[platform/framework/web/crosswalk.git] / src / chrome_frame / test / test_with_web_server.h
1 // Copyright (c) 2012 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 #ifndef CHROME_FRAME_TEST_TEST_WITH_WEB_SERVER_H_
6 #define CHROME_FRAME_TEST_TEST_WITH_WEB_SERVER_H_
7
8 #include <windows.h>
9 #include <string>
10
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/win/scoped_handle.h"
16 #include "chrome_frame/chrome_tab.h"
17 #include "chrome_frame/test/chrome_frame_test_utils.h"
18 #include "chrome_frame/test/test_server.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 // Specifies the invocation method for CF.
23 class CFInvocation {
24  public:
25   enum Type {
26     NONE = 0,
27     META_TAG,
28     HTTP_HEADER
29   };
30
31   CFInvocation(): method_(NONE) {}
32   explicit CFInvocation(Type method): method_(method) {}
33
34   // Convience methods for creating this class.
35   static CFInvocation None() { return CFInvocation(NONE); }
36   static CFInvocation MetaTag() { return CFInvocation(META_TAG); }
37   static CFInvocation HttpHeader() { return CFInvocation(HTTP_HEADER); }
38
39   // Returns whether this page does invoke CF.
40   bool invokes_cf() const {
41     return method_ != NONE;
42   }
43
44   Type type() const { return method_; }
45
46  private:
47   Type method_;
48 };
49
50 // An interface for listeners of interesting events on a MockWebServer.
51 class WebServerListener {
52  public:
53   virtual ~WebServerListener() {}
54
55   // Invoked when a MockWebServer receives an expected response; see
56   // MockWebServer::ExpectAndHandlePostedResult.
57   virtual void OnExpectedResponse() = 0;
58 };
59
60 // Simple Gmock friendly web server. Sample usage:
61 // MockWebServer mock(9999, "0.0.0.0");
62 // EXPECT_CALL(mock, Get(_, StrEq("/favicon.ico"), _)).WillRepeatedly(SendFast(
63 //     "HTTP/1.1 404 Not Found"
64 //     "text/html; charset=UTF-8", EmptyString()));
65 //
66 // EXPECT_CALL(mock, Get(_, StrEq("/book"), _)).WillRepeatedly(Send(
67 //     "HTTP/1.1 302 Found\r\n"
68 //     "Connection: close\r\n"
69 //     "Content-Type: text/html\r\n"
70 //     "Location: library\r\n",
71 //     "<html>Lalalala</html>", 3, 1000));
72 //
73 // EXPECT_CALL(mock, Get(_, StrEq("/library"), _)).WillRepeatedly(Send(
74 //     "HTTP/1.1 200 OK\r\n"
75 //     "Connection: close\r\n"
76 //     "Content-Type: text/html\r\n",
77 //     "<html><meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\" />"
78 //     "<body>Rendered in CF.</body></html>", 4, 1000));
79 class MockWebServer : public test_server::HTTPTestServer {
80  public:
81   MockWebServer(int port, const std::wstring& address, base::FilePath root_dir)
82       : test_server::HTTPTestServer(port, address, root_dir), listener_(NULL) {}
83
84   // Overriden from test_server::HTTPTestServer.
85   MOCK_METHOD3(Get, void(test_server::ConfigurableConnection* connection,
86                          const std::wstring& path,
87                          const test_server::Request& r));
88   MOCK_METHOD3(Post, void(test_server::ConfigurableConnection* connection,
89                           const std::wstring& path,
90                           const test_server::Request& r));
91
92   // Expect a GET request for |url|. Respond with the file appropriate for
93   // the given |url|. Modify the file to follow the given CFInvocation method.
94   // The response includes a no-cache header. |allow_meta_tag_double_req|
95   // specifies whether to allow the request to happen twice if the invocation
96   // is using the CF meta tag.
97   void ExpectAndServeRequest(CFInvocation invocation, const std::wstring& url);
98
99   // Expect a number of GET requests for |url|. Rest is similar to the function
100   // ExpectAndServeRequest.
101   void ExpectAndServeRequestWithCardinality(CFInvocation invocation,
102                                             const std::wstring& url,
103                                             testing::Cardinality cardinality);
104
105   // Same as above except do not include the no-cache header.
106   void ExpectAndServeRequestAllowCache(CFInvocation invocation,
107                                        const std::wstring& url);
108
109   // Expect any number of GETs for the given resource path (e.g, /favicon.ico)
110   // and respond with the file, if it exists, or a 404 if it does not.
111   void ExpectAndServeRequestAnyNumberTimes(CFInvocation invocation,
112                                            const std::wstring& path_prefix);
113
114   void set_listener(WebServerListener* listener) { listener_ = listener; }
115
116   // Expect a POST to an URL containing |post_suffix|, saving the response
117   // contents for retrieval by posted_result(). Invokes the listener's
118   // OnExpectedResponse method if the posted response matches the expected
119   // result.
120   void ExpectAndHandlePostedResult(CFInvocation invocation,
121                                    const std::wstring& post_suffix);
122
123   // Expect and serve all incoming GET requests.
124   void ExpectAndServeAnyRequests(CFInvocation invocation) {
125     ExpectAndServeRequestAnyNumberTimes(invocation, L"");
126   }
127
128
129   // Send a response on the given connection appropriate for |resource_uri|.
130   // If the file referred to by |path| exists, send the file data, otherwise
131   // send 404. Modify the file data according to the given invocation method.
132   void SendResponseHelper(test_server::ConfigurableConnection* connection,
133                           const std::wstring& resource_uri,
134                           const test_server::Request& request,
135                           CFInvocation invocation,
136                           bool add_no_cache_header);
137   // Handles the posted /writefile response
138   void HandlePostedResponse(test_server::ConfigurableConnection* connection,
139                             const test_server::Request& request);
140
141   void ClearResults() {
142     posted_result_.clear();
143     expected_result_.clear();
144   }
145
146   void set_expected_result(const std::string& expected_result) {
147     expected_result_  = expected_result;
148   }
149
150   const std::string& posted_result() const {
151     return posted_result_;
152   }
153
154  private:
155   WebServerListener* listener_;
156   // Holds the results of tests which post success/failure.
157   std::string posted_result_;
158   std::string expected_result_;
159 };
160
161 class MockWebServerListener : public WebServerListener {
162  public:
163   MOCK_METHOD0(OnExpectedResponse, void());
164 };
165
166 // Class that:
167 // 1) Starts the local webserver,
168 // 2) Supports launching browsers - Internet Explorer with local url
169 // 3) Wait the webserver to finish. It is supposed the test webpage to shutdown
170 //    the server by navigating to "kill" page
171 // 4) Supports read the posted results from the test webpage to the "dump"
172 //    webserver directory
173 class ChromeFrameTestWithWebServer : public testing::Test {
174  public:
175   ChromeFrameTestWithWebServer();
176
177  protected:
178   enum BrowserKind { INVALID, IE, CHROME };
179
180   bool LaunchBrowser(BrowserKind browser, const wchar_t* url);
181
182   // Returns true if the test completed in time, or false if it timed out.
183   bool WaitForTestToComplete(base::TimeDelta duration);
184
185   // Waits for the page to notify us of the window.onload event firing.
186   // Note that the milliseconds value is only approximate.
187   bool WaitForOnLoad(int milliseconds);
188
189   // Launches the specified browser and waits for the test to complete (see
190   // WaitForTestToComplete).  Then checks that the outcome is equal to the
191   // expected result.  The test is repeated once if it fails due to a timeout.
192   // This function uses EXPECT_TRUE and ASSERT_TRUE for all steps performed
193   // hence no return value.
194   void SimpleBrowserTestExpectedResult(BrowserKind browser,
195       const wchar_t* page, const char* result);
196   void SimpleBrowserTest(BrowserKind browser, const wchar_t* page);
197
198   // Sets up expectations for a page to post back a result.
199   void ExpectAndHandlePostedResult();
200
201   // Test if chrome frame correctly reports its version.
202   void VersionTest(BrowserKind browser, const wchar_t* page);
203
204   void CloseBrowser();
205
206   // Ensures (well, at least tries to ensure) that the browser window has focus.
207   bool BringBrowserToTop();
208
209   const base::FilePath& GetCFTestFilePath() {
210     return test_file_path_;
211   }
212
213   static chrome_frame_test::TimedMsgLoop& loop() {
214     return *loop_;
215   }
216
217   static testing::StrictMock<MockWebServerListener>& listener_mock() {
218     return *listener_mock_;
219   }
220
221   static testing::StrictMock<MockWebServer>& server_mock() {
222     return *server_mock_;
223   }
224
225   static void SetUpTestCase();
226   static void TearDownTestCase();
227
228   static const base::FilePath& GetChromeUserDataDirectory();
229
230   virtual void SetUp() OVERRIDE;
231   virtual void TearDown() OVERRIDE;
232
233   // The on-disk path to our html test files.
234   static base::FilePath test_file_path_;
235   static base::FilePath results_dir_;
236   static base::FilePath CFInstall_path_;
237   static base::FilePath CFInstance_path_;
238   static base::FilePath chrome_user_data_dir_;
239
240   // The user data directory used for Chrome instances.
241   static base::ScopedTempDir temp_dir_;
242
243   // The web server from which we serve the web!
244   static chrome_frame_test::TimedMsgLoop* loop_;
245   static std::string local_address_;
246   static testing::StrictMock<MockWebServerListener>* listener_mock_;
247   static testing::StrictMock<MockWebServer>* server_mock_;
248
249   BrowserKind browser_;
250   base::win::ScopedHandle browser_handle_;
251 };
252
253 // A helper class for doing some bookkeeping when using the
254 // SimpleWebServer class.
255 class SimpleWebServerTest {
256  public:
257   SimpleWebServerTest(const std::string& address, int port)
258       : server_(address, port), port_(port) {
259   }
260
261   ~SimpleWebServerTest() {
262     server_.DeleteAllResponses();
263   }
264
265   template <class ResponseClass>
266   void PopulateStaticFileListT(const wchar_t* pages[], int count,
267                                const base::FilePath& directory) {
268     for (int i = 0; i < count; ++i) {
269       server_.AddResponse(new ResponseClass(
270           base::StringPrintf("/%ls", pages[i]).c_str(),
271                              directory.Append(pages[i])));
272     }
273   }
274
275   std::wstring FormatHttpPath(const wchar_t* document_path) {
276     return base::StringPrintf(L"http://%ls:%i/%ls",
277                               ASCIIToWide(server_.host()).c_str(), port_,
278                               document_path);
279   }
280
281   // Returns the last client request object.
282   // Under normal circumstances this will be the request for /quit.
283   const test_server::Request& last_request() const {
284     const test_server::ConnectionList& connections = server_.connections();
285     DCHECK(connections.size());
286     const test_server::Connection* c = connections.back();
287     return c->request();
288   }
289
290   bool FindRequest(const std::string& path,
291                    const test_server::Request** request) {
292     test_server::ConnectionList::const_iterator index;
293     for (index = server_.connections().begin();
294          index != server_.connections().end(); index++) {
295       const test_server::Connection* connection = *index;
296       if (!lstrcmpiA(connection->request().path().c_str(), path.c_str())) {
297         if (request)
298           *request = &connection->request();
299         return true;
300       }
301     }
302     return false;
303   }
304
305   // Counts the number of times a page was requested.
306   // Optionally checks if the request method for each is equal to
307   // |expected_method|.  If expected_method is NULL no such check is made.
308   int GetRequestCountForPage(const wchar_t* page, const char* expected_method) {
309     // Check how many requests we got for the cf page.
310     test_server::ConnectionList::const_iterator it;
311     int requests = 0;
312     const test_server::ConnectionList& connections = server_.connections();
313     for (it = connections.begin(); it != connections.end(); ++it) {
314       const test_server::Connection* c = (*it);
315       const test_server::Request& r = c->request();
316       if (!r.path().empty() &&
317           ASCIIToWide(r.path().substr(1)).compare(page) == 0) {
318         if (expected_method) {
319           EXPECT_EQ(expected_method, r.method());
320         }
321         requests++;
322       }
323     }
324     return requests;
325   }
326
327   test_server::SimpleWebServer* web_server() {
328     return &server_;
329   }
330
331  protected:
332   test_server::SimpleWebServer server_;
333   int port_;
334 };
335
336 ACTION_P2(SendFast, headers, content) {
337   arg0->Send(headers, content);
338 }
339
340 ACTION_P4(Send, headers, content, chunk, timeout) {
341   test_server::ConfigurableConnection::SendOptions options(
342       test_server::ConfigurableConnection::SendOptions::
343         IMMEDIATE_HEADERS_DELAYED_CONTENT, chunk, timeout);
344   arg0->SendWithOptions(std::string(headers),
345                         std::string(content),
346                         options);
347 }
348
349 ACTION_P4(SendSlow, headers, content, chunk, timeout) {
350   test_server::ConfigurableConnection::SendOptions options(
351     test_server::ConfigurableConnection::SendOptions::DELAYED, chunk, timeout);
352   arg0->SendWithOptions(std::string(headers),
353                         std::string(content),
354                         options);
355 }
356
357 // Sends a response with the file data for the given path, if the file exists,
358 // or a 404 if the file does not. This response includes a no-cache header.
359 ACTION_P2(SendResponse, server, invocation) {
360   server->SendResponseHelper(arg0, arg1, arg2, invocation, true);
361 }
362
363 // Same as above except that the response does not include the no-cache header.
364 ACTION_P2(SendAllowCacheResponse, server, invocation) {
365   server->SendResponseHelper(arg0, arg1, invocation, false);
366 }
367
368 ACTION_P2(HandlePostedResponseHelper, server, invocation) {
369   server->HandlePostedResponse(arg0, arg2);
370 }
371
372 #endif  // CHROME_FRAME_TEST_TEST_WITH_WEB_SERVER_H_