// // Copyright (C) 2013 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "shill/result_aggregator.h" #include #include #include #include #include "shill/mock_event_dispatcher.h" #include "shill/test_event_dispatcher.h" #include "shill/testing.h" namespace shill { using testing::StrictMock; using testing::_; using base::Bind; using base::Unretained; namespace { const int kTimeoutMilliseconds = 0; } // namespace class ResultAggregatorTest : public ::testing::Test { public: ResultAggregatorTest() : aggregator_(new ResultAggregator( Bind(&ResultAggregatorTest::ReportResult, Unretained(this)))) {} virtual ~ResultAggregatorTest() {} virtual void TearDown() { aggregator_ = nullptr; // Ensure ReportResult is invoked before our dtor. } MOCK_METHOD1(ReportResult, void(const Error&)); protected: scoped_refptr aggregator_; }; class ResultAggregatorTestWithDispatcher : public ResultAggregatorTest { public: ResultAggregatorTestWithDispatcher() : ResultAggregatorTest() {} virtual ~ResultAggregatorTestWithDispatcher() {} void InitializeResultAggregatorWithTimeout() { aggregator_ = new ResultAggregator( Bind(&ResultAggregatorTest::ReportResult, Unretained(this)), &dispatcher_, kTimeoutMilliseconds); } protected: EventDispatcherForTest dispatcher_; }; class ResultAggregatorTestWithMockDispatcher : public ResultAggregatorTest { public: ResultAggregatorTestWithMockDispatcher() : ResultAggregatorTest() {} virtual ~ResultAggregatorTestWithMockDispatcher() {} protected: StrictMock dispatcher_; }; class ResultGenerator { public: explicit ResultGenerator(const scoped_refptr& aggregator) : aggregator_(aggregator) {} ~ResultGenerator() {} void GenerateResult(const Error::Type error_type) { aggregator_->ReportResult(Error(error_type)); } private: scoped_refptr aggregator_; DISALLOW_COPY_AND_ASSIGN(ResultGenerator); }; TEST_F(ResultAggregatorTestWithMockDispatcher, Unused) { EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kSuccess))).Times(0); } TEST_F(ResultAggregatorTestWithMockDispatcher, BothSucceed) { EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kSuccess))); ResultGenerator first_generator(aggregator_); ResultGenerator second_generator(aggregator_); first_generator.GenerateResult(Error::kSuccess); second_generator.GenerateResult(Error::kSuccess); } TEST_F(ResultAggregatorTestWithMockDispatcher, FirstFails) { EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kOperationTimeout))); ResultGenerator first_generator(aggregator_); ResultGenerator second_generator(aggregator_); first_generator.GenerateResult(Error::kOperationTimeout); second_generator.GenerateResult(Error::kSuccess); } TEST_F(ResultAggregatorTestWithMockDispatcher, SecondFails) { EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kOperationTimeout))); ResultGenerator first_generator(aggregator_); ResultGenerator second_generator(aggregator_); first_generator.GenerateResult(Error::kSuccess); second_generator.GenerateResult(Error::kOperationTimeout); } TEST_F(ResultAggregatorTestWithMockDispatcher, BothFail) { EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kOperationTimeout))); ResultGenerator first_generator(aggregator_); ResultGenerator second_generator(aggregator_); first_generator.GenerateResult(Error::kOperationTimeout); second_generator.GenerateResult(Error::kPermissionDenied); } TEST_F(ResultAggregatorTestWithMockDispatcher, TimeoutCallbackPostedOnConstruction) { EXPECT_CALL(dispatcher_, PostDelayedTask(_, kTimeoutMilliseconds)); auto result_aggregator = make_scoped_refptr(new ResultAggregator( Bind(&ResultAggregatorTest::ReportResult, Unretained(this)), &dispatcher_, kTimeoutMilliseconds)); } TEST_F(ResultAggregatorTestWithDispatcher, TimeoutReceivedWithoutAnyResultsReceived) { InitializeResultAggregatorWithTimeout(); EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kOperationTimeout))); ResultGenerator generator(aggregator_); dispatcher_.DispatchPendingEvents(); // Invoke timeout callback. } TEST_F(ResultAggregatorTestWithDispatcher, TimeoutAndOtherResultReceived) { // Timeout should override any other error results. InitializeResultAggregatorWithTimeout(); EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kOperationTimeout))); ResultGenerator first_generator(aggregator_); ResultGenerator second_generator(aggregator_); first_generator.GenerateResult(Error::kSuccess); dispatcher_.DispatchPendingEvents(); // Invoke timeout callback. second_generator.GenerateResult(Error::kPermissionDenied); } TEST_F(ResultAggregatorTestWithDispatcher, TimeoutCallbackNotInvokedIfAllActionsComplete) { { auto result_aggregator = make_scoped_refptr(new ResultAggregator( Bind(&ResultAggregatorTest::ReportResult, Unretained(this)), &dispatcher_, kTimeoutMilliseconds)); // The result aggregator receives the one callback it expects, and goes // out of scope. At this point, it should invoke the ReportResult callback // with the error type kPermissionDenied that it copied. ResultGenerator generator(result_aggregator); generator.GenerateResult(Error::kPermissionDenied); EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kPermissionDenied))); } // The timeout callback should be canceled after the ResultAggregator went // out of scope and was destructed. EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kOperationTimeout))) .Times(0); dispatcher_.DispatchPendingEvents(); } } // namespace shill