blob: ccc49c95889e1bc233dbb4655e7ea45bf8d00bf7 [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 Deymo23949d42014-02-05 15:20:59 -080011#include "update_engine/policy_manager/evaluation_context.h"
Alex Deymo53556ec2014-03-17 10:05:57 -070012#include "update_engine/policy_manager/fake_variable.h"
Alex Deymo23949d42014-02-05 15:20:59 -080013#include "update_engine/policy_manager/generic_variables.h"
Alex Deymo41a75a72014-04-15 15:36:22 -070014#include "update_engine/policy_manager/mock_variable.h"
Alex Deymo23949d42014-02-05 15:20:59 -080015#include "update_engine/policy_manager/pmtest_utils.h"
Alex Deymo53556ec2014-03-17 10:05:57 -070016#include "update_engine/test_utils.h"
Alex Deymo23949d42014-02-05 15:20:59 -080017
Alex Deymo53556ec2014-03-17 10:05:57 -070018using base::Bind;
Alex Deymo41a75a72014-04-15 15:36:22 -070019using base::Time;
Alex Deymo53556ec2014-03-17 10:05:57 -070020using base::TimeDelta;
Alex Deymo41a75a72014-04-15 15:36:22 -070021using chromeos_update_engine::FakeClock;
Alex Deymo53556ec2014-03-17 10:05:57 -070022using chromeos_update_engine::RunGMainLoopMaxIterations;
23using chromeos_update_engine::RunGMainLoopUntil;
Alex Deymo23949d42014-02-05 15:20:59 -080024using std::string;
Alex Deymo41a75a72014-04-15 15:36:22 -070025using testing::Return;
26using testing::StrictMock;
27using testing::_;
Alex Deymo23949d42014-02-05 15:20:59 -080028
Alex Deymo53556ec2014-03-17 10:05:57 -070029namespace {
30
31void DoNothing() {}
32
33// Sets the value of the passed pointer to true.
34void SetTrue(bool* value) {
35 *value = true;
36}
37
38bool GetBoolean(bool* value) {
39 return *value;
40}
41
42} // namespace
43
Alex Deymo23949d42014-02-05 15:20:59 -080044namespace chromeos_policy_manager {
45
46class PmEvaluationContextTest : public ::testing::Test {
Alex Deymo23949d42014-02-05 15:20:59 -080047 protected:
48 virtual void SetUp() {
Alex Deymo41a75a72014-04-15 15:36:22 -070049 // Set the clock to a fixed values.
50 fake_clock_.SetMonotonicTime(Time::FromInternalValue(12345678L));
David Zeuthenc1490282014-04-29 16:25:03 -070051 // Mar 2, 2006 1:23:45 UTC is 1141262625 since the Unix Epoch.
52 fake_clock_.SetWallclockTime(Time::FromTimeT(1141262625));
Alex Deymo41a75a72014-04-15 15:36:22 -070053 eval_ctx_ = new EvaluationContext(&fake_clock_);
Alex Deymo23949d42014-02-05 15:20:59 -080054 }
55
Alex Deymo53556ec2014-03-17 10:05:57 -070056 virtual void TearDown() {
57 eval_ctx_ = NULL;
58 // Check that the evaluation context removed all the observers.
59 EXPECT_TRUE(fake_int_var_.observer_list_.empty());
60 EXPECT_TRUE(fake_async_var_.observer_list_.empty());
61 EXPECT_TRUE(fake_const_var_.observer_list_.empty());
62 EXPECT_TRUE(fake_poll_var_.observer_list_.empty());
63 }
64
Alex Deymo41a75a72014-04-15 15:36:22 -070065 // TODO(deymo): Update the default timeout to the one passed on construction.
66 // See crbug.com/363790
67 base::TimeDelta default_timeout_ = base::TimeDelta::FromSeconds(5);
68
69 FakeClock fake_clock_;
Alex Deymo7b948f02014-03-10 17:01:10 -070070 scoped_refptr<EvaluationContext> eval_ctx_;
Alex Deymo53556ec2014-03-17 10:05:57 -070071
72 // FakeVariables used for testing the EvaluationContext. These are required
73 // here to prevent them from going away *before* the EvaluationContext under
74 // test does, which keeps a reference to them.
David Zeuthenc1490282014-04-29 16:25:03 -070075 FakeVariable<bool> fail_var_ = {"fail_var", kVariableModePoll};
Alex Deymo53556ec2014-03-17 10:05:57 -070076 FakeVariable<int> fake_int_var_ = {"fake_int", kVariableModePoll};
77 FakeVariable<string> fake_async_var_ = {"fake_async", kVariableModeAsync};
78 FakeVariable<string> fake_const_var_ = {"fake_const", kVariableModeConst};
79 FakeVariable<string> fake_poll_var_ = {"fake_poll",
80 TimeDelta::FromSeconds(1)};
Alex Deymo41a75a72014-04-15 15:36:22 -070081 StrictMock<MockVariable<string>> mock_var_async_{"mock_var_async",
82 kVariableModeAsync};
83 StrictMock<MockVariable<string>> mock_var_poll_{"mock_var_poll",
84 kVariableModePoll};
Alex Deymo23949d42014-02-05 15:20:59 -080085};
86
87TEST_F(PmEvaluationContextTest, GetValueFails) {
88 // FakeVariable is initialized as returning NULL.
89 PMTEST_EXPECT_NULL(eval_ctx_->GetValue(&fake_int_var_));
90}
91
92TEST_F(PmEvaluationContextTest, GetValueFailsWithInvalidVar) {
93 PMTEST_EXPECT_NULL(eval_ctx_->GetValue(
94 reinterpret_cast<Variable<int>*>(NULL)));
95}
96
97TEST_F(PmEvaluationContextTest, GetValueReturns) {
98 const int* p_fake_int;
99
100 fake_int_var_.reset(new int(42));
101 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
102 PMTEST_ASSERT_NOT_NULL(p_fake_int);
103 EXPECT_EQ(42, *p_fake_int);
104}
105
106TEST_F(PmEvaluationContextTest, GetValueCached) {
107 const int* p_fake_int;
108
109 fake_int_var_.reset(new int(42));
110 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
111
112 // Check that if the variable changes, the EvaluationContext keeps returning
113 // the cached value.
114 fake_int_var_.reset(new int(5));
115
116 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
117 PMTEST_ASSERT_NOT_NULL(p_fake_int);
118 EXPECT_EQ(42, *p_fake_int);
119}
120
Alex Deymocc0e5cf2014-04-23 20:20:11 -0700121TEST_F(PmEvaluationContextTest, GetValueCachesNull) {
Alex Deymo23949d42014-02-05 15:20:59 -0800122 const int* p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
123 PMTEST_EXPECT_NULL(p_fake_int);
124
125 fake_int_var_.reset(new int(42));
Alex Deymocc0e5cf2014-04-23 20:20:11 -0700126 // A second attempt to read the variable should not work because this
127 // EvaluationContext already got a NULL value.
Alex Deymo23949d42014-02-05 15:20:59 -0800128 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymocc0e5cf2014-04-23 20:20:11 -0700129 PMTEST_EXPECT_NULL(p_fake_int);
Alex Deymo23949d42014-02-05 15:20:59 -0800130}
131
132TEST_F(PmEvaluationContextTest, GetValueMixedTypes) {
Alex Deymo23949d42014-02-05 15:20:59 -0800133 const int* p_fake_int;
134 const string* p_fake_string;
135
136 fake_int_var_.reset(new int(42));
Alex Deymo53556ec2014-03-17 10:05:57 -0700137 fake_poll_var_.reset(new string("Hello world!"));
Alex Deymo23949d42014-02-05 15:20:59 -0800138 // Check that the EvaluationContext can handle multiple Variable types. This
139 // is mostly a compile-time check due to the template nature of this method.
140 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymo53556ec2014-03-17 10:05:57 -0700141 p_fake_string = eval_ctx_->GetValue(&fake_poll_var_);
Alex Deymo23949d42014-02-05 15:20:59 -0800142
143 PMTEST_ASSERT_NOT_NULL(p_fake_int);
144 EXPECT_EQ(42, *p_fake_int);
145
146 PMTEST_ASSERT_NOT_NULL(p_fake_string);
147 EXPECT_EQ("Hello world!", *p_fake_string);
148}
149
Alex Deymo53556ec2014-03-17 10:05:57 -0700150// Test that we don't schedule an event if there's no variable to wait for.
151TEST_F(PmEvaluationContextTest, RunOnValueChangeOrTimeoutWithoutVariablesTest) {
152 fake_const_var_.reset(new string("Hello world!"));
153 EXPECT_EQ(*eval_ctx_->GetValue(&fake_const_var_), "Hello world!");
154
155 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
156}
157
158// Test that we don't schedule an event if there's no variable to wait for.
159TEST_F(PmEvaluationContextTest, RunOnValueChangeOrTimeoutWithVariablesTest) {
160 fake_async_var_.reset(new string("Async value"));
161 eval_ctx_->GetValue(&fake_async_var_);
162
163 bool value = false;
164 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
165 // Check that the scheduled callback isn't run until we signal a ValueChaged.
166 RunGMainLoopMaxIterations(100);
167 EXPECT_FALSE(value);
168
169 fake_async_var_.NotifyValueChanged();
170 EXPECT_FALSE(value);
171 // Ensure that the scheduled callback isn't run until we are back on the main
172 // loop.
173 RunGMainLoopMaxIterations(100);
174 EXPECT_TRUE(value);
175}
176
177// Test that we don't re-schedule the events if we are attending one.
178TEST_F(PmEvaluationContextTest, RunOnValueChangeOrTimeoutCalledTwiceTest) {
179 fake_async_var_.reset(new string("Async value"));
180 eval_ctx_->GetValue(&fake_async_var_);
181
182 bool value = false;
183 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
184 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
185
186 // The scheduled event should still work.
187 fake_async_var_.NotifyValueChanged();
188 RunGMainLoopMaxIterations(100);
189 EXPECT_TRUE(value);
190}
191
192// Test that we clear the events when destroying the EvaluationContext.
193TEST_F(PmEvaluationContextTest, RemoveObserversAndTimeoutTest) {
194 fake_async_var_.reset(new string("Async value"));
195 eval_ctx_->GetValue(&fake_async_var_);
196
197 bool value = false;
198 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
199 eval_ctx_ = NULL;
200
201 // This should not trigger the callback since the EvaluationContext waiting
202 // for it is gone, and it should have remove all its observers.
203 fake_async_var_.NotifyValueChanged();
204 RunGMainLoopMaxIterations(100);
205 EXPECT_FALSE(value);
206}
207
208// Test that we don't schedule an event if there's no variable to wait for.
209TEST_F(PmEvaluationContextTest, RunOnValueChangeOrTimeoutRunsFromTimeoutTest) {
210 fake_poll_var_.reset(new string("Polled value"));
211 eval_ctx_->GetValue(&fake_poll_var_);
212
213 bool value = false;
214 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
215 // Check that the scheduled callback isn't run until the timeout occurs.
216 RunGMainLoopMaxIterations(10);
217 EXPECT_FALSE(value);
218 RunGMainLoopUntil(10000, Bind(&GetBoolean, &value));
219 EXPECT_TRUE(value);
220}
221
Alex Deymodb799532014-03-21 13:00:00 -0700222// Test that we can delete the EvaluationContext while having pending events.
223TEST_F(PmEvaluationContextTest, ObjectDeletedWithPendingEventsTest) {
224 fake_async_var_.reset(new string("Async value"));
225 fake_poll_var_.reset(new string("Polled value"));
226 eval_ctx_->GetValue(&fake_async_var_);
227 eval_ctx_->GetValue(&fake_poll_var_);
228 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
229 // TearDown() checks for leaked observers on this async_variable, which means
230 // that our object is still alive after removing its reference.
231}
232
233// Test that timed events fired after removal of the EvaluationContext don't
234// crash.
235TEST_F(PmEvaluationContextTest, TimeoutEventAfterDeleteTest) {
236 FakeVariable<string> fake_short_poll_var = {"fake_short_poll", TimeDelta()};
237 fake_short_poll_var.reset(new string("Polled value"));
238 eval_ctx_->GetValue(&fake_short_poll_var);
239 bool value = false;
240 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
241 // Remove the last reference to the EvaluationContext and run the loop for
242 // 1 second to give time to the main loop to trigger the timeout Event (of 0
243 // seconds). Our callback should not be called because the EvaluationContext
244 // was removed before the timeout event is attended.
245 eval_ctx_ = NULL;
246 RunGMainLoopUntil(1000, Bind(&GetBoolean, &value));
247 EXPECT_FALSE(value);
248}
249
Alex Deymo41a75a72014-04-15 15:36:22 -0700250TEST_F(PmEvaluationContextTest, DefaultTimeout) {
251 // Test that the RemainingTime() uses the default timeout on setup.
252 EXPECT_CALL(mock_var_async_, GetValue(default_timeout_, _))
253 .WillOnce(Return(nullptr));
254 PMTEST_EXPECT_NULL(eval_ctx_->GetValue(&mock_var_async_));
255}
256
257TEST_F(PmEvaluationContextTest, TimeoutUpdatesWithMonotonicTime) {
258 fake_clock_.SetMonotonicTime(
259 fake_clock_.GetMonotonicTime() + TimeDelta::FromSeconds(1));
260
261 TimeDelta timeout = default_timeout_ - TimeDelta::FromSeconds(1);
262
263 EXPECT_CALL(mock_var_async_, GetValue(timeout, _))
264 .WillOnce(Return(nullptr));
265 PMTEST_EXPECT_NULL(eval_ctx_->GetValue(&mock_var_async_));
266}
267
268TEST_F(PmEvaluationContextTest, ResetEvaluationResetsTimes) {
269 base::Time cur_time = fake_clock_.GetWallclockTime();
270 // Advance the time on the clock but don't call ResetEvaluation yet.
271 fake_clock_.SetWallclockTime(cur_time + TimeDelta::FromSeconds(4));
272
273 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(cur_time -
274 TimeDelta::FromSeconds(1)));
275 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time));
276 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time +
277 TimeDelta::FromSeconds(1)));
278 // Call ResetEvaluation now, which should use the new evaluation time.
279 eval_ctx_->ResetEvaluation();
280
281 cur_time = fake_clock_.GetWallclockTime();
282 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(cur_time -
283 TimeDelta::FromSeconds(1)));
284 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time));
285 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time +
286 TimeDelta::FromSeconds(1)));
287}
288
289TEST_F(PmEvaluationContextTest, IsTimeGreaterThanSignalsTriggerReevaluation) {
290 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(
291 fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(1)));
292
293 // The "false" from IsTimeGreaterThan means that's not that timestamp yet, so
294 // this should schedule a callback for when that happens.
295 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
296}
297
298TEST_F(PmEvaluationContextTest, IsTimeGreaterThanDoesntRecordPastTimestamps) {
299 // IsTimeGreaterThan() should ignore timestamps on the past for reevaluation.
300 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(
301 fake_clock_.GetWallclockTime() - TimeDelta::FromSeconds(20)));
302 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(
303 fake_clock_.GetWallclockTime() - TimeDelta::FromSeconds(1)));
304
305 // Callback should not be scheduled.
306 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
307}
308
David Zeuthenc1490282014-04-29 16:25:03 -0700309TEST_F(PmEvaluationContextTest, DumpContext) {
310 // |fail_var_| yield "(no value)" since it is unset.
311 eval_ctx_->GetValue(&fail_var_);
312
313 // Check that this is included.
314 fake_int_var_.reset(new int(42));
315 eval_ctx_->GetValue(&fake_int_var_);
316
317 // Check that double-quotes are escaped properly.
318 fake_poll_var_.reset(new string("Hello \"world\"!"));
319 eval_ctx_->GetValue(&fake_poll_var_);
320
321 // Note that the variables are printed in alphabetical order. Also
322 // see PmEvaluationContextText::SetUp() where the value used for
323 // |evaluation_start| is set.
324 EXPECT_EQ("{\n"
325 " \"evaluation_start\": \"3/2/2006 1:23:45 GMT\",\n"
326 " \"variables\": {\n"
327 " \"fail_var\": \"(no value)\",\n"
328 " \"fake_int\": \"42\",\n"
329 " \"fake_poll\": \"Hello \\\"world\\\"!\"\n"
330 " }\n"
331 "}\n",
332 eval_ctx_->DumpContext());
333}
334
Alex Deymo23949d42014-02-05 15:20:59 -0800335} // namespace chromeos_policy_manager