blob: ce3ca6204e4541cf3568604702c4109753638ce5 [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
Darin Petkov92c43902011-06-09 20:46:06 -07005#include <base/file_util.h>
6#include <base/memory/scoped_temp_dir.h>
7#include <base/stringprintf.h>
8
Darin Petkove7cb7f82011-06-03 13:21:51 -07009#include "shill/dhcp_config.h"
Darin Petkovf7897bc2011-06-08 17:13:36 -070010#include "shill/dhcp_provider.h"
Darin Petkove7cb7f82011-06-03 13:21:51 -070011#include "shill/mock_control.h"
12#include "shill/mock_device.h"
Darin Petkov98dd6a02011-06-10 15:12:57 -070013#include "shill/mock_dhcp_proxy.h"
Darin Petkovf7897bc2011-06-08 17:13:36 -070014#include "shill/mock_glib.h"
Darin Petkove7cb7f82011-06-03 13:21:51 -070015
16using std::string;
17using std::vector;
Darin Petkovf7897bc2011-06-08 17:13:36 -070018using testing::_;
19using testing::Return;
20using testing::SetArgumentPointee;
Darin Petkove7cb7f82011-06-03 13:21:51 -070021using testing::Test;
22
23namespace shill {
24
Darin Petkov92c43902011-06-09 20:46:06 -070025namespace {
26const char kDeviceName[] = "testdevicename";
27} // namespace {}
28
Darin Petkove7cb7f82011-06-03 13:21:51 -070029class DHCPConfigTest : public Test {
30 public:
Darin Petkovf7897bc2011-06-08 17:13:36 -070031 DHCPConfigTest()
Darin Petkov92c43902011-06-09 20:46:06 -070032 : device_(new MockDevice(&control_interface_,
33 NULL,
34 NULL,
35 kDeviceName,
36 0)),
Darin Petkov98dd6a02011-06-10 15:12:57 -070037 proxy_(new MockDHCPProxy()),
38 config_(new DHCPConfig(DHCPProvider::GetInstance(), device_, &glib_)) {
39 config_->proxy_.reset(proxy_); // pass ownership
40 }
Darin Petkove7cb7f82011-06-03 13:21:51 -070041
42 protected:
Darin Petkovf7897bc2011-06-08 17:13:36 -070043 MockGLib glib_;
Darin Petkove7cb7f82011-06-03 13:21:51 -070044 MockControl control_interface_;
45 scoped_refptr<MockDevice> device_;
Darin Petkov98dd6a02011-06-10 15:12:57 -070046 MockDHCPProxy * const proxy_;
Darin Petkovf7897bc2011-06-08 17:13:36 -070047 DHCPConfigRefPtr config_;
Darin Petkove7cb7f82011-06-03 13:21:51 -070048};
49
50TEST_F(DHCPConfigTest, GetIPv4AddressString) {
Darin Petkovf7897bc2011-06-08 17:13:36 -070051 EXPECT_EQ("255.255.255.255", config_->GetIPv4AddressString(0xffffffff));
52 EXPECT_EQ("0.0.0.0", config_->GetIPv4AddressString(0));
53 EXPECT_EQ("1.2.3.4", config_->GetIPv4AddressString(0x04030201));
Darin Petkove7cb7f82011-06-03 13:21:51 -070054}
55
56TEST_F(DHCPConfigTest, ParseConfiguration) {
57 DHCPConfig::Configuration conf;
58 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
59 0x01020304);
60 conf[DHCPConfig::kConfigurationKeySubnetCIDR].writer().append_byte(
61 16);
62 conf[DHCPConfig::kConfigurationKeyBroadcastAddress].writer().append_uint32(
63 0x10203040);
64 {
Darin Petkove7cb7f82011-06-03 13:21:51 -070065 vector<unsigned int> routers;
66 routers.push_back(0x02040608);
67 routers.push_back(0x03050709);
Darin Petkovf7897bc2011-06-08 17:13:36 -070068 DBus::MessageIter writer =
69 conf[DHCPConfig::kConfigurationKeyRouters].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -070070 writer << routers;
Darin Petkove7cb7f82011-06-03 13:21:51 -070071 }
72 {
Darin Petkove7cb7f82011-06-03 13:21:51 -070073 vector<unsigned int> dns;
74 dns.push_back(0x09070503);
75 dns.push_back(0x08060402);
Darin Petkovf7897bc2011-06-08 17:13:36 -070076 DBus::MessageIter writer = conf[DHCPConfig::kConfigurationKeyDNS].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -070077 writer << dns;
Darin Petkove7cb7f82011-06-03 13:21:51 -070078 }
79 conf[DHCPConfig::kConfigurationKeyDomainName].writer().append_string(
80 "domain-name");
81 {
Darin Petkove7cb7f82011-06-03 13:21:51 -070082 vector<string> search;
83 search.push_back("foo.com");
84 search.push_back("bar.com");
Darin Petkovf7897bc2011-06-08 17:13:36 -070085 DBus::MessageIter writer =
86 conf[DHCPConfig::kConfigurationKeyDomainSearch].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -070087 writer << search;
Darin Petkove7cb7f82011-06-03 13:21:51 -070088 }
89 conf[DHCPConfig::kConfigurationKeyMTU].writer().append_uint16(600);
90 conf["UnknownKey"] = DBus::Variant();
91
Darin Petkove7cb7f82011-06-03 13:21:51 -070092 IPConfig::Properties properties;
Darin Petkovf7897bc2011-06-08 17:13:36 -070093 ASSERT_TRUE(config_->ParseConfiguration(conf, &properties));
Darin Petkove7cb7f82011-06-03 13:21:51 -070094 EXPECT_EQ("4.3.2.1", properties.address);
95 EXPECT_EQ(16, properties.subnet_cidr);
96 EXPECT_EQ("64.48.32.16", properties.broadcast_address);
97 EXPECT_EQ("8.6.4.2", properties.gateway);
98 ASSERT_EQ(2, properties.dns_servers.size());
99 EXPECT_EQ("3.5.7.9", properties.dns_servers[0]);
100 EXPECT_EQ("2.4.6.8", properties.dns_servers[1]);
101 EXPECT_EQ("domain-name", properties.domain_name);
102 ASSERT_EQ(2, properties.domain_search.size());
103 EXPECT_EQ("foo.com", properties.domain_search[0]);
104 EXPECT_EQ("bar.com", properties.domain_search[1]);
105 EXPECT_EQ(600, properties.mtu);
106}
107
Darin Petkov92c43902011-06-09 20:46:06 -0700108TEST_F(DHCPConfigTest, StartFail) {
Darin Petkovf7897bc2011-06-08 17:13:36 -0700109 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
110 .WillOnce(Return(false));
Darin Petkov92c43902011-06-09 20:46:06 -0700111 EXPECT_CALL(glib_, ChildWatchAdd(_, _, _)).Times(0);
Darin Petkovf7897bc2011-06-08 17:13:36 -0700112 EXPECT_FALSE(config_->Start());
113 EXPECT_EQ(0, config_->pid_);
Darin Petkov92c43902011-06-09 20:46:06 -0700114}
Darin Petkovf7897bc2011-06-08 17:13:36 -0700115
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700116namespace {
117
118class UpdateCallbackTest {
119 public:
120 UpdateCallbackTest(const string &message,
121 IPConfigRefPtr ipconfig,
122 bool success)
123 : message_(message),
124 ipconfig_(ipconfig),
125 success_(success),
126 called_(false) {}
127
128 void Callback(IPConfigRefPtr ipconfig, bool success) {
129 called_ = true;
130 EXPECT_EQ(ipconfig_.get(), ipconfig.get()) << message_;
131 EXPECT_EQ(success_, success) << message_;
132 }
133
134 bool called() const { return called_; }
135
136 private:
137 const string message_;
138 IPConfigRefPtr ipconfig_;
139 bool success_;
140 bool called_;
141};
142
143} // namespace {}
144
145TEST_F(DHCPConfigTest, ProcessEventSignalFail) {
146 DHCPConfig::Configuration conf;
147 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
148 0x01020304);
149 UpdateCallbackTest callback_test(DHCPConfig::kReasonFail, config_, false);
150 config_->RegisterUpdateCallback(
151 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
152 config_->ProcessEventSignal(DHCPConfig::kReasonFail, conf);
153 EXPECT_TRUE(callback_test.called());
154 EXPECT_TRUE(config_->properties().address.empty());
155}
156
157TEST_F(DHCPConfigTest, ProcessEventSignalSuccess) {
158 static const char * const kReasons[] = {
159 DHCPConfig::kReasonBound,
160 DHCPConfig::kReasonRebind,
161 DHCPConfig::kReasonReboot,
162 DHCPConfig::kReasonRenew
163 };
164 for (size_t r = 0; r < arraysize(kReasons); r++) {
165 DHCPConfig::Configuration conf;
166 string message = string(kReasons[r]) + " failed";
167 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(r);
168 UpdateCallbackTest callback_test(message, config_, true);
169 config_->RegisterUpdateCallback(
170 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
171 config_->ProcessEventSignal(kReasons[r], conf);
172 EXPECT_TRUE(callback_test.called()) << message;
173 EXPECT_EQ(base::StringPrintf("%u.0.0.0", r), config_->properties().address)
174 << message;
175 }
176}
177
178TEST_F(DHCPConfigTest, ProcessEventSignalUnknown) {
179 DHCPConfig::Configuration conf;
180 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
181 0x01020304);
182 static const char kReasonUnknown[] = "UNKNOWN_REASON";
183 UpdateCallbackTest callback_test(kReasonUnknown, config_, false);
184 config_->RegisterUpdateCallback(
185 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
186 config_->ProcessEventSignal(kReasonUnknown, conf);
187 EXPECT_FALSE(callback_test.called());
188 EXPECT_TRUE(config_->properties().address.empty());
189}
190
191
Darin Petkov98dd6a02011-06-10 15:12:57 -0700192TEST_F(DHCPConfigTest, ReleaseIP) {
193 config_->pid_ = 1 << 18; // Ensure unknown positive PID.
194 EXPECT_CALL(*proxy_, DoRelease(kDeviceName)).Times(1);
195 EXPECT_TRUE(config_->ReleaseIP());
196 config_->pid_ = 0;
197}
198
199TEST_F(DHCPConfigTest, RenewIP) {
200 config_->pid_ = 456;
201 EXPECT_CALL(*proxy_, DoRebind(kDeviceName)).Times(1);
202 EXPECT_TRUE(config_->RenewIP());
203 config_->pid_ = 0;
204}
205
206TEST_F(DHCPConfigTest, RequestIP) {
207 config_->pid_ = 567;
208 EXPECT_CALL(*proxy_, DoRebind(kDeviceName)).Times(1);
209 EXPECT_TRUE(config_->RenewIP());
210 config_->pid_ = 0;
211}
212
213TEST_F(DHCPConfigTest, Restart) {
214 const int kPID1 = 1 << 17; // Ensure unknown positive PID.
215 const int kPID2 = 987;
216 const unsigned int kTag1 = 11;
217 const unsigned int kTag2 = 22;
218 config_->pid_ = kPID1;
219 config_->child_watch_tag_ = kTag1;
220 DHCPProvider::GetInstance()->BindPID(kPID1, config_);
221 EXPECT_CALL(glib_, SourceRemove(kTag1)).WillOnce(Return(true));
222 EXPECT_CALL(glib_, SpawnClosePID(kPID1)).Times(1);
223 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
224 .WillOnce(DoAll(SetArgumentPointee<6>(kPID2), Return(true)));
225 EXPECT_CALL(glib_, ChildWatchAdd(kPID2, _, _)).WillOnce(Return(kTag2));
226 EXPECT_TRUE(config_->Restart());
227 EXPECT_EQ(kPID2, config_->pid_);
228 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID2).get());
229 EXPECT_EQ(kTag2, config_->child_watch_tag_);
230 DHCPProvider::GetInstance()->UnbindPID(kPID2);
231 config_->pid_ = 0;
232 config_->child_watch_tag_ = 0;
233}
234
235TEST_F(DHCPConfigTest, RestartNoClient) {
236 const int kPID = 777;
237 const unsigned int kTag = 66;
238 EXPECT_CALL(glib_, SourceRemove(_)).Times(0);
239 EXPECT_CALL(glib_, SpawnClosePID(_)).Times(0);
240 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
241 .WillOnce(DoAll(SetArgumentPointee<6>(kPID), Return(true)));
242 EXPECT_CALL(glib_, ChildWatchAdd(kPID, _, _)).WillOnce(Return(kTag));
243 EXPECT_TRUE(config_->Restart());
244 EXPECT_EQ(kPID, config_->pid_);
245 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID).get());
246 EXPECT_EQ(kTag, config_->child_watch_tag_);
247 DHCPProvider::GetInstance()->UnbindPID(kPID);
248 config_->pid_ = 0;
249 config_->child_watch_tag_ = 0;
250}
251
Darin Petkov92c43902011-06-09 20:46:06 -0700252TEST_F(DHCPConfigTest, StartSuccess) {
253 const int kPID = 123456;
254 const unsigned int kTag = 55;
Darin Petkovf7897bc2011-06-08 17:13:36 -0700255 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
256 .WillOnce(DoAll(SetArgumentPointee<6>(kPID), Return(true)));
Darin Petkov92c43902011-06-09 20:46:06 -0700257 EXPECT_CALL(glib_, ChildWatchAdd(kPID, _, _)).WillOnce(Return(kTag));
Darin Petkovf7897bc2011-06-08 17:13:36 -0700258 EXPECT_TRUE(config_->Start());
259 EXPECT_EQ(kPID, config_->pid_);
Darin Petkov98dd6a02011-06-10 15:12:57 -0700260 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID).get());
261 EXPECT_EQ(kTag, config_->child_watch_tag_);
Darin Petkov92c43902011-06-09 20:46:06 -0700262
263 ScopedTempDir temp_dir;
264 config_->root_ = temp_dir.path();
265 FilePath varrun = temp_dir.path().Append("var/run");
266 EXPECT_TRUE(file_util::CreateDirectory(varrun));
267 FilePath pid_file =
268 varrun.Append(base::StringPrintf("dhcpcd-%s.pid", kDeviceName));
269 FilePath lease_file =
270 varrun.Append(base::StringPrintf("dhcpcd-%s.lease", kDeviceName));
271 EXPECT_EQ(0, file_util::WriteFile(pid_file, "", 0));
272 EXPECT_EQ(0, file_util::WriteFile(lease_file, "", 0));
273 ASSERT_TRUE(file_util::PathExists(pid_file));
274 ASSERT_TRUE(file_util::PathExists(lease_file));
275
276 EXPECT_CALL(glib_, SpawnClosePID(kPID)).Times(1);
277 DHCPConfig::ChildWatchCallback(kPID, 0, config_.get());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700278 EXPECT_EQ(NULL, DHCPProvider::GetInstance()->GetConfig(kPID).get());
Darin Petkov92c43902011-06-09 20:46:06 -0700279 EXPECT_FALSE(file_util::PathExists(pid_file));
280 EXPECT_FALSE(file_util::PathExists(lease_file));
Darin Petkovf7897bc2011-06-08 17:13:36 -0700281}
282
Darin Petkov98dd6a02011-06-10 15:12:57 -0700283TEST_F(DHCPConfigTest, Stop) {
284 // Ensure no crashes.
285 const int kPID = 1 << 17; // Ensure unknown positive PID.
286 config_->Stop();
287 config_->pid_ = kPID;
288 config_->Stop();
289 EXPECT_CALL(glib_, SpawnClosePID(kPID)).Times(1); // Invoked by destuctor.
290}
291
Darin Petkove7cb7f82011-06-03 13:21:51 -0700292} // namespace shill