Parallel test on CI (#2364)

* Parallel test on CI

* Fix problem with Windows

* Use cache for vcpkg

* Parallel 'No Exception' test

* Use one job to run all shards
This commit is contained in:
yhirose
2026-02-13 01:55:30 -05:00
committed by GitHub
parent c1ee85d89e
commit ed5c5d325b
7 changed files with 166 additions and 51 deletions
+39 -5
View File
@@ -94,12 +94,12 @@ jobs:
run: sudo apt-get install -y libmbedtls-dev
- name: build and run tests (OpenSSL)
if: matrix.tls_backend == 'openssl'
run: cd test && make
run: cd test && make test_split && make test_openssl_parallel
env:
LSAN_OPTIONS: suppressions=lsan_suppressions.txt
- name: build and run tests (Mbed TLS)
if: matrix.tls_backend == 'mbedtls'
run: cd test && make test_split_mbedtls && make test_mbedtls && ./test_mbedtls
run: cd test && make test_split_mbedtls && make test_mbedtls_parallel
- name: run fuzz test target
if: matrix.tls_backend == 'openssl'
run: cd test && make fuzz_test
@@ -123,12 +123,12 @@ jobs:
run: brew install mbedtls@3
- name: build and run tests (OpenSSL)
if: matrix.tls_backend == 'openssl'
run: cd test && make
run: cd test && make test_split && make test_openssl_parallel
env:
LSAN_OPTIONS: suppressions=lsan_suppressions.txt
- name: build and run tests (Mbed TLS)
if: matrix.tls_backend == 'mbedtls'
run: cd test && make test_split_mbedtls && make test_mbedtls && ./test_mbedtls
run: cd test && make test_split_mbedtls && make test_mbedtls_parallel
- name: run fuzz test target
if: matrix.tls_backend == 'openssl'
run: cd test && make fuzz_test
@@ -171,7 +171,14 @@ jobs:
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Setup msbuild on windows
uses: microsoft/setup-msbuild@v2
- name: Cache vcpkg packages
id: vcpkg-cache
uses: actions/cache@v4
with:
path: C:/vcpkg/installed
key: vcpkg-installed-windows-gtest-curl-zlib-brotli-zstd
- name: Install vcpkg dependencies
if: steps.vcpkg-cache.outputs.cache-hit != 'true'
run: vcpkg install gtest curl zlib brotli zstd
- name: Install OpenSSL
if: ${{ matrix.config.with_ssl }}
@@ -192,7 +199,34 @@ jobs:
run: cmake --build build --config Release -- /v:m /clp:ShowCommandLine
- name: Run tests ${{ matrix.config.name }}
if: ${{ matrix.config.run_tests }}
run: ctest --output-on-failure --test-dir build -C Release -E "BenchmarkTest"
shell: pwsh
working-directory: build/test
run: |
$shards = 4
$procs = @()
for ($i = 0; $i -lt $shards; $i++) {
$log = "shard_${i}.log"
$procs += Start-Process -FilePath ./Release/httplib-test.exe `
-ArgumentList "--gtest_color=yes","--gtest_filter=${{ github.event.inputs.gtest_filter || '*' }}-*BenchmarkTest*" `
-NoNewWindow -PassThru -RedirectStandardOutput $log -RedirectStandardError "${log}.err" `
-Environment @{ GTEST_TOTAL_SHARDS="$shards"; GTEST_SHARD_INDEX="$i" }
}
$procs | Wait-Process
$failed = $false
for ($i = 0; $i -lt $shards; $i++) {
$log = "shard_${i}.log"
if (Select-String -Path $log -Pattern "\[ PASSED \]" -Quiet) {
$passed = (Select-String -Path $log -Pattern "\[ PASSED \]").Line
Write-Host "Shard ${i}: $passed"
} else {
Write-Host "=== Shard $i FAILED ==="
Get-Content $log
if (Test-Path "${log}.err") { Get-Content "${log}.err" }
$failed = $true
}
}
if ($failed) { exit 1 }
Write-Host "All shards passed."
- name: Run benchmark tests with retry ${{ matrix.config.name }}
if: ${{ matrix.config.run_tests }}
run: ctest --output-on-failure --test-dir build -C Release -R "BenchmarkTest" --repeat until-pass:5
+1 -1
View File
@@ -17,4 +17,4 @@ jobs:
- name: Run tests with CPPHTTPLIB_NO_EXCEPTIONS
run: |
cd test && make EXTRA_CXXFLAGS="-fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS"
cd test && make test_split EXTRA_CXXFLAGS="-fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS" && make test_openssl_parallel EXTRA_CXXFLAGS="-fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS"
+2 -2
View File
@@ -49,12 +49,12 @@ jobs:
sudo ip6tables -A OUTPUT -j REJECT
- name: build and run tests (OpenSSL)
if: matrix.tls_backend == 'openssl'
run: cd test && make
run: cd test && make test_split && make test_openssl_parallel
env:
LSAN_OPTIONS: suppressions=lsan_suppressions.txt
- name: build and run tests (No TLS)
if: matrix.tls_backend == 'no-tls'
run: cd test && make test_no_tls && ./test_no_tls
run: cd test && make test_no_tls_parallel
- name: restore network
if: always()
run: |
+1
View File
@@ -46,6 +46,7 @@ test/test.xcodeproj/*/xcuser*
test/*.o
test/*.pem
test/*.srl
test/*.log
test/_build_*
work/
benchmark/server*
+9
View File
@@ -9,13 +9,22 @@ openssl:
@(cd test && make test && LSAN_OPTIONS=suppressions=lsan_suppressions.txt ./test)
@(cd test && make proxy)
openssl_parallel:
@(cd test && make test_openssl_parallel)
mbedtls:
@(cd test && make test_mbedtls && LSAN_OPTIONS=suppressions=lsan_suppressions.txt ./test_mbedtls)
@(cd test && make proxy_mbedtls)
mbedtls_parallel:
@(cd test && make test_mbedtls_parallel)
no_tls:
@(cd test && make test_no_tls && ./test_no_tls)
no_tls_parallel:
@(cd test && make test_no_tls_parallel)
fuzz:
@(cd test && make fuzz_test)
+37 -1
View File
@@ -56,6 +56,42 @@ STYLE_CHECK_FILES = $(filter-out httplib.h httplib.cc, \
all : test test_split
LSAN_OPTIONS=suppressions=lsan_suppressions.txt ./test
SHARDS ?= 4
define run_parallel
@echo "Running $(1) with $(SHARDS) shards in parallel..."
@fail=0; \
for i in $$(seq 0 $$(($(SHARDS) - 1))); do \
GTEST_TOTAL_SHARDS=$(SHARDS) GTEST_SHARD_INDEX=$$i \
LSAN_OPTIONS=suppressions=lsan_suppressions.txt \
./$(1) --gtest_color=yes > $(1)_shard_$$i.log 2>&1 & \
done; \
wait; \
for i in $$(seq 0 $$(($(SHARDS) - 1))); do \
if ! grep -q "\[ PASSED \]" $(1)_shard_$$i.log; then \
echo "=== Shard $$i FAILED ==="; \
cat $(1)_shard_$$i.log; \
fail=1; \
else \
passed=$$(grep "\[ PASSED \]" $(1)_shard_$$i.log); \
echo "Shard $$i: $$passed"; \
fi; \
done; \
if [ $$fail -ne 0 ]; then exit 1; fi; \
echo "All shards passed."
endef
.PHONY: test_openssl_parallel test_mbedtls_parallel test_no_tls_parallel
test_openssl_parallel : test
$(call run_parallel,test)
test_mbedtls_parallel : test_mbedtls
$(call run_parallel,test_mbedtls)
test_no_tls_parallel : test_no_tls
$(call run_parallel,test_no_tls)
proxy : test_proxy
@echo "Starting proxy server..."
cd proxy && \
@@ -172,5 +208,5 @@ cert.pem:
./gen-certs.sh
clean:
rm -rf test test_split test_mbedtls test_split_mbedtls test_no_tls, test_split_no_tls test_proxy test_proxy_mbedtls server_fuzzer *.pem *.0 *.o *.1 *.srl httplib.h httplib.cc _build* *.dSYM
rm -rf test test_split test_mbedtls test_split_mbedtls test_no_tls, test_split_no_tls test_proxy test_proxy_mbedtls server_fuzzer *.pem *.0 *.o *.1 *.srl httplib.h httplib.cc _build* *.dSYM *_shard_*.log
+77 -42
View File
@@ -55,7 +55,13 @@ using namespace std;
using namespace httplib;
const char *HOST = "localhost";
const int PORT = 1234;
static int get_base_port() {
const char *shard = getenv("GTEST_SHARD_INDEX");
return shard ? 11234 + std::atoi(shard) * 100 : 1234;
}
const int PORT = get_base_port();
const string LONG_QUERY_VALUE = string(25000, '@');
const string LONG_QUERY_URL = "/long-query-value?key=" + LONG_QUERY_VALUE;
@@ -178,7 +184,12 @@ protected:
EXPECT_EQ(resp.body, content_);
}
const std::string pathname_{"./httplib-server.sock"};
static std::string make_sock_path() {
const char *shard = getenv("GTEST_SHARD_INDEX");
return shard ? std::string("./httplib-server-") + shard + ".sock"
: "./httplib-server.sock";
}
const std::string pathname_{make_sock_path()};
const std::string pattern_{"/hi"};
const std::string content_{"Hello World!"};
};
@@ -2370,28 +2381,32 @@ TEST(RedirectFromPageWithContent, Redirect) {
TEST(RedirectFromPageWithContentIP6, Redirect) {
Server svr;
auto port_str = std::to_string(PORT);
auto redirect_url = "http://[::1]:" + port_str + "/2";
auto expected_host = "[::1]:" + port_str;
svr.Get("/1", [&](const Request & /*req*/, Response &res) {
res.set_content("___", "text/plain");
// res.set_redirect("/2");
res.set_redirect("http://[::1]:1234/2");
res.set_redirect(redirect_url);
});
svr.Get("/2", [&](const Request &req, Response &res) {
auto host_header = req.headers.find("Host");
ASSERT_TRUE(host_header != req.headers.end());
EXPECT_EQ("[::1]:1234", host_header->second);
EXPECT_EQ(expected_host, host_header->second);
res.set_content("Hello World!", "text/plain");
});
auto th = std::thread([&]() { svr.listen("::1", 1234); });
auto th = std::thread([&]() { svr.listen("::1", PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
th.join();
ASSERT_FALSE(svr.is_running());
});
// When IPV6 support isn't available svr.listen("::1", 1234) never
// When IPV6 support isn't available svr.listen("::1", PORT) never
// actually starts anything, so the condition !svr.is_running() will
// always remain true, and the loop never stops.
// This basically counts how many milliseconds have passed since the
@@ -2403,7 +2418,7 @@ TEST(RedirectFromPageWithContentIP6, Redirect) {
}
{
Client cli("http://[::1]:1234");
Client cli("::1", PORT);
cli.set_follow_location(true);
std::string body;
@@ -2418,7 +2433,7 @@ TEST(RedirectFromPageWithContentIP6, Redirect) {
}
{
Client cli("http://[::1]:1234");
Client cli("::1", PORT);
std::string body;
auto res = cli.Get("/1", [&](const char *data, size_t data_length) {
@@ -10471,7 +10486,8 @@ TEST(ClientImplMethods, GetSocketTest) {
res.status = StatusCode::OK_200;
});
auto thread = std::thread([&]() { svr.listen("127.0.0.1", 3333); });
auto port = svr.bind_to_any_port("127.0.0.1");
auto thread = std::thread([&]() { svr.listen_after_bind(); });
auto se = detail::scope_exit([&] {
svr.stop();
thread.join();
@@ -10481,7 +10497,7 @@ TEST(ClientImplMethods, GetSocketTest) {
svr.wait_until_ready();
{
httplib::Client cli("http://127.0.0.1:3333");
httplib::Client cli("127.0.0.1", port);
cli.set_keep_alive(true);
// Use the behavior of cpp-httplib of opening the connection
@@ -10640,10 +10656,13 @@ TEST(HttpsToHttpRedirectTest3, SimpleInterface_Online) {
}
TEST(HttpToHttpsRedirectTest, CertFile) {
auto ssl_port = PORT + 1;
Server svr;
ASSERT_TRUE(svr.is_valid());
svr.Get("/index", [&](const Request &, Response &res) {
res.set_redirect("https://127.0.0.1:1235/index");
res.set_redirect("https://127.0.0.1:" + std::to_string(ssl_port) +
"/index");
svr.stop();
});
@@ -10655,7 +10674,8 @@ TEST(HttpToHttpsRedirectTest, CertFile) {
});
thread t = thread([&]() { ASSERT_TRUE(svr.listen("127.0.0.1", PORT)); });
thread t2 = thread([&]() { ASSERT_TRUE(ssl_svr.listen("127.0.0.1", 1235)); });
thread t2 =
thread([&]() { ASSERT_TRUE(ssl_svr.listen("127.0.0.1", ssl_port)); });
auto se = detail::scope_exit([&] {
t2.join();
t.join();
@@ -10677,10 +10697,13 @@ TEST(HttpToHttpsRedirectTest, CertFile) {
}
TEST(SSLClientRedirectTest, CertFile) {
auto ssl_port = PORT + 1;
SSLServer ssl_svr1(SERVER_CERT2_FILE, SERVER_PRIVATE_KEY_FILE);
ASSERT_TRUE(ssl_svr1.is_valid());
ssl_svr1.Get("/index", [&](const Request &, Response &res) {
res.set_redirect("https://127.0.0.1:1235/index");
res.set_redirect("https://127.0.0.1:" + std::to_string(ssl_port) +
"/index");
ssl_svr1.stop();
});
@@ -10693,7 +10716,7 @@ TEST(SSLClientRedirectTest, CertFile) {
thread t = thread([&]() { ASSERT_TRUE(ssl_svr1.listen("127.0.0.1", PORT)); });
thread t2 =
thread([&]() { ASSERT_TRUE(ssl_svr2.listen("127.0.0.1", 1235)); });
thread([&]() { ASSERT_TRUE(ssl_svr2.listen("127.0.0.1", ssl_port)); });
auto se = detail::scope_exit([&] {
t2.join();
t.join();
@@ -10774,7 +10797,8 @@ TEST(MultipartFormDataTest, LargeData) {
}
});
auto t = std::thread([&]() { svr.listen(HOST, 8080); });
auto port = svr.bind_to_any_port(HOST);
auto t = std::thread([&]() { svr.listen_after_bind(); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
@@ -10788,7 +10812,7 @@ TEST(MultipartFormDataTest, LargeData) {
std::stringstream buffer;
buffer << data;
Client cli("https://localhost:8080");
SSLClient cli(HOST, port);
cli.enable_server_certificate_verification(false);
UploadFormDataItems items{
@@ -10921,7 +10945,8 @@ TEST(MultipartFormDataTest, DataProviderItems) {
EXPECT_EQ(items[3].content_type, "");
});
auto t = std::thread([&]() { svr.listen("localhost", 8080); });
auto port = svr.bind_to_any_port("localhost");
auto t = std::thread([&]() { svr.listen_after_bind(); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
@@ -10931,7 +10956,7 @@ TEST(MultipartFormDataTest, DataProviderItems) {
svr.wait_until_ready();
{
Client cli("https://localhost:8080");
SSLClient cli("localhost", port);
cli.enable_server_certificate_verification(false);
UploadFormDataItems items{
@@ -11122,7 +11147,8 @@ TEST(MultipartFormDataTest, PostCustomBoundary) {
}
});
auto t = std::thread([&]() { svr.listen("localhost", 8080); });
auto port = svr.bind_to_any_port("localhost");
auto t = std::thread([&]() { svr.listen_after_bind(); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
@@ -11136,7 +11162,7 @@ TEST(MultipartFormDataTest, PostCustomBoundary) {
std::stringstream buffer;
buffer << data;
Client cli("https://localhost:8080");
SSLClient cli("localhost", port);
cli.enable_server_certificate_verification(false);
UploadFormDataItems items{
@@ -11205,7 +11231,8 @@ TEST(MultipartFormDataTest, PutFormData) {
}
});
auto t = std::thread([&]() { svr.listen("localhost", 8080); });
auto port = svr.bind_to_any_port("localhost");
auto t = std::thread([&]() { svr.listen_after_bind(); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
@@ -11219,7 +11246,7 @@ TEST(MultipartFormDataTest, PutFormData) {
std::stringstream buffer;
buffer << data;
Client cli("https://localhost:8080");
SSLClient cli("localhost", port);
cli.enable_server_certificate_verification(false);
UploadFormDataItems items{
@@ -11269,7 +11296,8 @@ TEST(MultipartFormDataTest, PutFormDataCustomBoundary) {
}
});
auto t = std::thread([&]() { svr.listen("localhost", 8080); });
auto port = svr.bind_to_any_port("localhost");
auto t = std::thread([&]() { svr.listen_after_bind(); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
@@ -11283,7 +11311,7 @@ TEST(MultipartFormDataTest, PutFormDataCustomBoundary) {
std::stringstream buffer;
buffer << data;
Client cli("https://localhost:8080");
SSLClient cli("localhost", port);
cli.enable_server_certificate_verification(false);
UploadFormDataItems items{
@@ -13176,7 +13204,8 @@ protected:
}
res.set_content(body, "text/plain");
});
thread_ = std::thread([this]() { svr_.listen("127.0.0.1", 8787); });
port_ = svr_.bind_to_any_port("127.0.0.1");
thread_ = std::thread([this]() { svr_.listen_after_bind(); });
svr_.wait_until_ready();
}
void TearDown() override {
@@ -13185,17 +13214,18 @@ protected:
}
Server svr_;
std::thread thread_;
int port_ = 0;
};
TEST_F(OpenStreamTest, Basic) {
Client cli("127.0.0.1", 8787);
Client cli("127.0.0.1", port_);
auto handle = cli.open_stream("GET", "/hello");
EXPECT_TRUE(handle.is_valid());
EXPECT_EQ("Hello World!", read_all(handle));
}
TEST_F(OpenStreamTest, SmallBuffer) {
Client cli("127.0.0.1", 8787);
Client cli("127.0.0.1", port_);
auto handle = cli.open_stream("GET", "/hello");
std::string result;
char buf[4];
@@ -13206,14 +13236,15 @@ TEST_F(OpenStreamTest, SmallBuffer) {
}
TEST_F(OpenStreamTest, DefaultHeaders) {
Client cli("127.0.0.1", 8787);
Client cli("127.0.0.1", port_);
// open_stream GET should include Host, User-Agent and Accept-Encoding
{
auto handle = cli.open_stream("GET", "/echo-headers");
ASSERT_TRUE(handle.is_valid());
auto body = read_all(handle);
EXPECT_NE(body.find("Host:127.0.0.1:8787"), std::string::npos);
EXPECT_NE(body.find("Host:127.0.0.1:" + std::to_string(port_)),
std::string::npos);
EXPECT_NE(body.find("User-Agent:cpp-httplib/" CPPHTTPLIB_VERSION),
std::string::npos);
EXPECT_NE(body.find("Accept-Encoding:"), std::string::npos);
@@ -13251,7 +13282,7 @@ TEST_F(OpenStreamTest, DefaultHeaders) {
}
TEST_F(OpenStreamTest, Large) {
Client cli("127.0.0.1", 8787);
Client cli("127.0.0.1", port_);
auto handle = cli.open_stream("GET", "/large");
EXPECT_EQ(10000u, read_all(handle).size());
}
@@ -13263,7 +13294,7 @@ TEST_F(OpenStreamTest, ConnectionError) {
}
TEST_F(OpenStreamTest, Chunked) {
Client cli("127.0.0.1", 8787);
Client cli("127.0.0.1", port_);
auto handle = cli.open_stream("GET", "/chunked");
EXPECT_TRUE(handle.response && handle.response->get_header_value(
"Transfer-Encoding") == "chunked");
@@ -13271,7 +13302,7 @@ TEST_F(OpenStreamTest, Chunked) {
}
TEST_F(OpenStreamTest, ProhibitedTrailersAreIgnored_Stream) {
Client cli("127.0.0.1", 8787);
Client cli("127.0.0.1", port_);
auto handle =
cli.open_stream("GET", "/streamed-chunked-with-prohibited-trailer");
ASSERT_TRUE(handle.is_valid());
@@ -13304,7 +13335,7 @@ TEST_F(OpenStreamTest, ProhibitedTrailersAreIgnored_Stream) {
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
TEST_F(OpenStreamTest, Gzip) {
Client cli("127.0.0.1", 8787);
Client cli("127.0.0.1", port_);
auto handle = cli.open_stream("GET", "/compressible", {},
{{"Accept-Encoding", "gzip"}});
EXPECT_EQ("gzip", handle.response->get_header_value("Content-Encoding"));
@@ -13314,7 +13345,7 @@ TEST_F(OpenStreamTest, Gzip) {
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
TEST_F(OpenStreamTest, Brotli) {
Client cli("127.0.0.1", 8787);
Client cli("127.0.0.1", port_);
auto handle =
cli.open_stream("GET", "/compressible", {}, {{"Accept-Encoding", "br"}});
EXPECT_EQ("br", handle.response->get_header_value("Content-Encoding"));
@@ -13324,7 +13355,7 @@ TEST_F(OpenStreamTest, Brotli) {
#ifdef CPPHTTPLIB_ZSTD_SUPPORT
TEST_F(OpenStreamTest, Zstd) {
Client cli("127.0.0.1", 8787);
Client cli("127.0.0.1", port_);
auto handle = cli.open_stream("GET", "/compressible", {},
{{"Accept-Encoding", "zstd"}});
EXPECT_EQ("zstd", handle.response->get_header_value("Content-Encoding"));
@@ -13365,7 +13396,8 @@ protected:
return true;
});
});
thread_ = std::thread([this]() { svr_.listen("127.0.0.1", 8788); });
port_ = svr_.bind_to_any_port("127.0.0.1");
thread_ = std::thread([this]() { svr_.listen_after_bind(); });
svr_.wait_until_ready();
}
void TearDown() override {
@@ -13374,10 +13406,11 @@ protected:
}
SSLServer svr_;
std::thread thread_;
int port_ = 0;
};
TEST_F(SSLOpenStreamTest, Basic) {
SSLClient cli("127.0.0.1", 8788);
SSLClient cli("127.0.0.1", port_);
cli.enable_server_certificate_verification(false);
auto handle = cli.open_stream("GET", "/hello");
ASSERT_TRUE(handle.is_valid());
@@ -13385,7 +13418,7 @@ TEST_F(SSLOpenStreamTest, Basic) {
}
TEST_F(SSLOpenStreamTest, Chunked) {
SSLClient cli("127.0.0.1", 8788);
SSLClient cli("127.0.0.1", port_);
cli.enable_server_certificate_verification(false);
auto handle = cli.open_stream("GET", "/chunked");
@@ -13399,7 +13432,7 @@ TEST_F(SSLOpenStreamTest, Chunked) {
}
TEST_F(SSLOpenStreamTest, Post) {
SSLClient cli("127.0.0.1", 8788);
SSLClient cli("127.0.0.1", port_);
cli.enable_server_certificate_verification(false);
auto handle =
@@ -13413,7 +13446,7 @@ TEST_F(SSLOpenStreamTest, Post) {
}
TEST_F(SSLOpenStreamTest, PostChunked) {
SSLClient cli("127.0.0.1", 8788);
SSLClient cli("127.0.0.1", port_);
cli.enable_server_certificate_verification(false);
auto handle = cli.open_stream("POST", "/chunked-response", {}, {},
@@ -13738,7 +13771,8 @@ protected:
svr_.Post("/echo", [](const httplib::Request &req, httplib::Response &res) {
res.set_content(req.body, "text/plain");
});
thread_ = std::thread([this]() { svr_.listen("127.0.0.1", 8803); });
port_ = svr_.bind_to_any_port("127.0.0.1");
thread_ = std::thread([this]() { svr_.listen_after_bind(); });
svr_.wait_until_ready();
}
void TearDown() override {
@@ -13747,10 +13781,11 @@ protected:
}
httplib::SSLServer svr_{"cert.pem", "key.pem"};
std::thread thread_;
int port_ = 0;
};
TEST_F(SSLStreamApiTest, GetAndPost) {
httplib::SSLClient cli("127.0.0.1", 8803);
httplib::SSLClient cli("127.0.0.1", port_);
cli.enable_server_certificate_verification(false);
auto get = httplib::stream::Get(cli, "/hello");
EXPECT_EQ("Hello SSL!", read_body(get));