blob: 6f6bb3d870e62c6e723b364854e5ee2333d61a81 [file] [log] [blame]
// Copyright 2019 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 "platform/impl/udp_socket_reader_posix.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "platform/api/time.h"
#include "platform/impl/socket_handle_posix.h"
#include "platform/impl/udp_socket_posix.h"
#include "platform/test/fake_clock.h"
#include "platform/test/fake_task_runner.h"
#include "platform/test/fake_udp_socket.h"
namespace openscreen {
namespace {
using namespace ::testing;
using ::testing::_;
using ::testing::Invoke;
class MockUdpSocketPosix : public UdpSocketPosix {
public:
explicit MockUdpSocketPosix(TaskRunner* task_runner,
Client* client,
int fd,
Version version = Version::kV4)
: UdpSocketPosix(task_runner, client, SocketHandle(fd), IPEndpoint()),
version_(version) {}
~MockUdpSocketPosix() override = default;
bool IsIPv4() const override { return version_ == UdpSocket::Version::kV4; }
bool IsIPv6() const override { return version_ == UdpSocket::Version::kV6; }
MOCK_METHOD0(Bind, void());
MOCK_METHOD1(SetMulticastOutboundInterface, void(NetworkInterfaceIndex));
MOCK_METHOD2(JoinMulticastGroup,
void(const IPAddress&, NetworkInterfaceIndex));
MOCK_METHOD3(SendMessage, void(const void*, size_t, const IPEndpoint&));
MOCK_METHOD1(SetDscp, void(DscpMode));
private:
Version version_;
};
// Mock event waiter
class MockNetworkWaiter final : public SocketHandleWaiter {
public:
using ReadyHandle = SocketHandleWaiter::ReadyHandle;
MockNetworkWaiter() : SocketHandleWaiter(&FakeClock::now) {}
~MockNetworkWaiter() override = default;
MOCK_METHOD2(
AwaitSocketsReadable,
ErrorOr<std::vector<ReadyHandle>>(const std::vector<SocketHandleRef>&,
const Clock::duration&));
FakeClock fake_clock{Clock::time_point{Clock::duration{1234567}}};
};
// Mock Task Runner
class MockTaskRunner final : public TaskRunner {
public:
MockTaskRunner() {
tasks_posted = 0;
delayed_tasks_posted = 0;
}
void PostPackagedTask(Task t) override {
tasks_posted++;
t();
}
void PostPackagedTaskWithDelay(Task t, Clock::duration duration) override {
delayed_tasks_posted++;
t();
}
bool IsRunningOnTaskRunner() override { return true; }
uint32_t tasks_posted;
uint32_t delayed_tasks_posted;
};
} // namespace
// Class extending NetworkWaiter to allow for looking at protected data.
class TestingUdpSocketReader final : public UdpSocketReaderPosix {
public:
explicit TestingUdpSocketReader(SocketHandleWaiter* waiter)
: UdpSocketReaderPosix(waiter) {}
void OnDestroy(UdpSocket* socket) override {
OnDelete(static_cast<UdpSocketPosix*>(socket), true);
}
bool IsMappedRead(UdpSocketPosix* socket) const {
return IsMappedReadForTesting(socket);
}
};
TEST(UdpSocketReaderTest, WatchReadableSucceeds) {
std::unique_ptr<SocketHandleWaiter> mock_waiter =
std::unique_ptr<SocketHandleWaiter>(new MockNetworkWaiter());
std::unique_ptr<TaskRunner> task_runner =
std::unique_ptr<TaskRunner>(new MockTaskRunner());
FakeUdpSocket::MockClient client;
std::unique_ptr<MockUdpSocketPosix> socket =
std::make_unique<MockUdpSocketPosix>(task_runner.get(), &client, 42,
UdpSocket::Version::kV4);
}
TEST(UdpSocketReaderTest, UnwatchReadableSucceeds) {
std::unique_ptr<SocketHandleWaiter> mock_waiter =
std::unique_ptr<SocketHandleWaiter>(new MockNetworkWaiter());
std::unique_ptr<TaskRunner> task_runner =
std::unique_ptr<TaskRunner>(new MockTaskRunner());
FakeUdpSocket::MockClient client;
std::unique_ptr<MockUdpSocketPosix> socket =
std::make_unique<MockUdpSocketPosix>(task_runner.get(), &client, 17,
UdpSocket::Version::kV4);
TestingUdpSocketReader network_waiter(mock_waiter.get());
EXPECT_FALSE(network_waiter.IsMappedRead(socket.get()));
network_waiter.OnDestroy(socket.get());
EXPECT_FALSE(network_waiter.IsMappedRead(socket.get()));
network_waiter.OnCreate(socket.get());
EXPECT_TRUE(network_waiter.IsMappedRead(socket.get()));
network_waiter.OnDestroy(socket.get());
EXPECT_FALSE(network_waiter.IsMappedRead(socket.get()));
network_waiter.OnDestroy(socket.get());
EXPECT_FALSE(network_waiter.IsMappedRead(socket.get()));
}
} // namespace openscreen