1 // Copyright (c) 2012 The Chromium 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 "base/memory/ref_counted.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/message_loop/message_loop.h"
8 #include "chrome/browser/extensions/api/dial/dial_device_data.h"
9 #include "chrome/browser/extensions/api/dial/dial_service.h"
10 #include "net/base/capturing_net_log.h"
11 #include "net/base/ip_endpoint.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 using base::Time;
16 using base::TimeDelta;
17 using ::testing::A;
18 using ::testing::AtLeast;
19 using ::testing::Return;
20
21 namespace {
22
23 const char kValidResponse[] =
24 "HTTP/1.1 OK\r\n"
25 "LOCATION: http://127.0.0.1/dd.xml\r\n"
26 "USN: some_id\r\n"
27 "CACHE-CONTROL: max-age=1800\r\n"
28 "CONFIGID.UPNP.ORG: 1\r\n\r\n";
29
30 } // namespace
31
32 namespace extensions {
33
34 class MockObserver : public DialService::Observer {
35 public:
36 MOCK_METHOD1(OnDiscoveryRequest, void(DialService*));
37 MOCK_METHOD2(OnDeviceDiscovered, void(DialService*, const DialDeviceData&));
38 MOCK_METHOD1(OnDiscoveryFinished, void(DialService*));
39 MOCK_METHOD2(OnError, void(DialService*,
40 const DialService::DialServiceErrorCode&));
41 };
42
43 class DialServiceTest : public testing::Test {
44 public:
DialServiceTest()45 DialServiceTest()
46 : dial_service_(&capturing_net_log_) {
47 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &mock_ip_));
48 dial_service_.AddObserver(&mock_observer_);
49 dial_socket_ = dial_service_.CreateDialSocket();
50 }
51 protected:
52 net::CapturingNetLog capturing_net_log_;
53 net::IPAddressNumber mock_ip_;
54 DialServiceImpl dial_service_;
55 scoped_ptr<DialServiceImpl::DialSocket> dial_socket_;
56 MockObserver mock_observer_;
57 };
58
TEST_F(DialServiceTest,TestSendMultipleRequests)59 TEST_F(DialServiceTest, TestSendMultipleRequests) {
60 base::MessageLoopForIO loop;
61 // Setting the finish delay to zero disables the timer that invokes
62 // FinishDiscovery().
63 dial_service_.finish_delay_ = TimeDelta::FromSeconds(0);
64 dial_service_.request_interval_ = TimeDelta::FromSeconds(0);
65 dial_service_.max_requests_ = 4;
66 dial_service_.discovery_active_ = true;
67 EXPECT_CALL(mock_observer_, OnDiscoveryRequest(A<DialService*>())).Times(4);
68 EXPECT_CALL(mock_observer_, OnDiscoveryFinished(A<DialService*>())).Times(1);
69 dial_service_.BindAndAddSocket(mock_ip_);
70 EXPECT_EQ(1u, dial_service_.dial_sockets_.size());
71 dial_service_.SendOneRequest();
72 loop.RunUntilIdle();
73 dial_service_.FinishDiscovery();
74 }
75
TEST_F(DialServiceTest,TestMultipleNetworkInterfaces)76 TEST_F(DialServiceTest, TestMultipleNetworkInterfaces) {
77 base::MessageLoopForIO loop;
78 // Setting the finish delay to zero disables the timer that invokes
79 // FinishDiscovery().
80 dial_service_.finish_delay_ = TimeDelta::FromSeconds(0);
81 dial_service_.request_interval_ = TimeDelta::FromSeconds(0);
82 dial_service_.max_requests_ = 4;
83 dial_service_.discovery_active_ = true;
84 net::NetworkInterfaceList interface_list;
85 interface_list.push_back(
86 net::NetworkInterface("network1",
87 "network1",
88 0,
89 net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
90 mock_ip_,
91 0,
92 net::IP_ADDRESS_ATTRIBUTE_NONE));
93 interface_list.push_back(
94 net::NetworkInterface("network2",
95 "network2",
96 1,
97 net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
98 mock_ip_,
99 0,
100 net::IP_ADDRESS_ATTRIBUTE_NONE));
101 interface_list.push_back(
102 net::NetworkInterface("network3",
103 "network3",
104 2,
105 net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
106 mock_ip_,
107 0,
108 net::IP_ADDRESS_ATTRIBUTE_NONE));
109
110 // "network4" is equivalent to "network2" because both the address family
111 // and interface index are the same.
112 interface_list.push_back(
113 net::NetworkInterface("network4",
114 "network4",
115 1,
116 net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
117 mock_ip_,
118 0,
119 net::IP_ADDRESS_ATTRIBUTE_NONE));
120
121 // 3 sockets * 4 requests per socket = 12 requests
122 EXPECT_CALL(mock_observer_, OnDiscoveryRequest(A<DialService*>())).Times(12);
123 EXPECT_CALL(mock_observer_, OnDiscoveryFinished(A<DialService*>())).Times(1);
124
125 dial_service_.SendNetworkList(interface_list);
126 EXPECT_EQ(3u, dial_service_.dial_sockets_.size());
127
128 loop.RunUntilIdle();
129 dial_service_.FinishDiscovery();
130 }
131
TEST_F(DialServiceTest,TestOnDiscoveryRequest)132 TEST_F(DialServiceTest, TestOnDiscoveryRequest) {
133 dial_service_.discovery_active_ = true;
134 dial_service_.num_requests_sent_ = 1;
135 dial_service_.max_requests_ = 1;
136 size_t num_bytes = dial_service_.send_buffer_->size();
137 EXPECT_CALL(mock_observer_, OnDiscoveryRequest(A<DialService*>())).Times(1);
138 dial_socket_->OnSocketWrite(num_bytes, num_bytes);
139 }
140
TEST_F(DialServiceTest,TestOnDeviceDiscovered)141 TEST_F(DialServiceTest, TestOnDeviceDiscovered) {
142 dial_service_.discovery_active_ = true;
143 int response_size = arraysize(kValidResponse) - 1;
144 dial_socket_->recv_buffer_ =
145 new net::IOBufferWithSize(response_size);
146 strncpy(dial_socket_->recv_buffer_->data(),
147 kValidResponse,
148 response_size);
149 dial_socket_->recv_address_ = net::IPEndPoint(mock_ip_, 12345);
150
151 DialDeviceData expected_device;
152 expected_device.set_device_id("some_id");
153
154 EXPECT_CALL(mock_observer_,
155 OnDeviceDiscovered(A<DialService*>(), expected_device))
156 .Times(1);
157 dial_socket_->OnSocketRead(response_size);
158 };
159
TEST_F(DialServiceTest,TestOnDiscoveryFinished)160 TEST_F(DialServiceTest, TestOnDiscoveryFinished) {
161 dial_service_.discovery_active_ = true;
162
163 EXPECT_CALL(mock_observer_, OnDiscoveryFinished(A<DialService*>())).Times(1);
164 dial_service_.FinishDiscovery();
165 EXPECT_FALSE(dial_service_.discovery_active_);
166 }
167
TEST_F(DialServiceTest,TestResponseParsing)168 TEST_F(DialServiceTest, TestResponseParsing) {
169 Time now = Time::Now();
170
171 // Successful case
172 DialDeviceData parsed;
173 EXPECT_TRUE(DialServiceImpl::DialSocket::ParseResponse(
174 kValidResponse, now, &parsed));
175 EXPECT_EQ("some_id", parsed.device_id());
176 EXPECT_EQ("http://127.0.0.1/dd.xml", parsed.device_description_url().spec());
177 EXPECT_EQ(1, parsed.config_id());
178 EXPECT_EQ(now, parsed.response_time());
179
180 // Failure cases
181 DialDeviceData not_parsed;
182
183 // Empty, garbage
184 EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse(
185 std::string(), now, ¬_parsed));
186 EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse(
187 "\r\n\r\n",
188 now, ¬_parsed));
189 EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse(
190 "xyzzy",
191 now, ¬_parsed));
192
193 // No headers
194 EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse(
195 "HTTP/1.1 OK\r\n\r\n",
196 now, ¬_parsed));
197
198 // Missing LOCATION
199 EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse(
200 "HTTP/1.1 OK\r\n"
201 "USN: some_id\r\n\r\n",
202 now, ¬_parsed));
203
204 // Empty LOCATION
205 EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse(
206 "HTTP/1.1 OK\r\n"
207 "LOCATION:\r\n"
208 "USN: some_id\r\n\r\n",
209 now, ¬_parsed));
210
211 // Missing USN
212 EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse(
213 "HTTP/1.1 OK\r\n"
214 "LOCATION: http://127.0.0.1/dd.xml\r\n\r\n",
215 now, ¬_parsed));
216
217 // Empty USN
218 EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse(
219 "HTTP/1.1 OK\r\n"
220 "LOCATION: http://127.0.0.1/dd.xml\r\n"
221 "USN:\r\n\r\n",
222 now, ¬_parsed));
223 }
224
225 } // namespace extensions
226