1 //
2 // Copyright (C) 2015 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/pppoe/pppoe_service.h"
18 
19 #include <map>
20 #include <string>
21 
22 #include <gmock/gmock.h>
23 #include <gtest/gtest.h>
24 
25 #include <base/memory/ref_counted.h>
26 
27 #include "shill/ethernet/mock_ethernet.h"
28 #include "shill/mock_control.h"
29 #include "shill/mock_device_info.h"
30 #include "shill/mock_external_task.h"
31 #include "shill/mock_manager.h"
32 #include "shill/mock_metrics.h"
33 #include "shill/mock_ppp_device.h"
34 #include "shill/mock_ppp_device_factory.h"
35 #include "shill/mock_process_manager.h"
36 #include "shill/service.h"
37 #include "shill/test_event_dispatcher.h"
38 #include "shill/testing.h"
39 
40 using std::map;
41 using std::string;
42 using testing::Mock;
43 using testing::NiceMock;
44 using testing::Return;
45 using testing::StrEq;
46 using testing::_;
47 
48 namespace shill {
49 
50 class PPPoEServiceTest : public testing::Test {
51  public:
PPPoEServiceTest()52   PPPoEServiceTest()
53       : metrics_(&dispatcher_),
54         manager_(&control_interface_, &dispatcher_, &metrics_),
55         ethernet_(new MockEthernet(&control_interface_,
56                                    &dispatcher_,
57                                    &metrics_,
58                                    &manager_,
59                                    "ethernet",
60                                    "aabbccddeeff",
61                                    0)),
62         device_info_(&control_interface_,
63                      &dispatcher_,
64                      &metrics_,
65                      &manager_),
66         service_(new PPPoEService(&control_interface_,
67                                   &dispatcher_,
68                                   &metrics_,
69                                   &manager_,
70                                   ethernet_->weak_ptr_factory_.GetWeakPtr())) {
71     manager_.set_mock_device_info(&device_info_);
72     service_->process_manager_ = &process_manager_;
73   }
74 
~PPPoEServiceTest()75   ~PPPoEServiceTest() override {
76     Error error;
77     service_->Disconnect(&error, __func__);
78     dispatcher_.DispatchPendingEvents();
79   }
80 
81  protected:
FakeConnectionSuccess()82   void FakeConnectionSuccess() {
83     EXPECT_CALL(*ethernet_, link_up())
84         .WillRepeatedly(Return(true));
85     EXPECT_CALL(process_manager_, StartProcess(_, _, _, _, _, _))
86         .WillOnce(Return(0));
87     Error error;
88     service_->Connect(&error, "in test");
89     EXPECT_TRUE(error.IsSuccess());
90   }
91 
92   EventDispatcherForTest dispatcher_;
93   MockMetrics metrics_;
94   MockControl control_interface_;
95   MockProcessManager process_manager_;
96   MockManager manager_;
97   scoped_refptr<MockEthernet> ethernet_;
98   MockDeviceInfo device_info_;
99 
100   scoped_refptr<PPPoEService> service_;
101 
102  private:
103   DISALLOW_COPY_AND_ASSIGN(PPPoEServiceTest);
104 };
105 
106 MATCHER_P(LinkNamed, name, "") {
107   return arg->link_name() == name;
108 }
109 
TEST_F(PPPoEServiceTest,AuthenticationFailure)110 TEST_F(PPPoEServiceTest, AuthenticationFailure) {
111   EXPECT_CALL(*ethernet_, link_up()).WillRepeatedly(Return(true));
112   FakeConnectionSuccess();
113   map<string, string> empty_dict;
114   service_->Notify(kPPPReasonAuthenticating, empty_dict);
115   service_->Notify(kPPPReasonDisconnect, empty_dict);
116   EXPECT_EQ(service_->state(), Service::kStateFailure);
117   EXPECT_EQ(service_->failure(), Service::kFailurePPPAuth);
118 }
119 
TEST_F(PPPoEServiceTest,DisconnectBeforeConnect)120 TEST_F(PPPoEServiceTest, DisconnectBeforeConnect) {
121   EXPECT_CALL(*ethernet_, link_up()).WillRepeatedly(Return(true));
122   FakeConnectionSuccess();
123   map<string, string> empty_dict;
124   service_->Notify(kPPPReasonAuthenticating, empty_dict);
125   service_->Notify(kPPPReasonAuthenticated, empty_dict);
126   service_->Notify(kPPPReasonDisconnect, empty_dict);
127   EXPECT_EQ(service_->state(), Service::kStateFailure);
128   EXPECT_EQ(service_->failure(), Service::kFailureUnknown);
129 }
130 
TEST_F(PPPoEServiceTest,ConnectFailsWhenEthernetLinkDown)131 TEST_F(PPPoEServiceTest, ConnectFailsWhenEthernetLinkDown) {
132   EXPECT_CALL(*ethernet_, link_up()).WillRepeatedly(Return(false));
133 
134   Error error;
135   service_->Connect(&error, "in test");
136   EXPECT_FALSE(error.IsSuccess());
137 }
138 
TEST_F(PPPoEServiceTest,OnPPPConnected)139 TEST_F(PPPoEServiceTest, OnPPPConnected) {
140   // Setup device factory.
141   MockPPPDeviceFactory* factory = MockPPPDeviceFactory::GetInstance();
142   service_->ppp_device_factory_ = factory;
143 
144   static const char kLinkName[] = "ppp0";
145   map<string, string> params = { {kPPPInterfaceName, kLinkName} };
146   MockPPPDevice* device = new MockPPPDevice(
147       &control_interface_, &dispatcher_, &metrics_, &manager_, kLinkName, 0);
148 
149   EXPECT_CALL(device_info_, GetIndex(StrEq(kLinkName))).WillOnce(Return(0));
150   EXPECT_CALL(*factory, CreatePPPDevice(_, _, _, _, _, _))
151       .WillOnce(Return(device));
152   EXPECT_CALL(device_info_, RegisterDevice(IsRefPtrTo(device)));
153   EXPECT_CALL(*device, SetEnabled(true));
154   EXPECT_CALL(*device, SelectService(_));
155   EXPECT_CALL(*device, UpdateIPConfigFromPPP(params, false));
156 #ifndef DISABLE_DHCPV6
157   EXPECT_CALL(manager_, IsDHCPv6EnabledForDevice(StrEq(kLinkName)))
158       .WillOnce(Return(true));
159   EXPECT_CALL(*device, AcquireIPv6Config());
160 #endif  // DISABLE_DHCPV6
161   EXPECT_CALL(manager_, OnInnerDevicesChanged());
162   service_->OnPPPConnected(params);
163   Mock::VerifyAndClearExpectations(&manager_);
164 }
165 
TEST_F(PPPoEServiceTest,Connect)166 TEST_F(PPPoEServiceTest, Connect) {
167   static const char kLinkName[] = "ppp0";
168 
169   EXPECT_CALL(*ethernet_, link_up()).WillRepeatedly(Return(true));
170   EXPECT_CALL(device_info_, GetIndex(StrEq(kLinkName))).WillOnce(Return(0));
171   EXPECT_CALL(device_info_, RegisterDevice(LinkNamed(kLinkName)));
172 
173   FakeConnectionSuccess();
174   map<string, string> empty_dict;
175   service_->Notify(kPPPReasonAuthenticating, empty_dict);
176   service_->Notify(kPPPReasonAuthenticated, empty_dict);
177 
178   map<string, string> connect_dict = {
179     {kPPPInterfaceName, kLinkName},
180   };
181   service_->Notify(kPPPReasonConnect, connect_dict);
182   EXPECT_EQ(service_->state(), Service::kStateOnline);
183 }
184 
TEST_F(PPPoEServiceTest,Disconnect)185 TEST_F(PPPoEServiceTest, Disconnect) {
186   FakeConnectionSuccess();
187 
188   auto weak_ptr = service_->weak_ptr_factory_.GetWeakPtr();
189   MockExternalTask* pppd = new MockExternalTask(
190       &control_interface_, &process_manager_, weak_ptr,
191       base::Bind(&PPPoEService::OnPPPDied, weak_ptr));
192   service_->pppd_.reset(pppd);
193 
194   MockPPPDevice* ppp_device = new MockPPPDevice(
195       &control_interface_, &dispatcher_, &metrics_, &manager_, "ppp0", 0);
196   service_->ppp_device_ = ppp_device;
197 
198   EXPECT_CALL(*ppp_device, DropConnection());
199   EXPECT_CALL(*pppd, OnDelete());
200 
201   {
202     Error error;
203     service_->Disconnect(&error, "in test");
204     EXPECT_TRUE(error.IsSuccess());
205   }
206 }
207 
TEST_F(PPPoEServiceTest,DisconnectDuringAssociation)208 TEST_F(PPPoEServiceTest, DisconnectDuringAssociation) {
209   FakeConnectionSuccess();
210 
211   Error error;
212   service_->Disconnect(&error, "in test");
213   EXPECT_TRUE(error.IsSuccess());
214 
215   EXPECT_EQ(service_->state(), Service::kStateIdle);
216 }
217 
218 }  // namespace shill
219