1 // Copyright (c) 2011 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 "base/string_number_conversions.h"
6 #include "base/utf_string_conversions.h"
7 #include "chrome/browser/browser_process.h"
8 #include "chrome/browser/browser_signin.h"
9 #include "chrome/browser/extensions/extension_browsertest.h"
10 #include "chrome/browser/extensions/extension_test_message_listener.h"
11 #include "chrome/browser/extensions/extension_webstore_private_api.h"
12 #include "chrome/browser/net/gaia/token_service.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/browser/sync/profile_sync_service.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/common/net/gaia/gaia_constants.h"
18 #include "chrome/common/url_constants.h"
19 #include "chrome/test/ui_test_utils.h"
20 #include "content/browser/tab_contents/tab_contents.h"
21 #include "googleurl/src/gurl.h"
22 #include "net/base/mock_host_resolver.h"
23
24 using chrome::kHttpScheme;
25 using chrome::kStandardSchemeSeparator;
26
27 namespace {
28
29 const char kTestUrlHostname[] = "www.example.com";
30
31 } // namespace
32
33 // A fake version of ProfileSyncService used for testing.
34 class FakeProfileSyncService : public ProfileSyncService {
35 public:
FakeProfileSyncService()36 FakeProfileSyncService()
37 : ProfileSyncService(NULL, NULL, ""),
38 setup_(false) {
39 }
~FakeProfileSyncService()40 virtual ~FakeProfileSyncService() {}
41
42 // Overrides of virtual methods in ProfileSyncService.
HasSyncSetupCompleted() const43 virtual bool HasSyncSetupCompleted() const {
44 return setup_;
45 }
ChangePreferredDataTypes(const syncable::ModelTypeSet & types)46 virtual void ChangePreferredDataTypes(const syncable::ModelTypeSet& types) {
47 types_ = types;
48 }
GetPreferredDataTypes(syncable::ModelTypeSet * types) const49 virtual void GetPreferredDataTypes(syncable::ModelTypeSet* types) const {
50 *types = types_;
51 }
SetSyncSetupCompleted()52 virtual void SetSyncSetupCompleted() {
53 setup_ = true;
54 }
55
56 private:
57 bool setup_;
58 syncable::ModelTypeSet types_;
59 };
60
61 class FakeBrowserSignin : public BrowserSignin {
62 public:
63 // The |username_after_login| parameter determines what this fake
64 // BrowserSignin will set the username to when ShowLoginDialog is called.
FakeBrowserSignin(bool should_succeed,const std::string & initial_username,const std::string & username_after_login)65 FakeBrowserSignin(bool should_succeed,
66 const std::string& initial_username,
67 const std::string& username_after_login)
68 : BrowserSignin(NULL),
69 should_succeed_(should_succeed),
70 username_(initial_username),
71 username_after_login_(username_after_login) {
72 }
~FakeBrowserSignin()73 virtual ~FakeBrowserSignin() {}
74
GetSignedInUsername() const75 virtual std::string GetSignedInUsername() const {
76 return username_;
77 }
78
RequestSignin(TabContents * tab_contents,const string16 & preferred_email,const string16 & message,SigninDelegate * delegate)79 virtual void RequestSignin(TabContents* tab_contents,
80 const string16& preferred_email,
81 const string16& message,
82 SigninDelegate* delegate) {
83 if (should_succeed_) {
84 // Simulate valid login.
85 username_ = username_after_login_;
86 delegate->OnLoginSuccess();
87
88 // Fake a token available notification.
89 Profile* profile = tab_contents->profile();
90 if (profile->IsOffTheRecord()) {
91 profile = g_browser_process->profile_manager()->GetDefaultProfile();
92 }
93 TokenService* token_service = profile->GetTokenService();
94 token_service->IssueAuthTokenForTest(GaiaConstants::kGaiaService,
95 "new_token");
96 } else {
97 delegate->OnLoginFailure(GoogleServiceAuthError(
98 GoogleServiceAuthError::REQUEST_CANCELED));
99 }
100 }
101
102 private:
103 bool should_succeed_;
104 std::string username_;
105 std::string username_after_login_;
106 };
107
108 class ExtensionWebstorePrivateBrowserTest : public ExtensionBrowserTest {
109 public:
ExtensionWebstorePrivateBrowserTest()110 ExtensionWebstorePrivateBrowserTest() {
111 test_url_base_ = std::string() + kHttpScheme + kStandardSchemeSeparator +
112 kTestUrlHostname;
113 }
114
SetUpCommandLine(CommandLine * command_line)115 void SetUpCommandLine(CommandLine* command_line) {
116 ExtensionBrowserTest::SetUpCommandLine(command_line);
117 command_line->AppendSwitchASCII(switches::kAppsGalleryURL, test_url_base_);
118 }
119
120 // This generates a regular test server url pointing to a test file at
121 // |relative_path|, but replaces the hostname with kTestUrlHostname so that
122 // we get the webstore private APIs injected (this happens because of the
123 // command line switch we added in SetupCommandLine).
GetUrl(const std::string & relative_path)124 GURL GetUrl(const std::string& relative_path) {
125 GURL base_url = test_server()->GetURL(
126 "files/extensions/webstore_private/" + relative_path);
127 GURL::Replacements replacements;
128 std::string replacement_host = std::string(kTestUrlHostname);
129 replacements.SetHostStr(replacement_host);
130 return base_url.ReplaceComponents(replacements);
131 }
132
RunLoginTestImpl(bool incognito,const std::string & relative_path,const std::string & initial_login,bool login_succeeds,const std::string & login_result)133 void RunLoginTestImpl(bool incognito,
134 const std::string& relative_path,
135 const std::string& initial_login,
136 bool login_succeeds,
137 const std::string& login_result) {
138 // Clear the token service so previous tests don't affect things.
139 TokenService* token_service = browser()->profile()->GetTokenService();
140 token_service->ResetCredentialsInMemory();
141 if (!initial_login.empty()) {
142 // Initialize the token service with an existing token.
143 token_service->IssueAuthTokenForTest(GaiaConstants::kGaiaService,
144 "existing_token");
145 }
146
147 FakeProfileSyncService sync_service;
148 FakeBrowserSignin signin(login_succeeds, initial_login, login_result);
149 WebstorePrivateApi::SetTestingProfileSyncService(&sync_service);
150 WebstorePrivateApi::SetTestingBrowserSignin(&signin);
151
152 ExtensionTestMessageListener listener("success", false);
153 GURL url = GetUrl(relative_path);
154 if (incognito) {
155 ui_test_utils::OpenURLOffTheRecord(browser()->profile(), url);
156 } else {
157 ui_test_utils::NavigateToURL(browser(), url);
158 }
159 EXPECT_TRUE(listener.WaitUntilSatisfied());
160
161 WebstorePrivateApi::SetTestingBrowserSignin(NULL);
162 WebstorePrivateApi::SetTestingProfileSyncService(NULL);
163 }
164
RunLoginTest(const std::string & relative_path,const std::string & initial_login,bool login_succeeds,const std::string & login_result)165 void RunLoginTest(const std::string& relative_path,
166 const std::string& initial_login,
167 bool login_succeeds,
168 const std::string& login_result) {
169 RunLoginTestImpl(true,
170 relative_path,
171 initial_login,
172 login_succeeds,
173 login_result);
174 RunLoginTestImpl(false,
175 relative_path,
176 initial_login,
177 login_succeeds,
178 login_result);
179 }
180
181 protected:
182 std::string test_url_base_;
183 };
184
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateBrowserTest,BrowserLogin)185 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateBrowserTest, BrowserLogin) {
186 host_resolver()->AddRule(kTestUrlHostname, "127.0.0.1");
187 ASSERT_TRUE(test_server()->Start());
188
189 RunLoginTest("browser_login/expect_nonempty.html",
190 "foo@bar.com", false, "");
191
192 RunLoginTest("browser_login/prompt_no_preferred.html", "", true, "");
193
194 RunLoginTest("browser_login/prompt_preferred.html", "", true, "foo@bar.com");
195
196 RunLoginTest("browser_login/prompt_login_fails.html",
197 "", false, "foo@bar.com");
198 }
199