blob: 3edeeae3b5b6f90602b0776984b03dadb7b57987 [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 Petkov98dd6a02011-06-10 15:12:57 -070011#include "shill/mock_dhcp_proxy.h"
Darin Petkovf7897bc2011-06-08 17:13:36 -070012#include "shill/mock_glib.h"
Darin Petkove7cb7f82011-06-03 13:21:51 -070013
14using std::string;
15using std::vector;
Darin Petkovf7897bc2011-06-08 17:13:36 -070016using testing::_;
17using testing::Return;
18using testing::SetArgumentPointee;
Darin Petkove7cb7f82011-06-03 13:21:51 -070019using testing::Test;
20
21namespace shill {
22
Darin Petkov92c43902011-06-09 20:46:06 -070023namespace {
24const char kDeviceName[] = "testdevicename";
25} // namespace {}
26
Darin Petkove7cb7f82011-06-03 13:21:51 -070027class DHCPConfigTest : public Test {
28 public:
Darin Petkovf7897bc2011-06-08 17:13:36 -070029 DHCPConfigTest()
Darin Petkovf65e9282011-06-21 14:29:56 -070030 : proxy_(new MockDHCPProxy()),
31 config_(new DHCPConfig(DHCPProvider::GetInstance(),
Darin Petkov92c43902011-06-09 20:46:06 -070032 kDeviceName,
Darin Petkovf65e9282011-06-21 14:29:56 -070033 &glib_)) {
Darin Petkov98dd6a02011-06-10 15:12:57 -070034 config_->proxy_.reset(proxy_); // pass ownership
35 }
Darin Petkove7cb7f82011-06-03 13:21:51 -070036
37 protected:
Darin Petkovf7897bc2011-06-08 17:13:36 -070038 MockGLib glib_;
Darin Petkov98dd6a02011-06-10 15:12:57 -070039 MockDHCPProxy * const proxy_;
Darin Petkovf7897bc2011-06-08 17:13:36 -070040 DHCPConfigRefPtr config_;
Darin Petkove7cb7f82011-06-03 13:21:51 -070041};
42
43TEST_F(DHCPConfigTest, GetIPv4AddressString) {
Darin Petkovf7897bc2011-06-08 17:13:36 -070044 EXPECT_EQ("255.255.255.255", config_->GetIPv4AddressString(0xffffffff));
45 EXPECT_EQ("0.0.0.0", config_->GetIPv4AddressString(0));
46 EXPECT_EQ("1.2.3.4", config_->GetIPv4AddressString(0x04030201));
Darin Petkove7cb7f82011-06-03 13:21:51 -070047}
48
49TEST_F(DHCPConfigTest, ParseConfiguration) {
50 DHCPConfig::Configuration conf;
51 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
52 0x01020304);
53 conf[DHCPConfig::kConfigurationKeySubnetCIDR].writer().append_byte(
54 16);
55 conf[DHCPConfig::kConfigurationKeyBroadcastAddress].writer().append_uint32(
56 0x10203040);
57 {
Darin Petkove7cb7f82011-06-03 13:21:51 -070058 vector<unsigned int> routers;
59 routers.push_back(0x02040608);
60 routers.push_back(0x03050709);
Darin Petkovf7897bc2011-06-08 17:13:36 -070061 DBus::MessageIter writer =
62 conf[DHCPConfig::kConfigurationKeyRouters].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -070063 writer << routers;
Darin Petkove7cb7f82011-06-03 13:21:51 -070064 }
65 {
Darin Petkove7cb7f82011-06-03 13:21:51 -070066 vector<unsigned int> dns;
67 dns.push_back(0x09070503);
68 dns.push_back(0x08060402);
Darin Petkovf7897bc2011-06-08 17:13:36 -070069 DBus::MessageIter writer = conf[DHCPConfig::kConfigurationKeyDNS].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -070070 writer << dns;
Darin Petkove7cb7f82011-06-03 13:21:51 -070071 }
72 conf[DHCPConfig::kConfigurationKeyDomainName].writer().append_string(
73 "domain-name");
74 {
Darin Petkove7cb7f82011-06-03 13:21:51 -070075 vector<string> search;
76 search.push_back("foo.com");
77 search.push_back("bar.com");
Darin Petkovf7897bc2011-06-08 17:13:36 -070078 DBus::MessageIter writer =
79 conf[DHCPConfig::kConfigurationKeyDomainSearch].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -070080 writer << search;
Darin Petkove7cb7f82011-06-03 13:21:51 -070081 }
82 conf[DHCPConfig::kConfigurationKeyMTU].writer().append_uint16(600);
83 conf["UnknownKey"] = DBus::Variant();
84
Darin Petkove7cb7f82011-06-03 13:21:51 -070085 IPConfig::Properties properties;
Darin Petkovf7897bc2011-06-08 17:13:36 -070086 ASSERT_TRUE(config_->ParseConfiguration(conf, &properties));
Darin Petkove7cb7f82011-06-03 13:21:51 -070087 EXPECT_EQ("4.3.2.1", properties.address);
88 EXPECT_EQ(16, properties.subnet_cidr);
89 EXPECT_EQ("64.48.32.16", properties.broadcast_address);
90 EXPECT_EQ("8.6.4.2", properties.gateway);
91 ASSERT_EQ(2, properties.dns_servers.size());
92 EXPECT_EQ("3.5.7.9", properties.dns_servers[0]);
93 EXPECT_EQ("2.4.6.8", properties.dns_servers[1]);
94 EXPECT_EQ("domain-name", properties.domain_name);
95 ASSERT_EQ(2, properties.domain_search.size());
96 EXPECT_EQ("foo.com", properties.domain_search[0]);
97 EXPECT_EQ("bar.com", properties.domain_search[1]);
98 EXPECT_EQ(600, properties.mtu);
99}
100
Darin Petkov92c43902011-06-09 20:46:06 -0700101TEST_F(DHCPConfigTest, StartFail) {
Darin Petkovf7897bc2011-06-08 17:13:36 -0700102 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
103 .WillOnce(Return(false));
Darin Petkov92c43902011-06-09 20:46:06 -0700104 EXPECT_CALL(glib_, ChildWatchAdd(_, _, _)).Times(0);
Darin Petkovf7897bc2011-06-08 17:13:36 -0700105 EXPECT_FALSE(config_->Start());
106 EXPECT_EQ(0, config_->pid_);
Darin Petkov92c43902011-06-09 20:46:06 -0700107}
Darin Petkovf7897bc2011-06-08 17:13:36 -0700108
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700109namespace {
110
111class UpdateCallbackTest {
112 public:
113 UpdateCallbackTest(const string &message,
114 IPConfigRefPtr ipconfig,
115 bool success)
116 : message_(message),
117 ipconfig_(ipconfig),
118 success_(success),
119 called_(false) {}
120
121 void Callback(IPConfigRefPtr ipconfig, bool success) {
122 called_ = true;
123 EXPECT_EQ(ipconfig_.get(), ipconfig.get()) << message_;
124 EXPECT_EQ(success_, success) << message_;
125 }
126
127 bool called() const { return called_; }
128
129 private:
130 const string message_;
131 IPConfigRefPtr ipconfig_;
132 bool success_;
133 bool called_;
134};
135
136} // namespace {}
137
138TEST_F(DHCPConfigTest, ProcessEventSignalFail) {
139 DHCPConfig::Configuration conf;
140 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
141 0x01020304);
142 UpdateCallbackTest callback_test(DHCPConfig::kReasonFail, config_, false);
143 config_->RegisterUpdateCallback(
144 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
145 config_->ProcessEventSignal(DHCPConfig::kReasonFail, conf);
146 EXPECT_TRUE(callback_test.called());
147 EXPECT_TRUE(config_->properties().address.empty());
148}
149
150TEST_F(DHCPConfigTest, ProcessEventSignalSuccess) {
151 static const char * const kReasons[] = {
152 DHCPConfig::kReasonBound,
153 DHCPConfig::kReasonRebind,
154 DHCPConfig::kReasonReboot,
155 DHCPConfig::kReasonRenew
156 };
157 for (size_t r = 0; r < arraysize(kReasons); r++) {
158 DHCPConfig::Configuration conf;
159 string message = string(kReasons[r]) + " failed";
160 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(r);
161 UpdateCallbackTest callback_test(message, config_, true);
162 config_->RegisterUpdateCallback(
163 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
164 config_->ProcessEventSignal(kReasons[r], conf);
165 EXPECT_TRUE(callback_test.called()) << message;
166 EXPECT_EQ(base::StringPrintf("%u.0.0.0", r), config_->properties().address)
167 << message;
168 }
169}
170
171TEST_F(DHCPConfigTest, ProcessEventSignalUnknown) {
172 DHCPConfig::Configuration conf;
173 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
174 0x01020304);
175 static const char kReasonUnknown[] = "UNKNOWN_REASON";
176 UpdateCallbackTest callback_test(kReasonUnknown, config_, false);
177 config_->RegisterUpdateCallback(
178 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
179 config_->ProcessEventSignal(kReasonUnknown, conf);
180 EXPECT_FALSE(callback_test.called());
181 EXPECT_TRUE(config_->properties().address.empty());
182}
183
184
Darin Petkov98dd6a02011-06-10 15:12:57 -0700185TEST_F(DHCPConfigTest, ReleaseIP) {
186 config_->pid_ = 1 << 18; // Ensure unknown positive PID.
187 EXPECT_CALL(*proxy_, DoRelease(kDeviceName)).Times(1);
188 EXPECT_TRUE(config_->ReleaseIP());
189 config_->pid_ = 0;
190}
191
192TEST_F(DHCPConfigTest, RenewIP) {
193 config_->pid_ = 456;
194 EXPECT_CALL(*proxy_, DoRebind(kDeviceName)).Times(1);
195 EXPECT_TRUE(config_->RenewIP());
196 config_->pid_ = 0;
197}
198
199TEST_F(DHCPConfigTest, RequestIP) {
200 config_->pid_ = 567;
201 EXPECT_CALL(*proxy_, DoRebind(kDeviceName)).Times(1);
202 EXPECT_TRUE(config_->RenewIP());
203 config_->pid_ = 0;
204}
205
206TEST_F(DHCPConfigTest, Restart) {
207 const int kPID1 = 1 << 17; // Ensure unknown positive PID.
208 const int kPID2 = 987;
209 const unsigned int kTag1 = 11;
210 const unsigned int kTag2 = 22;
211 config_->pid_ = kPID1;
212 config_->child_watch_tag_ = kTag1;
213 DHCPProvider::GetInstance()->BindPID(kPID1, config_);
214 EXPECT_CALL(glib_, SourceRemove(kTag1)).WillOnce(Return(true));
215 EXPECT_CALL(glib_, SpawnClosePID(kPID1)).Times(1);
216 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
217 .WillOnce(DoAll(SetArgumentPointee<6>(kPID2), Return(true)));
218 EXPECT_CALL(glib_, ChildWatchAdd(kPID2, _, _)).WillOnce(Return(kTag2));
219 EXPECT_TRUE(config_->Restart());
220 EXPECT_EQ(kPID2, config_->pid_);
221 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID2).get());
222 EXPECT_EQ(kTag2, config_->child_watch_tag_);
223 DHCPProvider::GetInstance()->UnbindPID(kPID2);
224 config_->pid_ = 0;
225 config_->child_watch_tag_ = 0;
226}
227
228TEST_F(DHCPConfigTest, RestartNoClient) {
229 const int kPID = 777;
230 const unsigned int kTag = 66;
231 EXPECT_CALL(glib_, SourceRemove(_)).Times(0);
232 EXPECT_CALL(glib_, SpawnClosePID(_)).Times(0);
233 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
234 .WillOnce(DoAll(SetArgumentPointee<6>(kPID), Return(true)));
235 EXPECT_CALL(glib_, ChildWatchAdd(kPID, _, _)).WillOnce(Return(kTag));
236 EXPECT_TRUE(config_->Restart());
237 EXPECT_EQ(kPID, config_->pid_);
238 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID).get());
239 EXPECT_EQ(kTag, config_->child_watch_tag_);
240 DHCPProvider::GetInstance()->UnbindPID(kPID);
241 config_->pid_ = 0;
242 config_->child_watch_tag_ = 0;
243}
244
Darin Petkov92c43902011-06-09 20:46:06 -0700245TEST_F(DHCPConfigTest, StartSuccess) {
246 const int kPID = 123456;
247 const unsigned int kTag = 55;
Darin Petkovf7897bc2011-06-08 17:13:36 -0700248 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
249 .WillOnce(DoAll(SetArgumentPointee<6>(kPID), Return(true)));
Darin Petkov92c43902011-06-09 20:46:06 -0700250 EXPECT_CALL(glib_, ChildWatchAdd(kPID, _, _)).WillOnce(Return(kTag));
Darin Petkovf7897bc2011-06-08 17:13:36 -0700251 EXPECT_TRUE(config_->Start());
252 EXPECT_EQ(kPID, config_->pid_);
Darin Petkov98dd6a02011-06-10 15:12:57 -0700253 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID).get());
254 EXPECT_EQ(kTag, config_->child_watch_tag_);
Darin Petkov92c43902011-06-09 20:46:06 -0700255
256 ScopedTempDir temp_dir;
257 config_->root_ = temp_dir.path();
258 FilePath varrun = temp_dir.path().Append("var/run");
259 EXPECT_TRUE(file_util::CreateDirectory(varrun));
260 FilePath pid_file =
261 varrun.Append(base::StringPrintf("dhcpcd-%s.pid", kDeviceName));
262 FilePath lease_file =
263 varrun.Append(base::StringPrintf("dhcpcd-%s.lease", kDeviceName));
264 EXPECT_EQ(0, file_util::WriteFile(pid_file, "", 0));
265 EXPECT_EQ(0, file_util::WriteFile(lease_file, "", 0));
266 ASSERT_TRUE(file_util::PathExists(pid_file));
267 ASSERT_TRUE(file_util::PathExists(lease_file));
268
269 EXPECT_CALL(glib_, SpawnClosePID(kPID)).Times(1);
270 DHCPConfig::ChildWatchCallback(kPID, 0, config_.get());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700271 EXPECT_EQ(NULL, DHCPProvider::GetInstance()->GetConfig(kPID).get());
Darin Petkov92c43902011-06-09 20:46:06 -0700272 EXPECT_FALSE(file_util::PathExists(pid_file));
273 EXPECT_FALSE(file_util::PathExists(lease_file));
Darin Petkovf7897bc2011-06-08 17:13:36 -0700274}
275
Darin Petkov98dd6a02011-06-10 15:12:57 -0700276TEST_F(DHCPConfigTest, Stop) {
277 // Ensure no crashes.
278 const int kPID = 1 << 17; // Ensure unknown positive PID.
279 config_->Stop();
280 config_->pid_ = kPID;
281 config_->Stop();
282 EXPECT_CALL(glib_, SpawnClosePID(kPID)).Times(1); // Invoked by destuctor.
283}
284
Darin Petkove7cb7f82011-06-03 13:21:51 -0700285} // namespace shill