blob: 9c51022b3fd3117ba586bb76cbc0323dc9607f57 [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;
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 Deymo63784a52014-05-28 10:46:14 -070044namespace chromeos_update_manager {
Alex Deymo23949d42014-02-05 15:20:59 -080045
Alex Deymo63784a52014-05-28 10:46:14 -070046class UmEvaluationContextTest : 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));
Gilad Arnoldb2271992014-06-19 12:35:24 -070053 eval_ctx_ = new EvaluationContext(&fake_clock_, default_timeout_);
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 base::TimeDelta default_timeout_ = base::TimeDelta::FromSeconds(5);
66
67 FakeClock fake_clock_;
Alex Deymo7b948f02014-03-10 17:01:10 -070068 scoped_refptr<EvaluationContext> eval_ctx_;
Alex Deymo53556ec2014-03-17 10:05:57 -070069
70 // FakeVariables used for testing the EvaluationContext. These are required
71 // here to prevent them from going away *before* the EvaluationContext under
72 // test does, which keeps a reference to them.
David Zeuthenc1490282014-04-29 16:25:03 -070073 FakeVariable<bool> fail_var_ = {"fail_var", kVariableModePoll};
Alex Deymo53556ec2014-03-17 10:05:57 -070074 FakeVariable<int> fake_int_var_ = {"fake_int", kVariableModePoll};
75 FakeVariable<string> fake_async_var_ = {"fake_async", kVariableModeAsync};
76 FakeVariable<string> fake_const_var_ = {"fake_const", kVariableModeConst};
77 FakeVariable<string> fake_poll_var_ = {"fake_poll",
78 TimeDelta::FromSeconds(1)};
Alex Deymo41a75a72014-04-15 15:36:22 -070079 StrictMock<MockVariable<string>> mock_var_async_{"mock_var_async",
80 kVariableModeAsync};
81 StrictMock<MockVariable<string>> mock_var_poll_{"mock_var_poll",
82 kVariableModePoll};
Alex Deymo23949d42014-02-05 15:20:59 -080083};
84
Alex Deymo63784a52014-05-28 10:46:14 -070085TEST_F(UmEvaluationContextTest, GetValueFails) {
Alex Deymo23949d42014-02-05 15:20:59 -080086 // FakeVariable is initialized as returning NULL.
Alex Deymo63784a52014-05-28 10:46:14 -070087 UMTEST_EXPECT_NULL(eval_ctx_->GetValue(&fake_int_var_));
Alex Deymo23949d42014-02-05 15:20:59 -080088}
89
Alex Deymo63784a52014-05-28 10:46:14 -070090TEST_F(UmEvaluationContextTest, GetValueFailsWithInvalidVar) {
91 UMTEST_EXPECT_NULL(eval_ctx_->GetValue(
Alex Deymo23949d42014-02-05 15:20:59 -080092 reinterpret_cast<Variable<int>*>(NULL)));
93}
94
Alex Deymo63784a52014-05-28 10:46:14 -070095TEST_F(UmEvaluationContextTest, GetValueReturns) {
Alex Deymo23949d42014-02-05 15:20:59 -080096 const int* p_fake_int;
97
98 fake_int_var_.reset(new int(42));
99 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymo63784a52014-05-28 10:46:14 -0700100 UMTEST_ASSERT_NOT_NULL(p_fake_int);
Alex Deymo23949d42014-02-05 15:20:59 -0800101 EXPECT_EQ(42, *p_fake_int);
102}
103
Alex Deymo63784a52014-05-28 10:46:14 -0700104TEST_F(UmEvaluationContextTest, GetValueCached) {
Alex Deymo23949d42014-02-05 15:20:59 -0800105 const int* p_fake_int;
106
107 fake_int_var_.reset(new int(42));
108 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
109
110 // Check that if the variable changes, the EvaluationContext keeps returning
111 // the cached value.
112 fake_int_var_.reset(new int(5));
113
114 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymo63784a52014-05-28 10:46:14 -0700115 UMTEST_ASSERT_NOT_NULL(p_fake_int);
Alex Deymo23949d42014-02-05 15:20:59 -0800116 EXPECT_EQ(42, *p_fake_int);
117}
118
Alex Deymo63784a52014-05-28 10:46:14 -0700119TEST_F(UmEvaluationContextTest, GetValueCachesNull) {
Alex Deymo23949d42014-02-05 15:20:59 -0800120 const int* p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymo63784a52014-05-28 10:46:14 -0700121 UMTEST_EXPECT_NULL(p_fake_int);
Alex Deymo23949d42014-02-05 15:20:59 -0800122
123 fake_int_var_.reset(new int(42));
Alex Deymocc0e5cf2014-04-23 20:20:11 -0700124 // A second attempt to read the variable should not work because this
125 // EvaluationContext already got a NULL value.
Alex Deymo23949d42014-02-05 15:20:59 -0800126 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymo63784a52014-05-28 10:46:14 -0700127 UMTEST_EXPECT_NULL(p_fake_int);
Alex Deymo23949d42014-02-05 15:20:59 -0800128}
129
Alex Deymo63784a52014-05-28 10:46:14 -0700130TEST_F(UmEvaluationContextTest, GetValueMixedTypes) {
Alex Deymo23949d42014-02-05 15:20:59 -0800131 const int* p_fake_int;
132 const string* p_fake_string;
133
134 fake_int_var_.reset(new int(42));
Alex Deymo53556ec2014-03-17 10:05:57 -0700135 fake_poll_var_.reset(new string("Hello world!"));
Alex Deymo23949d42014-02-05 15:20:59 -0800136 // Check that the EvaluationContext can handle multiple Variable types. This
137 // is mostly a compile-time check due to the template nature of this method.
138 p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
Alex Deymo53556ec2014-03-17 10:05:57 -0700139 p_fake_string = eval_ctx_->GetValue(&fake_poll_var_);
Alex Deymo23949d42014-02-05 15:20:59 -0800140
Alex Deymo63784a52014-05-28 10:46:14 -0700141 UMTEST_ASSERT_NOT_NULL(p_fake_int);
Alex Deymo23949d42014-02-05 15:20:59 -0800142 EXPECT_EQ(42, *p_fake_int);
143
Alex Deymo63784a52014-05-28 10:46:14 -0700144 UMTEST_ASSERT_NOT_NULL(p_fake_string);
Alex Deymo23949d42014-02-05 15:20:59 -0800145 EXPECT_EQ("Hello world!", *p_fake_string);
146}
147
Alex Deymo53556ec2014-03-17 10:05:57 -0700148// Test that we don't schedule an event if there's no variable to wait for.
Alex Deymo63784a52014-05-28 10:46:14 -0700149TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutWithoutVariablesTest) {
Alex Deymo53556ec2014-03-17 10:05:57 -0700150 fake_const_var_.reset(new string("Hello world!"));
151 EXPECT_EQ(*eval_ctx_->GetValue(&fake_const_var_), "Hello world!");
152
153 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
154}
155
156// Test that we don't schedule an event if there's no variable to wait for.
Alex Deymo63784a52014-05-28 10:46:14 -0700157TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutWithVariablesTest) {
Alex Deymo53556ec2014-03-17 10:05:57 -0700158 fake_async_var_.reset(new string("Async value"));
159 eval_ctx_->GetValue(&fake_async_var_);
160
161 bool value = false;
162 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
163 // Check that the scheduled callback isn't run until we signal a ValueChaged.
164 RunGMainLoopMaxIterations(100);
165 EXPECT_FALSE(value);
166
167 fake_async_var_.NotifyValueChanged();
168 EXPECT_FALSE(value);
169 // Ensure that the scheduled callback isn't run until we are back on the main
170 // loop.
171 RunGMainLoopMaxIterations(100);
172 EXPECT_TRUE(value);
173}
174
175// Test that we don't re-schedule the events if we are attending one.
Alex Deymo63784a52014-05-28 10:46:14 -0700176TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutCalledTwiceTest) {
Alex Deymo53556ec2014-03-17 10:05:57 -0700177 fake_async_var_.reset(new string("Async value"));
178 eval_ctx_->GetValue(&fake_async_var_);
179
180 bool value = false;
181 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
182 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
183
184 // The scheduled event should still work.
185 fake_async_var_.NotifyValueChanged();
186 RunGMainLoopMaxIterations(100);
187 EXPECT_TRUE(value);
188}
189
190// Test that we clear the events when destroying the EvaluationContext.
Alex Deymo63784a52014-05-28 10:46:14 -0700191TEST_F(UmEvaluationContextTest, RemoveObserversAndTimeoutTest) {
Alex Deymo53556ec2014-03-17 10:05:57 -0700192 fake_async_var_.reset(new string("Async value"));
193 eval_ctx_->GetValue(&fake_async_var_);
194
195 bool value = false;
196 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
197 eval_ctx_ = NULL;
198
199 // This should not trigger the callback since the EvaluationContext waiting
200 // for it is gone, and it should have remove all its observers.
201 fake_async_var_.NotifyValueChanged();
202 RunGMainLoopMaxIterations(100);
203 EXPECT_FALSE(value);
204}
205
206// Test that we don't schedule an event if there's no variable to wait for.
Alex Deymo63784a52014-05-28 10:46:14 -0700207TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutRunsFromTimeoutTest) {
Alex Deymo53556ec2014-03-17 10:05:57 -0700208 fake_poll_var_.reset(new string("Polled value"));
209 eval_ctx_->GetValue(&fake_poll_var_);
210
211 bool value = false;
212 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
213 // Check that the scheduled callback isn't run until the timeout occurs.
214 RunGMainLoopMaxIterations(10);
215 EXPECT_FALSE(value);
216 RunGMainLoopUntil(10000, Bind(&GetBoolean, &value));
217 EXPECT_TRUE(value);
218}
219
Alex Deymodb799532014-03-21 13:00:00 -0700220// Test that we can delete the EvaluationContext while having pending events.
Alex Deymo63784a52014-05-28 10:46:14 -0700221TEST_F(UmEvaluationContextTest, ObjectDeletedWithPendingEventsTest) {
Alex Deymodb799532014-03-21 13:00:00 -0700222 fake_async_var_.reset(new string("Async value"));
223 fake_poll_var_.reset(new string("Polled value"));
224 eval_ctx_->GetValue(&fake_async_var_);
225 eval_ctx_->GetValue(&fake_poll_var_);
226 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
227 // TearDown() checks for leaked observers on this async_variable, which means
228 // that our object is still alive after removing its reference.
229}
230
231// Test that timed events fired after removal of the EvaluationContext don't
232// crash.
Alex Deymo63784a52014-05-28 10:46:14 -0700233TEST_F(UmEvaluationContextTest, TimeoutEventAfterDeleteTest) {
Alex Deymodb799532014-03-21 13:00:00 -0700234 FakeVariable<string> fake_short_poll_var = {"fake_short_poll", TimeDelta()};
235 fake_short_poll_var.reset(new string("Polled value"));
236 eval_ctx_->GetValue(&fake_short_poll_var);
237 bool value = false;
238 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
239 // Remove the last reference to the EvaluationContext and run the loop for
240 // 1 second to give time to the main loop to trigger the timeout Event (of 0
241 // seconds). Our callback should not be called because the EvaluationContext
242 // was removed before the timeout event is attended.
243 eval_ctx_ = NULL;
244 RunGMainLoopUntil(1000, Bind(&GetBoolean, &value));
245 EXPECT_FALSE(value);
246}
247
Alex Deymo63784a52014-05-28 10:46:14 -0700248TEST_F(UmEvaluationContextTest, DefaultTimeout) {
Alex Deymo41a75a72014-04-15 15:36:22 -0700249 // Test that the RemainingTime() uses the default timeout on setup.
250 EXPECT_CALL(mock_var_async_, GetValue(default_timeout_, _))
251 .WillOnce(Return(nullptr));
Alex Deymo63784a52014-05-28 10:46:14 -0700252 UMTEST_EXPECT_NULL(eval_ctx_->GetValue(&mock_var_async_));
Alex Deymo41a75a72014-04-15 15:36:22 -0700253}
254
Alex Deymo63784a52014-05-28 10:46:14 -0700255TEST_F(UmEvaluationContextTest, TimeoutUpdatesWithMonotonicTime) {
Alex Deymo41a75a72014-04-15 15:36:22 -0700256 fake_clock_.SetMonotonicTime(
257 fake_clock_.GetMonotonicTime() + TimeDelta::FromSeconds(1));
258
259 TimeDelta timeout = default_timeout_ - TimeDelta::FromSeconds(1);
260
261 EXPECT_CALL(mock_var_async_, GetValue(timeout, _))
262 .WillOnce(Return(nullptr));
Alex Deymo63784a52014-05-28 10:46:14 -0700263 UMTEST_EXPECT_NULL(eval_ctx_->GetValue(&mock_var_async_));
Alex Deymo41a75a72014-04-15 15:36:22 -0700264}
265
Alex Deymo63784a52014-05-28 10:46:14 -0700266TEST_F(UmEvaluationContextTest, ResetEvaluationResetsTimes) {
Alex Deymo41a75a72014-04-15 15:36:22 -0700267 base::Time cur_time = fake_clock_.GetWallclockTime();
268 // Advance the time on the clock but don't call ResetEvaluation yet.
269 fake_clock_.SetWallclockTime(cur_time + TimeDelta::FromSeconds(4));
270
271 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(cur_time -
272 TimeDelta::FromSeconds(1)));
273 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time));
274 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time +
275 TimeDelta::FromSeconds(1)));
276 // Call ResetEvaluation now, which should use the new evaluation time.
277 eval_ctx_->ResetEvaluation();
278
279 cur_time = fake_clock_.GetWallclockTime();
280 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(cur_time -
281 TimeDelta::FromSeconds(1)));
282 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time));
283 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(cur_time +
284 TimeDelta::FromSeconds(1)));
285}
286
Alex Deymo63784a52014-05-28 10:46:14 -0700287TEST_F(UmEvaluationContextTest, IsTimeGreaterThanSignalsTriggerReevaluation) {
Alex Deymo41a75a72014-04-15 15:36:22 -0700288 EXPECT_FALSE(eval_ctx_->IsTimeGreaterThan(
289 fake_clock_.GetWallclockTime() + TimeDelta::FromSeconds(1)));
290
291 // The "false" from IsTimeGreaterThan means that's not that timestamp yet, so
292 // this should schedule a callback for when that happens.
293 EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
294}
295
Alex Deymo63784a52014-05-28 10:46:14 -0700296TEST_F(UmEvaluationContextTest, IsTimeGreaterThanDoesntRecordPastTimestamps) {
Alex Deymo41a75a72014-04-15 15:36:22 -0700297 // IsTimeGreaterThan() should ignore timestamps on the past for reevaluation.
298 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(
299 fake_clock_.GetWallclockTime() - TimeDelta::FromSeconds(20)));
300 EXPECT_TRUE(eval_ctx_->IsTimeGreaterThan(
301 fake_clock_.GetWallclockTime() - TimeDelta::FromSeconds(1)));
302
303 // Callback should not be scheduled.
304 EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&DoNothing)));
305}
306
Alex Deymo63784a52014-05-28 10:46:14 -0700307TEST_F(UmEvaluationContextTest, DumpContext) {
David Zeuthenc1490282014-04-29 16:25:03 -0700308 // |fail_var_| yield "(no value)" since it is unset.
309 eval_ctx_->GetValue(&fail_var_);
310
311 // Check that this is included.
312 fake_int_var_.reset(new int(42));
313 eval_ctx_->GetValue(&fake_int_var_);
314
315 // Check that double-quotes are escaped properly.
316 fake_poll_var_.reset(new string("Hello \"world\"!"));
317 eval_ctx_->GetValue(&fake_poll_var_);
318
319 // Note that the variables are printed in alphabetical order. Also
Alex Deymo63784a52014-05-28 10:46:14 -0700320 // see UmEvaluationContextText::SetUp() where the value used for
David Zeuthenc1490282014-04-29 16:25:03 -0700321 // |evaluation_start| is set.
322 EXPECT_EQ("{\n"
323 " \"evaluation_start\": \"3/2/2006 1:23:45 GMT\",\n"
324 " \"variables\": {\n"
325 " \"fail_var\": \"(no value)\",\n"
326 " \"fake_int\": \"42\",\n"
327 " \"fake_poll\": \"Hello \\\"world\\\"!\"\n"
328 " }\n"
329 "}\n",
330 eval_ctx_->DumpContext());
331}
332
Alex Deymo63784a52014-05-28 10:46:14 -0700333} // namespace chromeos_update_manager