Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: ios/chrome/browser/net/cookies_egtest.mm

Issue 2734963004: Refactor Assert[No]CookieExists to return a boolean (Closed)
Patch Set: Move cookie helpers to a shared location Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <map> 5 #include <map>
6 #include <memory> 6 #include <memory>
7 #include <string> 7 #include <string>
8 8
9 #import <EarlGrey/EarlGrey.h> 9 #import <EarlGrey/EarlGrey.h>
10 #import <XCTest/XCTest.h> 10 #import <XCTest/XCTest.h>
(...skipping 11 matching lines...) Expand all
22 #include "url/gurl.h" 22 #include "url/gurl.h"
23 23
24 namespace { 24 namespace {
25 25
26 const char kTestUrlNormalBrowsing[] = "http://choux/normal/browsing"; 26 const char kTestUrlNormalBrowsing[] = "http://choux/normal/browsing";
27 const char kTestUrlNormalSetCookie[] = "http://choux/normal/set_cookie"; 27 const char kTestUrlNormalSetCookie[] = "http://choux/normal/set_cookie";
28 const char kTestUrlIncognitoBrowsing[] = "http://choux/incognito/browsing"; 28 const char kTestUrlIncognitoBrowsing[] = "http://choux/incognito/browsing";
29 const char kTestUrlIncognitoSetCookie[] = "http://choux/incognito/set_cookie"; 29 const char kTestUrlIncognitoSetCookie[] = "http://choux/incognito/set_cookie";
30 30
31 const char kTestResponse[] = "fleur"; 31 const char kTestResponse[] = "fleur";
32 NSString* const kNoCookieText = @"No cookies!";
33 NSString* const kNormalCookieKey = @"request"; 32 NSString* const kNormalCookieKey = @"request";
34 NSString* const kNormalCookieValue = @"pony"; 33 NSString* const kNormalCookieValue = @"pony";
35 NSString* const kIncognitoCookieKey = @"secret"; 34 NSString* const kIncognitoCookieKey = @"secret";
36 NSString* const kIncognitoCookieValue = @"rainbow"; 35 NSString* const kIncognitoCookieValue = @"rainbow";
37 36
38 NSString* const kGetCookieScript =
39 @"var c = document.cookie ? document.cookie.split(/;\\s*/) : [];"
40 "if (!c.length) {"
41 " document.documentElement.innerHTML = 'No cookies!';"
42 "} else {"
43 " document.documentElement.innerHTML = 'OK: ' + c.join(',');"
44 "}";
45
46 // Checks that a cookie of key=value is the only cookie exists in current domain
47 // in current web state.
48 // Returns true if cookie |key| of value |value| is the only cookie that exists.
49 bool CheckCookieExists(NSString* key, NSString* value) {
50 NSError* error = nil;
51 id result = chrome_test_util::ExecuteJavaScript(kGetCookieScript, &error);
52 if (error)
53 return false;
54 NSString* stringResult = base::mac::ObjCCastStrict<NSString>(result);
55 NSString* expectedText = [NSString stringWithFormat:@"OK: %@=%@", key, value];
56 return [stringResult isEqualToString:expectedText];
57 }
58
59 // Checks that there is no cookie in current domain in current web state.
60 bool CheckNoCookieExists() {
61 NSError* error = nil;
62 id result = chrome_test_util::ExecuteJavaScript(kGetCookieScript, &error);
63 if (error)
64 return false;
65 NSString* stringResult = base::mac::ObjCCastStrict<NSString>(result);
66 return [stringResult isEqualToString:kNoCookieText];
67 }
68
69 } // namespace 37 } // namespace
70 38
71 @interface CookiesTestCase : ChromeTestCase 39 @interface CookiesTestCase : ChromeTestCase
72 @end 40 @end
73 41
74 @implementation CookiesTestCase 42 @implementation CookiesTestCase
75 43
76 #pragma mark - Overrides superclass 44 #pragma mark - Overrides superclass
77 45
78 + (void)setUp { 46 + (void)setUp {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 // Tests toggling between Normal tabs and Incognito tabs. Different cookies 93 // Tests toggling between Normal tabs and Incognito tabs. Different cookies
126 // (request=pony for normal tabs, secret=rainbow for incognito tabs) are set. 94 // (request=pony for normal tabs, secret=rainbow for incognito tabs) are set.
127 // The goal is to verify that cookies set in incognito tabs are available in 95 // The goal is to verify that cookies set in incognito tabs are available in
128 // incognito tabs but not available in normal tabs. Cookies set in incognito 96 // incognito tabs but not available in normal tabs. Cookies set in incognito
129 // tabs are also deleted when all incognito tabs are closed. 97 // tabs are also deleted when all incognito tabs are closed.
130 - (void)testClearIncognitoFromMain { 98 - (void)testClearIncognitoFromMain {
131 // Loads a dummy page in normal tab. Sets a normal test cookie. Verifies that 99 // Loads a dummy page in normal tab. Sets a normal test cookie. Verifies that
132 // the incognito test cookie is not found. 100 // the incognito test cookie is not found.
133 [ChromeEarlGrey 101 [ChromeEarlGrey
134 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalSetCookie)]; 102 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalSetCookie)];
135 GREYAssertTrue(CheckCookieExists(kNormalCookieKey, kNormalCookieValue), 103 NSDictionary* cookies = [ChromeEarlGrey getCookies];
136 @"Failed to set normal cookie in normal mode. (1)"); 104 GREYAssertTrue(cookies, @"Failed to get cookies.");
137 GREYAssertFalse(CheckCookieExists(kIncognitoCookieKey, kIncognitoCookieValue), 105 GREYAssertTrue([kNormalCookieValue isEqualToString:cookies[kNormalCookieKey]],
138 @"Incognito cookie should not be found in normal mode. (1)"); 106 @"Failed to set normal cookie in normal mode.");
107 GREYAssertEqual(1U, cookies.count,
108 @"Only one cookie should be found in normal mode.");
baxley 2017/03/13 21:29:04 Do we need to check all three things for every cas
liaoyuke 2017/03/13 22:50:40 Done.
139 109
140 // Opens an incognito tab, loads the dummy page, and sets incognito test 110 // Opens an incognito tab, loads the dummy page, and sets incognito test
141 // cookie. 111 // cookie.
142 chrome_test_util::OpenNewIncognitoTab(); 112 chrome_test_util::OpenNewIncognitoTab();
143 [ChromeEarlGrey 113 [ChromeEarlGrey
144 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoSetCookie)]; 114 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoSetCookie)];
145 GREYAssertTrue(CheckCookieExists(kIncognitoCookieKey, kIncognitoCookieValue), 115 cookies = [ChromeEarlGrey getCookies];
146 @"Failed to set incognito cookie in incognito mode. (2)"); 116 GREYAssertTrue(cookies, @"Failed to get cookies.");
117 GREYAssertTrue(
118 [kIncognitoCookieValue isEqualToString:cookies[kIncognitoCookieKey]],
119 @"Failed to set incognito cookie in incognito mode.");
120 GREYAssertEqual(1U, cookies.count,
121 @"Only one cookie should be found in incognito mode.");
147 122
148 // Switches back to normal profile by opening up a new tab. Test cookie 123 // Switches back to normal profile by opening up a new tab. Test cookie
149 // should not be found. 124 // should not be found.
150 chrome_test_util::OpenNewTab(); 125 chrome_test_util::OpenNewTab();
151 [ChromeEarlGrey 126 [ChromeEarlGrey
152 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)]; 127 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)];
153 GREYAssertTrue(CheckCookieExists(kNormalCookieKey, kNormalCookieValue), 128 cookies = [ChromeEarlGrey getCookies];
154 @"Normal cookie should be found in normal mode. (3)"); 129 GREYAssertTrue(cookies, @"Failed to get cookies.");
155 GREYAssertFalse(CheckCookieExists(kIncognitoCookieKey, kIncognitoCookieValue), 130 GREYAssertTrue([kNormalCookieValue isEqualToString:cookies[kNormalCookieKey]],
156 @"Incognito cookie should not be found in normal mode. (3)"); 131 @"Normal cookie should still exist in normal mode.");
132 GREYAssertEqual(1U, cookies.count,
133 @"Only one cookie should be found in normal mode.");
157 134
158 // Finally, closes all incognito tabs while still in normal tab. 135 // Finally, closes all incognito tabs while still in normal tab.
159 // Checks that incognito cookie is gone. 136 // Checks that incognito cookie is gone.
160 chrome_test_util::CloseAllIncognitoTabs(); 137 chrome_test_util::CloseAllIncognitoTabs();
161 chrome_test_util::OpenNewTab(); 138 chrome_test_util::OpenNewTab();
162 [ChromeEarlGrey 139 [ChromeEarlGrey
163 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)]; 140 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoBrowsing)];
164 GREYAssertTrue(CheckCookieExists(kNormalCookieKey, kNormalCookieValue), 141 cookies = [ChromeEarlGrey getCookies];
165 @"Normal cookie should be found in normal mode. (4)"); 142 GREYAssertTrue(cookies, @"Failed to get cookies.");
166 GREYAssertFalse(CheckCookieExists(kIncognitoCookieKey, kIncognitoCookieValue), 143 GREYAssertEqual(0U, cookies.count,
167 @"Incognito cookie should be gone from normal mode. (4)"); 144 @"Incognito cookie should be gone from normal mode.");
168 } 145 }
169 146
170 // Tests that a cookie set in incognito tab is removed after closing all 147 // Tests that a cookie set in incognito tab is removed after closing all
171 // incognito tabs and then when new incognito tab is created the cookie will 148 // incognito tabs and then when new incognito tab is created the cookie will
172 // not reappear. 149 // not reappear.
173 - (void)testClearIncognitoFromIncognito { 150 - (void)testClearIncognitoFromIncognito {
174 // Loads a page in normal tab. 151 // Loads a page in normal tab.
175 [ChromeEarlGrey 152 [ChromeEarlGrey
176 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)]; 153 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)];
177 154
178 // Opens an incognito tab, loads a page, and sets an incognito cookie. 155 // Opens an incognito tab, loads a page, and sets an incognito cookie.
179 chrome_test_util::OpenNewIncognitoTab(); 156 chrome_test_util::OpenNewIncognitoTab();
180 [ChromeEarlGrey 157 [ChromeEarlGrey
181 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoSetCookie)]; 158 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoSetCookie)];
182 GREYAssertTrue(CheckCookieExists(kIncognitoCookieKey, kIncognitoCookieValue), 159 NSDictionary* cookies = [ChromeEarlGrey getCookies];
183 @"Failed to set incognito cookie in incognito mode. (1)"); 160 GREYAssertTrue(cookies, @"Failed to get cookies.");
161 GREYAssertTrue(
162 [kIncognitoCookieValue isEqualToString:cookies[kIncognitoCookieKey]],
163 @"Failed to set incognito cookie in incognito mode.");
164 GREYAssertEqual(1U, cookies.count,
165 @"Only one cookie should be found in incognito mode.");
184 166
185 // Closes all incognito tabs and switch back to a normal tab. 167 // Closes all incognito tabs and switch back to a normal tab.
186 chrome_test_util::CloseAllIncognitoTabs(); 168 chrome_test_util::CloseAllIncognitoTabs();
187 chrome_test_util::OpenNewTab(); 169 chrome_test_util::OpenNewTab();
188 [ChromeEarlGrey 170 [ChromeEarlGrey
189 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)]; 171 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)];
190 172
191 // Opens a new incognito tab and verify that the previously set cookie 173 // Opens a new incognito tab and verify that the previously set cookie
192 // is no longer there. 174 // is no longer there.
193 chrome_test_util::OpenNewIncognitoTab(); 175 chrome_test_util::OpenNewIncognitoTab();
194 [ChromeEarlGrey 176 [ChromeEarlGrey
195 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoBrowsing)]; 177 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoBrowsing)];
196 GREYAssertTrue(CheckNoCookieExists(), 178 cookies = [ChromeEarlGrey getCookies];
197 @"Incognito cookie should be gone from incognito mode. (2)"); 179 GREYAssertTrue(cookies, @"Failed to get cookies.");
180 GREYAssertEqual(0U, cookies.count,
181 @"Incognito cookie should be gone from incognito mode.");
198 182
199 // Verifies that new incognito cookies can be set. 183 // Verifies that new incognito cookies can be set.
200 [ChromeEarlGrey 184 [ChromeEarlGrey
201 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoSetCookie)]; 185 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoSetCookie)];
202 GREYAssertTrue(CheckCookieExists(kIncognitoCookieKey, kIncognitoCookieValue), 186 cookies = [ChromeEarlGrey getCookies];
203 @"Failed to set incognito cookie in incognito mode. (3)"); 187 GREYAssertTrue(cookies, @"Failed to get cookies.");
188 GREYAssertTrue(
189 [kIncognitoCookieValue isEqualToString:cookies[kIncognitoCookieKey]],
190 @"Failed to set incognito cookie in incognito mode.");
191 GREYAssertEqual(1U, cookies.count,
192 @"Only one cookie should be found in incognito mode.");
204 } 193 }
205 194
206 // Tests that a cookie set in normal tab is not available in an incognito tab. 195 // Tests that a cookie set in normal tab is not available in an incognito tab.
207 - (void)testSwitchToIncognito { 196 - (void)testSwitchToIncognito {
208 // Sets cookie in normal tab. 197 // Sets cookie in normal tab.
209 [ChromeEarlGrey 198 [ChromeEarlGrey
210 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalSetCookie)]; 199 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalSetCookie)];
211 GREYAssertTrue(CheckCookieExists(kNormalCookieKey, kNormalCookieValue), 200 NSDictionary* cookies = [ChromeEarlGrey getCookies];
212 @"Failed to set normal cookie in normal mode. (1)"); 201 GREYAssertTrue(cookies, @"Failed to get cookies.");
202 GREYAssertTrue([kNormalCookieValue isEqualToString:cookies[kNormalCookieKey]],
203 @"Normal cookie should still exist in normal mode.");
204 GREYAssertEqual(1U, cookies.count,
205 @"Only one cookie should be found in normal mode.");
213 206
214 // Switches to a new incognito tab and verifies that cookie is not there. 207 // Switches to a new incognito tab and verifies that cookie is not there.
215 chrome_test_util::OpenNewIncognitoTab(); 208 chrome_test_util::OpenNewIncognitoTab();
216 [ChromeEarlGrey 209 [ChromeEarlGrey
217 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoBrowsing)]; 210 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoBrowsing)];
218 GREYAssertTrue(CheckNoCookieExists(), 211 cookies = [ChromeEarlGrey getCookies];
219 @"Normal cookie should not be found in incognito mode. (2)"); 212 GREYAssertTrue(cookies, @"Failed to get cookies.");
213 GREYAssertEqual(0U, cookies.count,
214 @"Normal cookie should not be found in incognito mode.");
220 215
221 // Closes all incognito tabs and then switching back to a normal tab. Verifies 216 // Closes all incognito tabs and then switching back to a normal tab. Verifies
222 // that the cookie set earlier is still there. 217 // that the cookie set earlier is still there.
223 chrome_test_util::CloseAllIncognitoTabs(); 218 chrome_test_util::CloseAllIncognitoTabs();
224 chrome_test_util::OpenNewTab(); 219 chrome_test_util::OpenNewTab();
225 [ChromeEarlGrey 220 [ChromeEarlGrey
226 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)]; 221 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)];
227 GREYAssertTrue(CheckCookieExists(kNormalCookieKey, kNormalCookieValue), 222 cookies = [ChromeEarlGrey getCookies];
228 @"Normal cookie should still be found in normal mode. (3)"); 223 GREYAssertTrue(cookies, @"Failed to get cookies.");
224 GREYAssertTrue([kNormalCookieValue isEqualToString:cookies[kNormalCookieKey]],
225 @"Normal cookie should still be found in normal mode.");
226 GREYAssertEqual(1U, cookies.count,
227 @"Only one cookie should be found in normal mode.");
229 } 228 }
230 229
231 // Tests that a cookie set in incognito tab is only available in another 230 // Tests that a cookie set in incognito tab is only available in another
232 // incognito tab. They are not available in a normal tab. 231 // incognito tab. They are not available in a normal tab.
233 - (void)testSwitchToMain { 232 - (void)testSwitchToMain {
234 // Loads a page in normal tab and then switches to a new incognito tab. Sets 233 // Loads a page in normal tab and then switches to a new incognito tab. Sets
235 // cookie in incognito tab. 234 // cookie in incognito tab.
236 [ChromeEarlGrey 235 [ChromeEarlGrey
237 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)]; 236 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)];
238 chrome_test_util::OpenNewIncognitoTab(); 237 chrome_test_util::OpenNewIncognitoTab();
239 [ChromeEarlGrey 238 [ChromeEarlGrey
240 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoSetCookie)]; 239 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoSetCookie)];
241 GREYAssertTrue(CheckCookieExists(kIncognitoCookieKey, kIncognitoCookieValue), 240 NSDictionary* cookies = [ChromeEarlGrey getCookies];
242 @"Failed to set incognito cookie in incognito mode. (1)"); 241 GREYAssertTrue(cookies, @"Failed to get cookies.");
242 GREYAssertTrue(
243 [kIncognitoCookieValue isEqualToString:cookies[kIncognitoCookieKey]],
244 @"Failed to set incognito cookie in incognito mode.");
245 GREYAssertEqual(1U, cookies.count,
246 @"Only one cookie should be found in incognito mode.");
247
243 // Switches back to a normal tab and verifies that cookie set in incognito tab 248 // Switches back to a normal tab and verifies that cookie set in incognito tab
244 // is not available. 249 // is not available.
245 chrome_test_util::OpenNewTab(); 250 chrome_test_util::OpenNewTab();
246 [ChromeEarlGrey 251 [ChromeEarlGrey
247 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)]; 252 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)];
248 GREYAssertTrue(CheckNoCookieExists(), 253 cookies = [ChromeEarlGrey getCookies];
249 @"Incognito cookie should not be found in normal mode. (2)"); 254 GREYAssertTrue(cookies, @"Failed to get cookies.");
255 GREYAssertEqual(0U, cookies.count,
256 @"Incognito cookie should not be found in normal mode.");
257
250 // Returns back to Incognito tab and cookie is still there. 258 // Returns back to Incognito tab and cookie is still there.
251 chrome_test_util::OpenNewIncognitoTab(); 259 chrome_test_util::OpenNewIncognitoTab();
252 [ChromeEarlGrey 260 [ChromeEarlGrey
253 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoBrowsing)]; 261 loadURL:web::test::HttpServer::MakeUrl(kTestUrlIncognitoBrowsing)];
254 GREYAssertTrue(CheckCookieExists(kIncognitoCookieKey, kIncognitoCookieValue), 262 cookies = [ChromeEarlGrey getCookies];
255 @"Incognito cookie should be found in incognito mode. (3)"); 263 GREYAssertTrue(cookies, @"Failed to get cookies.");
264 GREYAssertTrue(
265 [kIncognitoCookieValue isEqualToString:cookies[kIncognitoCookieKey]],
266 @"Incognito cookie should be found in incognito mode.");
267 GREYAssertEqual(1U, cookies.count,
268 @"Only one cookie should be found in incognito mode.");
256 } 269 }
257 270
258 // Tests that a cookie set in a normal tab can be found in another normal tab. 271 // Tests that a cookie set in a normal tab can be found in another normal tab.
259 - (void)testShareCookiesBetweenTabs { 272 - (void)testShareCookiesBetweenTabs {
260 // Loads page and sets cookie in first normal tab. 273 // Loads page and sets cookie in first normal tab.
261 [ChromeEarlGrey 274 [ChromeEarlGrey
262 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalSetCookie)]; 275 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalSetCookie)];
263 GREYAssertTrue(CheckCookieExists(kNormalCookieKey, kNormalCookieValue), 276 NSDictionary* cookies = [ChromeEarlGrey getCookies];
264 @"Failed to set normal cookie in normal mode. (1)"); 277 GREYAssertTrue(cookies, @"Failed to get cookies.");
278 GREYAssertTrue([kNormalCookieValue isEqualToString:cookies[kNormalCookieKey]],
279 @"Failed to set normal cookie in normal mode.");
280 GREYAssertEqual(1U, cookies.count,
281 @"Only one cookie should be found in normal mode.");
265 282
266 // Creates another normal tab and verifies that the cookie is also there. 283 // Creates another normal tab and verifies that the cookie is also there.
267 chrome_test_util::OpenNewTab(); 284 chrome_test_util::OpenNewTab();
268 [ChromeEarlGrey 285 [ChromeEarlGrey
269 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)]; 286 loadURL:web::test::HttpServer::MakeUrl(kTestUrlNormalBrowsing)];
270 GREYAssertTrue(CheckCookieExists(kNormalCookieKey, kNormalCookieValue), 287 cookies = [ChromeEarlGrey getCookies];
271 @"Normal cookie should still be found in normal mode. (2)"); 288 GREYAssertTrue(cookies, @"Failed to get cookies.");
289 GREYAssertTrue([kNormalCookieValue isEqualToString:cookies[kNormalCookieKey]],
290 @"Normal cookie should still be found in normal mode.");
291 GREYAssertEqual(1U, cookies.count,
292 @"Only one cookie should be found in normal mode.");
272 } 293 }
273 294
274 @end 295 @end
OLDNEW
« no previous file with comments | « no previous file | ios/chrome/browser/ui/settings/settings_egtest.mm » ('j') | ios/chrome/browser/ui/settings/settings_egtest.mm » ('J')

Powered by Google App Engine
This is Rietveld 408576698