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