blob: 1ddec84a7aec97465952be8198e08d46a115fc2c [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>
8#include <base/memory/scoped_ptr.h>
9#include <gtest/gtest.h>
10
Alex Deymo41a75a72014-04-15 15:36:22 -070011#include "update_engine/fake_clock.h"
Alex Deymo23949d42014-02-05 15:20:59 -080012#include "update_engine/policy_manager/evaluation_context.h"
Alex Deymo53556ec2014-03-17 10:05:57 -070013#include "update_engine/policy_manager/fake_variable.h"
Alex Deymo23949d42014-02-05 15:20:59 -080014#include "update_engine/policy_manager/generic_variables.h"
Alex Deymo41a75a72014-04-15 15:36:22 -070015#include "update_engine/policy_manager/mock_variable.h"
Alex Deymo23949d42014-02-05 15:20:59 -080016#include "update_engine/policy_manager/pmtest_utils.h"
Alex Deymo53556ec2014-03-17 10:05:57 -070017#include "update_engine/test_utils.h"
Alex Deymo23949d42014-02-05 15:20:59 -080018
Alex Deymo53556ec2014-03-17 10:05:57 -070019using base::Bind;
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
Alex Deymo53556ec2014-03-17 10:05:57 -070030namespace {
31
32void DoNothing() {}
33
34// Sets the value of the passed pointer to true.
35void SetTrue(bool* value) {
36 *value = true;
37}
38
39bool GetBoolean(bool* value) {
40 return *value;
41}
42
43} // namespace
44
Alex Deymo23949d42014-02-05 15:20:59 -080045namespace chromeos_policy_manager {
46
47class PmEvaluationContextTest : public ::testing::Test {
Alex Deymo23949d42014-02-05 15:20:59 -080048 protected:
49 virtual void SetUp() {
Alex Deymo41a75a72014-04-15 15:36:22 -070050 // Set the clock to a fixed values.
51 fake_clock_.SetMonotonicTime(Time::FromInternalValue(12345678L));
52 fake_clock_.SetWallclockTime(Time::FromInternalValue(12345678901234L));
53 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.
75 FakeVariable<int> fake_int_var_ = {"fake_int", kVariableModePoll};
76 FakeVariable<string> fake_async_var_ = {"fake_async", kVariableModeAsync};
77 FakeVariable<string> fake_const_var_ = {"fake_const", kVariableModeConst};
78 FakeVariable<string> fake_poll_var_ = {"fake_poll",
79 TimeDelta::FromSeconds(1)};
Alex Deymo41a75a72014-04-15 15:36:22 -070080 StrictMock<MockVariable<string>> mock_var_async_{"mock_var_async",
81 kVariableModeAsync};
82 StrictMock<MockVariable<string>> mock_var_poll_{"mock_var_poll",
83 kVariableModePoll};
Alex Deymo23949d42014-02-05 15:20:59 -080084};
85
86TEST_F(PmEvaluationContextTest, GetValueFails) {
87 // FakeVariable is initialized as returning NULL.
88 PMTEST_EXPECT_NULL(eval_ctx_->GetValue(&fake_int_var_));
89}
90
91TEST_F(PmEvaluationContextTest, GetValueFailsWithInvalidVar) {
92 PMTEST_EXPECT_NULL(eval_ctx_->GetValue(
93 reinterpret_cast<Variable<int>*>(NULL)));
94}
95
96TEST_F(PmEvaluationContextTest, GetValueReturns) {
97 const int* p_fake_int;
98
99 fake_int_var_.reset(new int(42));
100 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
101 PMTEST_ASSERT_NOT_NULL(p_fake_int);
102 EXPECT_EQ(42, *p_fake_int);
103}
104
105TEST_F(PmEvaluationContextTest, GetValueCached) {
106 const int* p_fake_int;
107
108 fake_int_var_.reset(new int(42));
109 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
110
111 // Check that if the variable changes, the EvaluationContext keeps returning
112 // the cached value.
113 fake_int_var_.reset(new int(5));
114
115 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
116 PMTEST_ASSERT_NOT_NULL(p_fake_int);
117 EXPECT_EQ(42, *p_fake_int);
118}
119
Alex Deymocc0e5cf2014-04-23 20:20:11 -0700120TEST_F(PmEvaluationContextTest, GetValueCachesNull) {
Alex Deymo23949d42014-02-05 15:20:59 -0800121 const int* p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
122 PMTEST_EXPECT_NULL(p_fake_int);
123
124 fake_int_var_.reset(new int(42));
Alex Deymocc0e5cf2014-04-23 20:20:11 -0700125 // A second attempt to read the variable should not work because this
126 // EvaluationContext already got a NULL value.
Alex Deymo23949d42014-02-05 15:20:59 -0800127 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymocc0e5cf2014-04-23 20:20:11 -0700128 PMTEST_EXPECT_NULL(p_fake_int);
Alex Deymo23949d42014-02-05 15:20:59 -0800129}
130
131TEST_F(PmEvaluationContextTest, GetValueMixedTypes) {
Alex Deymo23949d42014-02-05 15:20:59 -0800132 const int* p_fake_int;
133 const string* p_fake_string;
134
135 fake_int_var_.reset(new int(42));
Alex Deymo53556ec2014-03-17 10:05:57 -0700136 fake_poll_var_.reset(new string("Hello world!"));
Alex Deymo23949d42014-02-05 15:20:59 -0800137 // Check that the EvaluationContext can handle multiple Variable types. This
138 // is mostly a compile-time check due to the template nature of this method.
139 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymo53556ec2014-03-17 10:05:57 -0700140 p_fake_string = eval_ctx_->GetValue(&fake_poll_var_);
Alex Deymo23949d42014-02-05 15:20:59 -0800141
142 PMTEST_ASSERT_NOT_NULL(p_fake_int);
143 EXPECT_EQ(42, *p_fake_int);
144
145 PMTEST_ASSERT_NOT_NULL(p_fake_string);
146 EXPECT_EQ("Hello world!", *p_fake_string);
147}
148
Alex Deymo53556ec2014-03-17 10:05:57 -0700149// Test that we don't schedule an event if there's no variable to wait for.
150TEST_F(PmEvaluationContextTest, RunOnValueChangeOrTimeoutWithoutVariablesTest) {
151 fake_const_var_.reset(new string("Hello world!"));
152 EXPECT_EQ(*eval_ctx_->GetValue(&fake_const_var_), "Hello world!");
153
154 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
155}
156
157// Test that we don't schedule an event if there's no variable to wait for.
158TEST_F(PmEvaluationContextTest, RunOnValueChangeOrTimeoutWithVariablesTest) {
159 fake_async_var_.reset(new string("Async value"));
160 eval_ctx_->GetValue(&fake_async_var_);
161
162 bool value = false;
163 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
164 // Check that the scheduled callback isn't run until we signal a ValueChaged.
165 RunGMainLoopMaxIterations(100);
166 EXPECT_FALSE(value);
167
168 fake_async_var_.NotifyValueChanged();
169 EXPECT_FALSE(value);
170 // Ensure that the scheduled callback isn't run until we are back on the main
171 // loop.
172 RunGMainLoopMaxIterations(100);
173 EXPECT_TRUE(value);
174}
175
176// Test that we don't re-schedule the events if we are attending one.
177TEST_F(PmEvaluationContextTest, RunOnValueChangeOrTimeoutCalledTwiceTest) {
178 fake_async_var_.reset(new string("Async value"));
179 eval_ctx_->GetValue(&fake_async_var_);
180
181 bool value = false;
182 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
183 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
184
185 // The scheduled event should still work.
186 fake_async_var_.NotifyValueChanged();
187 RunGMainLoopMaxIterations(100);
188 EXPECT_TRUE(value);
189}
190
191// Test that we clear the events when destroying the EvaluationContext.
192TEST_F(PmEvaluationContextTest, RemoveObserversAndTimeoutTest) {
193 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 eval_ctx_ = NULL;
199
200 // This should not trigger the callback since the EvaluationContext waiting
201 // for it is gone, and it should have remove all its observers.
202 fake_async_var_.NotifyValueChanged();
203 RunGMainLoopMaxIterations(100);
204 EXPECT_FALSE(value);
205}
206
207// Test that we don't schedule an event if there's no variable to wait for.
208TEST_F(PmEvaluationContextTest, RunOnValueChangeOrTimeoutRunsFromTimeoutTest) {
209 fake_poll_var_.reset(new string("Polled value"));
210 eval_ctx_->GetValue(&fake_poll_var_);
211
212 bool value = false;
213 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
214 // Check that the scheduled callback isn't run until the timeout occurs.
215 RunGMainLoopMaxIterations(10);
216 EXPECT_FALSE(value);
217 RunGMainLoopUntil(10000, Bind(&GetBoolean, &value));
218 EXPECT_TRUE(value);
219}
220
Alex Deymodb799532014-03-21 13:00:00 -0700221// Test that we can delete the EvaluationContext while having pending events.
222TEST_F(PmEvaluationContextTest, ObjectDeletedWithPendingEventsTest) {
223 fake_async_var_.reset(new string("Async value"));
224 fake_poll_var_.reset(new string("Polled value"));
225 eval_ctx_->GetValue(&fake_async_var_);
226 eval_ctx_->GetValue(&fake_poll_var_);
227 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
228 // TearDown() checks for leaked observers on this async_variable, which means
229 // that our object is still alive after removing its reference.
230}
231
232// Test that timed events fired after removal of the EvaluationContext don't
233// crash.
234TEST_F(PmEvaluationContextTest, TimeoutEventAfterDeleteTest) {
235 FakeVariable<string> fake_short_poll_var = {"fake_short_poll", TimeDelta()};
236 fake_short_poll_var.reset(new string("Polled value"));
237 eval_ctx_->GetValue(&fake_short_poll_var);
238 bool value = false;
239 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
240 // Remove the last reference to the EvaluationContext and run the loop for
241 // 1 second to give time to the main loop to trigger the timeout Event (of 0
242 // seconds). Our callback should not be called because the EvaluationContext
243 // was removed before the timeout event is attended.
244 eval_ctx_ = NULL;
245 RunGMainLoopUntil(1000, Bind(&GetBoolean, &value));
246 EXPECT_FALSE(value);
247}
248
Alex Deymo41a75a72014-04-15 15:36:22 -0700249TEST_F(PmEvaluationContextTest, DefaultTimeout) {
250 // Test that the RemainingTime() uses the default timeout on setup.
251 EXPECT_CALL(mock_var_async_, GetValue(default_timeout_, _))
252 .WillOnce(Return(nullptr));
253 PMTEST_EXPECT_NULL(eval_ctx_->GetValue(&mock_var_async_));
254}
255
256TEST_F(PmEvaluationContextTest, TimeoutUpdatesWithMonotonicTime) {
257 fake_clock_.SetMonotonicTime(
258 fake_clock_.GetMonotonicTime() + TimeDelta::FromSeconds(1));
259
260 TimeDelta timeout = default_timeout_ - TimeDelta::FromSeconds(1);
261
262 EXPECT_CALL(mock_var_async_, GetValue(timeout, _))
263 .WillOnce(Return(nullptr));
264 PMTEST_EXPECT_NULL(eval_ctx_->GetValue(&mock_var_async_));
265}
266
267TEST_F(PmEvaluationContextTest, ResetEvaluationResetsTimes) {
268 base::Time cur_time = fake_clock_.GetWallclockTime();
269 // Advance the time on the clock but don't call ResetEvaluation yet.
270 fake_clock_.SetWallclockTime(cur_time + TimeDelta::FromSeconds(4));
271
272 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(cur_time -
273 TimeDelta::FromSeconds(1)));
274 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time));
275 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time +
276 TimeDelta::FromSeconds(1)));
277 // Call ResetEvaluation now, which should use the new evaluation time.
278 eval_ctx_->ResetEvaluation();
279
280 cur_time = fake_clock_.GetWallclockTime();
281 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(cur_time -
282 TimeDelta::FromSeconds(1)));
283 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time));
284 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time +
285 TimeDelta::FromSeconds(1)));
286}
287
288TEST_F(PmEvaluationContextTest, IsTimeGreaterThanSignalsTriggerReevaluation) {
289 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(
290 fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(1)));
291
292 // The "false" from IsTimeGreaterThan means that's not that timestamp yet, so
293 // this should schedule a callback for when that happens.
294 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
295}
296
297TEST_F(PmEvaluationContextTest, IsTimeGreaterThanDoesntRecordPastTimestamps) {
298 // IsTimeGreaterThan() should ignore timestamps on the past for reevaluation.
299 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(
300 fake_clock_.GetWallclockTime() - TimeDelta::FromSeconds(20)));
301 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(
302 fake_clock_.GetWallclockTime() - TimeDelta::FromSeconds(1)));
303
304 // Callback should not be scheduled.
305 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
306}
307
Alex Deymo23949d42014-02-05 15:20:59 -0800308} // namespace chromeos_policy_manager