blob: c60bcd6a2b403bf688f3ca98d1ec4c2b42624c29 [file] [log] [blame]
Alex Deymo23949d42014-02-05 15:20:59 -08001// Copyright (c) 2014 The Chromium OS 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
Alex Deymo23949d42014-02-05 15:20:59 -08005#include <string>
6
Alex Deymo53556ec2014-03-17 10:05:57 -07007#include <base/bind.h>
Alex Deymo53556ec2014-03-17 10:05:57 -07008#include <gtest/gtest.h>
9
Alex Deymo41a75a72014-04-15 15:36:22 -070010#include "update_engine/fake_clock.h"
Alex Deymo53556ec2014-03-17 10:05:57 -070011#include "update_engine/test_utils.h"
Alex Deymo63784a52014-05-28 10:46:14 -070012#include "update_engine/update_manager/evaluation_context.h"
13#include "update_engine/update_manager/fake_variable.h"
14#include "update_engine/update_manager/generic_variables.h"
15#include "update_engine/update_manager/mock_variable.h"
16#include "update_engine/update_manager/umtest_utils.h"
Alex Deymo23949d42014-02-05 15:20:59 -080017
Alex Deymo53556ec2014-03-17 10:05:57 -070018using base::Bind;
Gilad Arnoldfb794f42014-07-01 15:36:31 -070019using base::Closure;
Alex Deymo41a75a72014-04-15 15:36:22 -070020using base::Time;
Alex Deymo53556ec2014-03-17 10:05:57 -070021using base::TimeDelta;
Alex Deymo41a75a72014-04-15 15:36:22 -070022using chromeos_update_engine::FakeClock;
Alex Deymo53556ec2014-03-17 10:05:57 -070023using chromeos_update_engine::RunGMainLoopMaxIterations;
24using chromeos_update_engine::RunGMainLoopUntil;
Alex Deymo23949d42014-02-05 15:20:59 -080025using std::string;
Alex Deymo41a75a72014-04-15 15:36:22 -070026using testing::Return;
27using testing::StrictMock;
28using testing::_;
Alex Deymo23949d42014-02-05 15:20:59 -080029
Gilad Arnoldfb794f42014-07-01 15:36:31 -070030namespace chromeos_update_manager {
31
Alex Deymo53556ec2014-03-17 10:05:57 -070032namespace {
33
34void DoNothing() {}
35
36// Sets the value of the passed pointer to true.
37void SetTrue(bool* value) {
38 *value = true;
39}
40
41bool GetBoolean(bool* value) {
42 return *value;
43}
44
Gilad Arnoldfb794f42014-07-01 15:36:31 -070045template<typename T>
46void ReadVar(scoped_refptr<EvaluationContext> ec, Variable<T>* var) {
47 ec->GetValue(var);
48}
Alex Deymo53556ec2014-03-17 10:05:57 -070049
Gilad Arnoldfb794f42014-07-01 15:36:31 -070050// Runs |evaluation|; if the value pointed by |count_p| is greater than zero,
51// decrement it and schedule a reevaluation; otherwise, writes true to |done_p|.
52void EvaluateRepeatedly(Closure evaluation, scoped_refptr<EvaluationContext> ec,
53 int* count_p, bool* done_p) {
54 evaluation.Run();
55
56 // Schedule reevaluation if needed.
57 if (*count_p > 0) {
58 Closure closure = Bind(EvaluateRepeatedly, evaluation, ec, count_p, done_p);
59 ASSERT_TRUE(ec->RunOnValueChangeOrTimeout(closure))
60 << "Failed to schedule reevaluation, count_p=" << *count_p;
61 (*count_p)--;
62 } else {
63 *done_p = true;
64 }
65}
66
67} // namespace
Alex Deymo23949d42014-02-05 15:20:59 -080068
Alex Deymo63784a52014-05-28 10:46:14 -070069class UmEvaluationContextTest : public ::testing::Test {
Alex Deymo23949d42014-02-05 15:20:59 -080070 protected:
71 virtual void SetUp() {
Alex Deymo41a75a72014-04-15 15:36:22 -070072 // Set the clock to a fixed values.
73 fake_clock_.SetMonotonicTime(Time::FromInternalValue(12345678L));
David Zeuthenc1490282014-04-29 16:25:03 -070074 // Mar 2, 2006 1:23:45 UTC is 1141262625 since the Unix Epoch.
75 fake_clock_.SetWallclockTime(Time::FromTimeT(1141262625));
Gilad Arnoldb2271992014-06-19 12:35:24 -070076 eval_ctx_ = new EvaluationContext(&fake_clock_, default_timeout_);
Alex Deymo23949d42014-02-05 15:20:59 -080077 }
78
Alex Deymo53556ec2014-03-17 10:05:57 -070079 virtual void TearDown() {
Gilad Arnoldfb794f42014-07-01 15:36:31 -070080 // Ensure that the evaluation context did not leak and is actually being
81 // destroyed.
82 if (eval_ctx_) {
83 base::WeakPtr<EvaluationContext> eval_ctx_weak_alias =
84 eval_ctx_->weak_ptr_factory_.GetWeakPtr();
85 UMTEST_ASSERT_NOT_NULL(eval_ctx_weak_alias.get());
86 eval_ctx_ = nullptr;
87 UMTEST_EXPECT_NULL(eval_ctx_weak_alias.get())
88 << "The evaluation context was not destroyed! This is likely a bug "
89 "in how the test was written, look for leaking handles to the EC, "
90 "possibly through closure objects.";
91 }
92
Alex Deymo53556ec2014-03-17 10:05:57 -070093 // Check that the evaluation context removed all the observers.
94 EXPECT_TRUE(fake_int_var_.observer_list_.empty());
95 EXPECT_TRUE(fake_async_var_.observer_list_.empty());
96 EXPECT_TRUE(fake_const_var_.observer_list_.empty());
97 EXPECT_TRUE(fake_poll_var_.observer_list_.empty());
98 }
99
Alex Deymo41a75a72014-04-15 15:36:22 -0700100 base::TimeDelta default_timeout_ = base::TimeDelta::FromSeconds(5);
101
102 FakeClock fake_clock_;
Alex Deymo7b948f02014-03-10 17:01:10 -0700103 scoped_refptr<EvaluationContext> eval_ctx_;
Alex Deymo53556ec2014-03-17 10:05:57 -0700104
105 // FakeVariables used for testing the EvaluationContext. These are required
106 // here to prevent them from going away *before* the EvaluationContext under
107 // test does, which keeps a reference to them.
David Zeuthenc1490282014-04-29 16:25:03 -0700108 FakeVariable<bool> fail_var_ = {"fail_var", kVariableModePoll};
Alex Deymo53556ec2014-03-17 10:05:57 -0700109 FakeVariable<int> fake_int_var_ = {"fake_int", kVariableModePoll};
110 FakeVariable<string> fake_async_var_ = {"fake_async", kVariableModeAsync};
111 FakeVariable<string> fake_const_var_ = {"fake_const", kVariableModeConst};
112 FakeVariable<string> fake_poll_var_ = {"fake_poll",
113 TimeDelta::FromSeconds(1)};
Gilad Arnoldfb794f42014-07-01 15:36:31 -0700114 StrictMock<MockVariable<string>> mock_var_async_ {
115 "mock_var_async", kVariableModeAsync};
116 StrictMock<MockVariable<string>> mock_var_poll_ {
117 "mock_var_poll", kVariableModePoll};
Alex Deymo23949d42014-02-05 15:20:59 -0800118};
119
Alex Deymo63784a52014-05-28 10:46:14 -0700120TEST_F(UmEvaluationContextTest, GetValueFails) {
Alex Deymo23949d42014-02-05 15:20:59 -0800121 // FakeVariable is initialized as returning NULL.
Alex Deymo63784a52014-05-28 10:46:14 -0700122 UMTEST_EXPECT_NULL(eval_ctx_->GetValue(&fake_int_var_));
Alex Deymo23949d42014-02-05 15:20:59 -0800123}
124
Alex Deymo63784a52014-05-28 10:46:14 -0700125TEST_F(UmEvaluationContextTest, GetValueFailsWithInvalidVar) {
126 UMTEST_EXPECT_NULL(eval_ctx_->GetValue(
Alex Deymo23949d42014-02-05 15:20:59 -0800127 reinterpret_cast<Variable<int>*>(NULL)));
128}
129
Alex Deymo63784a52014-05-28 10:46:14 -0700130TEST_F(UmEvaluationContextTest, GetValueReturns) {
Alex Deymo23949d42014-02-05 15:20:59 -0800131 const int* p_fake_int;
132
133 fake_int_var_.reset(new int(42));
134 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymo63784a52014-05-28 10:46:14 -0700135 UMTEST_ASSERT_NOT_NULL(p_fake_int);
Alex Deymo23949d42014-02-05 15:20:59 -0800136 EXPECT_EQ(42, *p_fake_int);
137}
138
Alex Deymo63784a52014-05-28 10:46:14 -0700139TEST_F(UmEvaluationContextTest, GetValueCached) {
Alex Deymo23949d42014-02-05 15:20:59 -0800140 const int* p_fake_int;
141
142 fake_int_var_.reset(new int(42));
143 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
144
145 // Check that if the variable changes, the EvaluationContext keeps returning
146 // the cached value.
147 fake_int_var_.reset(new int(5));
148
149 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymo63784a52014-05-28 10:46:14 -0700150 UMTEST_ASSERT_NOT_NULL(p_fake_int);
Alex Deymo23949d42014-02-05 15:20:59 -0800151 EXPECT_EQ(42, *p_fake_int);
152}
153
Alex Deymo63784a52014-05-28 10:46:14 -0700154TEST_F(UmEvaluationContextTest, GetValueCachesNull) {
Alex Deymo23949d42014-02-05 15:20:59 -0800155 const int* p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymo63784a52014-05-28 10:46:14 -0700156 UMTEST_EXPECT_NULL(p_fake_int);
Alex Deymo23949d42014-02-05 15:20:59 -0800157
158 fake_int_var_.reset(new int(42));
Alex Deymocc0e5cf2014-04-23 20:20:11 -0700159 // A second attempt to read the variable should not work because this
160 // EvaluationContext already got a NULL value.
Alex Deymo23949d42014-02-05 15:20:59 -0800161 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymo63784a52014-05-28 10:46:14 -0700162 UMTEST_EXPECT_NULL(p_fake_int);
Alex Deymo23949d42014-02-05 15:20:59 -0800163}
164
Alex Deymo63784a52014-05-28 10:46:14 -0700165TEST_F(UmEvaluationContextTest, GetValueMixedTypes) {
Alex Deymo23949d42014-02-05 15:20:59 -0800166 const int* p_fake_int;
167 const string* p_fake_string;
168
169 fake_int_var_.reset(new int(42));
Alex Deymo53556ec2014-03-17 10:05:57 -0700170 fake_poll_var_.reset(new string("Hello world!"));
Alex Deymo23949d42014-02-05 15:20:59 -0800171 // Check that the EvaluationContext can handle multiple Variable types. This
172 // is mostly a compile-time check due to the template nature of this method.
173 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymo53556ec2014-03-17 10:05:57 -0700174 p_fake_string = eval_ctx_->GetValue(&fake_poll_var_);
Alex Deymo23949d42014-02-05 15:20:59 -0800175
Alex Deymo63784a52014-05-28 10:46:14 -0700176 UMTEST_ASSERT_NOT_NULL(p_fake_int);
Alex Deymo23949d42014-02-05 15:20:59 -0800177 EXPECT_EQ(42, *p_fake_int);
178
Alex Deymo63784a52014-05-28 10:46:14 -0700179 UMTEST_ASSERT_NOT_NULL(p_fake_string);
Alex Deymo23949d42014-02-05 15:20:59 -0800180 EXPECT_EQ("Hello world!", *p_fake_string);
181}
182
Alex Deymo53556ec2014-03-17 10:05:57 -0700183// Test that we don't schedule an event if there's no variable to wait for.
Alex Deymo63784a52014-05-28 10:46:14 -0700184TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutWithoutVariablesTest) {
Alex Deymo53556ec2014-03-17 10:05:57 -0700185 fake_const_var_.reset(new string("Hello world!"));
186 EXPECT_EQ(*eval_ctx_->GetValue(&fake_const_var_), "Hello world!");
187
188 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
189}
190
Gilad Arnoldfb794f42014-07-01 15:36:31 -0700191// Test that reevaluation occurs when an async variable it depends on changes.
Alex Deymo63784a52014-05-28 10:46:14 -0700192TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutWithVariablesTest) {
Alex Deymo53556ec2014-03-17 10:05:57 -0700193 fake_async_var_.reset(new string("Async value"));
194 eval_ctx_->GetValue(&fake_async_var_);
195
196 bool value = false;
197 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
198 // Check that the scheduled callback isn't run until we signal a ValueChaged.
199 RunGMainLoopMaxIterations(100);
200 EXPECT_FALSE(value);
201
202 fake_async_var_.NotifyValueChanged();
203 EXPECT_FALSE(value);
204 // Ensure that the scheduled callback isn't run until we are back on the main
205 // loop.
206 RunGMainLoopMaxIterations(100);
207 EXPECT_TRUE(value);
208}
209
210// Test that we don't re-schedule the events if we are attending one.
Alex Deymo63784a52014-05-28 10:46:14 -0700211TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutCalledTwiceTest) {
Alex Deymo53556ec2014-03-17 10:05:57 -0700212 fake_async_var_.reset(new string("Async value"));
213 eval_ctx_->GetValue(&fake_async_var_);
214
215 bool value = false;
216 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
217 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
218
219 // The scheduled event should still work.
220 fake_async_var_.NotifyValueChanged();
221 RunGMainLoopMaxIterations(100);
222 EXPECT_TRUE(value);
223}
224
225// Test that we clear the events when destroying the EvaluationContext.
Alex Deymo63784a52014-05-28 10:46:14 -0700226TEST_F(UmEvaluationContextTest, RemoveObserversAndTimeoutTest) {
Alex Deymo53556ec2014-03-17 10:05:57 -0700227 fake_async_var_.reset(new string("Async value"));
228 eval_ctx_->GetValue(&fake_async_var_);
229
230 bool value = false;
231 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
232 eval_ctx_ = NULL;
233
234 // This should not trigger the callback since the EvaluationContext waiting
235 // for it is gone, and it should have remove all its observers.
236 fake_async_var_.NotifyValueChanged();
237 RunGMainLoopMaxIterations(100);
238 EXPECT_FALSE(value);
239}
240
Gilad Arnoldfb794f42014-07-01 15:36:31 -0700241// Test that reevaluation occurs when a polling timeout fires.
Alex Deymo63784a52014-05-28 10:46:14 -0700242TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutRunsFromTimeoutTest) {
Alex Deymo53556ec2014-03-17 10:05:57 -0700243 fake_poll_var_.reset(new string("Polled value"));
244 eval_ctx_->GetValue(&fake_poll_var_);
245
246 bool value = false;
247 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
248 // Check that the scheduled callback isn't run until the timeout occurs.
249 RunGMainLoopMaxIterations(10);
250 EXPECT_FALSE(value);
251 RunGMainLoopUntil(10000, Bind(&GetBoolean, &value));
252 EXPECT_TRUE(value);
253}
254
Gilad Arnoldfb794f42014-07-01 15:36:31 -0700255// Scheduling two reevaluations from the callback should succeed.
256TEST_F(UmEvaluationContextTest,
257 RunOnValueChangeOrTimeoutReevaluatesRepeatedly) {
258 fake_poll_var_.reset(new string("Polled value"));
259 Closure evaluation = Bind(ReadVar<string>, eval_ctx_, &fake_poll_var_);
260 int num_reevaluations = 2;
261 bool done = false;
262
263 // Run the evaluation once.
264 evaluation.Run();
265
266 // Schedule repeated reevaluations.
267 Closure closure = Bind(EvaluateRepeatedly, evaluation, eval_ctx_,
268 &num_reevaluations, &done);
269 ASSERT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(closure));
270 RunGMainLoopUntil(10000, Bind(&GetBoolean, &done));
271 EXPECT_EQ(0, num_reevaluations);
272}
273
Alex Deymodb799532014-03-21 13:00:00 -0700274// Test that we can delete the EvaluationContext while having pending events.
Alex Deymo63784a52014-05-28 10:46:14 -0700275TEST_F(UmEvaluationContextTest, ObjectDeletedWithPendingEventsTest) {
Alex Deymodb799532014-03-21 13:00:00 -0700276 fake_async_var_.reset(new string("Async value"));
277 fake_poll_var_.reset(new string("Polled value"));
278 eval_ctx_->GetValue(&fake_async_var_);
279 eval_ctx_->GetValue(&fake_poll_var_);
280 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
281 // TearDown() checks for leaked observers on this async_variable, which means
282 // that our object is still alive after removing its reference.
283}
284
285// Test that timed events fired after removal of the EvaluationContext don't
286// crash.
Alex Deymo63784a52014-05-28 10:46:14 -0700287TEST_F(UmEvaluationContextTest, TimeoutEventAfterDeleteTest) {
Alex Deymodb799532014-03-21 13:00:00 -0700288 FakeVariable<string> fake_short_poll_var = {"fake_short_poll", TimeDelta()};
289 fake_short_poll_var.reset(new string("Polled value"));
290 eval_ctx_->GetValue(&fake_short_poll_var);
291 bool value = false;
292 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
293 // Remove the last reference to the EvaluationContext and run the loop for
294 // 1 second to give time to the main loop to trigger the timeout Event (of 0
295 // seconds). Our callback should not be called because the EvaluationContext
296 // was removed before the timeout event is attended.
297 eval_ctx_ = NULL;
298 RunGMainLoopUntil(1000, Bind(&GetBoolean, &value));
299 EXPECT_FALSE(value);
300}
301
Alex Deymo63784a52014-05-28 10:46:14 -0700302TEST_F(UmEvaluationContextTest, DefaultTimeout) {
Alex Deymo41a75a72014-04-15 15:36:22 -0700303 // Test that the RemainingTime() uses the default timeout on setup.
304 EXPECT_CALL(mock_var_async_, GetValue(default_timeout_, _))
305 .WillOnce(Return(nullptr));
Alex Deymo63784a52014-05-28 10:46:14 -0700306 UMTEST_EXPECT_NULL(eval_ctx_->GetValue(&mock_var_async_));
Alex Deymo41a75a72014-04-15 15:36:22 -0700307}
308
Alex Deymo63784a52014-05-28 10:46:14 -0700309TEST_F(UmEvaluationContextTest, TimeoutUpdatesWithMonotonicTime) {
Alex Deymo41a75a72014-04-15 15:36:22 -0700310 fake_clock_.SetMonotonicTime(
311 fake_clock_.GetMonotonicTime() + TimeDelta::FromSeconds(1));
312
313 TimeDelta timeout = default_timeout_ - TimeDelta::FromSeconds(1);
314
315 EXPECT_CALL(mock_var_async_, GetValue(timeout, _))
316 .WillOnce(Return(nullptr));
Alex Deymo63784a52014-05-28 10:46:14 -0700317 UMTEST_EXPECT_NULL(eval_ctx_->GetValue(&mock_var_async_));
Alex Deymo41a75a72014-04-15 15:36:22 -0700318}
319
Alex Deymo63784a52014-05-28 10:46:14 -0700320TEST_F(UmEvaluationContextTest, ResetEvaluationResetsTimes) {
Alex Deymo41a75a72014-04-15 15:36:22 -0700321 base::Time cur_time = fake_clock_.GetWallclockTime();
322 // Advance the time on the clock but don't call ResetEvaluation yet.
323 fake_clock_.SetWallclockTime(cur_time + TimeDelta::FromSeconds(4));
324
325 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(cur_time -
326 TimeDelta::FromSeconds(1)));
327 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time));
328 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time +
329 TimeDelta::FromSeconds(1)));
330 // Call ResetEvaluation now, which should use the new evaluation time.
331 eval_ctx_->ResetEvaluation();
332
333 cur_time = fake_clock_.GetWallclockTime();
334 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(cur_time -
335 TimeDelta::FromSeconds(1)));
336 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time));
337 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time +
338 TimeDelta::FromSeconds(1)));
339}
340
Alex Deymo63784a52014-05-28 10:46:14 -0700341TEST_F(UmEvaluationContextTest, IsTimeGreaterThanSignalsTriggerReevaluation) {
Alex Deymo41a75a72014-04-15 15:36:22 -0700342 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(
343 fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(1)));
344
345 // The "false" from IsTimeGreaterThan means that's not that timestamp yet, so
346 // this should schedule a callback for when that happens.
347 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
348}
349
Alex Deymo63784a52014-05-28 10:46:14 -0700350TEST_F(UmEvaluationContextTest, IsTimeGreaterThanDoesntRecordPastTimestamps) {
Alex Deymo41a75a72014-04-15 15:36:22 -0700351 // IsTimeGreaterThan() should ignore timestamps on the past for reevaluation.
352 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(
353 fake_clock_.GetWallclockTime() - TimeDelta::FromSeconds(20)));
354 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(
355 fake_clock_.GetWallclockTime() - TimeDelta::FromSeconds(1)));
356
357 // Callback should not be scheduled.
358 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
359}
360
Alex Deymo63784a52014-05-28 10:46:14 -0700361TEST_F(UmEvaluationContextTest, DumpContext) {
David Zeuthenc1490282014-04-29 16:25:03 -0700362 // |fail_var_| yield "(no value)" since it is unset.
363 eval_ctx_->GetValue(&fail_var_);
364
365 // Check that this is included.
366 fake_int_var_.reset(new int(42));
367 eval_ctx_->GetValue(&fake_int_var_);
368
369 // Check that double-quotes are escaped properly.
370 fake_poll_var_.reset(new string("Hello \"world\"!"));
371 eval_ctx_->GetValue(&fake_poll_var_);
372
373 // Note that the variables are printed in alphabetical order. Also
Alex Deymo63784a52014-05-28 10:46:14 -0700374 // see UmEvaluationContextText::SetUp() where the value used for
David Zeuthenc1490282014-04-29 16:25:03 -0700375 // |evaluation_start| is set.
376 EXPECT_EQ("{\n"
377 " \"evaluation_start\": \"3/2/2006 1:23:45 GMT\",\n"
378 " \"variables\": {\n"
379 " \"fail_var\": \"(no value)\",\n"
380 " \"fake_int\": \"42\",\n"
381 " \"fake_poll\": \"Hello \\\"world\\\"!\"\n"
382 " }\n"
383 "}\n",
384 eval_ctx_->DumpContext());
385}
386
Alex Deymo63784a52014-05-28 10:46:14 -0700387} // namespace chromeos_update_manager