blob: a8b451282b8a6d90d4a4e324215ad083a4fec81a [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_,
Chris Masone2176a882011-09-14 22:29:15 -070041 dispatcher(),
Chris Masone19e30402011-07-19 15:48:47 -070042 DHCPProvider::GetInstance(),
Darin Petkov92c43902011-06-09 20:46:06 -070043 kDeviceName,
Chris Masone2176a882011-09-14 22:29:15 -070044 glib())) {}
Darin Petkova7b89492011-07-27 12:48:17 -070045
46 virtual void SetUp() {
Darin Petkovab565bb2011-10-06 02:55:51 -070047 config_->proxy_factory_ = &proxy_factory_;
Darin Petkova7b89492011-07-27 12:48:17 -070048 }
49
50 virtual void TearDown() {
Darin Petkovab565bb2011-10-06 02:55:51 -070051 config_->proxy_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
mukesh agrawal1830fa12011-09-26 14:31:40 -070059 virtual DHCPProxyInterface *CreateDHCPProxy(const string &/*service*/) {
Darin Petkova7b89492011-07-27 12:48:17 -070060 return test_->proxy_.release();
61 }
62
63 private:
64 DHCPConfigTest *test_;
65 };
66
Darin Petkova7b89492011-07-27 12:48:17 -070067 scoped_ptr<MockDHCPProxy> proxy_;
68 TestProxyFactory proxy_factory_;
Chris Masone19e30402011-07-19 15:48:47 -070069 MockControl control_;
Darin Petkovf7897bc2011-06-08 17:13:36 -070070 DHCPConfigRefPtr config_;
Darin Petkove7cb7f82011-06-03 13:21:51 -070071};
72
73TEST_F(DHCPConfigTest, GetIPv4AddressString) {
Darin Petkovf7897bc2011-06-08 17:13:36 -070074 EXPECT_EQ("255.255.255.255", config_->GetIPv4AddressString(0xffffffff));
75 EXPECT_EQ("0.0.0.0", config_->GetIPv4AddressString(0));
76 EXPECT_EQ("1.2.3.4", config_->GetIPv4AddressString(0x04030201));
Darin Petkove7cb7f82011-06-03 13:21:51 -070077}
78
Darin Petkova7b89492011-07-27 12:48:17 -070079TEST_F(DHCPConfigTest, InitProxy) {
80 static const char kService[] = ":1.200";
81 EXPECT_TRUE(config_->task_factory_.empty());
82 config_->InitProxy(kService);
83 EXPECT_FALSE(config_->task_factory_.empty());
84
85 EXPECT_TRUE(proxy_.get());
86 EXPECT_FALSE(config_->proxy_.get());
Chris Masone2176a882011-09-14 22:29:15 -070087 dispatcher()->DispatchPendingEvents();
Darin Petkova7b89492011-07-27 12:48:17 -070088 EXPECT_FALSE(proxy_.get());
89 EXPECT_TRUE(config_->proxy_.get());
90
91 config_->InitProxy(kService);
92 EXPECT_TRUE(config_->task_factory_.empty());
93}
94
Darin Petkove7cb7f82011-06-03 13:21:51 -070095TEST_F(DHCPConfigTest, ParseConfiguration) {
96 DHCPConfig::Configuration conf;
97 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
98 0x01020304);
99 conf[DHCPConfig::kConfigurationKeySubnetCIDR].writer().append_byte(
100 16);
101 conf[DHCPConfig::kConfigurationKeyBroadcastAddress].writer().append_uint32(
102 0x10203040);
103 {
Darin Petkove7cb7f82011-06-03 13:21:51 -0700104 vector<unsigned int> routers;
105 routers.push_back(0x02040608);
106 routers.push_back(0x03050709);
Darin Petkovf7897bc2011-06-08 17:13:36 -0700107 DBus::MessageIter writer =
108 conf[DHCPConfig::kConfigurationKeyRouters].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -0700109 writer << routers;
Darin Petkove7cb7f82011-06-03 13:21:51 -0700110 }
111 {
Darin Petkove7cb7f82011-06-03 13:21:51 -0700112 vector<unsigned int> dns;
113 dns.push_back(0x09070503);
114 dns.push_back(0x08060402);
Darin Petkovf7897bc2011-06-08 17:13:36 -0700115 DBus::MessageIter writer = conf[DHCPConfig::kConfigurationKeyDNS].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -0700116 writer << dns;
Darin Petkove7cb7f82011-06-03 13:21:51 -0700117 }
118 conf[DHCPConfig::kConfigurationKeyDomainName].writer().append_string(
119 "domain-name");
120 {
Darin Petkove7cb7f82011-06-03 13:21:51 -0700121 vector<string> search;
122 search.push_back("foo.com");
123 search.push_back("bar.com");
Darin Petkovf7897bc2011-06-08 17:13:36 -0700124 DBus::MessageIter writer =
125 conf[DHCPConfig::kConfigurationKeyDomainSearch].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -0700126 writer << search;
Darin Petkove7cb7f82011-06-03 13:21:51 -0700127 }
128 conf[DHCPConfig::kConfigurationKeyMTU].writer().append_uint16(600);
129 conf["UnknownKey"] = DBus::Variant();
130
Darin Petkove7cb7f82011-06-03 13:21:51 -0700131 IPConfig::Properties properties;
Darin Petkovf7897bc2011-06-08 17:13:36 -0700132 ASSERT_TRUE(config_->ParseConfiguration(conf, &properties));
Darin Petkove7cb7f82011-06-03 13:21:51 -0700133 EXPECT_EQ("4.3.2.1", properties.address);
134 EXPECT_EQ(16, properties.subnet_cidr);
135 EXPECT_EQ("64.48.32.16", properties.broadcast_address);
136 EXPECT_EQ("8.6.4.2", properties.gateway);
137 ASSERT_EQ(2, properties.dns_servers.size());
138 EXPECT_EQ("3.5.7.9", properties.dns_servers[0]);
139 EXPECT_EQ("2.4.6.8", properties.dns_servers[1]);
140 EXPECT_EQ("domain-name", properties.domain_name);
141 ASSERT_EQ(2, properties.domain_search.size());
142 EXPECT_EQ("foo.com", properties.domain_search[0]);
143 EXPECT_EQ("bar.com", properties.domain_search[1]);
144 EXPECT_EQ(600, properties.mtu);
145}
146
Darin Petkov92c43902011-06-09 20:46:06 -0700147TEST_F(DHCPConfigTest, StartFail) {
Chris Masone2176a882011-09-14 22:29:15 -0700148 EXPECT_CALL(*glib(), SpawnAsync(_, _, _, _, _, _, _, _))
Darin Petkovf7897bc2011-06-08 17:13:36 -0700149 .WillOnce(Return(false));
Chris Masone2176a882011-09-14 22:29:15 -0700150 EXPECT_CALL(*glib(), ChildWatchAdd(_, _, _)).Times(0);
Darin Petkovf7897bc2011-06-08 17:13:36 -0700151 EXPECT_FALSE(config_->Start());
152 EXPECT_EQ(0, config_->pid_);
Darin Petkov92c43902011-06-09 20:46:06 -0700153}
Darin Petkovf7897bc2011-06-08 17:13:36 -0700154
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700155namespace {
156
157class UpdateCallbackTest {
158 public:
159 UpdateCallbackTest(const string &message,
Chris Masone2b105542011-06-22 10:58:09 -0700160 const IPConfigRefPtr &ipconfig,
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700161 bool success)
162 : message_(message),
163 ipconfig_(ipconfig),
164 success_(success),
165 called_(false) {}
166
Chris Masone2b105542011-06-22 10:58:09 -0700167 void Callback(const IPConfigRefPtr &ipconfig, bool success) {
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700168 called_ = true;
169 EXPECT_EQ(ipconfig_.get(), ipconfig.get()) << message_;
170 EXPECT_EQ(success_, success) << message_;
171 }
172
173 bool called() const { return called_; }
174
175 private:
176 const string message_;
177 IPConfigRefPtr ipconfig_;
178 bool success_;
179 bool called_;
180};
181
182} // namespace {}
183
184TEST_F(DHCPConfigTest, ProcessEventSignalFail) {
185 DHCPConfig::Configuration conf;
186 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
187 0x01020304);
188 UpdateCallbackTest callback_test(DHCPConfig::kReasonFail, config_, false);
189 config_->RegisterUpdateCallback(
190 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
191 config_->ProcessEventSignal(DHCPConfig::kReasonFail, conf);
192 EXPECT_TRUE(callback_test.called());
193 EXPECT_TRUE(config_->properties().address.empty());
194}
195
196TEST_F(DHCPConfigTest, ProcessEventSignalSuccess) {
197 static const char * const kReasons[] = {
198 DHCPConfig::kReasonBound,
199 DHCPConfig::kReasonRebind,
200 DHCPConfig::kReasonReboot,
201 DHCPConfig::kReasonRenew
202 };
203 for (size_t r = 0; r < arraysize(kReasons); r++) {
204 DHCPConfig::Configuration conf;
205 string message = string(kReasons[r]) + " failed";
206 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(r);
207 UpdateCallbackTest callback_test(message, config_, true);
208 config_->RegisterUpdateCallback(
209 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
210 config_->ProcessEventSignal(kReasons[r], conf);
211 EXPECT_TRUE(callback_test.called()) << message;
212 EXPECT_EQ(base::StringPrintf("%u.0.0.0", r), config_->properties().address)
213 << message;
214 }
215}
216
217TEST_F(DHCPConfigTest, ProcessEventSignalUnknown) {
218 DHCPConfig::Configuration conf;
219 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
220 0x01020304);
221 static const char kReasonUnknown[] = "UNKNOWN_REASON";
222 UpdateCallbackTest callback_test(kReasonUnknown, config_, false);
223 config_->RegisterUpdateCallback(
224 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
225 config_->ProcessEventSignal(kReasonUnknown, conf);
226 EXPECT_FALSE(callback_test.called());
227 EXPECT_TRUE(config_->properties().address.empty());
228}
229
230
Darin Petkov98dd6a02011-06-10 15:12:57 -0700231TEST_F(DHCPConfigTest, ReleaseIP) {
232 config_->pid_ = 1 << 18; // Ensure unknown positive PID.
Darin Petkovaceede32011-07-18 15:32:38 -0700233 EXPECT_CALL(*proxy_, Release(kDeviceName)).Times(1);
Darin Petkova7b89492011-07-27 12:48:17 -0700234 config_->proxy_.reset(proxy_.release());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700235 EXPECT_TRUE(config_->ReleaseIP());
236 config_->pid_ = 0;
237}
238
239TEST_F(DHCPConfigTest, RenewIP) {
240 config_->pid_ = 456;
Darin Petkovaceede32011-07-18 15:32:38 -0700241 EXPECT_CALL(*proxy_, Rebind(kDeviceName)).Times(1);
Darin Petkova7b89492011-07-27 12:48:17 -0700242 config_->proxy_.reset(proxy_.release());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700243 EXPECT_TRUE(config_->RenewIP());
244 config_->pid_ = 0;
245}
246
247TEST_F(DHCPConfigTest, RequestIP) {
248 config_->pid_ = 567;
Darin Petkovaceede32011-07-18 15:32:38 -0700249 EXPECT_CALL(*proxy_, Rebind(kDeviceName)).Times(1);
Darin Petkova7b89492011-07-27 12:48:17 -0700250 config_->proxy_.reset(proxy_.release());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700251 EXPECT_TRUE(config_->RenewIP());
252 config_->pid_ = 0;
253}
254
255TEST_F(DHCPConfigTest, Restart) {
256 const int kPID1 = 1 << 17; // Ensure unknown positive PID.
257 const int kPID2 = 987;
258 const unsigned int kTag1 = 11;
259 const unsigned int kTag2 = 22;
260 config_->pid_ = kPID1;
261 config_->child_watch_tag_ = kTag1;
262 DHCPProvider::GetInstance()->BindPID(kPID1, config_);
Chris Masone2176a882011-09-14 22:29:15 -0700263 EXPECT_CALL(*glib(), SourceRemove(kTag1)).WillOnce(Return(true));
264 EXPECT_CALL(*glib(), SpawnClosePID(kPID1)).Times(1);
265 EXPECT_CALL(*glib(), SpawnAsync(_, _, _, _, _, _, _, _))
Darin Petkov98dd6a02011-06-10 15:12:57 -0700266 .WillOnce(DoAll(SetArgumentPointee<6>(kPID2), Return(true)));
Chris Masone2176a882011-09-14 22:29:15 -0700267 EXPECT_CALL(*glib(), ChildWatchAdd(kPID2, _, _)).WillOnce(Return(kTag2));
Darin Petkov98dd6a02011-06-10 15:12:57 -0700268 EXPECT_TRUE(config_->Restart());
269 EXPECT_EQ(kPID2, config_->pid_);
270 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID2).get());
271 EXPECT_EQ(kTag2, config_->child_watch_tag_);
272 DHCPProvider::GetInstance()->UnbindPID(kPID2);
273 config_->pid_ = 0;
274 config_->child_watch_tag_ = 0;
275}
276
277TEST_F(DHCPConfigTest, RestartNoClient) {
278 const int kPID = 777;
279 const unsigned int kTag = 66;
Chris Masone2176a882011-09-14 22:29:15 -0700280 EXPECT_CALL(*glib(), SourceRemove(_)).Times(0);
281 EXPECT_CALL(*glib(), SpawnClosePID(_)).Times(0);
282 EXPECT_CALL(*glib(), SpawnAsync(_, _, _, _, _, _, _, _))
Darin Petkov98dd6a02011-06-10 15:12:57 -0700283 .WillOnce(DoAll(SetArgumentPointee<6>(kPID), Return(true)));
Chris Masone2176a882011-09-14 22:29:15 -0700284 EXPECT_CALL(*glib(), ChildWatchAdd(kPID, _, _)).WillOnce(Return(kTag));
Darin Petkov98dd6a02011-06-10 15:12:57 -0700285 EXPECT_TRUE(config_->Restart());
286 EXPECT_EQ(kPID, config_->pid_);
287 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID).get());
288 EXPECT_EQ(kTag, config_->child_watch_tag_);
289 DHCPProvider::GetInstance()->UnbindPID(kPID);
290 config_->pid_ = 0;
291 config_->child_watch_tag_ = 0;
292}
293
Darin Petkov92c43902011-06-09 20:46:06 -0700294TEST_F(DHCPConfigTest, StartSuccess) {
295 const int kPID = 123456;
296 const unsigned int kTag = 55;
Chris Masone2176a882011-09-14 22:29:15 -0700297 EXPECT_CALL(*glib(), SpawnAsync(_, _, _, _, _, _, _, _))
Darin Petkovf7897bc2011-06-08 17:13:36 -0700298 .WillOnce(DoAll(SetArgumentPointee<6>(kPID), Return(true)));
Chris Masone2176a882011-09-14 22:29:15 -0700299 EXPECT_CALL(*glib(), ChildWatchAdd(kPID, _, _)).WillOnce(Return(kTag));
Darin Petkovf7897bc2011-06-08 17:13:36 -0700300 EXPECT_TRUE(config_->Start());
301 EXPECT_EQ(kPID, config_->pid_);
Darin Petkov98dd6a02011-06-10 15:12:57 -0700302 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID).get());
303 EXPECT_EQ(kTag, config_->child_watch_tag_);
Darin Petkov92c43902011-06-09 20:46:06 -0700304
305 ScopedTempDir temp_dir;
306 config_->root_ = temp_dir.path();
307 FilePath varrun = temp_dir.path().Append("var/run");
308 EXPECT_TRUE(file_util::CreateDirectory(varrun));
309 FilePath pid_file =
310 varrun.Append(base::StringPrintf("dhcpcd-%s.pid", kDeviceName));
311 FilePath lease_file =
312 varrun.Append(base::StringPrintf("dhcpcd-%s.lease", kDeviceName));
313 EXPECT_EQ(0, file_util::WriteFile(pid_file, "", 0));
314 EXPECT_EQ(0, file_util::WriteFile(lease_file, "", 0));
315 ASSERT_TRUE(file_util::PathExists(pid_file));
316 ASSERT_TRUE(file_util::PathExists(lease_file));
317
Chris Masone2176a882011-09-14 22:29:15 -0700318 EXPECT_CALL(*glib(), SpawnClosePID(kPID)).Times(1);
Darin Petkov92c43902011-06-09 20:46:06 -0700319 DHCPConfig::ChildWatchCallback(kPID, 0, config_.get());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700320 EXPECT_EQ(NULL, DHCPProvider::GetInstance()->GetConfig(kPID).get());
Darin Petkov92c43902011-06-09 20:46:06 -0700321 EXPECT_FALSE(file_util::PathExists(pid_file));
322 EXPECT_FALSE(file_util::PathExists(lease_file));
Darin Petkovf7897bc2011-06-08 17:13:36 -0700323}
324
Darin Petkov98dd6a02011-06-10 15:12:57 -0700325TEST_F(DHCPConfigTest, Stop) {
326 // Ensure no crashes.
327 const int kPID = 1 << 17; // Ensure unknown positive PID.
328 config_->Stop();
329 config_->pid_ = kPID;
330 config_->Stop();
Chris Masone2176a882011-09-14 22:29:15 -0700331 EXPECT_CALL(*glib(), SpawnClosePID(kPID)).Times(1); // Invoked by destructor.
Darin Petkov98dd6a02011-06-10 15:12:57 -0700332}
333
Chris Masone43b48a12011-07-01 13:37:07 -0700334TEST_F(DHCPConfigTest, Dispatch) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700335 EXPECT_TRUE(DBusAdaptor::DispatchOnType(config_->mutable_store(),
Chris Masone43b48a12011-07-01 13:37:07 -0700336 flimflam::kMtuProperty,
337 PropertyStoreTest::kInt32V,
338 NULL));
339 ::DBus::Error error;
340 // Ensure that an attempt to write a R/O property returns InvalidArgs error.
mukesh agrawalde29fa82011-09-16 16:16:36 -0700341 EXPECT_FALSE(DBusAdaptor::DispatchOnType(config_->mutable_store(),
Chris Masone43b48a12011-07-01 13:37:07 -0700342 flimflam::kAddressProperty,
343 PropertyStoreTest::kStringV,
344 &error));
Chris Masone9d779932011-08-25 16:33:41 -0700345 EXPECT_EQ(invalid_args(), error.name());
Chris Masone43b48a12011-07-01 13:37:07 -0700346}
347
Darin Petkove7cb7f82011-06-03 13:21:51 -0700348} // namespace shill