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