blob: 9ca6592ea0016c42fe82db6a6ae0c6f31a9c02c1 [file] [log] [blame]
Darin Petkove7cb7f82011-06-03 13:21:51 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Chris Masone8a7b8be2011-07-22 12:43:37 -07005#include "shill/dhcp_config.h"
6
Darin Petkov92c43902011-06-09 20:46:06 -07007#include <base/file_util.h>
8#include <base/memory/scoped_temp_dir.h>
9#include <base/stringprintf.h>
Chris Masone43b48a12011-07-01 13:37:07 -070010#include <chromeos/dbus/service_constants.h>
Chris Masone8a7b8be2011-07-22 12:43:37 -070011#include <gtest/gtest.h>
Darin Petkov92c43902011-06-09 20:46:06 -070012
Chris Masone43b48a12011-07-01 13:37:07 -070013#include "shill/dbus_adaptor.h"
Darin Petkovf7897bc2011-06-08 17:13:36 -070014#include "shill/dhcp_provider.h"
Chris Masone19e30402011-07-19 15:48:47 -070015#include "shill/mock_control.h"
Darin Petkov98dd6a02011-06-10 15:12:57 -070016#include "shill/mock_dhcp_proxy.h"
Darin Petkovf7897bc2011-06-08 17:13:36 -070017#include "shill/mock_glib.h"
Chris Masone43b48a12011-07-01 13:37:07 -070018#include "shill/property_store_unittest.h"
Darin Petkova7b89492011-07-27 12:48:17 -070019#include "shill/proxy_factory.h"
20#include "shill/shill_event.h"
Darin Petkove7cb7f82011-06-03 13:21:51 -070021
22using std::string;
23using std::vector;
Darin Petkovf7897bc2011-06-08 17:13:36 -070024using testing::_;
25using testing::Return;
26using testing::SetArgumentPointee;
Darin Petkove7cb7f82011-06-03 13:21:51 -070027using testing::Test;
28
29namespace shill {
30
Darin Petkov92c43902011-06-09 20:46:06 -070031namespace {
Darin Petkova7b89492011-07-27 12:48:17 -070032const char kDeviceName[] = "eth0";
Darin Petkov92c43902011-06-09 20:46:06 -070033} // namespace {}
34
Chris Masone43b48a12011-07-01 13:37:07 -070035class DHCPConfigTest : public PropertyStoreTest {
Darin Petkove7cb7f82011-06-03 13:21:51 -070036 public:
Darin Petkovf7897bc2011-06-08 17:13:36 -070037 DHCPConfigTest()
Darin Petkovf65e9282011-06-21 14:29:56 -070038 : proxy_(new MockDHCPProxy()),
Darin Petkova7b89492011-07-27 12:48:17 -070039 proxy_factory_(this),
Chris Masone19e30402011-07-19 15:48:47 -070040 config_(new DHCPConfig(&control_,
Darin Petkova7b89492011-07-27 12:48:17 -070041 &dispatcher_,
Chris Masone19e30402011-07-19 15:48:47 -070042 DHCPProvider::GetInstance(),
Darin Petkov92c43902011-06-09 20:46:06 -070043 kDeviceName,
Darin Petkova7b89492011-07-27 12:48:17 -070044 &glib_)) {}
45
46 virtual void SetUp() {
47 ProxyFactory::set_factory(&proxy_factory_);
48 }
49
50 virtual void TearDown() {
51 ProxyFactory::set_factory(NULL);
Darin Petkov98dd6a02011-06-10 15:12:57 -070052 }
Darin Petkove7cb7f82011-06-03 13:21:51 -070053
54 protected:
Darin Petkova7b89492011-07-27 12:48:17 -070055 class TestProxyFactory : public ProxyFactory {
56 public:
Paul Stewart7355ce12011-09-02 10:47:01 -070057 explicit TestProxyFactory(DHCPConfigTest *test) : test_(test) {}
Darin Petkova7b89492011-07-27 12:48:17 -070058
59 virtual DHCPProxyInterface *CreateDHCPProxy(const string &service) {
60 return test_->proxy_.release();
61 }
62
63 private:
64 DHCPConfigTest *test_;
65 };
66
Darin Petkovf7897bc2011-06-08 17:13:36 -070067 MockGLib glib_;
Darin Petkova7b89492011-07-27 12:48:17 -070068 scoped_ptr<MockDHCPProxy> proxy_;
69 TestProxyFactory proxy_factory_;
Chris Masone19e30402011-07-19 15:48:47 -070070 MockControl control_;
Darin Petkovf7897bc2011-06-08 17:13:36 -070071 DHCPConfigRefPtr config_;
Darin Petkove7cb7f82011-06-03 13:21:51 -070072};
73
74TEST_F(DHCPConfigTest, GetIPv4AddressString) {
Darin Petkovf7897bc2011-06-08 17:13:36 -070075 EXPECT_EQ("255.255.255.255", config_->GetIPv4AddressString(0xffffffff));
76 EXPECT_EQ("0.0.0.0", config_->GetIPv4AddressString(0));
77 EXPECT_EQ("1.2.3.4", config_->GetIPv4AddressString(0x04030201));
Darin Petkove7cb7f82011-06-03 13:21:51 -070078}
79
Darin Petkova7b89492011-07-27 12:48:17 -070080TEST_F(DHCPConfigTest, InitProxy) {
81 static const char kService[] = ":1.200";
82 EXPECT_TRUE(config_->task_factory_.empty());
83 config_->InitProxy(kService);
84 EXPECT_FALSE(config_->task_factory_.empty());
85
86 EXPECT_TRUE(proxy_.get());
87 EXPECT_FALSE(config_->proxy_.get());
88 dispatcher_.DispatchPendingEvents();
89 EXPECT_FALSE(proxy_.get());
90 EXPECT_TRUE(config_->proxy_.get());
91
92 config_->InitProxy(kService);
93 EXPECT_TRUE(config_->task_factory_.empty());
94}
95
Darin Petkove7cb7f82011-06-03 13:21:51 -070096TEST_F(DHCPConfigTest, ParseConfiguration) {
97 DHCPConfig::Configuration conf;
98 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
99 0x01020304);
100 conf[DHCPConfig::kConfigurationKeySubnetCIDR].writer().append_byte(
101 16);
102 conf[DHCPConfig::kConfigurationKeyBroadcastAddress].writer().append_uint32(
103 0x10203040);
104 {
Darin Petkove7cb7f82011-06-03 13:21:51 -0700105 vector<unsigned int> routers;
106 routers.push_back(0x02040608);
107 routers.push_back(0x03050709);
Darin Petkovf7897bc2011-06-08 17:13:36 -0700108 DBus::MessageIter writer =
109 conf[DHCPConfig::kConfigurationKeyRouters].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -0700110 writer << routers;
Darin Petkove7cb7f82011-06-03 13:21:51 -0700111 }
112 {
Darin Petkove7cb7f82011-06-03 13:21:51 -0700113 vector<unsigned int> dns;
114 dns.push_back(0x09070503);
115 dns.push_back(0x08060402);
Darin Petkovf7897bc2011-06-08 17:13:36 -0700116 DBus::MessageIter writer = conf[DHCPConfig::kConfigurationKeyDNS].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -0700117 writer << dns;
Darin Petkove7cb7f82011-06-03 13:21:51 -0700118 }
119 conf[DHCPConfig::kConfigurationKeyDomainName].writer().append_string(
120 "domain-name");
121 {
Darin Petkove7cb7f82011-06-03 13:21:51 -0700122 vector<string> search;
123 search.push_back("foo.com");
124 search.push_back("bar.com");
Darin Petkovf7897bc2011-06-08 17:13:36 -0700125 DBus::MessageIter writer =
126 conf[DHCPConfig::kConfigurationKeyDomainSearch].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -0700127 writer << search;
Darin Petkove7cb7f82011-06-03 13:21:51 -0700128 }
129 conf[DHCPConfig::kConfigurationKeyMTU].writer().append_uint16(600);
130 conf["UnknownKey"] = DBus::Variant();
131
Darin Petkove7cb7f82011-06-03 13:21:51 -0700132 IPConfig::Properties properties;
Darin Petkovf7897bc2011-06-08 17:13:36 -0700133 ASSERT_TRUE(config_->ParseConfiguration(conf, &properties));
Darin Petkove7cb7f82011-06-03 13:21:51 -0700134 EXPECT_EQ("4.3.2.1", properties.address);
135 EXPECT_EQ(16, properties.subnet_cidr);
136 EXPECT_EQ("64.48.32.16", properties.broadcast_address);
137 EXPECT_EQ("8.6.4.2", properties.gateway);
138 ASSERT_EQ(2, properties.dns_servers.size());
139 EXPECT_EQ("3.5.7.9", properties.dns_servers[0]);
140 EXPECT_EQ("2.4.6.8", properties.dns_servers[1]);
141 EXPECT_EQ("domain-name", properties.domain_name);
142 ASSERT_EQ(2, properties.domain_search.size());
143 EXPECT_EQ("foo.com", properties.domain_search[0]);
144 EXPECT_EQ("bar.com", properties.domain_search[1]);
145 EXPECT_EQ(600, properties.mtu);
146}
147
Darin Petkov92c43902011-06-09 20:46:06 -0700148TEST_F(DHCPConfigTest, StartFail) {
Darin Petkovf7897bc2011-06-08 17:13:36 -0700149 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
150 .WillOnce(Return(false));
Darin Petkov92c43902011-06-09 20:46:06 -0700151 EXPECT_CALL(glib_, ChildWatchAdd(_, _, _)).Times(0);
Darin Petkovf7897bc2011-06-08 17:13:36 -0700152 EXPECT_FALSE(config_->Start());
153 EXPECT_EQ(0, config_->pid_);
Darin Petkov92c43902011-06-09 20:46:06 -0700154}
Darin Petkovf7897bc2011-06-08 17:13:36 -0700155
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700156namespace {
157
158class UpdateCallbackTest {
159 public:
160 UpdateCallbackTest(const string &message,
Chris Masone2b105542011-06-22 10:58:09 -0700161 const IPConfigRefPtr &ipconfig,
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700162 bool success)
163 : message_(message),
164 ipconfig_(ipconfig),
165 success_(success),
166 called_(false) {}
167
Chris Masone2b105542011-06-22 10:58:09 -0700168 void Callback(const IPConfigRefPtr &ipconfig, bool success) {
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700169 called_ = true;
170 EXPECT_EQ(ipconfig_.get(), ipconfig.get()) << message_;
171 EXPECT_EQ(success_, success) << message_;
172 }
173
174 bool called() const { return called_; }
175
176 private:
177 const string message_;
178 IPConfigRefPtr ipconfig_;
179 bool success_;
180 bool called_;
181};
182
183} // namespace {}
184
185TEST_F(DHCPConfigTest, ProcessEventSignalFail) {
186 DHCPConfig::Configuration conf;
187 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
188 0x01020304);
189 UpdateCallbackTest callback_test(DHCPConfig::kReasonFail, config_, false);
190 config_->RegisterUpdateCallback(
191 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
192 config_->ProcessEventSignal(DHCPConfig::kReasonFail, conf);
193 EXPECT_TRUE(callback_test.called());
194 EXPECT_TRUE(config_->properties().address.empty());
195}
196
197TEST_F(DHCPConfigTest, ProcessEventSignalSuccess) {
198 static const char * const kReasons[] = {
199 DHCPConfig::kReasonBound,
200 DHCPConfig::kReasonRebind,
201 DHCPConfig::kReasonReboot,
202 DHCPConfig::kReasonRenew
203 };
204 for (size_t r = 0; r < arraysize(kReasons); r++) {
205 DHCPConfig::Configuration conf;
206 string message = string(kReasons[r]) + " failed";
207 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(r);
208 UpdateCallbackTest callback_test(message, config_, true);
209 config_->RegisterUpdateCallback(
210 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
211 config_->ProcessEventSignal(kReasons[r], conf);
212 EXPECT_TRUE(callback_test.called()) << message;
213 EXPECT_EQ(base::StringPrintf("%u.0.0.0", r), config_->properties().address)
214 << message;
215 }
216}
217
218TEST_F(DHCPConfigTest, ProcessEventSignalUnknown) {
219 DHCPConfig::Configuration conf;
220 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
221 0x01020304);
222 static const char kReasonUnknown[] = "UNKNOWN_REASON";
223 UpdateCallbackTest callback_test(kReasonUnknown, config_, false);
224 config_->RegisterUpdateCallback(
225 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
226 config_->ProcessEventSignal(kReasonUnknown, conf);
227 EXPECT_FALSE(callback_test.called());
228 EXPECT_TRUE(config_->properties().address.empty());
229}
230
231
Darin Petkov98dd6a02011-06-10 15:12:57 -0700232TEST_F(DHCPConfigTest, ReleaseIP) {
233 config_->pid_ = 1 << 18; // Ensure unknown positive PID.
Darin Petkovaceede32011-07-18 15:32:38 -0700234 EXPECT_CALL(*proxy_, Release(kDeviceName)).Times(1);
Darin Petkova7b89492011-07-27 12:48:17 -0700235 config_->proxy_.reset(proxy_.release());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700236 EXPECT_TRUE(config_->ReleaseIP());
237 config_->pid_ = 0;
238}
239
240TEST_F(DHCPConfigTest, RenewIP) {
241 config_->pid_ = 456;
Darin Petkovaceede32011-07-18 15:32:38 -0700242 EXPECT_CALL(*proxy_, Rebind(kDeviceName)).Times(1);
Darin Petkova7b89492011-07-27 12:48:17 -0700243 config_->proxy_.reset(proxy_.release());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700244 EXPECT_TRUE(config_->RenewIP());
245 config_->pid_ = 0;
246}
247
248TEST_F(DHCPConfigTest, RequestIP) {
249 config_->pid_ = 567;
Darin Petkovaceede32011-07-18 15:32:38 -0700250 EXPECT_CALL(*proxy_, Rebind(kDeviceName)).Times(1);
Darin Petkova7b89492011-07-27 12:48:17 -0700251 config_->proxy_.reset(proxy_.release());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700252 EXPECT_TRUE(config_->RenewIP());
253 config_->pid_ = 0;
254}
255
256TEST_F(DHCPConfigTest, Restart) {
257 const int kPID1 = 1 << 17; // Ensure unknown positive PID.
258 const int kPID2 = 987;
259 const unsigned int kTag1 = 11;
260 const unsigned int kTag2 = 22;
261 config_->pid_ = kPID1;
262 config_->child_watch_tag_ = kTag1;
263 DHCPProvider::GetInstance()->BindPID(kPID1, config_);
264 EXPECT_CALL(glib_, SourceRemove(kTag1)).WillOnce(Return(true));
265 EXPECT_CALL(glib_, SpawnClosePID(kPID1)).Times(1);
266 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
267 .WillOnce(DoAll(SetArgumentPointee<6>(kPID2), Return(true)));
268 EXPECT_CALL(glib_, ChildWatchAdd(kPID2, _, _)).WillOnce(Return(kTag2));
269 EXPECT_TRUE(config_->Restart());
270 EXPECT_EQ(kPID2, config_->pid_);
271 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID2).get());
272 EXPECT_EQ(kTag2, config_->child_watch_tag_);
273 DHCPProvider::GetInstance()->UnbindPID(kPID2);
274 config_->pid_ = 0;
275 config_->child_watch_tag_ = 0;
276}
277
278TEST_F(DHCPConfigTest, RestartNoClient) {
279 const int kPID = 777;
280 const unsigned int kTag = 66;
281 EXPECT_CALL(glib_, SourceRemove(_)).Times(0);
282 EXPECT_CALL(glib_, SpawnClosePID(_)).Times(0);
283 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
284 .WillOnce(DoAll(SetArgumentPointee<6>(kPID), Return(true)));
285 EXPECT_CALL(glib_, ChildWatchAdd(kPID, _, _)).WillOnce(Return(kTag));
286 EXPECT_TRUE(config_->Restart());
287 EXPECT_EQ(kPID, config_->pid_);
288 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID).get());
289 EXPECT_EQ(kTag, config_->child_watch_tag_);
290 DHCPProvider::GetInstance()->UnbindPID(kPID);
291 config_->pid_ = 0;
292 config_->child_watch_tag_ = 0;
293}
294
Darin Petkov92c43902011-06-09 20:46:06 -0700295TEST_F(DHCPConfigTest, StartSuccess) {
296 const int kPID = 123456;
297 const unsigned int kTag = 55;
Darin Petkovf7897bc2011-06-08 17:13:36 -0700298 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
299 .WillOnce(DoAll(SetArgumentPointee<6>(kPID), Return(true)));
Darin Petkov92c43902011-06-09 20:46:06 -0700300 EXPECT_CALL(glib_, ChildWatchAdd(kPID, _, _)).WillOnce(Return(kTag));
Darin Petkovf7897bc2011-06-08 17:13:36 -0700301 EXPECT_TRUE(config_->Start());
302 EXPECT_EQ(kPID, config_->pid_);
Darin Petkov98dd6a02011-06-10 15:12:57 -0700303 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID).get());
304 EXPECT_EQ(kTag, config_->child_watch_tag_);
Darin Petkov92c43902011-06-09 20:46:06 -0700305
306 ScopedTempDir temp_dir;
307 config_->root_ = temp_dir.path();
308 FilePath varrun = temp_dir.path().Append("var/run");
309 EXPECT_TRUE(file_util::CreateDirectory(varrun));
310 FilePath pid_file =
311 varrun.Append(base::StringPrintf("dhcpcd-%s.pid", kDeviceName));
312 FilePath lease_file =
313 varrun.Append(base::StringPrintf("dhcpcd-%s.lease", kDeviceName));
314 EXPECT_EQ(0, file_util::WriteFile(pid_file, "", 0));
315 EXPECT_EQ(0, file_util::WriteFile(lease_file, "", 0));
316 ASSERT_TRUE(file_util::PathExists(pid_file));
317 ASSERT_TRUE(file_util::PathExists(lease_file));
318
319 EXPECT_CALL(glib_, SpawnClosePID(kPID)).Times(1);
320 DHCPConfig::ChildWatchCallback(kPID, 0, config_.get());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700321 EXPECT_EQ(NULL, DHCPProvider::GetInstance()->GetConfig(kPID).get());
Darin Petkov92c43902011-06-09 20:46:06 -0700322 EXPECT_FALSE(file_util::PathExists(pid_file));
323 EXPECT_FALSE(file_util::PathExists(lease_file));
Darin Petkovf7897bc2011-06-08 17:13:36 -0700324}
325
Darin Petkov98dd6a02011-06-10 15:12:57 -0700326TEST_F(DHCPConfigTest, Stop) {
327 // Ensure no crashes.
328 const int kPID = 1 << 17; // Ensure unknown positive PID.
329 config_->Stop();
330 config_->pid_ = kPID;
331 config_->Stop();
Darin Petkova7b89492011-07-27 12:48:17 -0700332 EXPECT_CALL(glib_, SpawnClosePID(kPID)).Times(1); // Invoked by destructor.
Darin Petkov98dd6a02011-06-10 15:12:57 -0700333}
334
Chris Masone43b48a12011-07-01 13:37:07 -0700335TEST_F(DHCPConfigTest, Dispatch) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700336 EXPECT_TRUE(DBusAdaptor::DispatchOnType(config_->store(),
Chris Masone43b48a12011-07-01 13:37:07 -0700337 flimflam::kMtuProperty,
338 PropertyStoreTest::kInt32V,
339 NULL));
340 ::DBus::Error error;
341 // Ensure that an attempt to write a R/O property returns InvalidArgs error.
Chris Masone27c4aa52011-07-02 13:10:14 -0700342 EXPECT_FALSE(DBusAdaptor::DispatchOnType(config_->store(),
Chris Masone43b48a12011-07-01 13:37:07 -0700343 flimflam::kAddressProperty,
344 PropertyStoreTest::kStringV,
345 &error));
Chris Masone9d779932011-08-25 16:33:41 -0700346 EXPECT_EQ(invalid_args(), error.name());
Chris Masone43b48a12011-07-01 13:37:07 -0700347}
348
Darin Petkove7cb7f82011-06-03 13:21:51 -0700349} // namespace shill