1 //
2 // Copyright (C) 2012 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/vpn/vpn_provider.h"
18
19 #include <memory>
20 #include <set>
21
22 #if defined(__ANDROID__)
23 #include <dbus/service_constants.h>
24 #else
25 #include <chromeos/dbus/service_constants.h>
26 #endif // __ANDROID__
27 #include <gtest/gtest.h>
28
29 #include "shill/error.h"
30 #include "shill/fake_store.h"
31 #include "shill/mock_adaptors.h"
32 #include "shill/mock_device_info.h"
33 #include "shill/mock_manager.h"
34 #include "shill/mock_metrics.h"
35 #include "shill/mock_profile.h"
36 #include "shill/mock_store.h"
37 #include "shill/nice_mock_control.h"
38 #include "shill/vpn/mock_vpn_driver.h"
39 #include "shill/vpn/mock_vpn_service.h"
40
41 using std::string;
42 using std::unique_ptr;
43 using testing::_;
44 using testing::DoAll;
45 using testing::NiceMock;
46 using testing::Return;
47 using testing::SetArgumentPointee;
48 using testing::StartsWith;
49
50 namespace shill {
51
52 class VPNProviderTest : public testing::Test {
53 public:
VPNProviderTest()54 VPNProviderTest()
55 : metrics_(nullptr),
56 manager_(&control_, nullptr, &metrics_),
57 device_info_(&control_, nullptr, &metrics_, &manager_),
58 provider_(&control_, nullptr, &metrics_, &manager_) {}
59
~VPNProviderTest()60 virtual ~VPNProviderTest() {}
61
62 protected:
63 static const char kHost[];
64 static const char kName[];
65
GetServiceFriendlyName(const ServiceRefPtr & service)66 string GetServiceFriendlyName(const ServiceRefPtr& service) {
67 return service->friendly_name();
68 }
69
SetConnectState(const ServiceRefPtr & service,Service::ConnectState state)70 void SetConnectState(const ServiceRefPtr& service,
71 Service::ConnectState state) {
72 service->state_ = state;
73 }
74
AddService(const VPNServiceRefPtr & service)75 void AddService(const VPNServiceRefPtr& service) {
76 provider_.services_.push_back(service);
77 }
78
GetServiceAt(int idx)79 VPNServiceRefPtr GetServiceAt(int idx) {
80 return provider_.services_[idx];
81 }
82
GetServiceCount() const83 size_t GetServiceCount() const {
84 return provider_.services_.size();
85 }
86
87 NiceMockControl control_;
88 MockMetrics metrics_;
89 MockManager manager_;
90 MockDeviceInfo device_info_;
91 VPNProvider provider_;
92 };
93
94 const char VPNProviderTest::kHost[] = "10.8.0.1";
95 const char VPNProviderTest::kName[] = "vpn-name";
96
TEST_F(VPNProviderTest,GetServiceNoType)97 TEST_F(VPNProviderTest, GetServiceNoType) {
98 KeyValueStore args;
99 Error e;
100 args.SetString(kTypeProperty, kTypeVPN);
101 ServiceRefPtr service = provider_.GetService(args, &e);
102 EXPECT_EQ(Error::kNotSupported, e.type());
103 EXPECT_FALSE(service);
104 }
105
TEST_F(VPNProviderTest,GetServiceUnsupportedType)106 TEST_F(VPNProviderTest, GetServiceUnsupportedType) {
107 KeyValueStore args;
108 Error e;
109 args.SetString(kTypeProperty, kTypeVPN);
110 args.SetString(kProviderTypeProperty, "unknown-vpn-type");
111 args.SetString(kProviderHostProperty, kHost);
112 args.SetString(kNameProperty, kName);
113 ServiceRefPtr service = provider_.GetService(args, &e);
114 EXPECT_EQ(Error::kNotSupported, e.type());
115 EXPECT_FALSE(service);
116 }
117
TEST_F(VPNProviderTest,GetService)118 TEST_F(VPNProviderTest, GetService) {
119 KeyValueStore args;
120 args.SetString(kTypeProperty, kTypeVPN);
121 args.SetString(kProviderTypeProperty, kProviderOpenVpn);
122 args.SetString(kProviderHostProperty, kHost);
123 args.SetString(kNameProperty, kName);
124
125 {
126 Error error;
127 ServiceRefPtr service = provider_.FindSimilarService(args, &error);
128 EXPECT_EQ(Error::kNotFound, error.type());
129 EXPECT_EQ(nullptr, service.get());
130 }
131
132 EXPECT_EQ(0, GetServiceCount());
133
134 ServiceRefPtr service;
135 {
136 Error error;
137 EXPECT_CALL(manager_, device_info()).WillOnce(Return(&device_info_));
138 EXPECT_CALL(manager_, RegisterService(_));
139 service = provider_.GetService(args, &error);
140 EXPECT_TRUE(error.IsSuccess());
141 ASSERT_TRUE(service);
142 testing::Mock::VerifyAndClearExpectations(&manager_);
143 }
144
145 EXPECT_EQ("vpn_10_8_0_1_vpn_name", service->GetStorageIdentifier());
146 EXPECT_EQ(kName, GetServiceFriendlyName(service));
147
148 EXPECT_EQ(1, GetServiceCount());
149
150 // Configure the service to set its properties (including Provider.Host).
151 {
152 Error error;
153 service->Configure(args, &error);
154 EXPECT_TRUE(error.IsSuccess());
155 }
156
157 // None of the calls below should cause a new service to be registered.
158 EXPECT_CALL(manager_, RegisterService(_)).Times(0);
159
160 // A second call should return the same service.
161 {
162 Error error;
163 ServiceRefPtr get_service = provider_.GetService(args, &error);
164 EXPECT_TRUE(error.IsSuccess());
165 ASSERT_EQ(service, get_service);
166 }
167
168 EXPECT_EQ(1, GetServiceCount());
169
170 // FindSimilarService should also return this service.
171 {
172 Error error;
173 ServiceRefPtr similar_service = provider_.FindSimilarService(args, &error);
174 EXPECT_TRUE(error.IsSuccess());
175 EXPECT_EQ(service, similar_service);
176 }
177
178 EXPECT_EQ(1, GetServiceCount());
179
180 // However, CreateTemporaryService should create a different service.
181 {
182 Error error;
183 ServiceRefPtr temporary_service =
184 provider_.CreateTemporaryService(args, &error);
185 EXPECT_TRUE(error.IsSuccess());
186 EXPECT_NE(service, temporary_service);
187
188 // However this service will not be part of the provider.
189 EXPECT_EQ(1, GetServiceCount());
190 }
191 }
192
TEST_F(VPNProviderTest,OnDeviceInfoAvailable)193 TEST_F(VPNProviderTest, OnDeviceInfoAvailable) {
194 const string kInterfaceName("tun0");
195 const int kInterfaceIndex = 1;
196
197 unique_ptr<MockVPNDriver> bad_driver(new MockVPNDriver());
198 EXPECT_CALL(*bad_driver.get(), ClaimInterface(_, _))
199 .Times(2)
200 .WillRepeatedly(Return(false));
201 provider_.services_.push_back(new VPNService(&control_, nullptr, &metrics_,
202 nullptr, bad_driver.release()));
203
204 EXPECT_FALSE(provider_.OnDeviceInfoAvailable(kInterfaceName,
205 kInterfaceIndex));
206
207 unique_ptr<MockVPNDriver> good_driver(new MockVPNDriver());
208 EXPECT_CALL(*good_driver.get(), ClaimInterface(_, _))
209 .WillOnce(Return(true));
210 provider_.services_.push_back(new VPNService(&control_, nullptr, &metrics_,
211 nullptr, good_driver.release()));
212
213 unique_ptr<MockVPNDriver> dup_driver(new MockVPNDriver());
214 EXPECT_CALL(*dup_driver.get(), ClaimInterface(_, _))
215 .Times(0);
216 provider_.services_.push_back(new VPNService(&control_, nullptr, &metrics_,
217 nullptr, dup_driver.release()));
218
219 EXPECT_TRUE(provider_.OnDeviceInfoAvailable(kInterfaceName, kInterfaceIndex));
220 provider_.services_.clear();
221 }
222
TEST_F(VPNProviderTest,RemoveService)223 TEST_F(VPNProviderTest, RemoveService) {
224 scoped_refptr<MockVPNService> service0(
225 new MockVPNService(&control_, nullptr, &metrics_, nullptr, nullptr));
226 scoped_refptr<MockVPNService> service1(
227 new MockVPNService(&control_, nullptr, &metrics_, nullptr, nullptr));
228 scoped_refptr<MockVPNService> service2(
229 new MockVPNService(&control_, nullptr, &metrics_, nullptr, nullptr));
230
231 provider_.services_.push_back(service0.get());
232 provider_.services_.push_back(service1.get());
233 provider_.services_.push_back(service2.get());
234
235 ASSERT_EQ(3, provider_.services_.size());
236
237 provider_.RemoveService(service1);
238
239 EXPECT_EQ(2, provider_.services_.size());
240 EXPECT_EQ(service0, provider_.services_[0]);
241 EXPECT_EQ(service2, provider_.services_[1]);
242
243 provider_.RemoveService(service2);
244
245 EXPECT_EQ(1, provider_.services_.size());
246 EXPECT_EQ(service0, provider_.services_[0]);
247
248 provider_.RemoveService(service0);
249 EXPECT_EQ(0, provider_.services_.size());
250 }
251
252 MATCHER_P(ServiceWithStorageId, storage_id, "") {
253 return arg->GetStorageIdentifier() == storage_id;
254 }
255
TEST_F(VPNProviderTest,CreateServicesFromProfile)256 TEST_F(VPNProviderTest, CreateServicesFromProfile) {
257 FakeStore storage;
258 storage.SetString("no_type", "Name", "No Type Entry");
259 storage.SetString("no_vpn", "Type", "wimax");
260 storage.SetString("vpn_no_provider_type", "Type", "vpn");
261 storage.SetString("vpn_no_name", "Type", "vpn");
262 storage.SetString("vpn_no_name", "Provider.Type", "openvpn");
263 storage.SetString("vpn_no_host", "Type", "vpn");
264 storage.SetString("vpn_no_host", "Provider.Type", "openvpn");
265 storage.SetString("vpn_ho_host", "Name", "name");
266 storage.SetString("vpn_complete", "Type", "vpn");
267 storage.SetString("vpn_complete", "Provider.Type", "openvpn");
268 storage.SetString("vpn_complete", "Name", "name");
269 storage.SetString("vpn_complete", "Provider.Host", "1.2.3.4");
270
271 scoped_refptr<MockProfile> profile(
272 new NiceMock<MockProfile>(&control_, &metrics_, &manager_, ""));
273 EXPECT_CALL(*profile, GetConstStorage()).WillRepeatedly(Return(&storage));
274
275 EXPECT_CALL(manager_, device_info()).WillRepeatedly(Return(nullptr));
276 EXPECT_CALL(manager_,
277 RegisterService(ServiceWithStorageId("vpn_complete")));
278 EXPECT_CALL(*profile,
279 ConfigureService(ServiceWithStorageId("vpn_complete")))
280 .WillOnce(Return(true));
281 provider_.CreateServicesFromProfile(profile);
282
283 GetServiceAt(0)->driver()->args()->SetString(kProviderHostProperty,
284 "1.2.3.4");
285 // Calling this again should not create any more services (checked by the
286 // Times(1) above).
287 provider_.CreateServicesFromProfile(profile);
288 }
289
TEST_F(VPNProviderTest,CreateService)290 TEST_F(VPNProviderTest, CreateService) {
291 static const char kName[] = "test-vpn-service";
292 static const char kStorageID[] = "test_vpn_storage_id";
293 static const char* kTypes[] = {
294 kProviderOpenVpn,
295 kProviderL2tpIpsec,
296 kProviderThirdPartyVpn
297 };
298 const size_t kTypesCount = arraysize(kTypes);
299 EXPECT_CALL(manager_, device_info())
300 .Times(kTypesCount)
301 .WillRepeatedly(Return(&device_info_));
302 EXPECT_CALL(manager_, RegisterService(_)).Times(kTypesCount);
303 for (size_t i = 0; i < kTypesCount; i++) {
304 Error error;
305 VPNServiceRefPtr service =
306 provider_.CreateService(kTypes[i], kName, kStorageID, &error);
307 ASSERT_TRUE(service) << kTypes[i];
308 ASSERT_TRUE(service->driver()) << kTypes[i];
309 EXPECT_EQ(kTypes[i], service->driver()->GetProviderType());
310 EXPECT_EQ(kName, GetServiceFriendlyName(service)) << kTypes[i];
311 EXPECT_EQ(kStorageID, service->GetStorageIdentifier()) << kTypes[i];
312 EXPECT_TRUE(error.IsSuccess()) << kTypes[i];
313 }
314 Error error;
315 VPNServiceRefPtr unknown_service =
316 provider_.CreateService("unknown-vpn-type", kName, kStorageID, &error);
317 EXPECT_FALSE(unknown_service);
318 EXPECT_EQ(Error::kNotSupported, error.type());
319 }
320
TEST_F(VPNProviderTest,CreateTemporaryServiceFromProfile)321 TEST_F(VPNProviderTest, CreateTemporaryServiceFromProfile) {
322 FakeStore storage;
323 storage.SetString("no_vpn", "Type", "wimax");
324 storage.SetString("vpn_no_provider_type", "Type", "vpn");
325 storage.SetString("vpn_no_name", "Type", "vpn");
326 storage.SetString("vpn_no_name", "Provider.Type", "openvpn");
327 storage.SetString("vpn_no_host", "Type", "vpn");
328 storage.SetString("vpn_no_host", "Provider.Type", "openvpn");
329 storage.SetString("vpn_no_host", "Name", "name");
330 storage.SetString("vpn_complete", "Type", "vpn");
331 storage.SetString("vpn_complete", "Provider.Type", "openvpn");
332 storage.SetString("vpn_complete", "Name", "name");
333 storage.SetString("vpn_complete", "Provider.Host", "1.2.3.4");
334
335 scoped_refptr<MockProfile> profile(
336 new NiceMock<MockProfile>(&control_, &metrics_, &manager_, ""));
337 EXPECT_CALL(*profile, GetConstStorage()).WillRepeatedly(Return(&storage));
338 Error error;
339
340 // Non VPN entry.
341 EXPECT_EQ(nullptr,
342 provider_.CreateTemporaryServiceFromProfile(profile,
343 "no_vpn",
344 &error));
345 EXPECT_FALSE(error.IsSuccess());
346 EXPECT_THAT(error.message(),
347 StartsWith("Unspecified or invalid network type"));
348
349 // VPN type not specified.
350 error.Reset();
351 EXPECT_EQ(nullptr,
352 provider_.CreateTemporaryServiceFromProfile(profile,
353 "vpn_no_provider_type",
354 &error));
355 EXPECT_FALSE(error.IsSuccess());
356 EXPECT_THAT(error.message(), StartsWith("VPN type not specified"));
357
358 // Name not specified.
359 error.Reset();
360 EXPECT_EQ(nullptr,
361 provider_.CreateTemporaryServiceFromProfile(profile,
362 "vpn_no_name",
363 &error));
364 EXPECT_FALSE(error.IsSuccess());
365 EXPECT_THAT(error.message(), StartsWith("Network name not specified"));
366
367 // Host not specified.
368 error.Reset();
369 EXPECT_EQ(nullptr,
370 provider_.CreateTemporaryServiceFromProfile(profile,
371 "vpn_no_host",
372 &error));
373 EXPECT_FALSE(error.IsSuccess());
374 EXPECT_THAT(error.message(), StartsWith("Host not specified"));
375
376 // Valid VPN service entry.
377 error.Reset();
378 EXPECT_NE(nullptr,
379 provider_.CreateTemporaryServiceFromProfile(profile,
380 "vpn_complete",
381 &error));
382 EXPECT_TRUE(error.IsSuccess());
383 }
384
TEST_F(VPNProviderTest,HasActiveService)385 TEST_F(VPNProviderTest, HasActiveService) {
386 EXPECT_FALSE(provider_.HasActiveService());
387
388 scoped_refptr<MockVPNService> service0(
389 new MockVPNService(&control_, nullptr, &metrics_, nullptr, nullptr));
390 scoped_refptr<MockVPNService> service1(
391 new MockVPNService(&control_, nullptr, &metrics_, nullptr, nullptr));
392 scoped_refptr<MockVPNService> service2(
393 new MockVPNService(&control_, nullptr, &metrics_, nullptr, nullptr));
394
395 AddService(service0);
396 AddService(service1);
397 AddService(service2);
398 EXPECT_FALSE(provider_.HasActiveService());
399
400 SetConnectState(service1, Service::kStateAssociating);
401 EXPECT_TRUE(provider_.HasActiveService());
402
403 SetConnectState(service1, Service::kStateOnline);
404 EXPECT_TRUE(provider_.HasActiveService());
405 }
406
407 } // namespace shill
408