198 lines · cpp
1//===-- PipeTest.cpp ------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Host/Pipe.h"10#include "TestingSupport/SubsystemRAII.h"11#include "lldb/Host/FileSystem.h"12#include "lldb/Host/HostInfo.h"13#include "llvm/Testing/Support/Error.h"14#include "gtest/gtest.h"15#include <chrono>16#include <fcntl.h>17#include <future>18#include <numeric>19#include <thread>20#include <vector>21 22using namespace lldb_private;23 24class PipeTest : public testing::Test {25public:26 SubsystemRAII<FileSystem, HostInfo> subsystems;27};28 29TEST_F(PipeTest, CreateWithUniqueName) {30 Pipe pipe;31 llvm::SmallString<0> name;32 ASSERT_THAT_ERROR(33 pipe.CreateWithUniqueName("PipeTest-CreateWithUniqueName", name)34 .ToError(),35 llvm::Succeeded());36}37 38// Test broken39#ifndef _WIN3240TEST_F(PipeTest, OpenAsReader) {41 Pipe pipe;42 llvm::SmallString<0> name;43 ASSERT_THAT_ERROR(44 pipe.CreateWithUniqueName("PipeTest-OpenAsReader", name).ToError(),45 llvm::Succeeded());46 47 // Ensure name is not null-terminated48 size_t name_len = name.size();49 name += "foobar";50 llvm::StringRef name_ref(name.data(), name_len);51 ASSERT_THAT_ERROR(pipe.OpenAsReader(name_ref).ToError(), llvm::Succeeded());52 53 ASSERT_TRUE(pipe.CanRead());54}55#endif56 57// Tests flaky on Windows58#ifndef _WIN3259TEST_F(PipeTest, WriteWithTimeout) {60 Pipe pipe;61 ASSERT_THAT_ERROR(pipe.CreateNew().ToError(), llvm::Succeeded());62 63 // The pipe buffer is 1024 for PipeWindows and at least 512 on Darwin.64 // In Linux versions before 2.6.11, the capacity of a pipe was the same as the65 // system page size (e.g., 4096 bytes on i386).66 // Since Linux 2.6.11, the pipe capacity is 16 pages (i.e., 65,536 bytes in a67 // system with a page size of 4096 bytes).68 // Since Linux 2.6.35, the default pipe capacity is 16 pages, but the capacity69 // can be queried and set using the fcntl(2) F_GETPIPE_SZ and F_SETPIPE_SZ70 // operations:71 72#if !defined(_WIN32) && defined(F_SETPIPE_SZ)73 ::fcntl(pipe.GetWriteFileDescriptor(), F_SETPIPE_SZ, 4096);74#endif75 76 const size_t buf_size = 66000;77 78 // Note write_chunk_size must be less than the pipe buffer.79 const size_t write_chunk_size = 234;80 81 std::vector<int32_t> write_buf(buf_size / sizeof(int32_t));82 std::iota(write_buf.begin(), write_buf.end(), 0);83 std::vector<int32_t> read_buf(write_buf.size() + 100, -1);84 85 char *write_ptr = reinterpret_cast<char *>(write_buf.data());86 char *read_ptr = reinterpret_cast<char *>(read_buf.data());87 size_t write_bytes = 0;88 size_t read_bytes = 0;89 90 // Write to the pipe until it is full.91 while (write_bytes + write_chunk_size <= buf_size) {92 llvm::Expected<size_t> num_bytes =93 pipe.Write(write_ptr + write_bytes, write_chunk_size,94 std::chrono::milliseconds(10));95 if (num_bytes) {96 write_bytes += *num_bytes;97 } else {98 ASSERT_THAT_ERROR(num_bytes.takeError(), llvm::Failed());99 break; // The write buffer is full.100 }101 }102 ASSERT_LE(write_bytes + write_chunk_size, buf_size)103 << "Pipe buffer larger than expected";104 105 // Attempt a write with a long timeout.106 auto start_time = std::chrono::steady_clock::now();107 // TODO: Assert a specific error (EAGAIN?) here.108 ASSERT_THAT_EXPECTED(pipe.Write(write_ptr + write_bytes, write_chunk_size,109 std::chrono::seconds(2)),110 llvm::Failed());111 auto dur = std::chrono::steady_clock::now() - start_time;112 ASSERT_GE(dur, std::chrono::seconds(2));113 114 // Attempt a write with a short timeout.115 start_time = std::chrono::steady_clock::now();116 ASSERT_THAT_EXPECTED(pipe.Write(write_ptr + write_bytes, write_chunk_size,117 std::chrono::milliseconds(200)),118 llvm::Failed());119 dur = std::chrono::steady_clock::now() - start_time;120 ASSERT_GE(dur, std::chrono::milliseconds(200));121 ASSERT_LT(dur, std::chrono::seconds(2));122 123 // Drain the pipe.124 while (read_bytes < write_bytes) {125 llvm::Expected<size_t> num_bytes =126 pipe.Read(read_ptr + read_bytes, write_bytes - read_bytes,127 std::chrono::milliseconds(10));128 ASSERT_THAT_EXPECTED(num_bytes, llvm::Succeeded());129 read_bytes += *num_bytes;130 }131 132 // Be sure the pipe is empty.133 ASSERT_THAT_EXPECTED(134 pipe.Read(read_ptr + read_bytes, 100, std::chrono::milliseconds(10)),135 llvm::Failed());136 137 // Check that we got what we wrote.138 ASSERT_EQ(write_bytes, read_bytes);139 ASSERT_TRUE(std::equal(write_buf.begin(),140 write_buf.begin() + write_bytes / sizeof(uint32_t),141 read_buf.begin()));142 143 // Write to the pipe again and check that it succeeds.144 ASSERT_THAT_EXPECTED(145 pipe.Write(write_ptr, write_chunk_size, std::chrono::milliseconds(10)),146 llvm::Succeeded());147}148 149TEST_F(PipeTest, ReadWithTimeout) {150 Pipe pipe;151 ASSERT_THAT_ERROR(pipe.CreateNew().ToError(), llvm::Succeeded());152 153 char buf[100];154 // The pipe is initially empty. A polling read returns immediately.155 ASSERT_THAT_EXPECTED(pipe.Read(buf, sizeof(buf), std::chrono::seconds(0)),156 llvm::Failed());157 158 // With a timeout, we should wait for at least this amount of time (but not159 // too much).160 auto start = std::chrono::steady_clock::now();161 ASSERT_THAT_EXPECTED(162 pipe.Read(buf, sizeof(buf), std::chrono::milliseconds(200)),163 llvm::Failed());164 auto dur = std::chrono::steady_clock::now() - start;165 EXPECT_GT(dur, std::chrono::milliseconds(200));166 EXPECT_LT(dur, std::chrono::seconds(2));167 168 // Write something into the pipe, and read it back. The blocking read call169 // should return even though it hasn't filled the buffer.170 llvm::StringRef hello_world("Hello world!");171 ASSERT_THAT_EXPECTED(pipe.Write(hello_world.data(), hello_world.size()),172 llvm::HasValue(hello_world.size()));173 ASSERT_THAT_EXPECTED(pipe.Read(buf, sizeof(buf)),174 llvm::HasValue(hello_world.size()));175 EXPECT_EQ(llvm::StringRef(buf, hello_world.size()), hello_world);176 177 // Now write something and try to read it in chunks.178 memset(buf, 0, sizeof(buf));179 ASSERT_THAT_EXPECTED(pipe.Write(hello_world.data(), hello_world.size()),180 llvm::HasValue(hello_world.size()));181 ASSERT_THAT_EXPECTED(pipe.Read(buf, 4), llvm::HasValue(4));182 ASSERT_THAT_EXPECTED(pipe.Read(buf + 4, sizeof(buf) - 4),183 llvm::HasValue(hello_world.size() - 4));184 EXPECT_EQ(llvm::StringRef(buf, hello_world.size()), hello_world);185 186 // A blocking read should wait until the data arrives.187 memset(buf, 0, sizeof(buf));188 std::future<llvm::Expected<size_t>> future_num_bytes = std::async(189 std::launch::async, [&] { return pipe.Read(buf, sizeof(buf)); });190 std::this_thread::sleep_for(std::chrono::milliseconds(10));191 ASSERT_THAT_EXPECTED(pipe.Write(hello_world.data(), hello_world.size()),192 llvm::HasValue(hello_world.size()));193 ASSERT_THAT_EXPECTED(future_num_bytes.get(),194 llvm::HasValue(hello_world.size()));195 EXPECT_EQ(llvm::StringRef(buf, hello_world.size()), hello_world);196}197#endif /*ifndef _WIN32*/198