普通文本  |  181行  |  6.18 KB

//
// 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 <base/bind.h>
#include <base/memory/ref_counted.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#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<ResultAggregator> 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<MockEventDispatcher> dispatcher_;
};

class ResultGenerator {
 public:
  explicit ResultGenerator(const scoped_refptr<ResultAggregator>& aggregator)
      : aggregator_(aggregator) {}
  ~ResultGenerator() {}

  void GenerateResult(const Error::Type error_type) {
    aggregator_->ReportResult(Error(error_type));
  }

 private:
  scoped_refptr<ResultAggregator> 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