summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcppdap/src/socket_test.cpp
blob: 186fd9a38642166d1b0b39ecf8018f83988caf16 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "socket.h"

#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include <chrono>
#include <thread>
#include <vector>

// Basic socket send & receive test
TEST(Socket, SendRecv) {
  const char* port = "19021";

  auto server = dap::Socket("localhost", port);

  auto client = dap::Socket::connect("localhost", port, 0);
  ASSERT_TRUE(client != nullptr);

  const std::string expect = "Hello World!";
  std::string read;

  auto thread = std::thread([&] {
    auto conn = server.accept();
    ASSERT_TRUE(conn != nullptr);
    char c;
    while (conn->read(&c, 1) != 0) {
      read += c;
    }
  });

  ASSERT_TRUE(client->write(expect.data(), expect.size()));

  client->close();
  thread.join();

  ASSERT_EQ(read, expect);
}

// See https://github.com/google/cppdap/issues/37
TEST(Socket, CloseOnDifferentThread) {
  const char* port = "19021";

  auto server = dap::Socket("localhost", port);

  auto client = dap::Socket::connect("localhost", port, 0);
  ASSERT_TRUE(client != nullptr);

  auto conn = server.accept();

  auto thread = std::thread([&] {
    // Closing client on different thread should unblock client->read().
    client->close();
  });

  char c;
  while (client->read(&c, 1) != 0) {
  }

  thread.join();
}

TEST(Socket, ConnectTimeout) {
  const char* port = "19021";
  const int timeoutMillis = 200;
  const int maxAttempts = 1024;

  using namespace std::chrono;

  auto server = dap::Socket("localhost", port);

  std::vector<std::shared_ptr<dap::ReaderWriter>> connections;

  for (int i = 0; i < maxAttempts; i++) {
    auto start = system_clock::now();
    auto connection = dap::Socket::connect("localhost", port, timeoutMillis);
    auto end = system_clock::now();

    if (!connection) {
      auto timeTakenMillis = duration_cast<milliseconds>(end - start).count();
      ASSERT_GE(timeTakenMillis + 20,  // +20ms for a bit of timing wiggle room
                timeoutMillis);
      return;
    }

    // Keep hold of the connections to saturate any incoming socket buffers.
    connections.emplace_back(std::move(connection));
  }

  FAIL() << "Failed to test timeout after " << maxAttempts << " attempts";
}