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
40using std::map;
41using std::string;
42using testing::Mock;
43using testing::NiceMock;
44using testing::Return;
45using testing::StrEq;
46using testing::_;
47
48namespace shill {
49
50class PPPoEServiceTest : public testing::Test {
51 public:
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
75  ~PPPoEServiceTest() override {
76    Error error;
77    service_->Disconnect(&error, __func__);
78    dispatcher_.DispatchPendingEvents();
79  }
80
81 protected:
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
106MATCHER_P(LinkNamed, name, "") {
107  return arg->link_name() == name;
108}
109
110TEST_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
120TEST_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
131TEST_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
139TEST_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
166TEST_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
185TEST_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
208TEST_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