| Index: chrome/browser/local_discovery/service_discovery_client_unittest.cc
|
| diff --git a/chrome/browser/local_discovery/service_discovery_client_unittest.cc b/chrome/browser/local_discovery/service_discovery_client_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a0c5e3f9f63298737f4d582689cfa1655b6bc821
|
| --- /dev/null
|
| +++ b/chrome/browser/local_discovery/service_discovery_client_unittest.cc
|
| @@ -0,0 +1,545 @@
|
| +// Copyright (c) 2013 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/weak_ptr.h"
|
| +#include "chrome/browser/local_discovery/service_discovery_client_impl.h"
|
| +#include "net/base/net_errors.h"
|
| +#include "net/dns/dns_protocol.h"
|
| +#include "net/dns/mdns_client_impl.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using ::testing::_;
|
| +using ::testing::Invoke;
|
| +using ::testing::StrictMock;
|
| +using ::testing::NiceMock;
|
| +using ::testing::Mock;
|
| +using ::testing::SaveArg;
|
| +using ::testing::SetArgPointee;
|
| +using ::testing::Return;
|
| +using ::testing::Exactly;
|
| +
|
| +namespace local_discovery {
|
| +
|
| +namespace {
|
| +
|
| +const char kSamplePacketPTR[] = {
|
| + // Header
|
| + 0x00, 0x00, // ID is zeroed out
|
| + 0x81, 0x80, // Standard query response, RA, no error
|
| + 0x00, 0x00, // No questions (for simplicity)
|
| + 0x00, 0x01, // 1 RR (answers)
|
| + 0x00, 0x00, // 0 authority RRs
|
| + 0x00, 0x00, // 0 additional RRs
|
| +
|
| + 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
|
| + 0x04, '_', 't', 'c', 'p',
|
| + 0x05, 'l', 'o', 'c', 'a', 'l',
|
| + 0x00,
|
| + 0x00, 0x0c, // TYPE is PTR.
|
| + 0x00, 0x01, // CLASS is IN.
|
| + 0x00, 0x00, // TTL (4 bytes) is 1 second.
|
| + 0x00, 0x01,
|
| + 0x00, 0x08, // RDLENGTH is 8 bytes.
|
| + 0x05, 'h', 'e', 'l', 'l', 'o',
|
| + 0xc0, 0x0c
|
| +};
|
| +
|
| +const char kSamplePacketSRV[] = {
|
| + // Header
|
| + 0x00, 0x00, // ID is zeroed out
|
| + 0x81, 0x80, // Standard query response, RA, no error
|
| + 0x00, 0x00, // No questions (for simplicity)
|
| + 0x00, 0x01, // 1 RR (answers)
|
| + 0x00, 0x00, // 0 authority RRs
|
| + 0x00, 0x00, // 0 additional RRs
|
| +
|
| + 0x05, 'h', 'e', 'l', 'l', 'o',
|
| + 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
|
| + 0x04, '_', 't', 'c', 'p',
|
| + 0x05, 'l', 'o', 'c', 'a', 'l',
|
| + 0x00,
|
| + 0x00, 0x21, // TYPE is SRV.
|
| + 0x00, 0x01, // CLASS is IN.
|
| + 0x00, 0x00, // TTL (4 bytes) is 1 second.
|
| + 0x00, 0x01,
|
| + 0x00, 0x15, // RDLENGTH is 21 bytes.
|
| + 0x00, 0x00,
|
| + 0x00, 0x00,
|
| + 0x22, 0xb8, // port 8888
|
| + 0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o',
|
| + 0x05, 'l', 'o', 'c', 'a', 'l',
|
| + 0x00,
|
| +};
|
| +
|
| +const char kSamplePacketTXT[] = {
|
| + // Header
|
| + 0x00, 0x00, // ID is zeroed out
|
| + 0x81, 0x80, // Standard query response, RA, no error
|
| + 0x00, 0x00, // No questions (for simplicity)
|
| + 0x00, 0x01, // 1 RR (answers)
|
| + 0x00, 0x00, // 0 authority RRs
|
| + 0x00, 0x00, // 0 additional RRs
|
| +
|
| + 0x05, 'h', 'e', 'l', 'l', 'o',
|
| + 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
|
| + 0x04, '_', 't', 'c', 'p',
|
| + 0x05, 'l', 'o', 'c', 'a', 'l',
|
| + 0x00,
|
| + 0x00, 0x10, // TYPE is PTR.
|
| + 0x00, 0x01, // CLASS is IN.
|
| + 0x00, 0x00, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
|
| + 0x00, 0x01,
|
| + 0x00, 0x06, // RDLENGTH is 21 bytes.
|
| + 0x05, 'h', 'e', 'l', 'l', 'o'
|
| +};
|
| +
|
| +class MockSocketFactory : public net::DatagramServerSocket {
|
| + public:
|
| + int Listen(const net::IPEndPoint& address) {
|
| + return ListenInternal(address.ToString());
|
| + }
|
| +
|
| + MOCK_METHOD1(ListenInternal, int(const std::string& address));
|
| +
|
| + MOCK_METHOD4(RecvFrom, int(net::IOBuffer* buffer, int size,
|
| + net::IPEndPoint* address,
|
| + const net::CompletionCallback& callback));
|
| +
|
| + int SendTo(net::IOBuffer* buf, int buf_len, const net::IPEndPoint& address,
|
| + const net::CompletionCallback& callback) {
|
| + return SendToInternal(std::string(buf->data(), buf_len), address.ToString(),
|
| + callback);
|
| + }
|
| +
|
| + MOCK_METHOD3(SendToInternal, int(const std::string& packet,
|
| + const std::string address,
|
| + const net::CompletionCallback& callback));
|
| +
|
| + MOCK_METHOD1(SetReceiveBufferSize, bool(int32 size));
|
| + MOCK_METHOD1(SetSendBufferSize, bool(int32 size));
|
| +
|
| + MOCK_METHOD0(Close, void());
|
| +
|
| + MOCK_CONST_METHOD1(GetPeerAddress, int(net::IPEndPoint* address));
|
| + MOCK_CONST_METHOD1(GetLocalAddress, int(net::IPEndPoint* address));
|
| + MOCK_CONST_METHOD0(NetLog, const net::BoundNetLog&());
|
| +
|
| + MOCK_METHOD0(AllowAddressReuse, void());
|
| + MOCK_METHOD0(AllowBroadcast, void());
|
| +
|
| + int JoinGroup(const net::IPAddressNumber& group_address) const {
|
| + return JoinGroupInternal(net::IPAddressToString(group_address));
|
| + }
|
| +
|
| + MOCK_CONST_METHOD1(JoinGroupInternal, int(const std::string& group));
|
| +
|
| + int LeaveGroup(const net::IPAddressNumber& group_address) const {
|
| + return LeaveGroupInternal(net::IPAddressToString(group_address));
|
| + }
|
| +
|
| + MOCK_CONST_METHOD1(LeaveGroupInternal, int(const std::string& group));
|
| +
|
| + MOCK_METHOD1(SetMulticastTimeToLive, int(int ttl));
|
| +
|
| + MOCK_METHOD1(SetMulticastLoopbackMode, int(bool loopback));
|
| +};
|
| +
|
| +class MockSocketFactoryFactory
|
| + : public net::MDnsConnection::SocketFactory {
|
| + public:
|
| + MockSocketFactoryFactory() {
|
| + }
|
| +
|
| + virtual ~MockSocketFactoryFactory() {
|
| + }
|
| +
|
| + virtual scoped_ptr<net::DatagramServerSocket> CreateSocket() OVERRIDE {
|
| + scoped_ptr<MockSocketFactory> new_socket(
|
| + new NiceMock<MockSocketFactory>);
|
| +
|
| + ON_CALL(*new_socket, SendToInternal(_, _, _))
|
| + .WillByDefault(Invoke(
|
| + this,
|
| + &MockSocketFactoryFactory::SendToInternal));
|
| +
|
| + ON_CALL(*new_socket, RecvFrom(_, _, _, _))
|
| + .WillByDefault(Invoke(
|
| + this,
|
| + &MockSocketFactoryFactory::RecvFromInternal));
|
| +
|
| + return new_socket.PassAs<net::DatagramServerSocket>();
|
| + }
|
| +
|
| + int SendToInternal(const std::string& packet, const std::string& address,
|
| + const net::CompletionCallback& callback) {
|
| + OnSendTo(packet);
|
| + return packet.size();
|
| + }
|
| +
|
| + // The latest recieve callback is always saved, since the net::MDnsConnection
|
| + // does not care which socket a packet is received on.
|
| + int RecvFromInternal(net::IOBuffer* buffer, int size,
|
| + net::IPEndPoint* address,
|
| + const net::CompletionCallback& callback) {
|
| + recv_buffer_ = buffer;
|
| + recv_buffer_size_ = size;
|
| + recv_callback_ = callback;
|
| + return net::ERR_IO_PENDING;
|
| + }
|
| +
|
| + void SimulateReceive(const char* packet, int size) {
|
| + DCHECK(recv_buffer_size_ >= size);
|
| + DCHECK(recv_buffer_.get());
|
| + DCHECK(!recv_callback_.is_null());
|
| +
|
| + memcpy(recv_buffer_->data(), packet, size);
|
| + net::CompletionCallback recv_callback = recv_callback_;
|
| + recv_callback_.Reset();
|
| + recv_callback.Run(size);
|
| + }
|
| +
|
| + MOCK_METHOD1(OnSendTo, void(const std::string&));
|
| +
|
| + private:
|
| + scoped_refptr<net::IOBuffer> recv_buffer_;
|
| + int recv_buffer_size_;
|
| + net::CompletionCallback recv_callback_;
|
| +};
|
| +
|
| +class MockServiceTypeWatcherDelegate : public ServiceTypeWatcher::Delegate {
|
| + public:
|
| + MockServiceTypeWatcherDelegate() {}
|
| + virtual ~MockServiceTypeWatcherDelegate() {}
|
| +
|
| + MOCK_METHOD2(OnServiceStatusChanged, void(bool, const std::string&));
|
| +};
|
| +
|
| +class ServiceDiscoveryTest : public ::testing::Test {
|
| + public:
|
| + ServiceDiscoveryTest() : socket_factory_(new MockSocketFactoryFactory),
|
| + mdns_client_(
|
| + scoped_ptr<net::MDnsConnection::SocketFactory>(
|
| + socket_factory_)) {
|
| + net::MDnsClient::SetInstance(&mdns_client_);
|
| + }
|
| +
|
| + virtual ~ServiceDiscoveryTest() {
|
| + net::MDnsClient::SetInstance(NULL);
|
| + }
|
| +
|
| + protected:
|
| + void RunFor(base::TimeDelta time_period) {
|
| + base::CancelableCallback<void()> callback(base::Bind(
|
| + &ServiceDiscoveryTest::Stop, base::Unretained(this)));
|
| + base::MessageLoop::current()->PostDelayedTask(
|
| + FROM_HERE, callback.callback(), time_period);
|
| +
|
| + base::MessageLoop::current()->Run();
|
| + callback.Cancel();
|
| + }
|
| +
|
| + void Stop() {
|
| + base::MessageLoop::current()->Quit();
|
| + }
|
| +
|
| + MockSocketFactoryFactory* socket_factory_;
|
| + net::MDnsClientImpl mdns_client_;
|
| + ServiceDiscoveryClientImpl service_discovery_client_;
|
| + base::MessageLoop loop_;
|
| +};
|
| +
|
| +TEST_F(ServiceDiscoveryTest, AddRemoveService) {
|
| + scoped_ptr<ServiceTypeWatcher> watcher;
|
| + StrictMock<MockServiceTypeWatcherDelegate> delegate;
|
| +
|
| + watcher = service_discovery_client_.CreateServiceTypeWatcher(
|
| + "_privet._tcp.local", true, false, &delegate);
|
| +
|
| + EXPECT_CALL(*socket_factory_, OnSendTo(_))
|
| + .Times(2);
|
| +
|
| + watcher->Start();
|
| +
|
| + EXPECT_CALL(delegate,
|
| + OnServiceStatusChanged(true, "hello._privet._tcp.local"))
|
| + .Times(Exactly(1));
|
| +
|
| + socket_factory_->SimulateReceive(
|
| + kSamplePacketPTR, sizeof(kSamplePacketPTR));
|
| +
|
| + EXPECT_CALL(delegate,
|
| + OnServiceStatusChanged(false, "hello._privet._tcp.local"))
|
| + .Times(Exactly(1));
|
| +
|
| + RunFor(base::TimeDelta::FromSeconds(2));
|
| +};
|
| +
|
| +TEST_F(ServiceDiscoveryTest, DiscoverNewServices) {
|
| + scoped_ptr<ServiceTypeWatcher> watcher;
|
| + StrictMock<MockServiceTypeWatcherDelegate> delegate;
|
| +
|
| + watcher = service_discovery_client_.CreateServiceTypeWatcher(
|
| + "_privet._tcp.local", false, false, &delegate);
|
| +
|
| + watcher->Start();
|
| +
|
| + EXPECT_CALL(*socket_factory_, OnSendTo(_))
|
| + .Times(2);
|
| +
|
| + watcher->DiscoverNewServices();
|
| +};
|
| +
|
| +TEST_F(ServiceDiscoveryTest, GetAvailableServices) {
|
| + NiceMock<MockServiceTypeWatcherDelegate> delegate;
|
| +
|
| + std::vector<std::string> data_expected;
|
| + std::vector<std::string> data;
|
| +
|
| + data_expected.push_back("hello._privet._tcp.local");
|
| +
|
| + scoped_ptr<ServiceTypeWatcher> watcher =
|
| + service_discovery_client_.CreateServiceTypeWatcher(
|
| + "_privet._tcp.local", false, false, &delegate);
|
| +
|
| + watcher->Start();
|
| +
|
| + socket_factory_->SimulateReceive(
|
| + kSamplePacketPTR, sizeof(kSamplePacketPTR));
|
| +
|
| + watcher->GetAvailableServices(&data);
|
| +
|
| + EXPECT_EQ(data, data_expected);
|
| +};
|
| +
|
| +class MockServiceReaderDelegate
|
| + : public ServiceReader::Delegate {
|
| + public:
|
| + MockServiceReaderDelegate() {}
|
| + virtual ~MockServiceReaderDelegate() {}
|
| +
|
| + virtual void OnAddressChanged(
|
| + const std::string& service_name,
|
| + const net::HostPortPair& address) OVERRIDE {
|
| + OnAddressChangedInternal(service_name, address.ToString());
|
| + }
|
| +
|
| + MOCK_METHOD2(OnAddressChangedInternal, void(const std::string& service_name,
|
| + const std::string& address));
|
| + MOCK_METHOD2(OnMetadataChanged,
|
| + void(const std::string& service_name,
|
| + const std::vector<std::string>& metadata));
|
| +};
|
| +
|
| +class ServiceReaderTest : public ServiceDiscoveryTest {
|
| + public:
|
| + ServiceReaderTest() {
|
| + metadata_expected_.push_back("hello");
|
| + address_expected_ = net::HostPortPair("myhello.local", 8888);
|
| + }
|
| +
|
| + ~ServiceReaderTest() {
|
| + }
|
| +
|
| + void SetUp() {
|
| + reader_ = service_discovery_client_.CreateServiceReader(
|
| + "hello._privet._tcp.local", &delegate_);
|
| +
|
| + EXPECT_CALL(*socket_factory_, OnSendTo(_))
|
| + .Times(4); // Two queries.
|
| +
|
| + reader_->Start();
|
| +
|
| + Mock::VerifyAndClear(&socket_factory_);
|
| + }
|
| +
|
| + void OnReceiveAddress(ServiceReader::RequestStatus status,
|
| + const net::HostPortPair& address) {
|
| + OnReceiveAddressInternal(status, address.ToString());
|
| + }
|
| +
|
| + MOCK_METHOD2(OnReceiveAddressInternal, void(ServiceReader::RequestStatus,
|
| + const std::string&));
|
| + MOCK_METHOD2(OnReceiveMetadata,
|
| + void(ServiceReader::RequestStatus,
|
| + const std::vector<std::string>&));
|
| + MOCK_METHOD1(OnReceiveTime, void(base::Time));
|
| +
|
| + protected:
|
| + StrictMock<MockServiceReaderDelegate> delegate_;
|
| + scoped_ptr<ServiceReader> reader_;
|
| + net::HostPortPair address_expected_;
|
| + std::vector<std::string> metadata_expected_;
|
| + net::HostPortPair address_recieved_;
|
| + std::vector<std::string> metadata_recieved_;
|
| +};
|
| +
|
| +TEST_F(ServiceReaderTest, ServiceWatcherUpdateDelegate) {
|
| + EXPECT_CALL(delegate_,
|
| + OnMetadataChanged("hello._privet._tcp.local",
|
| + metadata_expected_));
|
| +
|
| + socket_factory_->SimulateReceive(
|
| + kSamplePacketTXT, sizeof(kSamplePacketTXT));
|
| +
|
| + Mock::VerifyAndClear(&delegate_);
|
| +
|
| + EXPECT_CALL(delegate_,
|
| + OnAddressChangedInternal("hello._privet._tcp.local",
|
| + address_expected_.ToString()));
|
| +
|
| + socket_factory_->SimulateReceive(
|
| + kSamplePacketSRV, sizeof(kSamplePacketSRV));
|
| +
|
| + Mock::VerifyAndClear(&delegate_);
|
| +
|
| + EXPECT_TRUE(reader_->GetAddress(&address_recieved_));
|
| +
|
| + EXPECT_TRUE(address_expected_.Equals(address_recieved_));
|
| +
|
| + EXPECT_TRUE(reader_->GetMetadata(&metadata_recieved_));
|
| +
|
| + EXPECT_EQ(metadata_expected_, metadata_recieved_);
|
| +};
|
| +
|
| +TEST_F(ServiceReaderTest, NoData) {
|
| + Mock::VerifyAndClear(&socket_factory_);
|
| +
|
| + EXPECT_FALSE(reader_->GetAddress(&address_recieved_));
|
| + EXPECT_FALSE(reader_->GetMetadata(&metadata_recieved_));
|
| +}
|
| +
|
| +TEST_F(ServiceReaderTest, ServiceWatcherReadWithCallback) {
|
| + EXPECT_CALL(delegate_,
|
| + OnMetadataChanged("hello._privet._tcp.local",
|
| + metadata_expected_));
|
| + EXPECT_CALL(delegate_,
|
| + OnAddressChangedInternal("hello._privet._tcp.local",
|
| + address_expected_.ToString()));
|
| +
|
| + // Test that double calls to ReadAddress/Metadata get double responses.
|
| + reader_->ReadAddress(base::Bind(&ServiceReaderTest::OnReceiveAddress,
|
| + base::Unretained(this)), false);
|
| + reader_->ReadAddress(base::Bind(&ServiceReaderTest::OnReceiveAddress,
|
| + base::Unretained(this)), false);
|
| + reader_->ReadMetadata(base::Bind(&ServiceReaderTest::OnReceiveMetadata,
|
| + base::Unretained(this)), false);
|
| + reader_->ReadMetadata(base::Bind(&ServiceReaderTest::OnReceiveMetadata,
|
| + base::Unretained(this)), false);
|
| +
|
| + Mock::VerifyAndClear(socket_factory_);
|
| +
|
| + EXPECT_CALL(*this, OnReceiveAddressInternal(ServiceReader::STATUS_SUCCESS,
|
| + address_expected_.ToString()))
|
| + .Times(Exactly(2));
|
| +
|
| + EXPECT_CALL(*this, OnReceiveMetadata(ServiceReader::STATUS_SUCCESS,
|
| + metadata_expected_))
|
| + .Times(Exactly(2));
|
| +
|
| + socket_factory_->SimulateReceive(
|
| + kSamplePacketSRV, sizeof(kSamplePacketSRV));
|
| +
|
| + socket_factory_->SimulateReceive(
|
| + kSamplePacketTXT, sizeof(kSamplePacketTXT));
|
| +
|
| + Mock::VerifyAndClear(this);
|
| +
|
| + // Test that a successful read doesn't clobber read-ability, and reads from
|
| + // from cache.
|
| + EXPECT_CALL(*this, OnReceiveAddressInternal(ServiceReader::STATUS_SUCCESS,
|
| + address_expected_.ToString()))
|
| + .Times(Exactly(1));
|
| +
|
| + EXPECT_CALL(*this, OnReceiveMetadata(ServiceReader::STATUS_SUCCESS,
|
| + metadata_expected_))
|
| + .Times(Exactly(1));
|
| +
|
| + reader_->ReadAddress(base::Bind(&ServiceReaderTest::OnReceiveAddress,
|
| + base::Unretained(this)), false);
|
| + reader_->ReadMetadata(base::Bind(&ServiceReaderTest::OnReceiveMetadata,
|
| + base::Unretained(this)), false);
|
| +};
|
| +
|
| +TEST_F(ServiceReaderTest, ServiceWatcherReadWithTimeout) {
|
| + reader_->ReadAddress(base::Bind(&ServiceReaderTest::OnReceiveAddress,
|
| + base::Unretained(this)), false);
|
| + reader_->ReadMetadata(base::Bind(&ServiceReaderTest::OnReceiveMetadata,
|
| + base::Unretained(this)), false);
|
| +
|
| + EXPECT_CALL(*this, OnReceiveAddressInternal(ServiceReader::STATUS_TIMEOUT, _))
|
| + .Times(Exactly(1));
|
| +
|
| + EXPECT_CALL(*this, OnReceiveMetadata(ServiceReader::STATUS_TIMEOUT, _))
|
| + .Times(Exactly(1));
|
| +
|
| + RunFor(base::TimeDelta::FromSeconds(4));
|
| +};
|
| +
|
| +TEST_F(ServiceReaderTest, ServiceWatcherExpiration) {
|
| + EXPECT_CALL(delegate_,
|
| + OnMetadataChanged("hello._privet._tcp.local",
|
| + metadata_expected_));
|
| + EXPECT_CALL(delegate_,
|
| + OnAddressChangedInternal("hello._privet._tcp.local",
|
| + address_expected_.ToString()));
|
| +
|
| + socket_factory_->SimulateReceive(
|
| + kSamplePacketSRV, sizeof(kSamplePacketSRV));
|
| +
|
| + socket_factory_->SimulateReceive(
|
| + kSamplePacketTXT, sizeof(kSamplePacketTXT));
|
| +
|
| + EXPECT_TRUE(reader_->GetAddress(&address_recieved_));
|
| + EXPECT_TRUE(reader_->GetMetadata(&metadata_recieved_));
|
| +
|
| + EXPECT_CALL(delegate_,
|
| + OnMetadataChanged("hello._privet._tcp.local",
|
| + std::vector<std::string>() ));
|
| + EXPECT_CALL(delegate_,
|
| + OnAddressChangedInternal("hello._privet._tcp.local",
|
| + net::HostPortPair().ToString()));
|
| +
|
| + RunFor(base::TimeDelta::FromSeconds(2));
|
| +
|
| + EXPECT_FALSE(reader_->GetAddress(&address_recieved_));
|
| + EXPECT_FALSE(reader_->GetMetadata(&metadata_recieved_));
|
| +};
|
| +
|
| +TEST_F(ServiceReaderTest, Names) {
|
| + EXPECT_EQ("hello", reader_->GetHumanReadableName());
|
| + EXPECT_EQ("_privet._tcp.local", reader_->GetType());
|
| +
|
| + reader_ = service_discovery_client_.CreateServiceReader(
|
| + "hello", &delegate_);
|
| + EXPECT_EQ("hello", reader_->GetHumanReadableName());
|
| + EXPECT_EQ("", reader_->GetType());
|
| +}
|
| +
|
| +TEST_F(ServiceReaderTest, LastSeen) {
|
| + base::Time time_last_seen;
|
| + EXPECT_CALL(*this, OnReceiveTime(base::Time()));
|
| + reader_->ReadLastSeen(base::Bind(&ServiceReaderTest::OnReceiveTime,
|
| + base::Unretained(this)));
|
| + EXPECT_CALL(delegate_,
|
| + OnAddressChangedInternal("hello._privet._tcp.local",
|
| + address_expected_.ToString()));
|
| +
|
| + socket_factory_->SimulateReceive(
|
| + kSamplePacketSRV, sizeof(kSamplePacketSRV));
|
| +
|
| + EXPECT_CALL(*this, OnReceiveTime(_))
|
| + .WillOnce(SaveArg<0>(&time_last_seen));
|
| +
|
| + reader_->ReadLastSeen(base::Bind(&ServiceReaderTest::OnReceiveTime,
|
| + base::Unretained(this)));
|
| +
|
| + base::TimeDelta timediff = base::Time::Now() - time_last_seen;
|
| + if (timediff < base::TimeDelta()) timediff = -timediff;
|
| + EXPECT_TRUE(timediff < base::TimeDelta::FromSeconds(5));
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +} // namespace local_discovery
|
|
|