1 //
2 // Copyright (C) 2009 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/common/action_processor.h"
18
19 #include <string>
20 #include <utility>
21
22 #include <gtest/gtest.h>
23
24 #include "update_engine/common/action.h"
25 #include "update_engine/common/mock_action.h"
26
27 using std::string;
28
29 namespace chromeos_update_engine {
30
31 using chromeos_update_engine::ActionPipe;
32
33 class ActionProcessorTestAction;
34
35 template <>
36 class ActionTraits<ActionProcessorTestAction> {
37 public:
38 typedef string OutputObjectType;
39 typedef string InputObjectType;
40 };
41
42 // This is a simple Action class for testing.
43 class ActionProcessorTestAction : public Action<ActionProcessorTestAction> {
44 public:
45 typedef string InputObjectType;
46 typedef string OutputObjectType;
in_pipe()47 ActionPipe<string>* in_pipe() { return in_pipe_.get(); }
out_pipe()48 ActionPipe<string>* out_pipe() { return out_pipe_.get(); }
processor()49 ActionProcessor* processor() { return processor_; }
PerformAction()50 void PerformAction() {}
CompleteAction()51 void CompleteAction() {
52 ASSERT_TRUE(processor());
53 processor()->ActionComplete(this, ErrorCode::kSuccess);
54 }
Type() const55 string Type() const { return "ActionProcessorTestAction"; }
56 };
57
58 namespace {
59 class MyActionProcessorDelegate : public ActionProcessorDelegate {
60 public:
MyActionProcessorDelegate(const ActionProcessor * processor)61 explicit MyActionProcessorDelegate(const ActionProcessor* processor)
62 : processor_(processor),
63 processing_done_called_(false),
64 processing_stopped_called_(false),
65 action_completed_called_(false),
66 action_exit_code_(ErrorCode::kError) {}
67
ProcessingDone(const ActionProcessor * processor,ErrorCode code)68 virtual void ProcessingDone(const ActionProcessor* processor,
69 ErrorCode code) {
70 EXPECT_EQ(processor_, processor);
71 EXPECT_FALSE(processing_done_called_);
72 processing_done_called_ = true;
73 }
ProcessingStopped(const ActionProcessor * processor)74 virtual void ProcessingStopped(const ActionProcessor* processor) {
75 EXPECT_EQ(processor_, processor);
76 EXPECT_FALSE(processing_stopped_called_);
77 processing_stopped_called_ = true;
78 }
ActionCompleted(ActionProcessor * processor,AbstractAction * action,ErrorCode code)79 virtual void ActionCompleted(ActionProcessor* processor,
80 AbstractAction* action,
81 ErrorCode code) {
82 EXPECT_EQ(processor_, processor);
83 EXPECT_FALSE(action_completed_called_);
84 action_completed_called_ = true;
85 action_exit_code_ = code;
86 }
87
88 const ActionProcessor* processor_;
89 bool processing_done_called_;
90 bool processing_stopped_called_;
91 bool action_completed_called_;
92 ErrorCode action_exit_code_;
93 };
94 } // namespace
95
96 class ActionProcessorTest : public ::testing::Test {
SetUp()97 void SetUp() override {
98 action_processor_.set_delegate(&delegate_);
99 // Silence Type() calls used for logging.
100 mock_action_.reset(new testing::StrictMock<MockAction>());
101 mock_action_ptr_ = mock_action_.get();
102 action_.reset(new ActionProcessorTestAction());
103 action_ptr_ = action_.get();
104 EXPECT_CALL(*mock_action_, Type()).Times(testing::AnyNumber());
105 }
106
TearDown()107 void TearDown() override { action_processor_.set_delegate(nullptr); }
108
109 protected:
110 // The ActionProcessor under test.
111 ActionProcessor action_processor_;
112
113 MyActionProcessorDelegate delegate_{&action_processor_};
114
115 // Common actions used during most tests.
116 std::unique_ptr<testing::StrictMock<MockAction>> mock_action_;
117 testing::StrictMock<MockAction>* mock_action_ptr_;
118 std::unique_ptr<ActionProcessorTestAction> action_;
119 ActionProcessorTestAction* action_ptr_;
120 };
121
TEST_F(ActionProcessorTest,SimpleTest)122 TEST_F(ActionProcessorTest, SimpleTest) {
123 EXPECT_FALSE(action_processor_.IsRunning());
124 action_processor_.EnqueueAction(std::move(action_));
125 EXPECT_FALSE(action_processor_.IsRunning());
126 EXPECT_FALSE(action_ptr_->IsRunning());
127 action_processor_.StartProcessing();
128 EXPECT_TRUE(action_processor_.IsRunning());
129 EXPECT_TRUE(action_ptr_->IsRunning());
130 action_ptr_->CompleteAction();
131 EXPECT_FALSE(action_processor_.IsRunning());
132 EXPECT_EQ(action_processor_.current_action(), nullptr);
133 }
134
TEST_F(ActionProcessorTest,DelegateTest)135 TEST_F(ActionProcessorTest, DelegateTest) {
136 action_processor_.EnqueueAction(std::move(action_));
137 action_processor_.StartProcessing();
138 action_ptr_->CompleteAction();
139 EXPECT_TRUE(delegate_.processing_done_called_);
140 EXPECT_TRUE(delegate_.action_completed_called_);
141 }
142
TEST_F(ActionProcessorTest,StopProcessingTest)143 TEST_F(ActionProcessorTest, StopProcessingTest) {
144 action_processor_.EnqueueAction(std::move(action_));
145 action_processor_.StartProcessing();
146 action_processor_.StopProcessing();
147 EXPECT_TRUE(delegate_.processing_stopped_called_);
148 EXPECT_FALSE(delegate_.action_completed_called_);
149 EXPECT_FALSE(action_processor_.IsRunning());
150 EXPECT_EQ(nullptr, action_processor_.current_action());
151 }
152
TEST_F(ActionProcessorTest,ChainActionsTest)153 TEST_F(ActionProcessorTest, ChainActionsTest) {
154 // This test doesn't use a delegate since it terminates several actions.
155 action_processor_.set_delegate(nullptr);
156
157 auto action0 = std::make_unique<ActionProcessorTestAction>();
158 auto action1 = std::make_unique<ActionProcessorTestAction>();
159 auto action2 = std::make_unique<ActionProcessorTestAction>();
160 auto action0_ptr = action0.get();
161 auto action1_ptr = action1.get();
162 auto action2_ptr = action2.get();
163 action_processor_.EnqueueAction(std::move(action0));
164 action_processor_.EnqueueAction(std::move(action1));
165 action_processor_.EnqueueAction(std::move(action2));
166
167 EXPECT_EQ(action_processor_.actions_.size(), 3u);
168 EXPECT_EQ(action_processor_.actions_[0].get(), action0_ptr);
169 EXPECT_EQ(action_processor_.actions_[1].get(), action1_ptr);
170 EXPECT_EQ(action_processor_.actions_[2].get(), action2_ptr);
171
172 action_processor_.StartProcessing();
173 EXPECT_EQ(action0_ptr, action_processor_.current_action());
174 EXPECT_TRUE(action_processor_.IsRunning());
175 action0_ptr->CompleteAction();
176 EXPECT_EQ(action1_ptr, action_processor_.current_action());
177 EXPECT_TRUE(action_processor_.IsRunning());
178 action1_ptr->CompleteAction();
179 EXPECT_EQ(action2_ptr, action_processor_.current_action());
180 EXPECT_TRUE(action_processor_.actions_.empty());
181 EXPECT_TRUE(action_processor_.IsRunning());
182 action2_ptr->CompleteAction();
183 EXPECT_EQ(nullptr, action_processor_.current_action());
184 EXPECT_TRUE(action_processor_.actions_.empty());
185 EXPECT_FALSE(action_processor_.IsRunning());
186 }
187
TEST_F(ActionProcessorTest,DefaultDelegateTest)188 TEST_F(ActionProcessorTest, DefaultDelegateTest) {
189 // Just make sure it doesn't crash.
190 action_processor_.EnqueueAction(std::move(action_));
191 action_processor_.StartProcessing();
192 action_ptr_->CompleteAction();
193
194 action_.reset(new ActionProcessorTestAction());
195 action_processor_.EnqueueAction(std::move(action_));
196 action_processor_.StartProcessing();
197 action_processor_.StopProcessing();
198 }
199
200 // This test suspends and resume the action processor while running one action.
TEST_F(ActionProcessorTest,SuspendResumeTest)201 TEST_F(ActionProcessorTest, SuspendResumeTest) {
202 action_processor_.EnqueueAction(std::move(mock_action_));
203
204 testing::InSequence s;
205 EXPECT_CALL(*mock_action_ptr_, PerformAction());
206 action_processor_.StartProcessing();
207
208 EXPECT_CALL(*mock_action_ptr_, SuspendAction());
209 action_processor_.SuspendProcessing();
210 // Suspending the processor twice should not suspend the action twice.
211 action_processor_.SuspendProcessing();
212
213 // IsRunning should return whether there's is an action doing some work, even
214 // if it is suspended.
215 EXPECT_TRUE(action_processor_.IsRunning());
216 EXPECT_EQ(mock_action_ptr_, action_processor_.current_action());
217
218 EXPECT_CALL(*mock_action_ptr_, ResumeAction());
219 action_processor_.ResumeProcessing();
220
221 // Calling ResumeProcessing twice should not affect the action_.
222 action_processor_.ResumeProcessing();
223 action_processor_.ActionComplete(mock_action_ptr_, ErrorCode::kSuccess);
224 }
225
226 // This test suspends an action that presumably doesn't support suspend/resume
227 // and it finished before being resumed.
TEST_F(ActionProcessorTest,ActionCompletedWhileSuspendedTest)228 TEST_F(ActionProcessorTest, ActionCompletedWhileSuspendedTest) {
229 action_processor_.EnqueueAction(std::move(mock_action_));
230
231 testing::InSequence s;
232 EXPECT_CALL(*mock_action_ptr_, PerformAction());
233 action_processor_.StartProcessing();
234
235 EXPECT_CALL(*mock_action_ptr_, SuspendAction());
236 action_processor_.SuspendProcessing();
237
238 // Simulate the action completion while suspended. No other call to
239 // |mock_action_| is expected at this point.
240 action_processor_.ActionComplete(mock_action_ptr_, ErrorCode::kSuccess);
241
242 // The processing should not be done since the ActionProcessor is suspended
243 // and the processing is considered to be still running until resumed.
244 EXPECT_FALSE(delegate_.processing_done_called_);
245 EXPECT_TRUE(action_processor_.IsRunning());
246
247 action_processor_.ResumeProcessing();
248 EXPECT_TRUE(delegate_.processing_done_called_);
249 EXPECT_FALSE(delegate_.processing_stopped_called_);
250 }
251
TEST_F(ActionProcessorTest,StoppedWhileSuspendedTest)252 TEST_F(ActionProcessorTest, StoppedWhileSuspendedTest) {
253 action_processor_.EnqueueAction(std::move(mock_action_));
254
255 testing::InSequence s;
256 EXPECT_CALL(*mock_action_ptr_, PerformAction());
257 action_processor_.StartProcessing();
258 EXPECT_CALL(*mock_action_ptr_, SuspendAction());
259 action_processor_.SuspendProcessing();
260
261 EXPECT_CALL(*mock_action_ptr_, TerminateProcessing());
262 action_processor_.StopProcessing();
263 // Stopping the processing should abort the current execution no matter what.
264 EXPECT_TRUE(delegate_.processing_stopped_called_);
265 EXPECT_FALSE(delegate_.processing_done_called_);
266 EXPECT_FALSE(delegate_.action_completed_called_);
267 EXPECT_FALSE(action_processor_.IsRunning());
268 EXPECT_EQ(nullptr, action_processor_.current_action());
269 }
270
271 } // namespace chromeos_update_engine
272