blob: 744e0ad10c65c0491892a42935693efbcc0c63d9 [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 Petkove7cb7f82011-06-03 13:21:51 -070019
20using std::string;
21using std::vector;
Darin Petkovf7897bc2011-06-08 17:13:36 -070022using testing::_;
23using testing::Return;
24using testing::SetArgumentPointee;
Darin Petkove7cb7f82011-06-03 13:21:51 -070025using testing::Test;
26
27namespace shill {
28
Darin Petkov92c43902011-06-09 20:46:06 -070029namespace {
30const char kDeviceName[] = "testdevicename";
31} // namespace {}
32
Chris Masone43b48a12011-07-01 13:37:07 -070033class DHCPConfigTest : public PropertyStoreTest {
Darin Petkove7cb7f82011-06-03 13:21:51 -070034 public:
Darin Petkovf7897bc2011-06-08 17:13:36 -070035 DHCPConfigTest()
Darin Petkovf65e9282011-06-21 14:29:56 -070036 : proxy_(new MockDHCPProxy()),
Chris Masone19e30402011-07-19 15:48:47 -070037 config_(new DHCPConfig(&control_,
38 DHCPProvider::GetInstance(),
Darin Petkov92c43902011-06-09 20:46:06 -070039 kDeviceName,
Darin Petkovf65e9282011-06-21 14:29:56 -070040 &glib_)) {
Darin Petkov98dd6a02011-06-10 15:12:57 -070041 config_->proxy_.reset(proxy_); // pass ownership
42 }
Darin Petkove7cb7f82011-06-03 13:21:51 -070043
44 protected:
Darin Petkovf7897bc2011-06-08 17:13:36 -070045 MockGLib glib_;
Darin Petkov98dd6a02011-06-10 15:12:57 -070046 MockDHCPProxy * const proxy_;
Chris Masone19e30402011-07-19 15:48:47 -070047 MockControl control_;
Darin Petkovf7897bc2011-06-08 17:13:36 -070048 DHCPConfigRefPtr config_;
Darin Petkove7cb7f82011-06-03 13:21:51 -070049};
50
51TEST_F(DHCPConfigTest, GetIPv4AddressString) {
Darin Petkovf7897bc2011-06-08 17:13:36 -070052 EXPECT_EQ("255.255.255.255", config_->GetIPv4AddressString(0xffffffff));
53 EXPECT_EQ("0.0.0.0", config_->GetIPv4AddressString(0));
54 EXPECT_EQ("1.2.3.4", config_->GetIPv4AddressString(0x04030201));
Darin Petkove7cb7f82011-06-03 13:21:51 -070055}
56
57TEST_F(DHCPConfigTest, ParseConfiguration) {
58 DHCPConfig::Configuration conf;
59 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
60 0x01020304);
61 conf[DHCPConfig::kConfigurationKeySubnetCIDR].writer().append_byte(
62 16);
63 conf[DHCPConfig::kConfigurationKeyBroadcastAddress].writer().append_uint32(
64 0x10203040);
65 {
Darin Petkove7cb7f82011-06-03 13:21:51 -070066 vector<unsigned int> routers;
67 routers.push_back(0x02040608);
68 routers.push_back(0x03050709);
Darin Petkovf7897bc2011-06-08 17:13:36 -070069 DBus::MessageIter writer =
70 conf[DHCPConfig::kConfigurationKeyRouters].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -070071 writer << routers;
Darin Petkove7cb7f82011-06-03 13:21:51 -070072 }
73 {
Darin Petkove7cb7f82011-06-03 13:21:51 -070074 vector<unsigned int> dns;
75 dns.push_back(0x09070503);
76 dns.push_back(0x08060402);
Darin Petkovf7897bc2011-06-08 17:13:36 -070077 DBus::MessageIter writer = conf[DHCPConfig::kConfigurationKeyDNS].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -070078 writer << dns;
Darin Petkove7cb7f82011-06-03 13:21:51 -070079 }
80 conf[DHCPConfig::kConfigurationKeyDomainName].writer().append_string(
81 "domain-name");
82 {
Darin Petkove7cb7f82011-06-03 13:21:51 -070083 vector<string> search;
84 search.push_back("foo.com");
85 search.push_back("bar.com");
Darin Petkovf7897bc2011-06-08 17:13:36 -070086 DBus::MessageIter writer =
87 conf[DHCPConfig::kConfigurationKeyDomainSearch].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -070088 writer << search;
Darin Petkove7cb7f82011-06-03 13:21:51 -070089 }
90 conf[DHCPConfig::kConfigurationKeyMTU].writer().append_uint16(600);
91 conf["UnknownKey"] = DBus::Variant();
92
Darin Petkove7cb7f82011-06-03 13:21:51 -070093 IPConfig::Properties properties;
Darin Petkovf7897bc2011-06-08 17:13:36 -070094 ASSERT_TRUE(config_->ParseConfiguration(conf, &properties));
Darin Petkove7cb7f82011-06-03 13:21:51 -070095 EXPECT_EQ("4.3.2.1", properties.address);
96 EXPECT_EQ(16, properties.subnet_cidr);
97 EXPECT_EQ("64.48.32.16", properties.broadcast_address);
98 EXPECT_EQ("8.6.4.2", properties.gateway);
99 ASSERT_EQ(2, properties.dns_servers.size());
100 EXPECT_EQ("3.5.7.9", properties.dns_servers[0]);
101 EXPECT_EQ("2.4.6.8", properties.dns_servers[1]);
102 EXPECT_EQ("domain-name", properties.domain_name);
103 ASSERT_EQ(2, properties.domain_search.size());
104 EXPECT_EQ("foo.com", properties.domain_search[0]);
105 EXPECT_EQ("bar.com", properties.domain_search[1]);
106 EXPECT_EQ(600, properties.mtu);
107}
108
Darin Petkov92c43902011-06-09 20:46:06 -0700109TEST_F(DHCPConfigTest, StartFail) {
Darin Petkovf7897bc2011-06-08 17:13:36 -0700110 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
111 .WillOnce(Return(false));
Darin Petkov92c43902011-06-09 20:46:06 -0700112 EXPECT_CALL(glib_, ChildWatchAdd(_, _, _)).Times(0);
Darin Petkovf7897bc2011-06-08 17:13:36 -0700113 EXPECT_FALSE(config_->Start());
114 EXPECT_EQ(0, config_->pid_);
Darin Petkov92c43902011-06-09 20:46:06 -0700115}
Darin Petkovf7897bc2011-06-08 17:13:36 -0700116
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700117namespace {
118
119class UpdateCallbackTest {
120 public:
121 UpdateCallbackTest(const string &message,
Chris Masone2b105542011-06-22 10:58:09 -0700122 const IPConfigRefPtr &ipconfig,
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700123 bool success)
124 : message_(message),
125 ipconfig_(ipconfig),
126 success_(success),
127 called_(false) {}
128
Chris Masone2b105542011-06-22 10:58:09 -0700129 void Callback(const IPConfigRefPtr &ipconfig, bool success) {
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700130 called_ = true;
131 EXPECT_EQ(ipconfig_.get(), ipconfig.get()) << message_;
132 EXPECT_EQ(success_, success) << message_;
133 }
134
135 bool called() const { return called_; }
136
137 private:
138 const string message_;
139 IPConfigRefPtr ipconfig_;
140 bool success_;
141 bool called_;
142};
143
144} // namespace {}
145
146TEST_F(DHCPConfigTest, ProcessEventSignalFail) {
147 DHCPConfig::Configuration conf;
148 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
149 0x01020304);
150 UpdateCallbackTest callback_test(DHCPConfig::kReasonFail, config_, false);
151 config_->RegisterUpdateCallback(
152 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
153 config_->ProcessEventSignal(DHCPConfig::kReasonFail, conf);
154 EXPECT_TRUE(callback_test.called());
155 EXPECT_TRUE(config_->properties().address.empty());
156}
157
158TEST_F(DHCPConfigTest, ProcessEventSignalSuccess) {
159 static const char * const kReasons[] = {
160 DHCPConfig::kReasonBound,
161 DHCPConfig::kReasonRebind,
162 DHCPConfig::kReasonReboot,
163 DHCPConfig::kReasonRenew
164 };
165 for (size_t r = 0; r < arraysize(kReasons); r++) {
166 DHCPConfig::Configuration conf;
167 string message = string(kReasons[r]) + " failed";
168 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(r);
169 UpdateCallbackTest callback_test(message, config_, true);
170 config_->RegisterUpdateCallback(
171 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
172 config_->ProcessEventSignal(kReasons[r], conf);
173 EXPECT_TRUE(callback_test.called()) << message;
174 EXPECT_EQ(base::StringPrintf("%u.0.0.0", r), config_->properties().address)
175 << message;
176 }
177}
178
179TEST_F(DHCPConfigTest, ProcessEventSignalUnknown) {
180 DHCPConfig::Configuration conf;
181 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
182 0x01020304);
183 static const char kReasonUnknown[] = "UNKNOWN_REASON";
184 UpdateCallbackTest callback_test(kReasonUnknown, config_, false);
185 config_->RegisterUpdateCallback(
186 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
187 config_->ProcessEventSignal(kReasonUnknown, conf);
188 EXPECT_FALSE(callback_test.called());
189 EXPECT_TRUE(config_->properties().address.empty());
190}
191
192
Darin Petkov98dd6a02011-06-10 15:12:57 -0700193TEST_F(DHCPConfigTest, ReleaseIP) {
194 config_->pid_ = 1 << 18; // Ensure unknown positive PID.
Darin Petkovaceede32011-07-18 15:32:38 -0700195 EXPECT_CALL(*proxy_, Release(kDeviceName)).Times(1);
Darin Petkov98dd6a02011-06-10 15:12:57 -0700196 EXPECT_TRUE(config_->ReleaseIP());
197 config_->pid_ = 0;
198}
199
200TEST_F(DHCPConfigTest, RenewIP) {
201 config_->pid_ = 456;
Darin Petkovaceede32011-07-18 15:32:38 -0700202 EXPECT_CALL(*proxy_, Rebind(kDeviceName)).Times(1);
Darin Petkov98dd6a02011-06-10 15:12:57 -0700203 EXPECT_TRUE(config_->RenewIP());
204 config_->pid_ = 0;
205}
206
207TEST_F(DHCPConfigTest, RequestIP) {
208 config_->pid_ = 567;
Darin Petkovaceede32011-07-18 15:32:38 -0700209 EXPECT_CALL(*proxy_, Rebind(kDeviceName)).Times(1);
Darin Petkov98dd6a02011-06-10 15:12:57 -0700210 EXPECT_TRUE(config_->RenewIP());
211 config_->pid_ = 0;
212}
213
214TEST_F(DHCPConfigTest, Restart) {
215 const int kPID1 = 1 << 17; // Ensure unknown positive PID.
216 const int kPID2 = 987;
217 const unsigned int kTag1 = 11;
218 const unsigned int kTag2 = 22;
219 config_->pid_ = kPID1;
220 config_->child_watch_tag_ = kTag1;
221 DHCPProvider::GetInstance()->BindPID(kPID1, config_);
222 EXPECT_CALL(glib_, SourceRemove(kTag1)).WillOnce(Return(true));
223 EXPECT_CALL(glib_, SpawnClosePID(kPID1)).Times(1);
224 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
225 .WillOnce(DoAll(SetArgumentPointee<6>(kPID2), Return(true)));
226 EXPECT_CALL(glib_, ChildWatchAdd(kPID2, _, _)).WillOnce(Return(kTag2));
227 EXPECT_TRUE(config_->Restart());
228 EXPECT_EQ(kPID2, config_->pid_);
229 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID2).get());
230 EXPECT_EQ(kTag2, config_->child_watch_tag_);
231 DHCPProvider::GetInstance()->UnbindPID(kPID2);
232 config_->pid_ = 0;
233 config_->child_watch_tag_ = 0;
234}
235
236TEST_F(DHCPConfigTest, RestartNoClient) {
237 const int kPID = 777;
238 const unsigned int kTag = 66;
239 EXPECT_CALL(glib_, SourceRemove(_)).Times(0);
240 EXPECT_CALL(glib_, SpawnClosePID(_)).Times(0);
241 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
242 .WillOnce(DoAll(SetArgumentPointee<6>(kPID), Return(true)));
243 EXPECT_CALL(glib_, ChildWatchAdd(kPID, _, _)).WillOnce(Return(kTag));
244 EXPECT_TRUE(config_->Restart());
245 EXPECT_EQ(kPID, config_->pid_);
246 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID).get());
247 EXPECT_EQ(kTag, config_->child_watch_tag_);
248 DHCPProvider::GetInstance()->UnbindPID(kPID);
249 config_->pid_ = 0;
250 config_->child_watch_tag_ = 0;
251}
252
Darin Petkov92c43902011-06-09 20:46:06 -0700253TEST_F(DHCPConfigTest, StartSuccess) {
254 const int kPID = 123456;
255 const unsigned int kTag = 55;
Darin Petkovf7897bc2011-06-08 17:13:36 -0700256 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
257 .WillOnce(DoAll(SetArgumentPointee<6>(kPID), Return(true)));
Darin Petkov92c43902011-06-09 20:46:06 -0700258 EXPECT_CALL(glib_, ChildWatchAdd(kPID, _, _)).WillOnce(Return(kTag));
Darin Petkovf7897bc2011-06-08 17:13:36 -0700259 EXPECT_TRUE(config_->Start());
260 EXPECT_EQ(kPID, config_->pid_);
Darin Petkov98dd6a02011-06-10 15:12:57 -0700261 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID).get());
262 EXPECT_EQ(kTag, config_->child_watch_tag_);
Darin Petkov92c43902011-06-09 20:46:06 -0700263
264 ScopedTempDir temp_dir;
265 config_->root_ = temp_dir.path();
266 FilePath varrun = temp_dir.path().Append("var/run");
267 EXPECT_TRUE(file_util::CreateDirectory(varrun));
268 FilePath pid_file =
269 varrun.Append(base::StringPrintf("dhcpcd-%s.pid", kDeviceName));
270 FilePath lease_file =
271 varrun.Append(base::StringPrintf("dhcpcd-%s.lease", kDeviceName));
272 EXPECT_EQ(0, file_util::WriteFile(pid_file, "", 0));
273 EXPECT_EQ(0, file_util::WriteFile(lease_file, "", 0));
274 ASSERT_TRUE(file_util::PathExists(pid_file));
275 ASSERT_TRUE(file_util::PathExists(lease_file));
276
277 EXPECT_CALL(glib_, SpawnClosePID(kPID)).Times(1);
278 DHCPConfig::ChildWatchCallback(kPID, 0, config_.get());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700279 EXPECT_EQ(NULL, DHCPProvider::GetInstance()->GetConfig(kPID).get());
Darin Petkov92c43902011-06-09 20:46:06 -0700280 EXPECT_FALSE(file_util::PathExists(pid_file));
281 EXPECT_FALSE(file_util::PathExists(lease_file));
Darin Petkovf7897bc2011-06-08 17:13:36 -0700282}
283
Darin Petkov98dd6a02011-06-10 15:12:57 -0700284TEST_F(DHCPConfigTest, Stop) {
285 // Ensure no crashes.
286 const int kPID = 1 << 17; // Ensure unknown positive PID.
287 config_->Stop();
288 config_->pid_ = kPID;
289 config_->Stop();
290 EXPECT_CALL(glib_, SpawnClosePID(kPID)).Times(1); // Invoked by destuctor.
291}
292
Chris Masone43b48a12011-07-01 13:37:07 -0700293TEST_F(DHCPConfigTest, Dispatch) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700294 EXPECT_TRUE(DBusAdaptor::DispatchOnType(config_->store(),
Chris Masone43b48a12011-07-01 13:37:07 -0700295 flimflam::kMtuProperty,
296 PropertyStoreTest::kInt32V,
297 NULL));
298 ::DBus::Error error;
299 // Ensure that an attempt to write a R/O property returns InvalidArgs error.
Chris Masone27c4aa52011-07-02 13:10:14 -0700300 EXPECT_FALSE(DBusAdaptor::DispatchOnType(config_->store(),
Chris Masone43b48a12011-07-01 13:37:07 -0700301 flimflam::kAddressProperty,
302 PropertyStoreTest::kStringV,
303 &error));
304 EXPECT_EQ(invalid_args_, error.name());
305}
306
Darin Petkove7cb7f82011-06-03 13:21:51 -0700307} // namespace shill