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