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