| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/message_loop/message_loop.h" |
| #include "chrome/browser/extensions/api/dial/dial_device_data.h" |
| #include "chrome/browser/extensions/api/dial/dial_service.h" |
| #include "net/base/capturing_net_log.h" |
| #include "net/base/ip_endpoint.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using base::Time; |
| using base::TimeDelta; |
| using ::testing::A; |
| using ::testing::AtLeast; |
| using ::testing::Return; |
| |
| namespace { |
| |
| const char kValidResponse[] = |
| "HTTP/1.1 OK\r\n" |
| "LOCATION: http://127.0.0.1/dd.xml\r\n" |
| "USN: some_id\r\n" |
| "CACHE-CONTROL: max-age=1800\r\n" |
| "CONFIGID.UPNP.ORG: 1\r\n\r\n"; |
| |
| } // namespace |
| |
| namespace extensions { |
| |
| class MockObserver : public DialService::Observer { |
| public: |
| MOCK_METHOD1(OnDiscoveryRequest, void(DialService*)); |
| MOCK_METHOD2(OnDeviceDiscovered, void(DialService*, const DialDeviceData&)); |
| MOCK_METHOD1(OnDiscoveryFinished, void(DialService*)); |
| MOCK_METHOD2(OnError, void(DialService*, |
| const DialService::DialServiceErrorCode&)); |
| }; |
| |
| class DialServiceTest : public testing::Test { |
| public: |
| DialServiceTest() |
| : dial_service_(&capturing_net_log_) { |
| CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &mock_ip_)); |
| dial_service_.AddObserver(&mock_observer_); |
| dial_socket_ = dial_service_.CreateDialSocket(); |
| } |
| protected: |
| net::CapturingNetLog capturing_net_log_; |
| net::IPAddressNumber mock_ip_; |
| DialServiceImpl dial_service_; |
| scoped_ptr<DialServiceImpl::DialSocket> dial_socket_; |
| MockObserver mock_observer_; |
| }; |
| |
| TEST_F(DialServiceTest, TestSendMultipleRequests) { |
| base::MessageLoop loop(base::MessageLoop::TYPE_IO); |
| // Setting the finish delay to zero disables the timer that invokes |
| // FinishDiscovery(). |
| dial_service_.finish_delay_ = TimeDelta::FromSeconds(0); |
| dial_service_.request_interval_ = TimeDelta::FromSeconds(0); |
| dial_service_.max_requests_ = 4; |
| dial_service_.discovery_active_ = true; |
| EXPECT_CALL(mock_observer_, OnDiscoveryRequest(A<DialService*>())).Times(4); |
| EXPECT_CALL(mock_observer_, OnDiscoveryFinished(A<DialService*>())).Times(1); |
| dial_service_.BindAndAddSocket(mock_ip_); |
| dial_service_.SendOneRequest(); |
| loop.RunUntilIdle(); |
| dial_service_.FinishDiscovery(); |
| } |
| |
| TEST_F(DialServiceTest, TestOnDiscoveryRequest) { |
| dial_service_.discovery_active_ = true; |
| dial_service_.num_requests_sent_ = 1; |
| dial_service_.max_requests_ = 1; |
| size_t num_bytes = dial_service_.send_buffer_->size(); |
| EXPECT_CALL(mock_observer_, OnDiscoveryRequest(A<DialService*>())).Times(1); |
| dial_socket_->OnSocketWrite(num_bytes, num_bytes); |
| } |
| |
| TEST_F(DialServiceTest, TestOnDeviceDiscovered) { |
| dial_service_.discovery_active_ = true; |
| int response_size = arraysize(kValidResponse) - 1; |
| dial_socket_->recv_buffer_ = |
| new net::IOBufferWithSize(response_size); |
| strncpy(dial_socket_->recv_buffer_->data(), |
| kValidResponse, |
| response_size); |
| dial_socket_->recv_address_ = net::IPEndPoint(mock_ip_, 12345); |
| |
| DialDeviceData expected_device; |
| expected_device.set_device_id("some_id"); |
| |
| EXPECT_CALL(mock_observer_, |
| OnDeviceDiscovered(A<DialService*>(), expected_device)) |
| .Times(1); |
| dial_socket_->OnSocketRead(response_size); |
| }; |
| |
| TEST_F(DialServiceTest, TestOnDiscoveryFinished) { |
| dial_service_.discovery_active_ = true; |
| |
| EXPECT_CALL(mock_observer_, OnDiscoveryFinished(A<DialService*>())).Times(1); |
| dial_service_.FinishDiscovery(); |
| EXPECT_FALSE(dial_service_.discovery_active_); |
| } |
| |
| TEST_F(DialServiceTest, TestResponseParsing) { |
| Time now = Time::Now(); |
| |
| // Successful case |
| DialDeviceData parsed; |
| EXPECT_TRUE(DialServiceImpl::DialSocket::ParseResponse( |
| kValidResponse, now, &parsed)); |
| EXPECT_EQ("some_id", parsed.device_id()); |
| EXPECT_EQ("http://127.0.0.1/dd.xml", parsed.device_description_url().spec()); |
| EXPECT_EQ(1, parsed.config_id()); |
| EXPECT_EQ(now, parsed.response_time()); |
| |
| // Failure cases |
| DialDeviceData not_parsed; |
| |
| // Empty, garbage |
| EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse( |
| std::string(), now, ¬_parsed)); |
| EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse( |
| "\r\n\r\n", |
| now, ¬_parsed)); |
| EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse( |
| "xyzzy", |
| now, ¬_parsed)); |
| |
| // No headers |
| EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse( |
| "HTTP/1.1 OK\r\n\r\n", |
| now, ¬_parsed)); |
| |
| // Missing LOCATION |
| EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse( |
| "HTTP/1.1 OK\r\n" |
| "USN: some_id\r\n\r\n", |
| now, ¬_parsed)); |
| |
| // Empty LOCATION |
| EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse( |
| "HTTP/1.1 OK\r\n" |
| "LOCATION:\r\n" |
| "USN: some_id\r\n\r\n", |
| now, ¬_parsed)); |
| |
| // Missing USN |
| EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse( |
| "HTTP/1.1 OK\r\n" |
| "LOCATION: http://127.0.0.1/dd.xml\r\n\r\n", |
| now, ¬_parsed)); |
| |
| // Empty USN |
| EXPECT_FALSE(DialServiceImpl::DialSocket::ParseResponse( |
| "HTTP/1.1 OK\r\n" |
| "LOCATION: http://127.0.0.1/dd.xml\r\n" |
| "USN:\r\n\r\n", |
| now, ¬_parsed)); |
| } |
| |
| } // namespace extensions |