extension_apitest.h revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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_BROWSER_EXTENSIONS_EXTENSION_APITEST_H_
6#define CHROME_BROWSER_EXTENSIONS_EXTENSION_APITEST_H_
7
8#include <deque>
9#include <string>
10
11#include "base/compiler_specific.h"
12#include "base/values.h"
13#include "chrome/browser/extensions/extension_browsertest.h"
14#include "content/public/browser/notification_registrar.h"
15
16namespace base {
17class FilePath;
18}
19
20namespace extensions {
21class Extension;
22}
23
24// The general flow of these API tests should work like this:
25// (1) Setup initial browser state (e.g. create some bookmarks for the
26//     bookmark test)
27// (2) Call ASSERT_TRUE(RunExtensionTest(name));
28// (3) In your extension code, run your test and call chrome.test.pass or
29//     chrome.test.fail
30// (4) Verify expected browser state.
31// TODO(erikkay): There should also be a way to drive events in these tests.
32class ExtensionApiTest : public ExtensionBrowserTest {
33 public:
34  // Flags used to configure how the tests are run.
35  // TODO(aa): Many of these are dupes of ExtensionBrowserTest::Flags. Combine
36  // somehow?
37  enum Flags {
38    kFlagNone = 0,
39
40    // Allow the extension to run in incognito mode.
41    kFlagEnableIncognito = 1 << 0,
42
43    // Launch the test page in an incognito window.
44    kFlagUseIncognito = 1 << 1,
45
46    // Allow file access for the extension.
47    kFlagEnableFileAccess = 1 << 2,
48
49    // Loads the extension with location COMPONENT.
50    kFlagLoadAsComponent = 1 << 3,
51
52    // Launch the extension as a platform app.
53    kFlagLaunchPlatformApp = 1 << 4,
54
55    // Don't fail when the loaded manifest has warnings.
56    kFlagIgnoreManifestWarnings = 1 << 5,
57
58    // Allow manifest versions older that Extension::kModernManifestVersion.
59    // Used to test old manifest features.
60    kFlagAllowOldManifestVersions = 1 << 6,
61  };
62
63  ExtensionApiTest();
64  virtual ~ExtensionApiTest();
65
66 protected:
67  // Helper class that observes tests failing or passing. Observation starts
68  // when the class is constructed. Get the next result by calling
69  // GetNextResult() and message() if GetNextResult() return false. If there
70  // are no results, this method will pump the UI message loop until one is
71  // received.
72  class ResultCatcher : public content::NotificationObserver {
73   public:
74    ResultCatcher();
75    virtual ~ResultCatcher();
76
77    // Pumps the UI loop until a notification is received that an API test
78    // succeeded or failed. Returns true if the test succeeded, false otherwise.
79    bool GetNextResult();
80
81    void RestrictToProfile(Profile* profile) { profile_restriction_ = profile; }
82
83    const std::string& message() { return message_; }
84
85   private:
86    virtual void Observe(int type,
87                         const content::NotificationSource& source,
88                         const content::NotificationDetails& details) OVERRIDE;
89
90    content::NotificationRegistrar registrar_;
91
92    // A sequential list of pass/fail notifications from the test extension(s).
93    std::deque<bool> results_;
94
95    // If it failed, what was the error message?
96    std::deque<std::string> messages_;
97    std::string message_;
98
99    // If non-NULL, we will listen to events from this profile only.
100    Profile* profile_restriction_;
101
102    // True if we're in a nested message loop waiting for results from
103    // the extension.
104    bool waiting_;
105  };
106
107  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE;
108  virtual void TearDownInProcessBrowserTestFixture() OVERRIDE;
109
110  // Load |extension_name| and wait for pass / fail notification.
111  // |extension_name| is a directory in "test/data/extensions/api_test".
112  bool RunExtensionTest(const std::string& extension_name);
113
114  // Same as RunExtensionTest, but enables the extension for incognito mode.
115  bool RunExtensionTestIncognito(const std::string& extension_name);
116
117  // Same as RunExtensionTest, but ignores any warnings in the manifest.
118  bool RunExtensionTestIgnoreManifestWarnings(
119      const std::string& extension_name);
120
121  // Same as RunExtensionTest, allow old manifest ersions.
122  bool RunExtensionTestAllowOldManifestVersion(
123      const std::string& extension_name);
124
125  // Same as RunExtensionTest, but loads extension as component.
126  bool RunComponentExtensionTest(const std::string& extension_name);
127
128  // Same as RunExtensionTest, but disables file access.
129  bool RunExtensionTestNoFileAccess(const std::string& extension_name);
130
131  // Same as RunExtensionTestIncognito, but disables file access.
132  bool RunExtensionTestIncognitoNoFileAccess(const std::string& extension_name);
133
134  // If not empty, Load |extension_name|, load |page_url| and wait for pass /
135  // fail notification from the extension API on the page. Note that if
136  // |page_url| is not a valid url, it will be treated as a resource within
137  // the extension. |extension_name| is a directory in
138  // "test/data/extensions/api_test".
139  bool RunExtensionSubtest(const std::string& extension_name,
140                           const std::string& page_url);
141
142  // Same as RunExtensionSubtest, except run with the specific |flags|
143  // (as defined in the Flags enum).
144  bool RunExtensionSubtest(const std::string& extension_name,
145                           const std::string& page_url,
146                           int flags);
147
148  // Load |page_url| and wait for pass / fail notification from the extension
149  // API on the page.
150  bool RunPageTest(const std::string& page_url);
151  bool RunPageTest(const std::string& page_url, int flags);
152
153  // Similar to RunExtensionTest, except used for running tests in platform app
154  // shell windows.
155  bool RunPlatformAppTest(const std::string& extension_name);
156
157  // Similar to RunPlatformAppTest, except sets an additional string argument
158  // |customArg| to the test config object.
159  bool RunPlatformAppTestWithArg(
160      const std::string& extension_name, const char* custom_arg);
161
162  // Start the test server, and store details of its state.  Those details
163  // will be available to javascript tests using chrome.test.getConfig().
164  bool StartEmbeddedTestServer();
165
166  // Start the test WebSocket server, and store details of its state. Those
167  // details will be available to javascript tests using
168  // chrome.test.getConfig().
169  bool StartWebSocketServer(const base::FilePath& root_directory);
170
171  // Test that exactly one extension loaded.  If so, return a pointer to
172  // the extension.  If not, return NULL and set message_.
173  const extensions::Extension* GetSingleLoadedExtension();
174
175  // All extensions tested by ExtensionApiTest are in the "api_test" dir.
176  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
177
178  // If it failed, what was the error message?
179  std::string message_;
180
181 private:
182  bool RunExtensionTestImpl(const std::string& extension_name,
183                            const std::string& test_page,
184                            const char* custom_arg,
185                            int flags);
186
187  // Hold details of the test, set in C++, which can be accessed by
188  // javascript using chrome.test.getConfig().
189  scoped_ptr<DictionaryValue> test_config_;
190
191  // Hold the test WebSocket server.
192  scoped_ptr<net::SpawnedTestServer> websocket_server_;
193};
194
195#endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_APITEST_H_
196