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
26using base::TimeDelta;
27using brillo::MessageLoop;
28using brillo::MessageLoopRunMaxIterations;
29using std::string;
30using std::vector;
31
32namespace chromeos_update_manager {
33
34// Variable class that returns a value constructed with the default value.
35template <typename T>
36class DefaultVariable : public Variable<T> {
37 public:
38  DefaultVariable(const string& name, VariableMode mode)
39      : Variable<T>(name, mode) {}
40  DefaultVariable(const string& name, const TimeDelta& poll_interval)
41      : Variable<T>(name, poll_interval) {}
42  ~DefaultVariable() override {}
43
44 protected:
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
54class UmBaseVariableTest : public ::testing::Test {
55 protected:
56  void SetUp() override {
57    loop_.SetAsCurrent();
58  }
59
60  brillo::FakeMessageLoop loop_{nullptr};
61};
62
63TEST_F(UmBaseVariableTest, GetNameTest) {
64  DefaultVariable<int> var("var", kVariableModeConst);
65  EXPECT_EQ(var.GetName(), string("var"));
66}
67
68TEST_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
75TEST_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
82TEST_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
88class BaseVariableObserver : public BaseVariable::ObserverInterface {
89 public:
90  void ValueChanged(BaseVariable* variable) {
91    calls_.push_back(variable);
92  }
93
94  // List of called functions.
95  vector<BaseVariable*> calls_;
96};
97
98TEST_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
111TEST_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
137class BaseVariableObserverRemover : public BaseVariable::ObserverInterface {
138 public:
139  BaseVariableObserverRemover() : calls_(0) {}
140
141  void ValueChanged(BaseVariable* variable) override {
142    for (auto& observer : remove_observers_) {
143      variable->RemoveObserver(observer);
144    }
145    calls_++;
146  }
147
148  void OnCallRemoveObserver(BaseVariable::ObserverInterface* observer) {
149    remove_observers_.push_back(observer);
150  }
151
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.
161TEST_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