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 26 using std::string; 27 28 namespace chromeos_update_engine { 29 30 using chromeos_update_engine::ActionPipe; 31 32 class ActionProcessorTestAction; 33 34 template<> 35 class ActionTraits<ActionProcessorTestAction> { 36 public: 37 typedef string OutputObjectType; 38 typedef string InputObjectType; 39 }; 40 41 // This is a simple Action class for testing. 42 class 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 57 namespace { 58 class 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 95 class 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 117 TEST_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 131 TEST_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 139 TEST_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 149 TEST_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 167 TEST_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 181 TEST_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_. 193 TEST_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. 221 TEST_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 245 TEST_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