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

Side by Side Diff: chrome/browser/extensions/api/networking_private/networking_private_apitest.cc

Issue 275543005: Use GUID instead of ServicePath in networkingPrivate API (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 6 years, 7 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 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 "base/bind.h" 5 #include "base/bind.h"
6 #include "base/callback.h" 6 #include "base/callback.h"
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/macros.h" 8 #include "base/macros.h"
9 #include "chrome/browser/browser_process.h" 9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/chromeos/login/user.h" 10 #include "chrome/browser/chromeos/login/user.h"
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 } 128 }
129 }; 129 };
130 #endif // defined(OS_CHROMEOS) 130 #endif // defined(OS_CHROMEOS)
131 131
132 class ExtensionNetworkingPrivateApiTest 132 class ExtensionNetworkingPrivateApiTest
133 : public ExtensionApiTest, 133 : public ExtensionApiTest,
134 public testing::WithParamInterface<bool> { 134 public testing::WithParamInterface<bool> {
135 public: 135 public:
136 ExtensionNetworkingPrivateApiTest() 136 ExtensionNetworkingPrivateApiTest()
137 #if defined(OS_CHROMEOS) 137 #if defined(OS_CHROMEOS)
138 : detector_(NULL) 138 : detector_(NULL),
139 service_test_(NULL)
139 #endif 140 #endif
140 { 141 {
141 } 142 }
142 143
143 bool RunNetworkingSubtest(const std::string& subtest) { 144 bool RunNetworkingSubtest(const std::string& subtest) {
144 return RunExtensionSubtest( 145 return RunExtensionSubtest(
145 "networking", "main.html?" + subtest, 146 "networking", "main.html?" + subtest,
146 kFlagEnableFileAccess | kFlagLoadAsComponent); 147 kFlagEnableFileAccess | kFlagLoadAsComponent);
147 } 148 }
148 149
149 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 150 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
150 #if defined(OS_CHROMEOS) 151 #if defined(OS_CHROMEOS)
151 EXPECT_CALL(provider_, IsInitializationComplete(_)) 152 EXPECT_CALL(provider_, IsInitializationComplete(_))
152 .WillRepeatedly(Return(true)); 153 .WillRepeatedly(Return(true));
153 policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_); 154 policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
154 #endif 155 #endif
155 156
156 ExtensionApiTest::SetUpInProcessBrowserTestFixture(); 157 ExtensionApiTest::SetUpInProcessBrowserTestFixture();
157 } 158 }
158 159
159 #if defined(OS_CHROMEOS) 160 #if defined(OS_CHROMEOS)
160 static void AssignString(std::string* out, 161 static void AssignString(std::string* out,
161 DBusMethodCallStatus call_status, 162 DBusMethodCallStatus call_status,
162 const std::string& result) { 163 const std::string& result) {
163 CHECK_EQ(call_status, DBUS_METHOD_CALL_SUCCESS); 164 CHECK_EQ(call_status, DBUS_METHOD_CALL_SUCCESS);
164 *out = result; 165 *out = result;
165 } 166 }
166 167
167 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 168 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
168 ExtensionApiTest::SetUpCommandLine(command_line); 169 ExtensionApiTest::SetUpCommandLine(command_line);
169 // Whitelist the extension ID of the test extension. 170 // Whitelist the extension ID of the test extension.
170 command_line->AppendSwitchASCII( 171 command_line->AppendSwitchASCII(
171 extensions::switches::kWhitelistedExtensionID, 172 extensions::switches::kWhitelistedExtensionID,
172 "epcifkihnkjgphfkloaaleeakhpmgdmn"); 173 "epcifkihnkjgphfkloaaleeakhpmgdmn");
(...skipping 15 matching lines...) Expand all
188 chromeos::User* user = user_manager->GetActiveUser(); 189 chromeos::User* user = user_manager->GetActiveUser();
189 CHECK(user); 190 CHECK(user);
190 std::string userhash; 191 std::string userhash;
191 DBusThreadManager::Get()->GetCryptohomeClient()->GetSanitizedUsername( 192 DBusThreadManager::Get()->GetCryptohomeClient()->GetSanitizedUsername(
192 user->email(), 193 user->email(),
193 base::Bind(&AssignString, &userhash_)); 194 base::Bind(&AssignString, &userhash_));
194 content::RunAllPendingInMessageLoop(); 195 content::RunAllPendingInMessageLoop();
195 CHECK(!userhash_.empty()); 196 CHECK(!userhash_.empty());
196 } 197 }
197 198
199 void AddService(const std::string& service_path,
200 const std::string& name,
201 const std::string& type,
202 const std::string& state) {
203 const bool add_to_watchlist = true;
204 const bool add_to_visible = true;
205 // Tests need a known GUID, so use 'service_path'.
206 service_test_->AddServiceWithIPConfig(
207 service_path, service_path /* guid */, name,
208 type, state, "" /* ipconfig_path */,
209 add_to_visible, add_to_watchlist);
210 }
211
198 virtual void SetUpOnMainThread() OVERRIDE { 212 virtual void SetUpOnMainThread() OVERRIDE {
199 detector_ = new NetworkPortalDetectorTestImpl(); 213 detector_ = new NetworkPortalDetectorTestImpl();
200 NetworkPortalDetector::InitializeForTesting(detector_); 214 NetworkPortalDetector::InitializeForTesting(detector_);
201 215
202 ExtensionApiTest::SetUpOnMainThread(); 216 ExtensionApiTest::SetUpOnMainThread();
203 content::RunAllPendingInMessageLoop(); 217 content::RunAllPendingInMessageLoop();
204 218
205 InitializeSanitizedUsername(); 219 InitializeSanitizedUsername();
206 220
207 DBusThreadManager* dbus_manager = DBusThreadManager::Get(); 221 DBusThreadManager* dbus_manager = DBusThreadManager::Get();
208 ShillManagerClient::TestInterface* manager_test = 222 ShillManagerClient::TestInterface* manager_test =
209 dbus_manager->GetShillManagerClient()->GetTestInterface(); 223 dbus_manager->GetShillManagerClient()->GetTestInterface();
210 ShillIPConfigClient::TestInterface* ip_config_test = 224 ShillIPConfigClient::TestInterface* ip_config_test =
211 dbus_manager->GetShillIPConfigClient()->GetTestInterface(); 225 dbus_manager->GetShillIPConfigClient()->GetTestInterface();
212 ShillDeviceClient::TestInterface* device_test = 226 ShillDeviceClient::TestInterface* device_test =
213 dbus_manager->GetShillDeviceClient()->GetTestInterface(); 227 dbus_manager->GetShillDeviceClient()->GetTestInterface();
214 ShillProfileClient::TestInterface* profile_test = 228 ShillProfileClient::TestInterface* profile_test =
215 dbus_manager->GetShillProfileClient()->GetTestInterface(); 229 dbus_manager->GetShillProfileClient()->GetTestInterface();
216 ShillServiceClient::TestInterface* service_test = 230
217 dbus_manager->GetShillServiceClient()->GetTestInterface(); 231 service_test_ = dbus_manager->GetShillServiceClient()->GetTestInterface();
218 232
219 device_test->ClearDevices(); 233 device_test->ClearDevices();
220 service_test->ClearServices(); 234 service_test_->ClearServices();
221 235
222 // Sends a notification about the added profile. 236 // Sends a notification about the added profile.
223 profile_test->AddProfile(kUser1ProfilePath, userhash_); 237 profile_test->AddProfile(kUser1ProfilePath, userhash_);
224 238
225 // Add IPConfigs 239 // Add IPConfigs
226 base::DictionaryValue ipconfig; 240 base::DictionaryValue ipconfig;
227 ipconfig.SetStringWithoutPathExpansion(shill::kAddressProperty, "0.0.0.0"); 241 ipconfig.SetStringWithoutPathExpansion(shill::kAddressProperty, "0.0.0.0");
228 ipconfig.SetStringWithoutPathExpansion(shill::kGatewayProperty, "0.0.0.1"); 242 ipconfig.SetStringWithoutPathExpansion(shill::kGatewayProperty, "0.0.0.1");
229 ipconfig.SetIntegerWithoutPathExpansion(shill::kPrefixlenProperty, 0); 243 ipconfig.SetIntegerWithoutPathExpansion(shill::kPrefixlenProperty, 0);
230 ipconfig.SetStringWithoutPathExpansion( 244 ipconfig.SetStringWithoutPathExpansion(
231 shill::kMethodProperty, shill::kTypeIPv4); 245 shill::kMethodProperty, shill::kTypeIPv4);
232 ip_config_test->AddIPConfig(kIPConfigPath, ipconfig); 246 ip_config_test->AddIPConfig(kIPConfigPath, ipconfig);
233 247
234 // Add Devices 248 // Add Devices
235 device_test->AddDevice( 249 device_test->AddDevice(
236 kWifiDevicePath, shill::kTypeWifi, "stub_wifi_device1"); 250 kWifiDevicePath, shill::kTypeWifi, "stub_wifi_device1");
237 base::ListValue wifi_ip_configs; 251 base::ListValue wifi_ip_configs;
238 wifi_ip_configs.AppendString(kIPConfigPath); 252 wifi_ip_configs.AppendString(kIPConfigPath);
239 device_test->SetDeviceProperty( 253 device_test->SetDeviceProperty(
240 kWifiDevicePath, shill::kIPConfigsProperty, wifi_ip_configs); 254 kWifiDevicePath, shill::kIPConfigsProperty, wifi_ip_configs);
241 device_test->AddDevice( 255 device_test->AddDevice(
242 kCellularDevicePath, shill::kTypeCellular, "stub_cellular_device1"); 256 kCellularDevicePath, shill::kTypeCellular, "stub_cellular_device1");
243 257
244 // Add Services 258 // Add Services
245 const bool add_to_watchlist = true; 259 AddService("stub_ethernet", "eth0",
246 const bool add_to_visible = true; 260 shill::kTypeEthernet, shill::kStateOnline);
247 service_test->AddService("stub_ethernet", "eth0", 261 service_test_->SetServiceProperty(
248 shill::kTypeEthernet, shill::kStateOnline,
249 add_to_visible, add_to_watchlist);
250 service_test->SetServiceProperty(
251 "stub_ethernet", 262 "stub_ethernet",
252 shill::kProfileProperty, 263 shill::kProfileProperty,
253 base::StringValue(ShillProfileClient::GetSharedProfilePath())); 264 base::StringValue(ShillProfileClient::GetSharedProfilePath()));
254 profile_test->AddService(ShillProfileClient::GetSharedProfilePath(), 265 profile_test->AddService(ShillProfileClient::GetSharedProfilePath(),
255 "stub_ethernet"); 266 "stub_ethernet");
256 267
257 service_test->AddService("stub_wifi1", "wifi1", 268 AddService("stub_wifi1", "wifi1", shill::kTypeWifi, shill::kStateOnline);
258 shill::kTypeWifi, shill::kStateOnline, 269 service_test_->SetServiceProperty("stub_wifi1",
259 add_to_visible, add_to_watchlist); 270 shill::kSecurityProperty,
260 service_test->SetServiceProperty("stub_wifi1", 271 base::StringValue(shill::kSecurityWep));
261 shill::kSecurityProperty, 272 service_test_->SetServiceProperty("stub_wifi1",
262 base::StringValue(shill::kSecurityWep)); 273 shill::kProfileProperty,
263 service_test->SetServiceProperty("stub_wifi1", 274 base::StringValue(kUser1ProfilePath));
264 shill::kProfileProperty, 275 service_test_->SetServiceProperty("stub_wifi1",
265 base::StringValue(kUser1ProfilePath)); 276 shill::kConnectableProperty,
266 service_test->SetServiceProperty("stub_wifi1", 277 base::FundamentalValue(true));
267 shill::kConnectableProperty, 278 service_test_->SetServiceProperty("stub_wifi1",
268 base::FundamentalValue(true)); 279 shill::kDeviceProperty,
269 service_test->SetServiceProperty("stub_wifi1", 280 base::StringValue(kWifiDevicePath));
270 shill::kDeviceProperty,
271 base::StringValue(kWifiDevicePath));
272 profile_test->AddService(kUser1ProfilePath, "stub_wifi1"); 281 profile_test->AddService(kUser1ProfilePath, "stub_wifi1");
273 base::ListValue frequencies1; 282 base::ListValue frequencies1;
274 frequencies1.AppendInteger(2400); 283 frequencies1.AppendInteger(2400);
275 service_test->SetServiceProperty("stub_wifi1", 284 service_test_->SetServiceProperty("stub_wifi1",
276 shill::kWifiFrequencyListProperty, 285 shill::kWifiFrequencyListProperty,
277 frequencies1); 286 frequencies1);
278 service_test->SetServiceProperty("stub_wifi1", 287 service_test_->SetServiceProperty("stub_wifi1",
279 shill::kWifiFrequency, 288 shill::kWifiFrequency,
280 base::FundamentalValue(2400)); 289 base::FundamentalValue(2400));
281 290
282 service_test->AddService("stub_wifi2", "wifi2_PSK", 291 AddService("stub_wifi2", "wifi2_PSK", shill::kTypeWifi, shill::kStateIdle);
283 shill::kTypeWifi, shill::kStateIdle, 292 service_test_->SetServiceProperty("stub_wifi2",
284 add_to_visible, add_to_watchlist); 293 shill::kGuidProperty,
285 service_test->SetServiceProperty("stub_wifi2", 294 base::StringValue("stub_wifi2"));
286 shill::kGuidProperty, 295 service_test_->SetServiceProperty("stub_wifi2",
287 base::StringValue("stub_wifi2")); 296 shill::kSecurityProperty,
288 service_test->SetServiceProperty("stub_wifi2", 297 base::StringValue(shill::kSecurityPsk));
289 shill::kSecurityProperty, 298 service_test_->SetServiceProperty("stub_wifi2",
290 base::StringValue(shill::kSecurityPsk)); 299 shill::kSignalStrengthProperty,
291 service_test->SetServiceProperty("stub_wifi2", 300 base::FundamentalValue(80));
292 shill::kSignalStrengthProperty, 301 service_test_->SetServiceProperty("stub_wifi2",
293 base::FundamentalValue(80)); 302 shill::kConnectableProperty,
294 service_test->SetServiceProperty("stub_wifi2", 303 base::FundamentalValue(true));
295 shill::kConnectableProperty,
296 base::FundamentalValue(true));
297 304
298 base::ListValue frequencies2; 305 base::ListValue frequencies2;
299 frequencies2.AppendInteger(2400); 306 frequencies2.AppendInteger(2400);
300 frequencies2.AppendInteger(5000); 307 frequencies2.AppendInteger(5000);
301 service_test->SetServiceProperty("stub_wifi2", 308 service_test_->SetServiceProperty("stub_wifi2",
302 shill::kWifiFrequencyListProperty, 309 shill::kWifiFrequencyListProperty,
303 frequencies2); 310 frequencies2);
304 service_test->SetServiceProperty("stub_wifi2", 311 service_test_->SetServiceProperty("stub_wifi2",
305 shill::kWifiFrequency, 312 shill::kWifiFrequency,
306 base::FundamentalValue(5000)); 313 base::FundamentalValue(5000));
307 service_test->SetServiceProperty("stub_wifi2", 314 service_test_->SetServiceProperty("stub_wifi2",
308 shill::kProfileProperty, 315 shill::kProfileProperty,
309 base::StringValue(kUser1ProfilePath)); 316 base::StringValue(kUser1ProfilePath));
310 profile_test->AddService(kUser1ProfilePath, "stub_wifi2"); 317 profile_test->AddService(kUser1ProfilePath, "stub_wifi2");
311 318
312 service_test->AddService("stub_cellular1", "cellular1", 319 AddService("stub_cellular1", "cellular1",
313 shill::kTypeCellular, shill::kStateIdle, 320 shill::kTypeCellular, shill::kStateIdle);
314 add_to_visible, add_to_watchlist); 321 service_test_->SetServiceProperty(
315 service_test->SetServiceProperty(
316 "stub_cellular1", 322 "stub_cellular1",
317 shill::kNetworkTechnologyProperty, 323 shill::kNetworkTechnologyProperty,
318 base::StringValue(shill::kNetworkTechnologyGsm)); 324 base::StringValue(shill::kNetworkTechnologyGsm));
319 service_test->SetServiceProperty( 325 service_test_->SetServiceProperty(
320 "stub_cellular1", 326 "stub_cellular1",
321 shill::kActivationStateProperty, 327 shill::kActivationStateProperty,
322 base::StringValue(shill::kActivationStateNotActivated)); 328 base::StringValue(shill::kActivationStateNotActivated));
323 service_test->SetServiceProperty( 329 service_test_->SetServiceProperty(
324 "stub_cellular1", 330 "stub_cellular1",
325 shill::kRoamingStateProperty, 331 shill::kRoamingStateProperty,
326 base::StringValue(shill::kRoamingStateHome)); 332 base::StringValue(shill::kRoamingStateHome));
327 333
328 service_test->AddService("stub_vpn1", "vpn1", 334 AddService("stub_vpn1", "vpn1", shill::kTypeVPN, shill::kStateOnline);
329 shill::kTypeVPN,
330 shill::kStateOnline,
331 add_to_visible, add_to_watchlist);
332 335
333 manager_test->SortManagerServices(); 336 manager_test->SortManagerServices();
334 337
335 content::RunAllPendingInMessageLoop(); 338 content::RunAllPendingInMessageLoop();
336 } 339 }
337 #else // !defined(OS_CHROMEOS) 340 #else // !defined(OS_CHROMEOS)
338 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 341 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
339 ExtensionApiTest::SetUpCommandLine(command_line); 342 ExtensionApiTest::SetUpCommandLine(command_line);
340 // Whitelist the extension ID of the test extension. 343 // Whitelist the extension ID of the test extension.
341 command_line->AppendSwitchASCII( 344 command_line->AppendSwitchASCII(
(...skipping 15 matching lines...) Expand all
357 &CreateNetworkingPrivateServiceClient); 360 &CreateNetworkingPrivateServiceClient);
358 } 361 }
359 362
360 #endif // OS_CHROMEOS 363 #endif // OS_CHROMEOS
361 364
362 protected: 365 protected:
363 #if defined(OS_CHROMEOS) 366 #if defined(OS_CHROMEOS)
364 NetworkPortalDetectorTestImpl* detector() { return detector_; } 367 NetworkPortalDetectorTestImpl* detector() { return detector_; }
365 368
366 NetworkPortalDetectorTestImpl* detector_; 369 NetworkPortalDetectorTestImpl* detector_;
370 ShillServiceClient::TestInterface* service_test_;
367 policy::MockConfigurationPolicyProvider provider_; 371 policy::MockConfigurationPolicyProvider provider_;
368 std::string userhash_; 372 std::string userhash_;
369 #endif 373 #endif
370 }; 374 };
371 375
372 // Place each subtest into a separate browser test so that the stub networking 376 // Place each subtest into a separate browser test so that the stub networking
373 // library state is reset for each subtest run. This way they won't affect each 377 // library state is reset for each subtest run. This way they won't affect each
374 // other. 378 // other.
375 379
376 IN_PROC_BROWSER_TEST_P(ExtensionNetworkingPrivateApiTest, StartConnect) { 380 IN_PROC_BROWSER_TEST_P(ExtensionNetworkingPrivateApiTest, StartConnect) {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 } 433 }
430 434
431 IN_PROC_BROWSER_TEST_P(ExtensionNetworkingPrivateApiTest, CreateNetwork) { 435 IN_PROC_BROWSER_TEST_P(ExtensionNetworkingPrivateApiTest, CreateNetwork) {
432 EXPECT_TRUE(RunNetworkingSubtest("createNetwork")) << message_; 436 EXPECT_TRUE(RunNetworkingSubtest("createNetwork")) << message_;
433 } 437 }
434 438
435 IN_PROC_BROWSER_TEST_P(ExtensionNetworkingPrivateApiTest, 439 IN_PROC_BROWSER_TEST_P(ExtensionNetworkingPrivateApiTest,
436 GetManagedProperties) { 440 GetManagedProperties) {
437 #if defined(OS_CHROMEOS) 441 #if defined(OS_CHROMEOS)
438 // TODO(mef): Move this to ChromeOS-specific helper or SetUpOnMainThread. 442 // TODO(mef): Move this to ChromeOS-specific helper or SetUpOnMainThread.
439 ShillServiceClient::TestInterface* service_test =
440 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
441 const std::string uidata_blob = 443 const std::string uidata_blob =
442 "{ \"user_settings\": {" 444 "{ \"user_settings\": {"
443 " \"WiFi\": {" 445 " \"WiFi\": {"
444 " \"Passphrase\": \"FAKE_CREDENTIAL_VPaJDV9x\" }" 446 " \"Passphrase\": \"FAKE_CREDENTIAL_VPaJDV9x\" }"
445 " }" 447 " }"
446 "}"; 448 "}";
447 service_test->SetServiceProperty("stub_wifi2", 449 service_test_->SetServiceProperty("stub_wifi2",
448 shill::kUIDataProperty, 450 shill::kUIDataProperty,
449 base::StringValue(uidata_blob)); 451 base::StringValue(uidata_blob));
450 service_test->SetServiceProperty("stub_wifi2", 452 service_test_->SetServiceProperty("stub_wifi2",
451 shill::kAutoConnectProperty, 453 shill::kAutoConnectProperty,
452 base::FundamentalValue(false)); 454 base::FundamentalValue(false));
453 455
454 ShillProfileClient::TestInterface* profile_test = 456 ShillProfileClient::TestInterface* profile_test =
455 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface(); 457 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
456 // Update the profile entry. 458 // Update the profile entry.
457 profile_test->AddService(kUser1ProfilePath, "stub_wifi2"); 459 profile_test->AddService(kUser1ProfilePath, "stub_wifi2");
458 460
459 content::RunAllPendingInMessageLoop(); 461 content::RunAllPendingInMessageLoop();
460 462
461 const std::string user_policy_blob = 463 const std::string user_policy_blob =
462 "{ \"NetworkConfigurations\": [" 464 "{ \"NetworkConfigurations\": ["
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 base::Unretained(detector()))); 569 base::Unretained(detector())));
568 EXPECT_TRUE(RunNetworkingSubtest("captivePortalNotification")) << message_; 570 EXPECT_TRUE(RunNetworkingSubtest("captivePortalNotification")) << message_;
569 } 571 }
570 #endif // defined(OS_CHROMEOS) 572 #endif // defined(OS_CHROMEOS)
571 573
572 INSTANTIATE_TEST_CASE_P(ExtensionNetworkingPrivateApiTestInstantiation, 574 INSTANTIATE_TEST_CASE_P(ExtensionNetworkingPrivateApiTestInstantiation,
573 ExtensionNetworkingPrivateApiTest, 575 ExtensionNetworkingPrivateApiTest,
574 testing::Bool()); 576 testing::Bool());
575 577
576 } // namespace 578 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698