blob: 4d736f6175b9ffc3c0ff8ffd745467f68164aad0 [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>
Chris Masone43b48a12011-07-01 13:37:07 -07008#include <chromeos/dbus/service_constants.h>
Darin Petkov92c43902011-06-09 20:46:06 -07009
Chris Masone43b48a12011-07-01 13:37:07 -070010#include "shill/dbus_adaptor.h"
Darin Petkove7cb7f82011-06-03 13:21:51 -070011#include "shill/dhcp_config.h"
Darin Petkovf7897bc2011-06-08 17:13:36 -070012#include "shill/dhcp_provider.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"
Chris Masone43b48a12011-07-01 13:37:07 -070015#include "shill/property_store_unittest.h"
Darin Petkove7cb7f82011-06-03 13:21:51 -070016
17using std::string;
18using std::vector;
Darin Petkovf7897bc2011-06-08 17:13:36 -070019using testing::_;
20using testing::Return;
21using testing::SetArgumentPointee;
Darin Petkove7cb7f82011-06-03 13:21:51 -070022using testing::Test;
23
24namespace shill {
25
Darin Petkov92c43902011-06-09 20:46:06 -070026namespace {
27const char kDeviceName[] = "testdevicename";
28} // namespace {}
29
Chris Masone43b48a12011-07-01 13:37:07 -070030class DHCPConfigTest : public PropertyStoreTest {
Darin Petkove7cb7f82011-06-03 13:21:51 -070031 public:
Darin Petkovf7897bc2011-06-08 17:13:36 -070032 DHCPConfigTest()
Darin Petkovf65e9282011-06-21 14:29:56 -070033 : proxy_(new MockDHCPProxy()),
34 config_(new DHCPConfig(DHCPProvider::GetInstance(),
Darin Petkov92c43902011-06-09 20:46:06 -070035 kDeviceName,
Darin Petkovf65e9282011-06-21 14:29:56 -070036 &glib_)) {
Darin Petkov98dd6a02011-06-10 15:12:57 -070037 config_->proxy_.reset(proxy_); // pass ownership
38 }
Darin Petkove7cb7f82011-06-03 13:21:51 -070039
40 protected:
Darin Petkovf7897bc2011-06-08 17:13:36 -070041 MockGLib glib_;
Darin Petkov98dd6a02011-06-10 15:12:57 -070042 MockDHCPProxy * const proxy_;
Darin Petkovf7897bc2011-06-08 17:13:36 -070043 DHCPConfigRefPtr config_;
Darin Petkove7cb7f82011-06-03 13:21:51 -070044};
45
46TEST_F(DHCPConfigTest, GetIPv4AddressString) {
Darin Petkovf7897bc2011-06-08 17:13:36 -070047 EXPECT_EQ("255.255.255.255", config_->GetIPv4AddressString(0xffffffff));
48 EXPECT_EQ("0.0.0.0", config_->GetIPv4AddressString(0));
49 EXPECT_EQ("1.2.3.4", config_->GetIPv4AddressString(0x04030201));
Darin Petkove7cb7f82011-06-03 13:21:51 -070050}
51
52TEST_F(DHCPConfigTest, ParseConfiguration) {
53 DHCPConfig::Configuration conf;
54 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
55 0x01020304);
56 conf[DHCPConfig::kConfigurationKeySubnetCIDR].writer().append_byte(
57 16);
58 conf[DHCPConfig::kConfigurationKeyBroadcastAddress].writer().append_uint32(
59 0x10203040);
60 {
Darin Petkove7cb7f82011-06-03 13:21:51 -070061 vector<unsigned int> routers;
62 routers.push_back(0x02040608);
63 routers.push_back(0x03050709);
Darin Petkovf7897bc2011-06-08 17:13:36 -070064 DBus::MessageIter writer =
65 conf[DHCPConfig::kConfigurationKeyRouters].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -070066 writer << routers;
Darin Petkove7cb7f82011-06-03 13:21:51 -070067 }
68 {
Darin Petkove7cb7f82011-06-03 13:21:51 -070069 vector<unsigned int> dns;
70 dns.push_back(0x09070503);
71 dns.push_back(0x08060402);
Darin Petkovf7897bc2011-06-08 17:13:36 -070072 DBus::MessageIter writer = conf[DHCPConfig::kConfigurationKeyDNS].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -070073 writer << dns;
Darin Petkove7cb7f82011-06-03 13:21:51 -070074 }
75 conf[DHCPConfig::kConfigurationKeyDomainName].writer().append_string(
76 "domain-name");
77 {
Darin Petkove7cb7f82011-06-03 13:21:51 -070078 vector<string> search;
79 search.push_back("foo.com");
80 search.push_back("bar.com");
Darin Petkovf7897bc2011-06-08 17:13:36 -070081 DBus::MessageIter writer =
82 conf[DHCPConfig::kConfigurationKeyDomainSearch].writer();
Darin Petkove7cb7f82011-06-03 13:21:51 -070083 writer << search;
Darin Petkove7cb7f82011-06-03 13:21:51 -070084 }
85 conf[DHCPConfig::kConfigurationKeyMTU].writer().append_uint16(600);
86 conf["UnknownKey"] = DBus::Variant();
87
Darin Petkove7cb7f82011-06-03 13:21:51 -070088 IPConfig::Properties properties;
Darin Petkovf7897bc2011-06-08 17:13:36 -070089 ASSERT_TRUE(config_->ParseConfiguration(conf, &properties));
Darin Petkove7cb7f82011-06-03 13:21:51 -070090 EXPECT_EQ("4.3.2.1", properties.address);
91 EXPECT_EQ(16, properties.subnet_cidr);
92 EXPECT_EQ("64.48.32.16", properties.broadcast_address);
93 EXPECT_EQ("8.6.4.2", properties.gateway);
94 ASSERT_EQ(2, properties.dns_servers.size());
95 EXPECT_EQ("3.5.7.9", properties.dns_servers[0]);
96 EXPECT_EQ("2.4.6.8", properties.dns_servers[1]);
97 EXPECT_EQ("domain-name", properties.domain_name);
98 ASSERT_EQ(2, properties.domain_search.size());
99 EXPECT_EQ("foo.com", properties.domain_search[0]);
100 EXPECT_EQ("bar.com", properties.domain_search[1]);
101 EXPECT_EQ(600, properties.mtu);
102}
103
Darin Petkov92c43902011-06-09 20:46:06 -0700104TEST_F(DHCPConfigTest, StartFail) {
Darin Petkovf7897bc2011-06-08 17:13:36 -0700105 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
106 .WillOnce(Return(false));
Darin Petkov92c43902011-06-09 20:46:06 -0700107 EXPECT_CALL(glib_, ChildWatchAdd(_, _, _)).Times(0);
Darin Petkovf7897bc2011-06-08 17:13:36 -0700108 EXPECT_FALSE(config_->Start());
109 EXPECT_EQ(0, config_->pid_);
Darin Petkov92c43902011-06-09 20:46:06 -0700110}
Darin Petkovf7897bc2011-06-08 17:13:36 -0700111
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700112namespace {
113
114class UpdateCallbackTest {
115 public:
116 UpdateCallbackTest(const string &message,
Chris Masone2b105542011-06-22 10:58:09 -0700117 const IPConfigRefPtr &ipconfig,
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700118 bool success)
119 : message_(message),
120 ipconfig_(ipconfig),
121 success_(success),
122 called_(false) {}
123
Chris Masone2b105542011-06-22 10:58:09 -0700124 void Callback(const IPConfigRefPtr &ipconfig, bool success) {
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700125 called_ = true;
126 EXPECT_EQ(ipconfig_.get(), ipconfig.get()) << message_;
127 EXPECT_EQ(success_, success) << message_;
128 }
129
130 bool called() const { return called_; }
131
132 private:
133 const string message_;
134 IPConfigRefPtr ipconfig_;
135 bool success_;
136 bool called_;
137};
138
139} // namespace {}
140
141TEST_F(DHCPConfigTest, ProcessEventSignalFail) {
142 DHCPConfig::Configuration conf;
143 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
144 0x01020304);
145 UpdateCallbackTest callback_test(DHCPConfig::kReasonFail, config_, false);
146 config_->RegisterUpdateCallback(
147 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
148 config_->ProcessEventSignal(DHCPConfig::kReasonFail, conf);
149 EXPECT_TRUE(callback_test.called());
150 EXPECT_TRUE(config_->properties().address.empty());
151}
152
153TEST_F(DHCPConfigTest, ProcessEventSignalSuccess) {
154 static const char * const kReasons[] = {
155 DHCPConfig::kReasonBound,
156 DHCPConfig::kReasonRebind,
157 DHCPConfig::kReasonReboot,
158 DHCPConfig::kReasonRenew
159 };
160 for (size_t r = 0; r < arraysize(kReasons); r++) {
161 DHCPConfig::Configuration conf;
162 string message = string(kReasons[r]) + " failed";
163 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(r);
164 UpdateCallbackTest callback_test(message, config_, true);
165 config_->RegisterUpdateCallback(
166 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
167 config_->ProcessEventSignal(kReasons[r], conf);
168 EXPECT_TRUE(callback_test.called()) << message;
169 EXPECT_EQ(base::StringPrintf("%u.0.0.0", r), config_->properties().address)
170 << message;
171 }
172}
173
174TEST_F(DHCPConfigTest, ProcessEventSignalUnknown) {
175 DHCPConfig::Configuration conf;
176 conf[DHCPConfig::kConfigurationKeyIPAddress].writer().append_uint32(
177 0x01020304);
178 static const char kReasonUnknown[] = "UNKNOWN_REASON";
179 UpdateCallbackTest callback_test(kReasonUnknown, config_, false);
180 config_->RegisterUpdateCallback(
181 NewCallback(&callback_test, &UpdateCallbackTest::Callback));
182 config_->ProcessEventSignal(kReasonUnknown, conf);
183 EXPECT_FALSE(callback_test.called());
184 EXPECT_TRUE(config_->properties().address.empty());
185}
186
187
Darin Petkov98dd6a02011-06-10 15:12:57 -0700188TEST_F(DHCPConfigTest, ReleaseIP) {
189 config_->pid_ = 1 << 18; // Ensure unknown positive PID.
190 EXPECT_CALL(*proxy_, DoRelease(kDeviceName)).Times(1);
191 EXPECT_TRUE(config_->ReleaseIP());
192 config_->pid_ = 0;
193}
194
195TEST_F(DHCPConfigTest, RenewIP) {
196 config_->pid_ = 456;
197 EXPECT_CALL(*proxy_, DoRebind(kDeviceName)).Times(1);
198 EXPECT_TRUE(config_->RenewIP());
199 config_->pid_ = 0;
200}
201
202TEST_F(DHCPConfigTest, RequestIP) {
203 config_->pid_ = 567;
204 EXPECT_CALL(*proxy_, DoRebind(kDeviceName)).Times(1);
205 EXPECT_TRUE(config_->RenewIP());
206 config_->pid_ = 0;
207}
208
209TEST_F(DHCPConfigTest, Restart) {
210 const int kPID1 = 1 << 17; // Ensure unknown positive PID.
211 const int kPID2 = 987;
212 const unsigned int kTag1 = 11;
213 const unsigned int kTag2 = 22;
214 config_->pid_ = kPID1;
215 config_->child_watch_tag_ = kTag1;
216 DHCPProvider::GetInstance()->BindPID(kPID1, config_);
217 EXPECT_CALL(glib_, SourceRemove(kTag1)).WillOnce(Return(true));
218 EXPECT_CALL(glib_, SpawnClosePID(kPID1)).Times(1);
219 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
220 .WillOnce(DoAll(SetArgumentPointee<6>(kPID2), Return(true)));
221 EXPECT_CALL(glib_, ChildWatchAdd(kPID2, _, _)).WillOnce(Return(kTag2));
222 EXPECT_TRUE(config_->Restart());
223 EXPECT_EQ(kPID2, config_->pid_);
224 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID2).get());
225 EXPECT_EQ(kTag2, config_->child_watch_tag_);
226 DHCPProvider::GetInstance()->UnbindPID(kPID2);
227 config_->pid_ = 0;
228 config_->child_watch_tag_ = 0;
229}
230
231TEST_F(DHCPConfigTest, RestartNoClient) {
232 const int kPID = 777;
233 const unsigned int kTag = 66;
234 EXPECT_CALL(glib_, SourceRemove(_)).Times(0);
235 EXPECT_CALL(glib_, SpawnClosePID(_)).Times(0);
236 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
237 .WillOnce(DoAll(SetArgumentPointee<6>(kPID), Return(true)));
238 EXPECT_CALL(glib_, ChildWatchAdd(kPID, _, _)).WillOnce(Return(kTag));
239 EXPECT_TRUE(config_->Restart());
240 EXPECT_EQ(kPID, config_->pid_);
241 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID).get());
242 EXPECT_EQ(kTag, config_->child_watch_tag_);
243 DHCPProvider::GetInstance()->UnbindPID(kPID);
244 config_->pid_ = 0;
245 config_->child_watch_tag_ = 0;
246}
247
Darin Petkov92c43902011-06-09 20:46:06 -0700248TEST_F(DHCPConfigTest, StartSuccess) {
249 const int kPID = 123456;
250 const unsigned int kTag = 55;
Darin Petkovf7897bc2011-06-08 17:13:36 -0700251 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _))
252 .WillOnce(DoAll(SetArgumentPointee<6>(kPID), Return(true)));
Darin Petkov92c43902011-06-09 20:46:06 -0700253 EXPECT_CALL(glib_, ChildWatchAdd(kPID, _, _)).WillOnce(Return(kTag));
Darin Petkovf7897bc2011-06-08 17:13:36 -0700254 EXPECT_TRUE(config_->Start());
255 EXPECT_EQ(kPID, config_->pid_);
Darin Petkov98dd6a02011-06-10 15:12:57 -0700256 EXPECT_EQ(config_.get(), DHCPProvider::GetInstance()->GetConfig(kPID).get());
257 EXPECT_EQ(kTag, config_->child_watch_tag_);
Darin Petkov92c43902011-06-09 20:46:06 -0700258
259 ScopedTempDir temp_dir;
260 config_->root_ = temp_dir.path();
261 FilePath varrun = temp_dir.path().Append("var/run");
262 EXPECT_TRUE(file_util::CreateDirectory(varrun));
263 FilePath pid_file =
264 varrun.Append(base::StringPrintf("dhcpcd-%s.pid", kDeviceName));
265 FilePath lease_file =
266 varrun.Append(base::StringPrintf("dhcpcd-%s.lease", kDeviceName));
267 EXPECT_EQ(0, file_util::WriteFile(pid_file, "", 0));
268 EXPECT_EQ(0, file_util::WriteFile(lease_file, "", 0));
269 ASSERT_TRUE(file_util::PathExists(pid_file));
270 ASSERT_TRUE(file_util::PathExists(lease_file));
271
272 EXPECT_CALL(glib_, SpawnClosePID(kPID)).Times(1);
273 DHCPConfig::ChildWatchCallback(kPID, 0, config_.get());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700274 EXPECT_EQ(NULL, DHCPProvider::GetInstance()->GetConfig(kPID).get());
Darin Petkov92c43902011-06-09 20:46:06 -0700275 EXPECT_FALSE(file_util::PathExists(pid_file));
276 EXPECT_FALSE(file_util::PathExists(lease_file));
Darin Petkovf7897bc2011-06-08 17:13:36 -0700277}
278
Darin Petkov98dd6a02011-06-10 15:12:57 -0700279TEST_F(DHCPConfigTest, Stop) {
280 // Ensure no crashes.
281 const int kPID = 1 << 17; // Ensure unknown positive PID.
282 config_->Stop();
283 config_->pid_ = kPID;
284 config_->Stop();
285 EXPECT_CALL(glib_, SpawnClosePID(kPID)).Times(1); // Invoked by destuctor.
286}
287
Chris Masone43b48a12011-07-01 13:37:07 -0700288TEST_F(DHCPConfigTest, Dispatch) {
289 EXPECT_TRUE(DBusAdaptor::DispatchOnType(config_.get(),
290 flimflam::kMtuProperty,
291 PropertyStoreTest::kInt32V,
292 NULL));
293 ::DBus::Error error;
294 // Ensure that an attempt to write a R/O property returns InvalidArgs error.
295 EXPECT_FALSE(DBusAdaptor::DispatchOnType(config_.get(),
296 flimflam::kAddressProperty,
297 PropertyStoreTest::kStringV,
298 &error));
299 EXPECT_EQ(invalid_args_, error.name());
300}
301
Darin Petkove7cb7f82011-06-03 13:21:51 -0700302} // namespace shill