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