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/variable.h"
18
19 #include <vector>
20
21 #include <brillo/message_loops/fake_message_loop.h>
22 #include <brillo/message_loops/message_loop.h>
23 #include <brillo/message_loops/message_loop_utils.h>
24 #include <gtest/gtest.h>
25
26 using base::TimeDelta;
27 using brillo::MessageLoop;
28 using brillo::MessageLoopRunMaxIterations;
29 using std::string;
30 using std::vector;
31
32 namespace chromeos_update_manager {
33
34 // Variable class that returns a value constructed with the default value.
35 template <typename T>
36 class DefaultVariable : public Variable<T> {
37 public:
DefaultVariable(const string & name,VariableMode mode)38 DefaultVariable(const string& name, VariableMode mode)
39 : Variable<T>(name, mode) {}
DefaultVariable(const string & name,const TimeDelta & poll_interval)40 DefaultVariable(const string& name, const TimeDelta& poll_interval)
41 : Variable<T>(name, poll_interval) {}
~DefaultVariable()42 ~DefaultVariable() override {}
43
44 protected:
GetValue(TimeDelta,string *)45 const T* GetValue(TimeDelta /* timeout */,
46 string* /* errmsg */) override {
47 return new T();
48 }
49
50 private:
51 DISALLOW_COPY_AND_ASSIGN(DefaultVariable);
52 };
53
54 class UmBaseVariableTest : public ::testing::Test {
55 protected:
SetUp()56 void SetUp() override {
57 loop_.SetAsCurrent();
58 }
59
60 brillo::FakeMessageLoop loop_{nullptr};
61 };
62
TEST_F(UmBaseVariableTest,GetNameTest)63 TEST_F(UmBaseVariableTest, GetNameTest) {
64 DefaultVariable<int> var("var", kVariableModeConst);
65 EXPECT_EQ(var.GetName(), string("var"));
66 }
67
TEST_F(UmBaseVariableTest,GetModeTest)68 TEST_F(UmBaseVariableTest, GetModeTest) {
69 DefaultVariable<int> var("var", kVariableModeConst);
70 EXPECT_EQ(var.GetMode(), kVariableModeConst);
71 DefaultVariable<int> other_var("other_var", kVariableModePoll);
72 EXPECT_EQ(other_var.GetMode(), kVariableModePoll);
73 }
74
TEST_F(UmBaseVariableTest,DefaultPollIntervalTest)75 TEST_F(UmBaseVariableTest, DefaultPollIntervalTest) {
76 DefaultVariable<int> const_var("const_var", kVariableModeConst);
77 EXPECT_EQ(const_var.GetPollInterval(), TimeDelta());
78 DefaultVariable<int> poll_var("poll_var", kVariableModePoll);
79 EXPECT_EQ(poll_var.GetPollInterval(), TimeDelta::FromMinutes(5));
80 }
81
TEST_F(UmBaseVariableTest,GetPollIntervalTest)82 TEST_F(UmBaseVariableTest, GetPollIntervalTest) {
83 DefaultVariable<int> var("var", TimeDelta::FromMinutes(3));
84 EXPECT_EQ(var.GetMode(), kVariableModePoll);
85 EXPECT_EQ(var.GetPollInterval(), TimeDelta::FromMinutes(3));
86 }
87
88 class BaseVariableObserver : public BaseVariable::ObserverInterface {
89 public:
ValueChanged(BaseVariable * variable)90 void ValueChanged(BaseVariable* variable) {
91 calls_.push_back(variable);
92 }
93
94 // List of called functions.
95 vector<BaseVariable*> calls_;
96 };
97
TEST_F(UmBaseVariableTest,RepeatedObserverTest)98 TEST_F(UmBaseVariableTest, RepeatedObserverTest) {
99 DefaultVariable<int> var("var", kVariableModeAsync);
100 BaseVariableObserver observer;
101 var.AddObserver(&observer);
102 EXPECT_EQ(1U, var.observer_list_.size());
103 var.AddObserver(&observer);
104 EXPECT_EQ(1U, var.observer_list_.size());
105 var.RemoveObserver(&observer);
106 EXPECT_EQ(0U, var.observer_list_.size());
107 var.RemoveObserver(&observer);
108 EXPECT_EQ(0U, var.observer_list_.size());
109 }
110
TEST_F(UmBaseVariableTest,NotifyValueChangedTest)111 TEST_F(UmBaseVariableTest, NotifyValueChangedTest) {
112 DefaultVariable<int> var("var", kVariableModeAsync);
113 BaseVariableObserver observer1;
114 var.AddObserver(&observer1);
115 // Simulate a value change on the variable's implementation.
116 var.NotifyValueChanged();
117 ASSERT_EQ(0U, observer1.calls_.size());
118 MessageLoopRunMaxIterations(MessageLoop::current(), 100);
119
120 ASSERT_EQ(1U, observer1.calls_.size());
121 // Check that the observer is called with the right argument.
122 EXPECT_EQ(&var, observer1.calls_[0]);
123
124 BaseVariableObserver observer2;
125 var.AddObserver(&observer2);
126 var.NotifyValueChanged();
127 MessageLoopRunMaxIterations(MessageLoop::current(), 100);
128
129 // Check that all the observers are called.
130 EXPECT_EQ(2U, observer1.calls_.size());
131 EXPECT_EQ(1U, observer2.calls_.size());
132
133 var.RemoveObserver(&observer1);
134 var.RemoveObserver(&observer2);
135 }
136
137 class BaseVariableObserverRemover : public BaseVariable::ObserverInterface {
138 public:
BaseVariableObserverRemover()139 BaseVariableObserverRemover() : calls_(0) {}
140
ValueChanged(BaseVariable * variable)141 void ValueChanged(BaseVariable* variable) override {
142 for (auto& observer : remove_observers_) {
143 variable->RemoveObserver(observer);
144 }
145 calls_++;
146 }
147
OnCallRemoveObserver(BaseVariable::ObserverInterface * observer)148 void OnCallRemoveObserver(BaseVariable::ObserverInterface* observer) {
149 remove_observers_.push_back(observer);
150 }
151
get_calls()152 int get_calls() { return calls_; }
153
154 private:
155 vector<BaseVariable::ObserverInterface*> remove_observers_;
156 int calls_;
157 };
158
159 // Tests that we can remove an observer from a Variable on the ValueChanged()
160 // call to that observer.
TEST_F(UmBaseVariableTest,NotifyValueRemovesObserversTest)161 TEST_F(UmBaseVariableTest, NotifyValueRemovesObserversTest) {
162 DefaultVariable<int> var("var", kVariableModeAsync);
163 BaseVariableObserverRemover observer1;
164 BaseVariableObserverRemover observer2;
165
166 var.AddObserver(&observer1);
167 var.AddObserver(&observer2);
168
169 // Make each observer remove both observers on ValueChanged.
170 observer1.OnCallRemoveObserver(&observer1);
171 observer1.OnCallRemoveObserver(&observer2);
172 observer2.OnCallRemoveObserver(&observer1);
173 observer2.OnCallRemoveObserver(&observer2);
174
175 var.NotifyValueChanged();
176 MessageLoopRunMaxIterations(MessageLoop::current(), 100);
177
178 EXPECT_EQ(1, observer1.get_calls() + observer2.get_calls());
179 }
180
181 } // namespace chromeos_update_manager
182