1 // Copyright (c) 2013 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 <map> 6 #include <string> 7 8 #include "base/basictypes.h" 9 #include "base/bind.h" 10 #include "base/callback.h" 11 #include "base/command_line.h" 12 #include "base/file_util.h" 13 #include "base/files/file_path.h" 14 #include "base/json/json_reader.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/message_loop/message_loop.h" 17 #include "base/path_service.h" 18 #include "base/run_loop.h" 19 #include "base/strings/string_util.h" 20 #include "base/strings/utf_string_conversions.h" 21 #include "base/values.h" 22 #include "chrome/browser/browser_process.h" 23 #include "chrome/browser/chrome_notification_types.h" 24 #include "chrome/browser/chromeos/login/existing_user_controller.h" 25 #include "chrome/browser/chromeos/login/login_display_host.h" 26 #include "chrome/browser/chromeos/login/login_display_host_impl.h" 27 #include "chrome/browser/chromeos/login/mock_login_status_consumer.h" 28 #include "chrome/browser/chromeos/login/screens/wizard_screen.h" 29 #include "chrome/browser/chromeos/login/user.h" 30 #include "chrome/browser/chromeos/login/user_manager.h" 31 #include "chrome/browser/chromeos/login/webui_login_view.h" 32 #include "chrome/browser/chromeos/login/wizard_controller.h" 33 #include "chrome/browser/chromeos/policy/device_local_account.h" 34 #include "chrome/browser/chromeos/policy/device_policy_builder.h" 35 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" 36 #include "chrome/browser/lifetime/application_lifetime.h" 37 #include "chrome/browser/policy/cloud/cloud_policy_constants.h" 38 #include "chrome/browser/policy/cloud/policy_builder.h" 39 #include "chrome/browser/policy/policy_service.h" 40 #include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h" 41 #include "chrome/browser/policy/test/local_policy_test_server.h" 42 #include "chrome/browser/prefs/session_startup_pref.h" 43 #include "chrome/browser/ui/browser.h" 44 #include "chrome/browser/ui/browser_finder.h" 45 #include "chrome/browser/ui/browser_list.h" 46 #include "chrome/browser/ui/host_desktop.h" 47 #include "chrome/browser/ui/tabs/tab_strip_model.h" 48 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" 49 #include "chrome/common/chrome_paths.h" 50 #include "chrome/common/chrome_switches.h" 51 #include "chromeos/chromeos_switches.h" 52 #include "chromeos/dbus/cryptohome_client.h" 53 #include "chromeos/dbus/dbus_method_call_status.h" 54 #include "chromeos/dbus/fake_cryptohome_client.h" 55 #include "chromeos/dbus/fake_session_manager_client.h" 56 #include "chromeos/dbus/session_manager_client.h" 57 #include "content/public/browser/web_contents.h" 58 #include "content/public/browser/web_ui.h" 59 #include "content/public/test/browser_test_utils.h" 60 #include "content/public/test/test_utils.h" 61 #include "crypto/rsa_private_key.h" 62 #include "grit/chromium_strings.h" 63 #include "grit/generated_resources.h" 64 #include "net/test/embedded_test_server/embedded_test_server.h" 65 #include "testing/gmock/include/gmock/gmock.h" 66 #include "third_party/cros_system_api/dbus/service_constants.h" 67 #include "ui/base/l10n/l10n_util.h" 68 #include "url/gurl.h" 69 70 namespace em = enterprise_management; 71 72 using testing::InvokeWithoutArgs; 73 using testing::Return; 74 using testing::_; 75 76 namespace policy { 77 78 namespace { 79 80 const char kDomain[] = "example.com"; 81 const char kAccountId1[] = "dla1 (at) example.com"; 82 const char kAccountId2[] = "dla2 (at) example.com"; 83 const char kDisplayName[] = "display name"; 84 const char* kStartupURLs[] = { 85 "chrome://policy", 86 "chrome://about", 87 }; 88 const char kExistentTermsOfServicePath[] = "chromeos/enterprise/tos.txt"; 89 const char kNonexistentTermsOfServicePath[] = "chromeos/enterprise/tos404.txt"; 90 91 } // namespace 92 93 class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest { 94 protected: 95 DeviceLocalAccountTest() 96 : user_id_1_(GenerateDeviceLocalAccountUserId( 97 kAccountId1, DeviceLocalAccount::TYPE_PUBLIC_SESSION)), 98 user_id_2_(GenerateDeviceLocalAccountUserId( 99 kAccountId2, DeviceLocalAccount::TYPE_PUBLIC_SESSION)) {} 100 101 virtual ~DeviceLocalAccountTest() {} 102 103 virtual void SetUp() OVERRIDE { 104 // Configure and start the test server. 105 scoped_ptr<crypto::RSAPrivateKey> signing_key( 106 PolicyBuilder::CreateTestSigningKey()); 107 ASSERT_TRUE(test_server_.SetSigningKey(signing_key.get())); 108 signing_key.reset(); 109 test_server_.RegisterClient(PolicyBuilder::kFakeToken, 110 PolicyBuilder::kFakeDeviceId); 111 ASSERT_TRUE(test_server_.Start()); 112 113 DevicePolicyCrosBrowserTest::SetUp(); 114 } 115 116 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 117 command_line->AppendSwitch(chromeos::switches::kLoginManager); 118 command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests); 119 command_line->AppendSwitchASCII( 120 switches::kDeviceManagementUrl, test_server_.GetServiceURL().spec()); 121 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user"); 122 } 123 124 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 125 DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture(); 126 127 // Clear command-line arguments (but keep command-line switches) so the 128 // startup pages policy takes effect. 129 CommandLine* command_line = CommandLine::ForCurrentProcess(); 130 CommandLine::StringVector argv(command_line->argv()); 131 argv.erase(argv.begin() + argv.size() - command_line->GetArgs().size(), 132 argv.end()); 133 command_line->InitFromArgv(argv); 134 135 InstallOwnerKey(); 136 MarkAsEnterpriseOwned(); 137 138 InitializePolicy(); 139 } 140 141 virtual void CleanUpOnMainThread() OVERRIDE { 142 // This shuts down the login UI. 143 base::MessageLoop::current()->PostTask(FROM_HERE, 144 base::Bind(&chrome::AttemptExit)); 145 base::RunLoop().RunUntilIdle(); 146 } 147 148 void InitializePolicy() { 149 device_policy()->policy_data().set_public_key_version(1); 150 em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); 151 proto.mutable_show_user_names()->set_show_user_names(true); 152 153 device_local_account_policy_.policy_data().set_policy_type( 154 dm_protocol::kChromePublicAccountPolicyType); 155 device_local_account_policy_.policy_data().set_username(kAccountId1); 156 device_local_account_policy_.policy_data().set_settings_entity_id( 157 kAccountId1); 158 device_local_account_policy_.policy_data().set_public_key_version(1); 159 device_local_account_policy_.payload().mutable_userdisplayname()->set_value( 160 kDisplayName); 161 } 162 163 void BuildDeviceLocalAccountPolicy() { 164 device_local_account_policy_.SetDefaultSigningKey(); 165 device_local_account_policy_.Build(); 166 } 167 168 void InstallDeviceLocalAccountPolicy() { 169 BuildDeviceLocalAccountPolicy(); 170 session_manager_client()->set_device_local_account_policy( 171 kAccountId1, device_local_account_policy_.GetBlob()); 172 } 173 174 void UploadDeviceLocalAccountPolicy() { 175 BuildDeviceLocalAccountPolicy(); 176 ASSERT_TRUE(session_manager_client()->device_local_account_policy( 177 kAccountId1).empty()); 178 test_server_.UpdatePolicy( 179 dm_protocol::kChromePublicAccountPolicyType, kAccountId1, 180 device_local_account_policy_.payload().SerializeAsString()); 181 } 182 183 void AddPublicSessionToDevicePolicy(const std::string& username) { 184 em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); 185 em::DeviceLocalAccountInfoProto* account = 186 proto.mutable_device_local_accounts()->add_account(); 187 account->set_account_id(username); 188 account->set_type( 189 em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION); 190 RefreshDevicePolicy(); 191 test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, 192 std::string(), proto.SerializeAsString()); 193 } 194 195 void CheckPublicSessionPresent(const std::string& id) { 196 const chromeos::User* user = chromeos::UserManager::Get()->FindUser(id); 197 ASSERT_TRUE(user); 198 EXPECT_EQ(id, user->email()); 199 EXPECT_EQ(chromeos::User::USER_TYPE_PUBLIC_ACCOUNT, user->GetType()); 200 } 201 202 const std::string user_id_1_; 203 const std::string user_id_2_; 204 205 UserPolicyBuilder device_local_account_policy_; 206 LocalPolicyTestServer test_server_; 207 }; 208 209 static bool IsKnownUser(const std::string& account_id) { 210 return chromeos::UserManager::Get()->IsKnownUser(account_id); 211 } 212 213 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LoginScreen) { 214 AddPublicSessionToDevicePolicy(kAccountId1); 215 AddPublicSessionToDevicePolicy(kAccountId2); 216 217 content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED, 218 base::Bind(&IsKnownUser, user_id_1_)) 219 .Wait(); 220 content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED, 221 base::Bind(&IsKnownUser, user_id_2_)) 222 .Wait(); 223 224 CheckPublicSessionPresent(user_id_1_); 225 CheckPublicSessionPresent(user_id_2_); 226 } 227 228 static bool DisplayNameMatches(const std::string& account_id, 229 const std::string& display_name) { 230 const chromeos::User* user = 231 chromeos::UserManager::Get()->FindUser(account_id); 232 if (!user || user->display_name().empty()) 233 return false; 234 EXPECT_EQ(UTF8ToUTF16(display_name), user->display_name()); 235 return true; 236 } 237 238 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DisplayName) { 239 InstallDeviceLocalAccountPolicy(); 240 AddPublicSessionToDevicePolicy(kAccountId1); 241 242 content::WindowedNotificationObserver( 243 chrome::NOTIFICATION_USER_LIST_CHANGED, 244 base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait(); 245 } 246 247 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PolicyDownload) { 248 UploadDeviceLocalAccountPolicy(); 249 AddPublicSessionToDevicePolicy(kAccountId1); 250 251 // Policy for the account is not installed in session_manager_client. Because 252 // of this, the presence of the display name (which comes from policy) can be 253 // used as a signal that indicates successful policy download. 254 content::WindowedNotificationObserver( 255 chrome::NOTIFICATION_USER_LIST_CHANGED, 256 base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait(); 257 258 // Sanity check: The policy should be present now. 259 ASSERT_FALSE(session_manager_client()->device_local_account_policy( 260 kAccountId1).empty()); 261 } 262 263 static bool IsNotKnownUser(const std::string& account_id) { 264 return !IsKnownUser(account_id); 265 } 266 267 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DevicePolicyChange) { 268 AddPublicSessionToDevicePolicy(kAccountId1); 269 AddPublicSessionToDevicePolicy(kAccountId2); 270 271 // Wait until the login screen is up. 272 content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED, 273 base::Bind(&IsKnownUser, user_id_1_)) 274 .Wait(); 275 content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED, 276 base::Bind(&IsKnownUser, user_id_2_)) 277 .Wait(); 278 279 // Update policy to remove kAccountId2. 280 em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); 281 proto.mutable_device_local_accounts()->clear_account(); 282 AddPublicSessionToDevicePolicy(kAccountId1); 283 284 em::ChromeDeviceSettingsProto policy; 285 policy.mutable_show_user_names()->set_show_user_names(true); 286 em::DeviceLocalAccountInfoProto* account1 = 287 policy.mutable_device_local_accounts()->add_account(); 288 account1->set_account_id(kAccountId1); 289 account1->set_type( 290 em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION); 291 292 test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, std::string(), 293 policy.SerializeAsString()); 294 g_browser_process->policy_service()->RefreshPolicies(base::Closure()); 295 296 // Make sure the second device-local account disappears. 297 content::WindowedNotificationObserver( 298 chrome::NOTIFICATION_USER_LIST_CHANGED, 299 base::Bind(&IsNotKnownUser, user_id_2_)).Wait(); 300 } 301 302 static bool IsSessionStarted() { 303 return chromeos::UserManager::Get()->IsSessionStarted(); 304 } 305 306 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, StartSession) { 307 // Specify startup pages. 308 device_local_account_policy_.payload().mutable_restoreonstartup()->set_value( 309 SessionStartupPref::kPrefValueURLs); 310 em::StringListPolicyProto* startup_urls_proto = 311 device_local_account_policy_.payload().mutable_restoreonstartupurls(); 312 for (size_t i = 0; i < arraysize(kStartupURLs); ++i) 313 startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]); 314 InstallDeviceLocalAccountPolicy(); 315 AddPublicSessionToDevicePolicy(kAccountId1); 316 317 // This observes the display name becoming available as this indicates 318 // device-local account policy is fully loaded, which is a prerequisite for 319 // successful login. 320 content::WindowedNotificationObserver( 321 chrome::NOTIFICATION_USER_LIST_CHANGED, 322 base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait(); 323 324 // Wait for the login UI to be ready. 325 chromeos::LoginDisplayHostImpl* host = 326 reinterpret_cast<chromeos::LoginDisplayHostImpl*>( 327 chromeos::LoginDisplayHostImpl::default_host()); 328 ASSERT_TRUE(host); 329 chromeos::OobeUI* oobe_ui = host->GetOobeUI(); 330 ASSERT_TRUE(oobe_ui); 331 base::RunLoop run_loop; 332 const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure()); 333 if (!oobe_ui_ready) 334 run_loop.Run(); 335 336 // Start login into the device-local account. 337 host->StartSignInScreen(); 338 chromeos::ExistingUserController* controller = 339 chromeos::ExistingUserController::current_controller(); 340 ASSERT_TRUE(controller); 341 controller->LoginAsPublicAccount(user_id_1_); 342 343 // Wait for the session to start. 344 content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED, 345 base::Bind(IsSessionStarted)).Wait(); 346 347 // Check that the startup pages specified in policy were opened. 348 BrowserList* browser_list = 349 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 350 EXPECT_EQ(1U, browser_list->size()); 351 Browser* browser = browser_list->get(0); 352 ASSERT_TRUE(browser); 353 354 TabStripModel* tabs = browser->tab_strip_model(); 355 ASSERT_TRUE(tabs); 356 int expected_tab_count = static_cast<int>(arraysize(kStartupURLs)); 357 EXPECT_EQ(expected_tab_count, tabs->count()); 358 for (int i = 0; i < expected_tab_count && i < tabs->count(); ++i) { 359 EXPECT_EQ(GURL(kStartupURLs[i]), 360 tabs->GetWebContentsAt(i)->GetVisibleURL()); 361 } 362 } 363 364 class TermsOfServiceTest : public DeviceLocalAccountTest, 365 public testing::WithParamInterface<bool> { 366 }; 367 368 IN_PROC_BROWSER_TEST_P(TermsOfServiceTest, TermsOfServiceScreen) { 369 // Specify Terms of Service URL. 370 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 371 device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value( 372 embedded_test_server()->GetURL( 373 std::string("/") + 374 (GetParam() ? kExistentTermsOfServicePath 375 : kNonexistentTermsOfServicePath)).spec()); 376 InstallDeviceLocalAccountPolicy(); 377 AddPublicSessionToDevicePolicy(kAccountId1); 378 379 // Wait for the device-local account policy to be fully loaded. 380 content::WindowedNotificationObserver( 381 chrome::NOTIFICATION_USER_LIST_CHANGED, 382 base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait(); 383 384 // Wait for the login UI to be ready. 385 chromeos::LoginDisplayHostImpl* host = 386 reinterpret_cast<chromeos::LoginDisplayHostImpl*>( 387 chromeos::LoginDisplayHostImpl::default_host()); 388 ASSERT_TRUE(host); 389 chromeos::OobeUI* oobe_ui = host->GetOobeUI(); 390 ASSERT_TRUE(oobe_ui); 391 base::RunLoop oobe_ui_wait_run_loop; 392 const bool oobe_ui_ready = 393 oobe_ui->IsJSReady(oobe_ui_wait_run_loop.QuitClosure()); 394 if (!oobe_ui_ready) 395 oobe_ui_wait_run_loop.Run(); 396 397 // Start login into the device-local account. 398 host->StartSignInScreen(); 399 chromeos::ExistingUserController* controller = 400 chromeos::ExistingUserController::current_controller(); 401 ASSERT_TRUE(controller); 402 controller->LoginAsPublicAccount(user_id_1_); 403 404 // Set up an observer that will quit the message loop when login has succeeded 405 // and the first wizard screen, if any, is being shown. 406 base::RunLoop login_wait_run_loop; 407 chromeos::MockConsumer login_status_consumer; 408 EXPECT_CALL(login_status_consumer, OnLoginSuccess(_, false, false)) 409 .Times(1) 410 .WillOnce(InvokeWithoutArgs(&login_wait_run_loop, &base::RunLoop::Quit)); 411 412 // Spin the loop until the observer fires. Then, unregister the observer. 413 controller->set_login_status_consumer(&login_status_consumer); 414 login_wait_run_loop.Run(); 415 controller->set_login_status_consumer(NULL); 416 417 // Verify that the Terms of Service screen is being shown. 418 chromeos::WizardController* wizard_controller = 419 chromeos::WizardController::default_controller(); 420 ASSERT_TRUE(wizard_controller); 421 ASSERT_TRUE(wizard_controller->current_screen()); 422 EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName, 423 wizard_controller->current_screen()->GetName()); 424 425 // Wait for the Terms of Service to finish downloading, then get the status of 426 // the screen's UI elements. 427 chromeos::WebUILoginView* web_ui_login_view = host->GetWebUILoginView(); 428 ASSERT_TRUE(web_ui_login_view); 429 content::WebUI* web_ui = web_ui_login_view->GetWebUI(); 430 ASSERT_TRUE(web_ui); 431 content::WebContents* contents = web_ui->GetWebContents(); 432 ASSERT_TRUE(contents); 433 std::string json; 434 ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents, 435 "var screen = document.getElementById('terms-of-service');" 436 "function SendReplyIfDownloadDone() {" 437 " if (screen.classList.contains('tos-loading'))" 438 " return false;" 439 " var status = {};" 440 " status.heading = document.getElementById('tos-heading').textContent;" 441 " status.subheading =" 442 " document.getElementById('tos-subheading').textContent;" 443 " status.contentHeading =" 444 " document.getElementById('tos-content-heading').textContent;" 445 " status.content =" 446 " document.getElementById('tos-content-main').textContent;" 447 " status.error = screen.classList.contains('error');" 448 " status.acceptEnabled =" 449 " !document.getElementById('tos-accept-button').disabled;" 450 " domAutomationController.send(JSON.stringify(status));" 451 " observer.disconnect();" 452 " return true;" 453 "}" 454 "var observer = new MutationObserver(SendReplyIfDownloadDone);" 455 "if (!SendReplyIfDownloadDone()) {" 456 " var options = { attributes: true, attributeFilter: [ 'class' ] };" 457 " observer.observe(screen, options);" 458 "}", 459 &json)); 460 scoped_ptr<base::Value> value_ptr(base::JSONReader::Read(json)); 461 const base::DictionaryValue* status = NULL; 462 ASSERT_TRUE(value_ptr.get()); 463 ASSERT_TRUE(value_ptr->GetAsDictionary(&status)); 464 std::string heading; 465 EXPECT_TRUE(status->GetString("heading", &heading)); 466 std::string subheading; 467 EXPECT_TRUE(status->GetString("subheading", &subheading)); 468 std::string content_heading; 469 EXPECT_TRUE(status->GetString("contentHeading", &content_heading)); 470 std::string content; 471 EXPECT_TRUE(status->GetString("content", &content)); 472 bool error; 473 EXPECT_TRUE(status->GetBoolean("error", &error)); 474 bool accept_enabled; 475 EXPECT_TRUE(status->GetBoolean("acceptEnabled", &accept_enabled)); 476 477 // Verify that the screen's headings have been set correctly. 478 EXPECT_EQ( 479 l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_HEADING, 480 UTF8ToUTF16(kDomain)), 481 heading); 482 EXPECT_EQ( 483 l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_SUBHEADING, 484 UTF8ToUTF16(kDomain)), 485 subheading); 486 EXPECT_EQ( 487 l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_CONTENT_HEADING, 488 UTF8ToUTF16(kDomain)), 489 content_heading); 490 491 if (!GetParam()) { 492 // The Terms of Service URL was invalid. Verify that the screen is showing 493 // an error and the accept button is disabled. 494 EXPECT_TRUE(error); 495 EXPECT_FALSE(accept_enabled); 496 return; 497 } 498 499 // The Terms of Service URL was valid. Verify that the screen is showing the 500 // downloaded Terms of Service and the accept button is enabled. 501 base::FilePath test_dir; 502 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); 503 std::string terms_of_service; 504 ASSERT_TRUE(file_util::ReadFileToString( 505 test_dir.Append(kExistentTermsOfServicePath), &terms_of_service)); 506 EXPECT_EQ(terms_of_service, content); 507 EXPECT_FALSE(error); 508 EXPECT_TRUE(accept_enabled); 509 510 // Click the accept button. 511 ASSERT_TRUE(content::ExecuteScript(contents, 512 "$('tos-accept-button').click();")); 513 514 // Wait for the session to start. 515 if (!IsSessionStarted()) { 516 content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED, 517 base::Bind(IsSessionStarted)).Wait(); 518 } 519 } 520 521 INSTANTIATE_TEST_CASE_P(TermsOfServiceTestInstance, 522 TermsOfServiceTest, testing::Bool()); 523 524 } // namespace policy 525