1 // Copyright 2019 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 "platform/impl/udp_socket_reader_posix.h"
6
7 #include "gmock/gmock.h"
8 #include "gtest/gtest.h"
9 #include "platform/api/time.h"
10 #include "platform/impl/socket_handle_posix.h"
11 #include "platform/impl/udp_socket_posix.h"
12 #include "platform/test/fake_clock.h"
13 #include "platform/test/fake_task_runner.h"
14 #include "platform/test/fake_udp_socket.h"
15
16 namespace openscreen {
17 namespace {
18
19 using namespace ::testing;
20 using ::testing::_;
21 using ::testing::Invoke;
22
23 class MockUdpSocketPosix : public UdpSocketPosix {
24 public:
MockUdpSocketPosix(TaskRunner * task_runner,Client * client,int fd,Version version=Version::kV4)25 explicit MockUdpSocketPosix(TaskRunner* task_runner,
26 Client* client,
27 int fd,
28 Version version = Version::kV4)
29 : UdpSocketPosix(task_runner, client, SocketHandle(fd), IPEndpoint()),
30 version_(version) {}
31 ~MockUdpSocketPosix() override = default;
32
IsIPv4() const33 bool IsIPv4() const override { return version_ == UdpSocket::Version::kV4; }
34
IsIPv6() const35 bool IsIPv6() const override { return version_ == UdpSocket::Version::kV6; }
36
37 MOCK_METHOD0(Bind, void());
38 MOCK_METHOD1(SetMulticastOutboundInterface, void(NetworkInterfaceIndex));
39 MOCK_METHOD2(JoinMulticastGroup,
40 void(const IPAddress&, NetworkInterfaceIndex));
41 MOCK_METHOD3(SendMessage, void(const void*, size_t, const IPEndpoint&));
42 MOCK_METHOD1(SetDscp, void(DscpMode));
43
44 private:
45 Version version_;
46 };
47
48 // Mock event waiter
49 class MockNetworkWaiter final : public SocketHandleWaiter {
50 public:
51 using ReadyHandle = SocketHandleWaiter::ReadyHandle;
52
MockNetworkWaiter()53 MockNetworkWaiter() : SocketHandleWaiter(&FakeClock::now) {}
54 ~MockNetworkWaiter() override = default;
55
56 MOCK_METHOD2(
57 AwaitSocketsReadable,
58 ErrorOr<std::vector<ReadyHandle>>(const std::vector<SocketHandleRef>&,
59 const Clock::duration&));
60
61 FakeClock fake_clock{Clock::time_point{Clock::duration{1234567}}};
62 };
63
64 // Mock Task Runner
65 class MockTaskRunner final : public TaskRunner {
66 public:
MockTaskRunner()67 MockTaskRunner() {
68 tasks_posted = 0;
69 delayed_tasks_posted = 0;
70 }
71
PostPackagedTask(Task t)72 void PostPackagedTask(Task t) override {
73 tasks_posted++;
74 t();
75 }
76
PostPackagedTaskWithDelay(Task t,Clock::duration duration)77 void PostPackagedTaskWithDelay(Task t, Clock::duration duration) override {
78 delayed_tasks_posted++;
79 t();
80 }
81
IsRunningOnTaskRunner()82 bool IsRunningOnTaskRunner() override { return true; }
83
84 uint32_t tasks_posted;
85 uint32_t delayed_tasks_posted;
86 };
87
88 } // namespace
89
90 // Class extending NetworkWaiter to allow for looking at protected data.
91 class TestingUdpSocketReader final : public UdpSocketReaderPosix {
92 public:
TestingUdpSocketReader(SocketHandleWaiter * waiter)93 explicit TestingUdpSocketReader(SocketHandleWaiter* waiter)
94 : UdpSocketReaderPosix(waiter) {}
95
OnDestroy(UdpSocket * socket)96 void OnDestroy(UdpSocket* socket) override {
97 OnDelete(static_cast<UdpSocketPosix*>(socket), true);
98 }
99
IsMappedRead(UdpSocketPosix * socket) const100 bool IsMappedRead(UdpSocketPosix* socket) const {
101 return IsMappedReadForTesting(socket);
102 }
103 };
104
TEST(UdpSocketReaderTest,WatchReadableSucceeds)105 TEST(UdpSocketReaderTest, WatchReadableSucceeds) {
106 std::unique_ptr<SocketHandleWaiter> mock_waiter =
107 std::unique_ptr<SocketHandleWaiter>(new MockNetworkWaiter());
108 std::unique_ptr<TaskRunner> task_runner =
109 std::unique_ptr<TaskRunner>(new MockTaskRunner());
110 FakeUdpSocket::MockClient client;
111 std::unique_ptr<MockUdpSocketPosix> socket =
112 std::make_unique<MockUdpSocketPosix>(task_runner.get(), &client, 42,
113 UdpSocket::Version::kV4);
114 }
115
TEST(UdpSocketReaderTest,UnwatchReadableSucceeds)116 TEST(UdpSocketReaderTest, UnwatchReadableSucceeds) {
117 std::unique_ptr<SocketHandleWaiter> mock_waiter =
118 std::unique_ptr<SocketHandleWaiter>(new MockNetworkWaiter());
119 std::unique_ptr<TaskRunner> task_runner =
120 std::unique_ptr<TaskRunner>(new MockTaskRunner());
121 FakeUdpSocket::MockClient client;
122 std::unique_ptr<MockUdpSocketPosix> socket =
123 std::make_unique<MockUdpSocketPosix>(task_runner.get(), &client, 17,
124 UdpSocket::Version::kV4);
125 TestingUdpSocketReader network_waiter(mock_waiter.get());
126
127 EXPECT_FALSE(network_waiter.IsMappedRead(socket.get()));
128 network_waiter.OnDestroy(socket.get());
129 EXPECT_FALSE(network_waiter.IsMappedRead(socket.get()));
130
131 network_waiter.OnCreate(socket.get());
132 EXPECT_TRUE(network_waiter.IsMappedRead(socket.get()));
133
134 network_waiter.OnDestroy(socket.get());
135 EXPECT_FALSE(network_waiter.IsMappedRead(socket.get()));
136
137 network_waiter.OnDestroy(socket.get());
138 EXPECT_FALSE(network_waiter.IsMappedRead(socket.get()));
139 }
140
141 } // namespace openscreen
142