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