blob: da900f0b591fdd2cec436617f384252293d586d1 [file] [log] [blame]
Peter Qiu24b34a02015-06-30 10:22:26 -07001// Copyright 2015 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
5#include <stdint.h>
6
7#include <memory>
8#include <vector>
9
10#include <base/bind.h>
11#include <base/memory/ref_counted.h>
12#include <gmock/gmock.h>
13#include <gtest/gtest.h>
14
15#include "shill/chromeos_daemon.h"
16#include "shill/dhcp/mock_dhcp_provider.h"
17#include "shill/logging.h"
18#include "shill/mock_control.h"
19#include "shill/mock_manager.h"
20#include "shill/mock_metrics.h"
21#include "shill/mock_proxy_factory.h"
22#include "shill/mock_routing_table.h"
23#include "shill/net/io_handler.h"
24#include "shill/net/mock_rtnl_handler.h"
25#include "shill/net/ndisc.h"
26#include "shill/shill_test_config.h"
27
28#if !defined(DISABLE_WIFI)
29#include "shill/net/mock_netlink_manager.h"
30#include "shill/net/nl80211_message.h"
31#endif // DISABLE_WIFI
32
33using base::Bind;
34using base::Callback;
35using base::Unretained;
36using std::string;
37using std::vector;
38
39using ::testing::Expectation;
40using ::testing::Mock;
41using ::testing::Return;
42using ::testing::Test;
43using ::testing::_;
44
45namespace shill {
46
47// TODO(zqiu): extend chromeos::Daemon for initializing the message loop once
48// we remove the message loop initialization in EventDispatcher.
49class TestChromeosDaemon : public ChromeosDaemon {
50 public:
51 TestChromeosDaemon(const Settings& setttings,
52 Config* config,
53 ControlInterface* control)
54 : ChromeosDaemon(Settings(), config, control) {}
55 virtual ~TestChromeosDaemon() {}
56
57 MOCK_METHOD0(RunMessageLoop, void());
58};
59
60class ChromeosDaemonTest : public Test {
61 public:
62 ChromeosDaemonTest()
63 : daemon_(ChromeosDaemon::Settings(), &config_, new MockControl()),
64 metrics_(new MockMetrics(&daemon_.dispatcher_)),
65 manager_(new MockManager(daemon_.control_.get(),
66 &daemon_.dispatcher_,
67 metrics_,
68 &daemon_.glib_)),
69 dispatcher_(&daemon_.dispatcher_),
70 device_info_(daemon_.control_.get(), dispatcher_, metrics_,
71 daemon_.manager_.get()) {
72 }
73 virtual ~ChromeosDaemonTest() {}
74 virtual void SetUp() {
75 // Tests initialization done by the daemon's constructor
76 ASSERT_NE(nullptr, daemon_.config_);
77 ASSERT_NE(nullptr, daemon_.control_.get());
78 daemon_.proxy_factory_ = &proxy_factory_;
79 daemon_.rtnl_handler_ = &rtnl_handler_;
80 daemon_.routing_table_ = &routing_table_;
81 daemon_.dhcp_provider_ = &dhcp_provider_;
82 daemon_.metrics_.reset(metrics_); // Passes ownership
83 daemon_.manager_.reset(manager_); // Passes ownership
84
85#if !defined(DISABLE_WIFI)
86 daemon_.netlink_manager_ = &netlink_manager_;
87 const uint16_t kNl80211MessageType = 42; // Arbitrary.
88 ON_CALL(netlink_manager_, GetFamily(Nl80211Message::kMessageTypeString, _)).
89 WillByDefault(Return(kNl80211MessageType));
90#endif // DISABLE_WIFI
91 }
92 void StartDaemon() {
93 daemon_.Start();
94 }
95
96 void StopDaemon() {
97 daemon_.Stop();
98 }
99
100 // TODO(zqiu): temporary until we remove message loop initialization in
101 // EventDispatcher.
102 void RunDaemon() {
103 dispatcher_->DispatchForever();
104 }
105
106 void ApplySettings(const ChromeosDaemon::Settings& settings) {
107 daemon_.ApplySettings(settings);
108 }
109
110 MOCK_METHOD0(TerminationAction, void());
111
112 protected:
113 TestConfig config_;
114 TestChromeosDaemon daemon_;
115 MockProxyFactory proxy_factory_;
116 MockRTNLHandler rtnl_handler_;
117 MockRoutingTable routing_table_;
118 MockDHCPProvider dhcp_provider_;
119 MockMetrics* metrics_;
120 MockManager* manager_;
121#if !defined(DISABLE_WIFI)
122 MockNetlinkManager netlink_manager_;
123#endif // DISABLE_WIFI
124 EventDispatcher* dispatcher_;
125 DeviceInfo device_info_;
126};
127
128TEST_F(ChromeosDaemonTest, StartStop) {
129 // To ensure we do not have any stale routes, we flush a device's routes
130 // when it is started. This requires that the routing table is fully
131 // populated before we create and start devices. So test to make sure that
132 // the RoutingTable starts before the Manager (which in turn starts
133 // DeviceInfo who is responsible for creating and starting devices).
134 // The result is that we request the dump of the routing table and when that
135 // completes, we request the dump of the links. For each link found, we
136 // create and start the device.
137 EXPECT_CALL(*metrics_, Start());
138 EXPECT_CALL(rtnl_handler_, Start(
139 RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
140 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE | RTMGRP_ND_USEROPT));
141 Expectation routing_table_started = EXPECT_CALL(routing_table_, Start());
142 EXPECT_CALL(dhcp_provider_, Init(_, _, _, _));
143 EXPECT_CALL(*manager_, Start()).After(routing_table_started);
144 StartDaemon();
145 Mock::VerifyAndClearExpectations(metrics_);
146 Mock::VerifyAndClearExpectations(manager_);
147
148 EXPECT_CALL(*manager_, Stop());
149 EXPECT_CALL(*metrics_, Stop());
150 StopDaemon();
151}
152
153ACTION_P2(CompleteAction, manager, name) {
154 manager->TerminationActionComplete(name);
155}
156
157TEST_F(ChromeosDaemonTest, Quit) {
158 // This expectation verifies that the termination actions are invoked.
159 EXPECT_CALL(*this, TerminationAction())
160 .WillOnce(CompleteAction(manager_, "daemon test"));
161
162 manager_->AddTerminationAction("daemon test",
163 Bind(&ChromeosDaemonTest::TerminationAction,
164 Unretained(this)));
165
166 // Run Daemon::Quit() after the daemon starts running.
167 dispatcher_->PostTask(Bind(&ChromeosDaemon::Quit, Unretained(&daemon_)));
168
169 RunDaemon();
170}
171
172TEST_F(ChromeosDaemonTest, ApplySettings) {
173 ChromeosDaemon::Settings settings;
174 EXPECT_CALL(*manager_, AddDeviceToBlackList(_)).Times(0);
175 vector<string> kEmptyStringList;
176 EXPECT_CALL(*manager_, SetDHCPv6EnabledDevices(kEmptyStringList));
177 EXPECT_CALL(*manager_, SetTechnologyOrder("", _));
178 EXPECT_CALL(*manager_, SetIgnoreUnknownEthernet(false));
179 EXPECT_CALL(*manager_, SetStartupPortalList(_)).Times(0);
180 EXPECT_CALL(*manager_, SetPassiveMode()).Times(0);
181 EXPECT_CALL(*manager_, SetPrependDNSServers(""));
182 EXPECT_CALL(*manager_, SetMinimumMTU(_)).Times(0);
183 EXPECT_CALL(*manager_, SetAcceptHostnameFrom(""));
184 ApplySettings(settings);
185 Mock::VerifyAndClearExpectations(manager_);
186
187 settings.device_blacklist = {"eth0", "eth1"};
188 settings.default_technology_order = "wifi,ethernet";
189 vector<string> kDHCPv6EnabledDevices {"eth2", "eth3"};
190 settings.dhcpv6_enabled_devices = kDHCPv6EnabledDevices;
191 settings.ignore_unknown_ethernet = false;
192 settings.portal_list = "wimax";
193 settings.use_portal_list = true;
194 settings.passive_mode = true;
195 settings.prepend_dns_servers = "8.8.8.8,8.8.4.4";
196 settings.minimum_mtu = 256;
197 settings.accept_hostname_from = "eth*";
198 EXPECT_CALL(*manager_, AddDeviceToBlackList("eth0"));
199 EXPECT_CALL(*manager_, AddDeviceToBlackList("eth1"));
200 EXPECT_CALL(*manager_, SetDHCPv6EnabledDevices(kDHCPv6EnabledDevices));
201 EXPECT_CALL(*manager_, SetTechnologyOrder("wifi,ethernet", _));
202 EXPECT_CALL(*manager_, SetIgnoreUnknownEthernet(false));
203 EXPECT_CALL(*manager_, SetStartupPortalList("wimax"));
204 EXPECT_CALL(*manager_, SetPassiveMode());
205 EXPECT_CALL(*manager_, SetPrependDNSServers("8.8.8.8,8.8.4.4"));
206 EXPECT_CALL(*manager_, SetMinimumMTU(256));
207 EXPECT_CALL(*manager_, SetAcceptHostnameFrom("eth*"));
208 ApplySettings(settings);
209 Mock::VerifyAndClearExpectations(manager_);
210}
211
212} // namespace shill