• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/dhcp/dhcpv4_config.h"
18 
19 #include <memory>
20 #include <string>
21 #include <vector>
22 
23 #include <base/bind.h>
24 #include <base/files/file_util.h>
25 #include <base/files/scoped_temp_dir.h>
26 #include <base/strings/stringprintf.h>
27 #if defined(__ANDROID__)
28 #include <dbus/service_constants.h>
29 #else
30 #include <chromeos/dbus/service_constants.h>
31 #endif  // __ANDROID__
32 
33 #include "shill/dhcp/mock_dhcp_provider.h"
34 #include "shill/dhcp/mock_dhcp_proxy.h"
35 #include "shill/event_dispatcher.h"
36 #include "shill/mock_control.h"
37 #include "shill/mock_dhcp_properties.h"
38 #include "shill/mock_log.h"
39 #include "shill/mock_metrics.h"
40 #include "shill/mock_process_manager.h"
41 #include "shill/mock_store.h"
42 #include "shill/property_store_unittest.h"
43 #include "shill/testing.h"
44 
45 using base::Bind;
46 using base::FilePath;
47 using base::ScopedTempDir;
48 using base::Unretained;
49 using std::string;
50 using std::unique_ptr;
51 using std::vector;
52 using testing::_;
53 using testing::AnyNumber;
54 using testing::ContainsRegex;
55 using testing::DoAll;
56 using testing::InvokeWithoutArgs;
57 using testing::Mock;
58 using testing::Return;
59 using testing::SetArgumentPointee;
60 using testing::Test;
61 
62 namespace shill {
63 
64 namespace {
65 const char kDeviceName[] = "eth0";
66 const char kHostName[] = "hostname";
67 const char kVendorClass[] = "vendorclass";
68 const char kLeaseFileSuffix[] = "leasefilesuffix";
69 const bool kArpGateway = true;
70 const bool kHasHostname = true;
71 const bool kHasVendorClass = true;
72 const bool kHasLeaseSuffix = true;
73 const char kStorageID[] = "dhcp_service_id";
74 }  // namespace
75 
76 typedef scoped_refptr<DHCPv4Config> DHCPv4ConfigRefPtr;
77 
78 class DHCPv4ConfigTest : public PropertyStoreTest {
79  public:
DHCPv4ConfigTest()80   DHCPv4ConfigTest()
81       : proxy_(new MockDHCPProxy()),
82         metrics_(dispatcher()),
83         config_(new DHCPv4Config(&control_,
84                                  dispatcher(),
85                                  &provider_,
86                                  kDeviceName,
87                                  kLeaseFileSuffix,
88                                  kArpGateway,
89                                  dhcp_props_,
90                                  &metrics_)) {}
91 
SetUp()92   virtual void SetUp() {
93     config_->process_manager_ = &process_manager_;
94   }
95 
StartInstance(DHCPv4ConfigRefPtr config)96   bool StartInstance(DHCPv4ConfigRefPtr config) {
97     return config->Start();
98   }
99 
StopInstance()100   void StopInstance() {
101     config_->Stop("In test");
102   }
103 
104   DHCPv4ConfigRefPtr CreateMockMinijailConfig(const string& hostname,
105                                               const string& vendorclass,
106                                               const string& lease_suffix,
107                                               bool arp_gateway);
108   DHCPv4ConfigRefPtr CreateRunningConfig(const string& hostname,
109                                          const string& vendorclass,
110                                          const string& lease_suffix,
111                                          bool arp_gateway);
112   void StopRunningConfigAndExpect(DHCPv4ConfigRefPtr config,
113                                   bool lease_file_exists);
114 
115  protected:
116   static const int kPID;
117 
118   FilePath lease_file_;
119   FilePath pid_file_;
120   ScopedTempDir temp_dir_;
121   unique_ptr<MockDHCPProxy> proxy_;
122   MockControl control_;
123   MockProcessManager process_manager_;
124   MockMetrics metrics_;
125   MockDHCPProvider provider_;
126   MockDhcpProperties dhcp_props_;
127   DHCPv4ConfigRefPtr config_;
128 };
129 
130 const int DHCPv4ConfigTest::kPID = 123456;
131 
CreateMockMinijailConfig(const string & hostname,const string & vendorclass,const string & lease_suffix,bool arp_gateway)132 DHCPv4ConfigRefPtr DHCPv4ConfigTest::CreateMockMinijailConfig(
133     const string& hostname,
134     const string& vendorclass,
135     const string& lease_suffix,
136     bool arp_gateway) {
137   MockStore storage;
138   DhcpProperties dhcp_props;
139   if (!hostname.empty()) {
140     EXPECT_CALL(storage, GetString(kStorageID, "DHCPProperty.Hostname", _))
141         .WillOnce(DoAll(SetArgumentPointee<2>(string(kHostName)),
142                         Return(true)));
143   } else {
144     EXPECT_CALL(storage, GetString(kStorageID, "DHCPProperty.Hostname", _))
145         .WillOnce(Return(false));
146   }
147   if (!vendorclass.empty()) {
148     EXPECT_CALL(storage, GetString(kStorageID, "DHCPProperty.VendorClass", _))
149         .WillOnce(DoAll(SetArgumentPointee<2>(string(kVendorClass)),
150                         Return(true)));
151   } else {
152     EXPECT_CALL(storage, GetString(kStorageID, "DHCPProperty.VendorClass", _))
153         .WillOnce(Return(false));
154   }
155   dhcp_props.Load(&storage, kStorageID);
156   DHCPv4ConfigRefPtr config(new DHCPv4Config(&control_,
157                                              dispatcher(),
158                                              &provider_,
159                                              kDeviceName,
160                                              lease_suffix,
161                                              arp_gateway,
162                                              dhcp_props,
163                                              &metrics_));
164   config->process_manager_ = &process_manager_;
165 
166   return config;
167 }
168 
CreateRunningConfig(const string & hostname,const string & vendorclass,const string & lease_suffix,bool arp_gateway)169 DHCPv4ConfigRefPtr DHCPv4ConfigTest::CreateRunningConfig(
170     const string& hostname, const string& vendorclass,
171     const string& lease_suffix, bool arp_gateway) {
172   MockStore storage;
173   DhcpProperties dhcp_props;
174   if (!hostname.empty()) {
175     EXPECT_CALL(storage, GetString(kStorageID, "DHCPProperty.Hostname", _))
176         .WillOnce(DoAll(SetArgumentPointee<2>(string(kHostName)),
177                         Return(true)));
178   } else {
179     EXPECT_CALL(storage, GetString(kStorageID, "DHCPProperty.Hostname", _))
180         .WillOnce(Return(false));
181   }
182   if (!vendorclass.empty()) {
183     EXPECT_CALL(storage, GetString(kStorageID, "DHCPProperty.VendorClass", _))
184         .WillOnce(DoAll(SetArgumentPointee<2>(string(kVendorClass)),
185                         Return(true)));
186   } else {
187     EXPECT_CALL(storage, GetString(kStorageID, "DHCPProperty.VendorClass", _))
188         .WillOnce(Return(false));
189   }
190   dhcp_props.Load(&storage, kStorageID);
191   DHCPv4ConfigRefPtr config(new DHCPv4Config(&control_,
192                                              dispatcher(),
193                                              &provider_,
194                                              kDeviceName,
195                                              lease_suffix,
196                                              arp_gateway,
197                                              dhcp_props,
198                                              &metrics_));
199   config->process_manager_ = &process_manager_;
200   EXPECT_CALL(process_manager_, StartProcessInMinijail(_, _, _, _, _, _, _))
201       .WillOnce(Return(kPID));
202   EXPECT_CALL(provider_, BindPID(kPID, IsRefPtrTo(config)));
203   EXPECT_TRUE(config->Start());
204   EXPECT_EQ(kPID, config->pid_);
205   EXPECT_EQ(config->hostname_, hostname);
206   EXPECT_EQ(config->vendor_class_, vendorclass);
207 
208   EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
209   config->root_ = temp_dir_.path();
210   FilePath varrun = temp_dir_.path().Append("var/run/dhcpcd");
211   EXPECT_TRUE(base::CreateDirectory(varrun));
212   pid_file_ = varrun.Append(base::StringPrintf("dhcpcd-%s-4.pid", kDeviceName));
213   FilePath varlib = temp_dir_.path().Append("var/lib/dhcpcd");
214   EXPECT_TRUE(base::CreateDirectory(varlib));
215   lease_file_ =
216       varlib.Append(base::StringPrintf("dhcpcd-%s.lease", kDeviceName));
217   EXPECT_EQ(0, base::WriteFile(pid_file_, "", 0));
218   EXPECT_EQ(0, base::WriteFile(lease_file_, "", 0));
219   EXPECT_TRUE(base::PathExists(pid_file_));
220   EXPECT_TRUE(base::PathExists(lease_file_));
221 
222   return config;
223 }
224 
StopRunningConfigAndExpect(DHCPv4ConfigRefPtr config,bool lease_file_exists)225 void DHCPv4ConfigTest::StopRunningConfigAndExpect(DHCPv4ConfigRefPtr config,
226                                                   bool lease_file_exists) {
227   ScopedMockLog log;
228   // We use a non-zero exit status so that we get the log message.
229   EXPECT_CALL(log, Log(_, _, ::testing::EndsWith("status 10")));
230   EXPECT_CALL(provider_, UnbindPID(kPID));
231   config->OnProcessExited(10);
232 
233   EXPECT_FALSE(base::PathExists(pid_file_));
234   EXPECT_EQ(lease_file_exists, base::PathExists(lease_file_));
235 }
236 
TEST_F(DHCPv4ConfigTest,GetIPv4AddressString)237 TEST_F(DHCPv4ConfigTest, GetIPv4AddressString) {
238   EXPECT_EQ("255.255.255.255", config_->GetIPv4AddressString(0xffffffff));
239   EXPECT_EQ("0.0.0.0", config_->GetIPv4AddressString(0));
240   EXPECT_EQ("1.2.3.4", config_->GetIPv4AddressString(0x04030201));
241 }
242 
TEST_F(DHCPv4ConfigTest,ParseClasslessStaticRoutes)243 TEST_F(DHCPv4ConfigTest, ParseClasslessStaticRoutes) {
244   const string kDefaultAddress = "0.0.0.0";
245   const string kDefaultDestination = kDefaultAddress + "/0";
246   const string kRouter0 = "10.0.0.254";
247   const string kAddress1 = "192.168.1.0";
248   const string kDestination1 = kAddress1 + "/24";
249   // Last gateway missing, leaving an odd number of parameters.
250   const string kBrokenClasslessRoutes0 = kDefaultDestination + " " + kRouter0 +
251       " " + kDestination1;
252   IPConfig::Properties properties;
253   EXPECT_FALSE(DHCPv4Config::ParseClasslessStaticRoutes(kBrokenClasslessRoutes0,
254                                                         &properties));
255   EXPECT_TRUE(properties.routes.empty());
256   EXPECT_TRUE(properties.gateway.empty());
257 
258   // Gateway argument for the second route is malformed, but we were able
259   // to salvage a default gateway.
260   const string kBrokenRouter1 = "10.0.0";
261   const string kBrokenClasslessRoutes1 = kBrokenClasslessRoutes0 + " " +
262       kBrokenRouter1;
263   EXPECT_FALSE(DHCPv4Config::ParseClasslessStaticRoutes(kBrokenClasslessRoutes1,
264                                                         &properties));
265   EXPECT_TRUE(properties.routes.empty());
266   EXPECT_EQ(kRouter0, properties.gateway);
267 
268   const string kRouter1 = "10.0.0.253";
269   const string kRouter2 = "10.0.0.252";
270   const string kClasslessRoutes0 = kDefaultDestination + " " + kRouter2 + " " +
271       kDestination1 + " " + kRouter1;
272   EXPECT_TRUE(DHCPv4Config::ParseClasslessStaticRoutes(kClasslessRoutes0,
273                                                        &properties));
274   // The old default route is preserved.
275   EXPECT_EQ(kRouter0, properties.gateway);
276 
277   // The two routes (including the one which would have otherwise been
278   // classified as a default route) are added to the routing table.
279   EXPECT_EQ(2, properties.routes.size());
280   const IPConfig::Route& route0 = properties.routes[0];
281   EXPECT_EQ(kDefaultAddress, route0.host);
282   EXPECT_EQ("0.0.0.0", route0.netmask);
283   EXPECT_EQ(kRouter2, route0.gateway);
284 
285   const IPConfig::Route& route1 = properties.routes[1];
286   EXPECT_EQ(kAddress1, route1.host);
287   EXPECT_EQ("255.255.255.0", route1.netmask);
288   EXPECT_EQ(kRouter1, route1.gateway);
289 
290   // A malformed routing table should not affect the current table.
291   EXPECT_FALSE(DHCPv4Config::ParseClasslessStaticRoutes(kBrokenClasslessRoutes1,
292                                                         &properties));
293   EXPECT_EQ(2, properties.routes.size());
294   EXPECT_EQ(kRouter0, properties.gateway);
295 }
296 
TEST_F(DHCPv4ConfigTest,ParseConfiguration)297 TEST_F(DHCPv4ConfigTest, ParseConfiguration) {
298   KeyValueStore conf;
299   conf.SetUint(DHCPv4Config::kConfigurationKeyIPAddress, 0x01020304);
300   conf.SetUint8(DHCPv4Config::kConfigurationKeySubnetCIDR, 16);
301   conf.SetUint(DHCPv4Config::kConfigurationKeyBroadcastAddress, 0x10203040);
302   {
303     vector<uint32_t> routers;
304     routers.push_back(0x02040608);
305     routers.push_back(0x03050709);
306     conf.SetUint32s(DHCPv4Config::kConfigurationKeyRouters, routers);
307   }
308   {
309     vector<uint32_t> dns;
310     dns.push_back(0x09070503);
311     dns.push_back(0x08060402);
312     conf.SetUint32s(DHCPv4Config::kConfigurationKeyDNS, dns);
313   }
314   conf.SetString(DHCPv4Config::kConfigurationKeyDomainName, "domain-name");
315   {
316     vector<string> search;
317     search.push_back("foo.com");
318     search.push_back("bar.com");
319     conf.SetStrings(DHCPv4Config::kConfigurationKeyDomainSearch, search);
320   }
321   conf.SetUint16(DHCPv4Config::kConfigurationKeyMTU, 600);
322   conf.SetString(DHCPv4Config::kConfigurationKeyHostname, "hostname");
323   conf.SetString("UnknownKey", "UnknownValue");
324 
325   EXPECT_CALL(metrics_,
326               SendSparseToUMA(Metrics::kMetricDhcpClientMTUValue, 600));
327   IPConfig::Properties properties;
328   ASSERT_TRUE(config_->ParseConfiguration(conf, &properties));
329   EXPECT_EQ("4.3.2.1", properties.address);
330   EXPECT_EQ(16, properties.subnet_prefix);
331   EXPECT_EQ("64.48.32.16", properties.broadcast_address);
332   EXPECT_EQ("8.6.4.2", properties.gateway);
333   ASSERT_EQ(2, properties.dns_servers.size());
334   EXPECT_EQ("3.5.7.9", properties.dns_servers[0]);
335   EXPECT_EQ("2.4.6.8", properties.dns_servers[1]);
336   EXPECT_EQ("domain-name", properties.domain_name);
337   ASSERT_EQ(2, properties.domain_search.size());
338   EXPECT_EQ("foo.com", properties.domain_search[0]);
339   EXPECT_EQ("bar.com", properties.domain_search[1]);
340   EXPECT_EQ(600, properties.mtu);
341   EXPECT_EQ("hostname", properties.accepted_hostname);
342 }
343 
TEST_F(DHCPv4ConfigTest,ParseConfigurationWithMinimumMTU)344 TEST_F(DHCPv4ConfigTest, ParseConfigurationWithMinimumMTU) {
345   // Even without a minimum MTU set, we should ignore a 576 value.
346   KeyValueStore conf;
347   conf.SetUint16(DHCPv4Config::kConfigurationKeyMTU, 576);
348 
349   IPConfig::Properties properties;
350   EXPECT_CALL(metrics_,
351               SendSparseToUMA(Metrics::kMetricDhcpClientMTUValue, 576));
352   ASSERT_TRUE(config_->ParseConfiguration(conf, &properties));
353   EXPECT_EQ(IPConfig::kUndefinedMTU, properties.mtu);
354   Mock::VerifyAndClearExpectations(&metrics_);
355 
356   // With a minimum MTU set, values below the minimum should be ignored.
357   config_->set_minimum_mtu(1500);
358   conf.RemoveUint16(DHCPv4Config::kConfigurationKeyMTU);
359   conf.SetUint16(DHCPv4Config::kConfigurationKeyMTU, 1499);
360   EXPECT_CALL(metrics_,
361               SendSparseToUMA(Metrics::kMetricDhcpClientMTUValue, 1499));
362   ASSERT_TRUE(config_->ParseConfiguration(conf, &properties));
363   EXPECT_EQ(IPConfig::kUndefinedMTU, properties.mtu);
364   Mock::VerifyAndClearExpectations(&metrics_);
365 
366   // A value (other than 576) should be accepted if it is >= mimimum_mtu.
367   config_->set_minimum_mtu(577);
368   conf.RemoveUint16(DHCPv4Config::kConfigurationKeyMTU);
369   conf.SetUint16(DHCPv4Config::kConfigurationKeyMTU, 577);
370   EXPECT_CALL(metrics_,
371               SendSparseToUMA(Metrics::kMetricDhcpClientMTUValue, 577));
372   ASSERT_TRUE(config_->ParseConfiguration(conf, &properties));
373   EXPECT_EQ(577, properties.mtu);
374 }
375 
376 MATCHER_P4(IsDHCPCDArgs,
377            has_hostname,
378            has_vendorclass,
379            has_arp_gateway,
380            has_lease_suffix, "") {
381   if (arg[0] != "-B" ||
382       arg[1] != "-q" ||
383       arg[2] != "-4") {
384     return false;
385   }
386 
387   int end_offset = 3;
388   if (has_hostname) {
389     if (arg[end_offset] != "-h" ||
390         arg[end_offset + 1] != kHostName) {
391       return false;
392     }
393     end_offset += 2;
394   }
395 
396   if (has_vendorclass){
397     if (arg[end_offset] != "-i" ||
398         arg[end_offset + 1] != kVendorClass) {
399       return false;
400     }
401     end_offset += 2;
402   }
403 
404   if (has_arp_gateway) {
405     if (arg[end_offset] != "-R" ||
406         arg[end_offset + 1] != "-P") {
407       return false;
408     }
409     end_offset += 2;
410   }
411 
412   string device_arg = has_lease_suffix ?
413       string(kDeviceName) + "=" + string(kLeaseFileSuffix) : kDeviceName;
414   return arg[end_offset] == device_arg;
415 }
416 
TEST_F(DHCPv4ConfigTest,StartWithHostname)417 TEST_F(DHCPv4ConfigTest, StartWithHostname) {
418   config_->hostname_ = kHostName;
419   EXPECT_CALL(process_manager_,
420               StartProcessInMinijail(_, _,
421                                      IsDHCPCDArgs(kHasHostname,
422                                                   !kHasVendorClass,
423                                                   kArpGateway,
424                                                   kHasLeaseSuffix), _, _, _, _))
425       .WillOnce(Return(-1));
426   EXPECT_FALSE(StartInstance(config_));
427 }
428 
TEST_F(DHCPv4ConfigTest,StartWithoutHostname)429 TEST_F(DHCPv4ConfigTest, StartWithoutHostname) {
430   DHCPv4ConfigRefPtr config = CreateMockMinijailConfig("",
431                                                        "",
432                                                        kLeaseFileSuffix,
433                                                        kArpGateway);
434   EXPECT_CALL(process_manager_,
435               StartProcessInMinijail(_, _,
436                                      IsDHCPCDArgs(!kHasHostname,
437                                                   !kHasVendorClass,
438                                                   kArpGateway,
439                                                   kHasLeaseSuffix), _, _, _, _))
440       .WillOnce(Return(-1));
441   EXPECT_FALSE(StartInstance(config));
442 }
443 
TEST_F(DHCPv4ConfigTest,StartWithEmptyHostname)444 TEST_F(DHCPv4ConfigTest, StartWithEmptyHostname) {
445   DHCPv4ConfigRefPtr config = CreateMockMinijailConfig("",
446                                                        "",
447                                                        kLeaseFileSuffix,
448                                                        kArpGateway);
449   EXPECT_CALL(process_manager_,
450               StartProcessInMinijail(_, _,
451                                      IsDHCPCDArgs(!kHasHostname,
452                                                   !kHasVendorClass,
453                                                   kArpGateway,
454                                                   kHasLeaseSuffix), _, _, _, _))
455       .WillOnce(Return(-1));
456   EXPECT_FALSE(StartInstance(config));
457 }
458 
TEST_F(DHCPv4ConfigTest,StartWithVendorClass)459 TEST_F(DHCPv4ConfigTest, StartWithVendorClass) {
460   config_->hostname_ = kHostName;
461   config_->vendor_class_ = kVendorClass;
462   EXPECT_CALL(process_manager_,
463               StartProcessInMinijail(_, _,
464                                      IsDHCPCDArgs(kHasHostname,
465                                                   kHasVendorClass,
466                                                   kArpGateway,
467                                                   kHasLeaseSuffix), _, _, _, _))
468       .WillOnce(Return(-1));
469   EXPECT_FALSE(StartInstance(config_));
470 }
471 
TEST_F(DHCPv4ConfigTest,StartWithoutVendorClass)472 TEST_F(DHCPv4ConfigTest, StartWithoutVendorClass) {
473   DHCPv4ConfigRefPtr config = CreateMockMinijailConfig(kHostName,
474                                                        "",
475                                                        kLeaseFileSuffix,
476                                                        kArpGateway);
477   EXPECT_CALL(process_manager_,
478               StartProcessInMinijail(_, _,
479                                      IsDHCPCDArgs(kHasHostname,
480                                                   !kHasVendorClass,
481                                                   kArpGateway,
482                                                   kHasLeaseSuffix), _, _, _, _))
483       .WillOnce(Return(-1));
484   EXPECT_FALSE(StartInstance(config));
485 }
486 
487 
TEST_F(DHCPv4ConfigTest,StartWithoutArpGateway)488 TEST_F(DHCPv4ConfigTest, StartWithoutArpGateway) {
489   DHCPv4ConfigRefPtr config = CreateMockMinijailConfig(kHostName,
490                                                        "",
491                                                        kLeaseFileSuffix,
492                                                        !kArpGateway);
493   EXPECT_CALL(process_manager_,
494               StartProcessInMinijail(_, _,
495                                      IsDHCPCDArgs(kHasHostname,
496                                                   !kHasVendorClass,
497                                                   !kArpGateway,
498                                                   kHasLeaseSuffix), _, _, _, _))
499       .WillOnce(Return(-1));
500   EXPECT_FALSE(StartInstance(config));
501 }
502 
503 namespace {
504 
505 class DHCPv4ConfigCallbackTest : public DHCPv4ConfigTest {
506  public:
SetUp()507   virtual void SetUp() {
508     DHCPv4ConfigTest::SetUp();
509     config_->RegisterUpdateCallback(
510         Bind(&DHCPv4ConfigCallbackTest::SuccessCallback, Unretained(this)));
511     config_->RegisterFailureCallback(
512         Bind(&DHCPv4ConfigCallbackTest::FailureCallback, Unretained(this)));
513     ip_config_ = config_;
514   }
515 
516   MOCK_METHOD2(SuccessCallback,
517                void(const IPConfigRefPtr& ipconfig, bool new_lease_acquired));
518   MOCK_METHOD1(FailureCallback, void(const IPConfigRefPtr& ipconfig));
519 
520   // The mock methods above take IPConfigRefPtr because this is the type
521   // that the registered callbacks take.  This conversion of the DHCP
522   // config ref pointer eases our work in setting up expectations.
ConfigRef()523   const IPConfigRefPtr& ConfigRef() { return ip_config_; }
524 
525  private:
526   IPConfigRefPtr ip_config_;
527 };
528 
529 }  // namespace
530 
TEST_F(DHCPv4ConfigCallbackTest,ProcessEventSignalFail)531 TEST_F(DHCPv4ConfigCallbackTest, ProcessEventSignalFail) {
532   KeyValueStore conf;
533   conf.SetUint(DHCPv4Config::kConfigurationKeyIPAddress, 0x01020304);
534   EXPECT_CALL(*this, SuccessCallback(_, _)).Times(0);
535   EXPECT_CALL(*this, FailureCallback(ConfigRef()));
536   config_->ProcessEventSignal(DHCPv4Config::kReasonFail, conf);
537   Mock::VerifyAndClearExpectations(this);
538   EXPECT_TRUE(config_->properties().address.empty());
539 }
540 
TEST_F(DHCPv4ConfigCallbackTest,ProcessEventSignalSuccess)541 TEST_F(DHCPv4ConfigCallbackTest, ProcessEventSignalSuccess) {
542   for (const auto& reason : { DHCPv4Config::kReasonBound,
543                               DHCPv4Config::kReasonRebind,
544                               DHCPv4Config::kReasonReboot,
545                               DHCPv4Config::kReasonRenew }) {
546     int address_octet = 0;
547     for (const auto lease_time_given : { false, true }) {
548       KeyValueStore conf;
549       conf.SetUint(DHCPv4Config::kConfigurationKeyIPAddress, ++address_octet);
550       if (lease_time_given) {
551         const uint32_t kLeaseTime = 1;
552         conf.SetUint(DHCPv4Config::kConfigurationKeyLeaseTime, kLeaseTime);
553       }
554       EXPECT_CALL(*this, SuccessCallback(ConfigRef(), true));
555       EXPECT_CALL(*this, FailureCallback(_)).Times(0);
556       config_->ProcessEventSignal(reason, conf);
557       string failure_message = string(reason) + " failed with lease time " +
558           (lease_time_given ? "given" : "not given");
559       EXPECT_TRUE(Mock::VerifyAndClearExpectations(this)) << failure_message;
560       EXPECT_EQ(base::StringPrintf("%d.0.0.0", address_octet),
561                 config_->properties().address) << failure_message;
562     }
563   }
564 }
565 
TEST_F(DHCPv4ConfigCallbackTest,StoppedDuringFailureCallback)566 TEST_F(DHCPv4ConfigCallbackTest, StoppedDuringFailureCallback) {
567   KeyValueStore conf;
568   conf.SetUint(DHCPv4Config::kConfigurationKeyIPAddress, 0x01020304);
569   // Stop the DHCP config while it is calling the failure callback.  We
570   // need to ensure that no callbacks are left running inadvertently as
571   // a result.
572   EXPECT_CALL(*this, FailureCallback(ConfigRef()))
573       .WillOnce(InvokeWithoutArgs(this, &DHCPv4ConfigTest::StopInstance));
574   config_->ProcessEventSignal(DHCPv4Config::kReasonFail, conf);
575   EXPECT_TRUE(Mock::VerifyAndClearExpectations(this));
576 }
577 
TEST_F(DHCPv4ConfigCallbackTest,StoppedDuringSuccessCallback)578 TEST_F(DHCPv4ConfigCallbackTest, StoppedDuringSuccessCallback) {
579   KeyValueStore conf;
580   conf.SetUint(DHCPv4Config::kConfigurationKeyIPAddress, 0x01020304);
581   const uint32_t kLeaseTime = 1;
582   conf.SetUint(DHCPv4Config::kConfigurationKeyLeaseTime, kLeaseTime);
583   // Stop the DHCP config while it is calling the success callback.  This
584   // can happen if the device has a static IP configuration and releases
585   // the lease after accepting other network parameters from the DHCP
586   // IPConfig properties.  We need to ensure that no callbacks are left
587   // running inadvertently as a result.
588   EXPECT_CALL(*this, SuccessCallback(ConfigRef(), true))
589       .WillOnce(InvokeWithoutArgs(this, &DHCPv4ConfigTest::StopInstance));
590   config_->ProcessEventSignal(DHCPv4Config::kReasonBound, conf);
591   EXPECT_TRUE(Mock::VerifyAndClearExpectations(this));
592 }
593 
TEST_F(DHCPv4ConfigCallbackTest,ProcessEventSignalUnknown)594 TEST_F(DHCPv4ConfigCallbackTest, ProcessEventSignalUnknown) {
595   KeyValueStore conf;
596   conf.SetUint(DHCPv4Config::kConfigurationKeyIPAddress, 0x01020304);
597   static const char kReasonUnknown[] = "UNKNOWN_REASON";
598   EXPECT_CALL(*this, SuccessCallback(_, _)).Times(0);
599   EXPECT_CALL(*this, FailureCallback(_)).Times(0);
600   config_->ProcessEventSignal(kReasonUnknown, conf);
601   Mock::VerifyAndClearExpectations(this);
602   EXPECT_TRUE(config_->properties().address.empty());
603 }
604 
TEST_F(DHCPv4ConfigCallbackTest,ProcessEventSignalGatewayArp)605 TEST_F(DHCPv4ConfigCallbackTest, ProcessEventSignalGatewayArp) {
606   KeyValueStore conf;
607   conf.SetUint(DHCPv4Config::kConfigurationKeyIPAddress, 0x01020304);
608   EXPECT_CALL(*this, SuccessCallback(ConfigRef(), false));
609   EXPECT_CALL(*this, FailureCallback(_)).Times(0);
610   EXPECT_CALL(process_manager_, StartProcessInMinijail(_, _, _, _, _, _, _))
611       .WillOnce(Return(0));
612   StartInstance(config_);
613   config_->ProcessEventSignal(DHCPv4Config::kReasonGatewayArp, conf);
614   Mock::VerifyAndClearExpectations(this);
615   EXPECT_EQ("4.3.2.1", config_->properties().address);
616   EXPECT_TRUE(config_->is_gateway_arp_active_);
617   // Will not fail on acquisition timeout since Gateway ARP is active.
618   EXPECT_FALSE(config_->ShouldFailOnAcquisitionTimeout());
619 
620   // An official reply from a DHCP server should reset our GatewayArp state.
621   EXPECT_CALL(*this, SuccessCallback(ConfigRef(), true));
622   EXPECT_CALL(*this, FailureCallback(_)).Times(0);
623   config_->ProcessEventSignal(DHCPv4Config::kReasonRenew, conf);
624   Mock::VerifyAndClearExpectations(this);
625   EXPECT_FALSE(config_->is_gateway_arp_active_);
626   // Will fail on acquisition timeout since Gateway ARP is not active.
627   EXPECT_TRUE(config_->ShouldFailOnAcquisitionTimeout());
628 }
629 
TEST_F(DHCPv4ConfigCallbackTest,ProcessEventSignalGatewayArpNak)630 TEST_F(DHCPv4ConfigCallbackTest, ProcessEventSignalGatewayArpNak) {
631   KeyValueStore conf;
632   conf.SetUint(DHCPv4Config::kConfigurationKeyIPAddress, 0x01020304);
633   EXPECT_CALL(process_manager_, StartProcessInMinijail(_, _, _, _, _, _, _))
634       .WillOnce(Return(0));
635   StartInstance(config_);
636   config_->ProcessEventSignal(DHCPv4Config::kReasonGatewayArp, conf);
637   EXPECT_TRUE(config_->is_gateway_arp_active_);
638 
639   // Sending a NAK should clear is_gateway_arp_active_.
640   config_->ProcessEventSignal(DHCPv4Config::kReasonNak, conf);
641   EXPECT_FALSE(config_->is_gateway_arp_active_);
642   // Will fail on acquisition timeout since Gateway ARP is not active.
643   EXPECT_TRUE(config_->ShouldFailOnAcquisitionTimeout());
644   Mock::VerifyAndClearExpectations(this);
645 }
646 
TEST_F(DHCPv4ConfigTest,ProcessStatusChangeSingal)647 TEST_F(DHCPv4ConfigTest, ProcessStatusChangeSingal) {
648   EXPECT_CALL(metrics_, NotifyDhcpClientStatus(
649       Metrics::kDhcpClientStatusBound));
650   config_->ProcessStatusChangeSignal(DHCPv4Config::kStatusBound);
651 }
652 
TEST_F(DHCPv4ConfigTest,StartSuccessEphemeral)653 TEST_F(DHCPv4ConfigTest, StartSuccessEphemeral) {
654   DHCPv4ConfigRefPtr config =
655       CreateRunningConfig(kHostName, kVendorClass, kDeviceName, kArpGateway);
656   StopRunningConfigAndExpect(config, false);
657 }
658 
TEST_F(DHCPv4ConfigTest,StartSuccessPersistent)659 TEST_F(DHCPv4ConfigTest, StartSuccessPersistent) {
660   DHCPv4ConfigRefPtr config =
661       CreateRunningConfig(kHostName, kVendorClass,
662                           kLeaseFileSuffix, kArpGateway);
663   StopRunningConfigAndExpect(config, true);
664 }
665 
666 }  // namespace shill
667