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