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