1 // 2 // Copyright (C) 2014 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "update_engine/update_manager/evaluation_context.h" 18 19 #include <memory> 20 #include <string> 21 22 #include <base/bind.h> 23 #include <base/bind_helpers.h> 24 #include <brillo/message_loops/fake_message_loop.h> 25 #include <brillo/message_loops/message_loop_utils.h> 26 #include <gtest/gtest.h> 27 28 #include "update_engine/common/fake_clock.h" 29 #include "update_engine/update_manager/fake_variable.h" 30 #include "update_engine/update_manager/generic_variables.h" 31 #include "update_engine/update_manager/mock_variable.h" 32 #include "update_engine/update_manager/umtest_utils.h" 33 34 using base::Bind; 35 using base::Closure; 36 using base::Time; 37 using base::TimeDelta; 38 using brillo::MessageLoop; 39 using brillo::MessageLoopRunMaxIterations; 40 using brillo::MessageLoopRunUntil; 41 using chromeos_update_engine::FakeClock; 42 using std::string; 43 using std::unique_ptr; 44 using testing::_; 45 using testing::Return; 46 using testing::StrictMock; 47 48 namespace chromeos_update_manager { 49 50 namespace { 51 52 // Sets the value of the passed pointer to true. 53 void SetTrue(bool* value) { 54 *value = true; 55 } 56 57 bool GetBoolean(bool* value) { 58 return *value; 59 } 60 61 template <typename T> 62 void ReadVar(scoped_refptr<EvaluationContext> ec, Variable<T>* var) { 63 ec->GetValue(var); 64 } 65 66 // Runs |evaluation|; if the value pointed by |count_p| is greater than zero, 67 // decrement it and schedule a reevaluation; otherwise, writes true to |done_p|. 68 void EvaluateRepeatedly(Closure evaluation, 69 scoped_refptr<EvaluationContext> ec, 70 int* count_p, 71 bool* done_p) { 72 evaluation.Run(); 73 74 // Schedule reevaluation if needed. 75 if (*count_p > 0) { 76 Closure closure = Bind(EvaluateRepeatedly, evaluation, ec, count_p, done_p); 77 ASSERT_TRUE(ec->RunOnValueChangeOrTimeout(closure)) 78 << "Failed to schedule reevaluation, count_p=" << *count_p; 79 (*count_p)--; 80 } else { 81 *done_p = true; 82 } 83 } 84 85 } // namespace 86 87 class UmEvaluationContextTest : public ::testing::Test { 88 protected: 89 void SetUp() override { 90 loop_.SetAsCurrent(); 91 // Apr 22, 2009 19:25:00 UTC (this is a random reference point). 92 fake_clock_.SetMonotonicTime(Time::FromTimeT(1240428300)); 93 // Mar 2, 2006 1:23:45 UTC. 94 fake_clock_.SetWallclockTime(Time::FromTimeT(1141262625)); 95 eval_ctx_ = new EvaluationContext( 96 &fake_clock_, 97 default_timeout_, 98 default_timeout_, 99 unique_ptr<base::Callback<void(EvaluationContext*)>>(nullptr)); 100 } 101 102 void TearDown() override { 103 // Ensure that the evaluation context did not leak and is actually being 104 // destroyed. 105 if (eval_ctx_) { 106 base::WeakPtr<EvaluationContext> eval_ctx_weak_alias = 107 eval_ctx_->weak_ptr_factory_.GetWeakPtr(); 108 ASSERT_NE(nullptr, eval_ctx_weak_alias.get()); 109 eval_ctx_ = nullptr; 110 EXPECT_EQ(nullptr, eval_ctx_weak_alias.get()) 111 << "The evaluation context was not destroyed! This is likely a bug " 112 "in how the test was written, look for leaking handles to the EC, " 113 "possibly through closure objects."; 114 } 115 116 // Check that the evaluation context removed all the observers. 117 EXPECT_TRUE(fake_int_var_.observer_list_.empty()); 118 EXPECT_TRUE(fake_async_var_.observer_list_.empty()); 119 EXPECT_TRUE(fake_const_var_.observer_list_.empty()); 120 EXPECT_TRUE(fake_poll_var_.observer_list_.empty()); 121 122 EXPECT_FALSE(loop_.PendingTasks()); 123 } 124 125 TimeDelta default_timeout_ = TimeDelta::FromSeconds(5); 126 127 brillo::FakeMessageLoop loop_{nullptr}; 128 FakeClock fake_clock_; 129 scoped_refptr<EvaluationContext> eval_ctx_; 130 131 // FakeVariables used for testing the EvaluationContext. These are required 132 // here to prevent them from going away *before* the EvaluationContext under 133 // test does, which keeps a reference to them. 134 FakeVariable<bool> fail_var_ = {"fail_var", kVariableModePoll}; 135 FakeVariable<int> fake_int_var_ = {"fake_int", kVariableModePoll}; 136 FakeVariable<string> fake_async_var_ = {"fake_async", kVariableModeAsync}; 137 FakeVariable<string> fake_const_var_ = {"fake_const", kVariableModeConst}; 138 FakeVariable<string> fake_poll_var_ = {"fake_poll", 139 TimeDelta::FromSeconds(1)}; 140 StrictMock<MockVariable<string>> mock_var_async_{"mock_var_async", 141 kVariableModeAsync}; 142 StrictMock<MockVariable<string>> mock_var_poll_{"mock_var_poll", 143 kVariableModePoll}; 144 }; 145 146 TEST_F(UmEvaluationContextTest, GetValueFails) { 147 // FakeVariable is initialized as returning null. 148 EXPECT_EQ(nullptr, eval_ctx_->GetValue(&fake_int_var_)); 149 } 150 151 TEST_F(UmEvaluationContextTest, GetValueFailsWithInvalidVar) { 152 EXPECT_EQ(nullptr, eval_ctx_->GetValue(static_cast<Variable<int>*>(nullptr))); 153 } 154 155 TEST_F(UmEvaluationContextTest, GetValueReturns) { 156 const int* p_fake_int; 157 158 fake_int_var_.reset(new int(42)); 159 p_fake_int = eval_ctx_->GetValue(&fake_int_var_); 160 ASSERT_NE(nullptr, p_fake_int); 161 EXPECT_EQ(42, *p_fake_int); 162 } 163 164 TEST_F(UmEvaluationContextTest, GetValueCached) { 165 const int* p_fake_int; 166 167 fake_int_var_.reset(new int(42)); 168 p_fake_int = eval_ctx_->GetValue(&fake_int_var_); 169 170 // Check that if the variable changes, the EvaluationContext keeps returning 171 // the cached value. 172 fake_int_var_.reset(new int(5)); 173 174 p_fake_int = eval_ctx_->GetValue(&fake_int_var_); 175 ASSERT_NE(nullptr, p_fake_int); 176 EXPECT_EQ(42, *p_fake_int); 177 } 178 179 TEST_F(UmEvaluationContextTest, GetValueCachesNull) { 180 const int* p_fake_int = eval_ctx_->GetValue(&fake_int_var_); 181 EXPECT_EQ(nullptr, p_fake_int); 182 183 fake_int_var_.reset(new int(42)); 184 // A second attempt to read the variable should not work because this 185 // EvaluationContext already got a null value. 186 p_fake_int = eval_ctx_->GetValue(&fake_int_var_); 187 EXPECT_EQ(nullptr, p_fake_int); 188 } 189 190 TEST_F(UmEvaluationContextTest, GetValueMixedTypes) { 191 const int* p_fake_int; 192 const string* p_fake_string; 193 194 fake_int_var_.reset(new int(42)); 195 fake_poll_var_.reset(new string("Hello world!")); 196 // Check that the EvaluationContext can handle multiple Variable types. This 197 // is mostly a compile-time check due to the template nature of this method. 198 p_fake_int = eval_ctx_->GetValue(&fake_int_var_); 199 p_fake_string = eval_ctx_->GetValue(&fake_poll_var_); 200 201 ASSERT_NE(nullptr, p_fake_int); 202 EXPECT_EQ(42, *p_fake_int); 203 204 ASSERT_NE(nullptr, p_fake_string); 205 EXPECT_EQ("Hello world!", *p_fake_string); 206 } 207 208 // Test that we don't schedule an event if there's no variable to wait for. 209 TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutWithoutVariables) { 210 fake_const_var_.reset(new string("Hello world!")); 211 EXPECT_EQ(*eval_ctx_->GetValue(&fake_const_var_), "Hello world!"); 212 213 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout( 214 #if BASE_VER < 576279 215 Bind(&base::DoNothing) 216 #else 217 base::DoNothing() 218 #endif 219 )); 220 } 221 222 // Test that reevaluation occurs when an async variable it depends on changes. 223 TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutWithVariables) { 224 fake_async_var_.reset(new string("Async value")); 225 eval_ctx_->GetValue(&fake_async_var_); 226 227 bool value = false; 228 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value))); 229 // Check that the scheduled callback isn't run until we signal a ValueChaged. 230 MessageLoopRunMaxIterations(MessageLoop::current(), 100); 231 EXPECT_FALSE(value); 232 233 fake_async_var_.NotifyValueChanged(); 234 EXPECT_FALSE(value); 235 // Ensure that the scheduled callback isn't run until we are back on the main 236 // loop. 237 MessageLoopRunMaxIterations(MessageLoop::current(), 100); 238 EXPECT_TRUE(value); 239 } 240 241 // Test that we don't re-schedule the events if we are attending one. 242 TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutCalledTwice) { 243 fake_async_var_.reset(new string("Async value")); 244 eval_ctx_->GetValue(&fake_async_var_); 245 246 bool value = false; 247 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value))); 248 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value))); 249 250 // The scheduled event should still work. 251 fake_async_var_.NotifyValueChanged(); 252 MessageLoopRunMaxIterations(MessageLoop::current(), 100); 253 EXPECT_TRUE(value); 254 } 255 256 // Test that reevaluation occurs when a polling timeout fires. 257 TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutRunsFromTimeout) { 258 fake_poll_var_.reset(new string("Polled value")); 259 eval_ctx_->GetValue(&fake_poll_var_); 260 261 bool value = false; 262 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value))); 263 // Check that the scheduled callback isn't run until the timeout occurs. 264 MessageLoopRunMaxIterations(MessageLoop::current(), 10); 265 EXPECT_FALSE(value); 266 MessageLoopRunUntil(MessageLoop::current(), 267 TimeDelta::FromSeconds(10), 268 Bind(&GetBoolean, &value)); 269 EXPECT_TRUE(value); 270 } 271 272 // Test that callback is called when evaluation context expires, and that it 273 // cannot be used again unless the expiration deadline is reset. 274 TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutExpires) { 275 fake_async_var_.reset(new string("Async value")); 276 eval_ctx_->GetValue(&fake_async_var_); 277 278 bool value = false; 279 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value))); 280 // Check that the scheduled callback isn't run until the timeout occurs. 281 MessageLoopRunMaxIterations(MessageLoop::current(), 10); 282 EXPECT_FALSE(value); 283 MessageLoopRunUntil(MessageLoop::current(), 284 TimeDelta::FromSeconds(10), 285 Bind(&GetBoolean, &value)); 286 EXPECT_TRUE(value); 287 288 // Ensure that we cannot reschedule an evaluation. 289 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout( 290 #if BASE_VER < 576279 291 Bind(&base::DoNothing) 292 #else 293 base::DoNothing() 294 #endif 295 )); 296 297 // Ensure that we can reschedule an evaluation after resetting expiration. 298 eval_ctx_->ResetExpiration(); 299 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout( 300 #if BASE_VER < 576279 301 Bind(&base::DoNothing) 302 #else 303 base::DoNothing() 304 #endif 305 )); 306 } 307 308 // Test that we clear the events when destroying the EvaluationContext. 309 TEST_F(UmEvaluationContextTest, RemoveObserversAndTimeoutTest) { 310 fake_async_var_.reset(new string("Async value")); 311 eval_ctx_->GetValue(&fake_async_var_); 312 313 bool value = false; 314 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value))); 315 eval_ctx_ = nullptr; 316 317 // This should not trigger the callback since the EvaluationContext waiting 318 // for it is gone, and it should have remove all its observers. 319 fake_async_var_.NotifyValueChanged(); 320 MessageLoopRunMaxIterations(MessageLoop::current(), 100); 321 EXPECT_FALSE(value); 322 } 323 324 // Scheduling two reevaluations from the callback should succeed. 325 TEST_F(UmEvaluationContextTest, 326 RunOnValueChangeOrTimeoutReevaluatesRepeatedly) { 327 fake_poll_var_.reset(new string("Polled value")); 328 Closure evaluation = Bind(ReadVar<string>, eval_ctx_, &fake_poll_var_); 329 int num_reevaluations = 2; 330 bool done = false; 331 332 // Run the evaluation once. 333 evaluation.Run(); 334 335 // Schedule repeated reevaluations. 336 Closure closure = Bind( 337 EvaluateRepeatedly, evaluation, eval_ctx_, &num_reevaluations, &done); 338 ASSERT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(closure)); 339 MessageLoopRunUntil(MessageLoop::current(), 340 TimeDelta::FromSeconds(10), 341 Bind(&GetBoolean, &done)); 342 EXPECT_EQ(0, num_reevaluations); 343 } 344 345 // Test that we can delete the EvaluationContext while having pending events. 346 TEST_F(UmEvaluationContextTest, ObjectDeletedWithPendingEventsTest) { 347 fake_async_var_.reset(new string("Async value")); 348 fake_poll_var_.reset(new string("Polled value")); 349 eval_ctx_->GetValue(&fake_async_var_); 350 eval_ctx_->GetValue(&fake_poll_var_); 351 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout( 352 #if BASE_VER < 576279 353 Bind(&base::DoNothing) 354 #else 355 base::DoNothing() 356 #endif 357 )); 358 // TearDown() checks for leaked observers on this async_variable, which means 359 // that our object is still alive after removing its reference. 360 } 361 362 // Test that timed events fired after removal of the EvaluationContext don't 363 // crash. 364 TEST_F(UmEvaluationContextTest, TimeoutEventAfterDeleteTest) { 365 FakeVariable<string> fake_short_poll_var = {"fake_short_poll", 366 TimeDelta::FromSeconds(1)}; 367 fake_short_poll_var.reset(new string("Polled value")); 368 eval_ctx_->GetValue(&fake_short_poll_var); 369 bool value = false; 370 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value))); 371 // Remove the last reference to the EvaluationContext and run the loop for 372 // 10 seconds to give time to the main loop to trigger the timeout Event (of 1 373 // second). Our callback should not be called because the EvaluationContext 374 // was removed before the timeout event is attended. 375 eval_ctx_ = nullptr; 376 MessageLoopRunUntil(MessageLoop::current(), 377 TimeDelta::FromSeconds(10), 378 Bind(&GetBoolean, &value)); 379 EXPECT_FALSE(value); 380 } 381 382 TEST_F(UmEvaluationContextTest, DefaultTimeout) { 383 // Test that the evaluation timeout calculation uses the default timeout on 384 // setup. 385 EXPECT_CALL(mock_var_async_, GetValue(default_timeout_, _)) 386 .WillOnce(Return(nullptr)); 387 EXPECT_EQ(nullptr, eval_ctx_->GetValue(&mock_var_async_)); 388 } 389 390 TEST_F(UmEvaluationContextTest, TimeoutUpdatesWithMonotonicTime) { 391 fake_clock_.SetMonotonicTime(fake_clock_.GetMonotonicTime() + 392 TimeDelta::FromSeconds(1)); 393 394 TimeDelta timeout = default_timeout_ - TimeDelta::FromSeconds(1); 395 396 EXPECT_CALL(mock_var_async_, GetValue(timeout, _)).WillOnce(Return(nullptr)); 397 EXPECT_EQ(nullptr, eval_ctx_->GetValue(&mock_var_async_)); 398 } 399 400 TEST_F(UmEvaluationContextTest, ResetEvaluationResetsTimesWallclock) { 401 Time cur_time = fake_clock_.GetWallclockTime(); 402 // Advance the time on the clock but don't call ResetEvaluation yet. 403 fake_clock_.SetWallclockTime(cur_time + TimeDelta::FromSeconds(4)); 404 405 EXPECT_TRUE(eval_ctx_->IsWallclockTimeGreaterThan(cur_time - 406 TimeDelta::FromSeconds(1))); 407 EXPECT_FALSE(eval_ctx_->IsWallclockTimeGreaterThan(cur_time)); 408 EXPECT_FALSE(eval_ctx_->IsWallclockTimeGreaterThan( 409 cur_time + TimeDelta::FromSeconds(1))); 410 // Call ResetEvaluation now, which should use the new evaluation time. 411 eval_ctx_->ResetEvaluation(); 412 413 cur_time = fake_clock_.GetWallclockTime(); 414 EXPECT_TRUE(eval_ctx_->IsWallclockTimeGreaterThan(cur_time - 415 TimeDelta::FromSeconds(1))); 416 EXPECT_FALSE(eval_ctx_->IsWallclockTimeGreaterThan(cur_time)); 417 EXPECT_FALSE(eval_ctx_->IsWallclockTimeGreaterThan( 418 cur_time + TimeDelta::FromSeconds(1))); 419 } 420 421 TEST_F(UmEvaluationContextTest, ResetEvaluationResetsTimesMonotonic) { 422 Time cur_time = fake_clock_.GetMonotonicTime(); 423 // Advance the time on the clock but don't call ResetEvaluation yet. 424 fake_clock_.SetMonotonicTime(cur_time + TimeDelta::FromSeconds(4)); 425 426 EXPECT_TRUE(eval_ctx_->IsMonotonicTimeGreaterThan(cur_time - 427 TimeDelta::FromSeconds(1))); 428 EXPECT_FALSE(eval_ctx_->IsMonotonicTimeGreaterThan(cur_time)); 429 EXPECT_FALSE(eval_ctx_->IsMonotonicTimeGreaterThan( 430 cur_time + TimeDelta::FromSeconds(1))); 431 // Call ResetEvaluation now, which should use the new evaluation time. 432 eval_ctx_->ResetEvaluation(); 433 434 cur_time = fake_clock_.GetMonotonicTime(); 435 EXPECT_TRUE(eval_ctx_->IsMonotonicTimeGreaterThan(cur_time - 436 TimeDelta::FromSeconds(1))); 437 EXPECT_FALSE(eval_ctx_->IsMonotonicTimeGreaterThan(cur_time)); 438 EXPECT_FALSE(eval_ctx_->IsMonotonicTimeGreaterThan( 439 cur_time + TimeDelta::FromSeconds(1))); 440 } 441 442 TEST_F(UmEvaluationContextTest, 443 IsWallclockTimeGreaterThanSignalsTriggerReevaluation) { 444 EXPECT_FALSE(eval_ctx_->IsWallclockTimeGreaterThan( 445 fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(1))); 446 447 // The "false" from IsWallclockTimeGreaterThan means that's not that timestamp 448 // yet, so this should schedule a callback for when that happens. 449 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout( 450 #if BASE_VER < 576279 451 Bind(&base::DoNothing) 452 #else 453 base::DoNothing() 454 #endif 455 )); 456 } 457 458 TEST_F(UmEvaluationContextTest, 459 IsMonotonicTimeGreaterThanSignalsTriggerReevaluation) { 460 EXPECT_FALSE(eval_ctx_->IsMonotonicTimeGreaterThan( 461 fake_clock_.GetMonotonicTime() + TimeDelta::FromSeconds(1))); 462 463 // The "false" from IsMonotonicTimeGreaterThan means that's not that timestamp 464 // yet, so this should schedule a callback for when that happens. 465 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout( 466 #if BASE_VER < 576279 467 Bind(&base::DoNothing) 468 #else 469 base::DoNothing() 470 #endif 471 )); 472 } 473 474 TEST_F(UmEvaluationContextTest, 475 IsWallclockTimeGreaterThanDoesntRecordPastTimestamps) { 476 // IsWallclockTimeGreaterThan() should ignore timestamps on the past for 477 // reevaluation. 478 EXPECT_TRUE(eval_ctx_->IsWallclockTimeGreaterThan( 479 fake_clock_.GetWallclockTime() - TimeDelta::FromSeconds(20))); 480 EXPECT_TRUE(eval_ctx_->IsWallclockTimeGreaterThan( 481 fake_clock_.GetWallclockTime() - TimeDelta::FromSeconds(1))); 482 483 // Callback should not be scheduled. 484 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout( 485 #if BASE_VER < 576279 486 Bind(&base::DoNothing) 487 #else 488 base::DoNothing() 489 #endif 490 )); 491 } 492 493 TEST_F(UmEvaluationContextTest, 494 IsMonotonicTimeGreaterThanDoesntRecordPastTimestamps) { 495 // IsMonotonicTimeGreaterThan() should ignore timestamps on the past for 496 // reevaluation. 497 EXPECT_TRUE(eval_ctx_->IsMonotonicTimeGreaterThan( 498 fake_clock_.GetMonotonicTime() - TimeDelta::FromSeconds(20))); 499 EXPECT_TRUE(eval_ctx_->IsMonotonicTimeGreaterThan( 500 fake_clock_.GetMonotonicTime() - TimeDelta::FromSeconds(1))); 501 502 // Callback should not be scheduled. 503 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout( 504 #if BASE_VER < 576279 505 Bind(&base::DoNothing) 506 #else 507 base::DoNothing() 508 #endif 509 )); 510 } 511 512 TEST_F(UmEvaluationContextTest, DumpContext) { 513 // |fail_var_| yield "(no value)" since it is unset. 514 eval_ctx_->GetValue(&fail_var_); 515 516 // Check that this is included. 517 fake_int_var_.reset(new int(42)); 518 eval_ctx_->GetValue(&fake_int_var_); 519 520 // Check that double-quotes are escaped properly. 521 fake_poll_var_.reset(new string("Hello \"world\"!")); 522 eval_ctx_->GetValue(&fake_poll_var_); 523 524 // Note that the variables are printed in alphabetical order. Also 525 // see UmEvaluationContextText::SetUp() where the values used for 526 // |evaluation_start_{monotonic,wallclock| are set. 527 EXPECT_EQ( 528 "{\n" 529 " \"evaluation_start_monotonic\": \"4/22/2009 19:25:00 GMT\",\n" 530 " \"evaluation_start_wallclock\": \"3/2/2006 1:23:45 GMT\",\n" 531 " \"variables\": {\n" 532 " \"fail_var\": \"(no value)\",\n" 533 " \"fake_int\": \"42\",\n" 534 " \"fake_poll\": \"Hello \\\"world\\\"!\"\n" 535 " }\n" 536 "}", 537 eval_ctx_->DumpContext()); 538 } 539 540 } // namespace chromeos_update_manager 541