result_aggregator_unittest.cc revision fa3043cd7dfabf084ee2daa177d197cf67fd3cd6
1// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/result_aggregator.h"
6
7#include <base/bind.h>
8#include <base/memory/ref_counted.h>
9#include <gmock/gmock.h>
10#include <gtest/gtest.h>
11
12#include "shill/mock_event_dispatcher.h"
13#include "shill/testing.h"
14
15namespace shill {
16
17using testing::StrictMock;
18using testing::_;
19using base::Bind;
20using base::Unretained;
21
22namespace {
23
24const int kTimeoutMilliseconds = 0;
25
26}  // namespace
27
28class ResultAggregatorTest : public ::testing::Test {
29 public:
30  ResultAggregatorTest()
31      : aggregator_(new ResultAggregator(
32            Bind(&ResultAggregatorTest::ReportResult, Unretained(this)))) {}
33  virtual ~ResultAggregatorTest() {}
34
35  virtual void TearDown() {
36    aggregator_ = nullptr;  // Ensure ReportResult is invoked before our dtor.
37  }
38
39  MOCK_METHOD1(ReportResult, void(const Error&));
40
41 protected:
42  scoped_refptr<ResultAggregator> aggregator_;
43};
44
45class ResultAggregatorTestWithDispatcher : public ResultAggregatorTest {
46 public:
47  ResultAggregatorTestWithDispatcher() : ResultAggregatorTest() {}
48  virtual ~ResultAggregatorTestWithDispatcher() {}
49
50  void InitializeResultAggregatorWithTimeout() {
51    aggregator_ = new ResultAggregator(
52        Bind(&ResultAggregatorTest::ReportResult, Unretained(this)),
53        &dispatcher_, kTimeoutMilliseconds);
54  }
55
56 protected:
57  EventDispatcher dispatcher_;
58};
59
60class ResultAggregatorTestWithMockDispatcher : public ResultAggregatorTest {
61 public:
62  ResultAggregatorTestWithMockDispatcher() : ResultAggregatorTest() {}
63  virtual ~ResultAggregatorTestWithMockDispatcher() {}
64
65 protected:
66  StrictMock<MockEventDispatcher> dispatcher_;
67};
68
69class ResultGenerator {
70 public:
71  explicit ResultGenerator(const scoped_refptr<ResultAggregator>& aggregator)
72      : aggregator_(aggregator) {}
73  ~ResultGenerator() {}
74
75  void GenerateResult(const Error::Type error_type) {
76    aggregator_->ReportResult(Error(error_type));
77  }
78
79 private:
80  scoped_refptr<ResultAggregator> aggregator_;
81  DISALLOW_COPY_AND_ASSIGN(ResultGenerator);
82};
83
84TEST_F(ResultAggregatorTestWithMockDispatcher, Unused) {
85  EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kSuccess))).Times(0);
86}
87
88TEST_F(ResultAggregatorTestWithMockDispatcher, BothSucceed) {
89  EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kSuccess)));
90  ResultGenerator first_generator(aggregator_);
91  ResultGenerator second_generator(aggregator_);
92  first_generator.GenerateResult(Error::kSuccess);
93  second_generator.GenerateResult(Error::kSuccess);
94}
95
96TEST_F(ResultAggregatorTestWithMockDispatcher, FirstFails) {
97  EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kOperationTimeout)));
98  ResultGenerator first_generator(aggregator_);
99  ResultGenerator second_generator(aggregator_);
100  first_generator.GenerateResult(Error::kOperationTimeout);
101  second_generator.GenerateResult(Error::kSuccess);
102}
103
104TEST_F(ResultAggregatorTestWithMockDispatcher, SecondFails) {
105  EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kOperationTimeout)));
106  ResultGenerator first_generator(aggregator_);
107  ResultGenerator second_generator(aggregator_);
108  first_generator.GenerateResult(Error::kSuccess);
109  second_generator.GenerateResult(Error::kOperationTimeout);
110}
111
112TEST_F(ResultAggregatorTestWithMockDispatcher, BothFail) {
113  EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kOperationTimeout)));
114  ResultGenerator first_generator(aggregator_);
115  ResultGenerator second_generator(aggregator_);
116  first_generator.GenerateResult(Error::kOperationTimeout);
117  second_generator.GenerateResult(Error::kPermissionDenied);
118}
119
120TEST_F(ResultAggregatorTestWithMockDispatcher,
121       TimeoutCallbackPostedOnConstruction) {
122  EXPECT_CALL(dispatcher_, PostDelayedTask(_, kTimeoutMilliseconds));
123  auto result_aggregator = make_scoped_refptr(new ResultAggregator(
124      Bind(&ResultAggregatorTest::ReportResult, Unretained(this)), &dispatcher_,
125      kTimeoutMilliseconds));
126}
127
128TEST_F(ResultAggregatorTestWithDispatcher,
129       TimeoutReceivedWithoutAnyResultsReceived) {
130  InitializeResultAggregatorWithTimeout();
131  EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kOperationTimeout)));
132  ResultGenerator generator(aggregator_);
133  dispatcher_.DispatchPendingEvents();  // Invoke timeout callback.
134}
135
136TEST_F(ResultAggregatorTestWithDispatcher, TimeoutAndOtherResultReceived) {
137  // Timeout should override any other error results.
138  InitializeResultAggregatorWithTimeout();
139  EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kOperationTimeout)));
140  ResultGenerator first_generator(aggregator_);
141  ResultGenerator second_generator(aggregator_);
142  first_generator.GenerateResult(Error::kSuccess);
143  dispatcher_.DispatchPendingEvents();  // Invoke timeout callback.
144  second_generator.GenerateResult(Error::kPermissionDenied);
145}
146
147TEST_F(ResultAggregatorTestWithDispatcher,
148       TimeoutCallbackNotInvokedIfAllActionsComplete) {
149  {
150    auto result_aggregator = make_scoped_refptr(new ResultAggregator(
151        Bind(&ResultAggregatorTest::ReportResult, Unretained(this)),
152        &dispatcher_, kTimeoutMilliseconds));
153    // The result aggregator receives the one callback it expects, and goes
154    // out of scope. At this point, it should invoke the ReportResult callback
155    // with the error type kPermissionDenied that it copied.
156    ResultGenerator generator(result_aggregator);
157    generator.GenerateResult(Error::kPermissionDenied);
158    EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kPermissionDenied)));
159  }
160  // The timeout callback should be canceled after the ResultAggregator went
161  // out of scope and was destructed.
162  EXPECT_CALL(*this, ReportResult(ErrorTypeIs(Error::kOperationTimeout)))
163      .Times(0);
164  dispatcher_.DispatchPendingEvents();
165}
166
167}  // namespace shill
168