Skip to content

Commit 3226730

Browse files
vitautmeta-codesync[bot]
authored andcommitted
Run IOBufFactoryIntegrationTest without io_uring instead of skipping
Summary: `FrameInArena` called `GTEST_SKIP()` when io_uring was unavailable. The fleet test runner records a skipped test as a per-test `SKIPPED` verdict that the ARM shadow sweep counts as a failure, so on the ~43% of hosts without io_uring the run scored as a failure. That dragged the target's ARM pass rate to 57.6% and kept it out of ARM enrollment. Fall back to a malloc-backed tracking arena when io_uring is unavailable. Both paths assert the same contract: every frame `RocketClientChannel` writes is allocated through the client's `IOBufFactory`. The test now always runs and exercises real behavior on every host. Beyond fixing the sweep, this adds real coverage: the ~43% of hosts without io_uring previously skipped and asserted nothing, so the `IOBufFactory` wiring is now regression-tested on every host, not just io_uring-capable ones. ___ Differential Revision: D117005107 fbshipit-source-id: a614d21a9f43715c863464e87ed64da9abf98797
1 parent 39445a1 commit 3226730

1 file changed

Lines changed: 73 additions & 11 deletions

File tree

third-party/thrift/src/thrift/lib/cpp2/transport/rocket/client/test/IOBufFactoryIntegrationTest.cpp

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@
1616

1717
#include <gtest/gtest.h>
1818

19+
#include <cstdint>
20+
#include <cstdlib>
21+
#include <functional>
22+
#include <mutex>
23+
#include <utility>
24+
#include <vector>
25+
1926
#include <folly/io/IOBuf.h>
2027
#include <folly/io/async/AsyncSocket.h>
2128
#include <folly/io/async/DecoratedAsyncTransportWrapper.h>
@@ -34,11 +41,56 @@ namespace {
3441

3542
using iua = folly::IoUringArena;
3643

44+
// A malloc-backed arena that records its allocations so the integration test
45+
// can verify buffers were sourced from our IOBufFactory. Always available, so
46+
// the test runs on hosts without io_uring support instead of skipping (a
47+
// GTEST_SKIP is scored as a test failure by the fleet test runner).
48+
// SIZED_FREE-safe because the buffers come from malloc.
49+
class TrackingArena {
50+
public:
51+
static bool initialized() { return true; }
52+
53+
static void* allocate(size_t size) {
54+
void* p = std::malloc(size);
55+
if (p) {
56+
auto addr = reinterpret_cast<uintptr_t>(p);
57+
std::lock_guard<std::mutex> g(state().mutex);
58+
state().ranges.emplace_back(addr, size);
59+
}
60+
return p;
61+
}
62+
63+
static bool addressInArena(const uint8_t* address) {
64+
auto a = reinterpret_cast<uintptr_t>(address);
65+
std::lock_guard<std::mutex> g(state().mutex);
66+
for (const auto& [start, size] : state().ranges) {
67+
if (a >= start && a < start + size) {
68+
return true;
69+
}
70+
}
71+
return false;
72+
}
73+
74+
private:
75+
struct State {
76+
std::mutex mutex;
77+
std::vector<std::pair<uintptr_t, size_t>> ranges;
78+
};
79+
static State& state() {
80+
static State s;
81+
return s;
82+
}
83+
};
84+
3785
class ArenaCheckingTransport
3886
: public folly::DecoratedAsyncTransportWrapper<folly::AsyncTransport> {
3987
public:
4088
using Base = folly::DecoratedAsyncTransportWrapper<folly::AsyncTransport>;
41-
using Base::Base;
89+
90+
ArenaCheckingTransport(
91+
folly::AsyncTransport::UniquePtr socket,
92+
std::function<bool(const uint8_t*)> inArena)
93+
: Base(std::move(socket)), inArena_(std::move(inArena)) {}
4294

4395
size_t writesChecked{0};
4496
size_t bufsChecked{0};
@@ -58,36 +110,46 @@ class ArenaCheckingTransport
58110
const auto* curr = buf.get();
59111
do {
60112
bufsChecked++;
61-
auto inArena = iua::addressInArena(const_cast<uint8_t*>(curr->data()));
62-
if (!inArena) {
113+
if (!inArena_(curr->data())) {
63114
allInArena = false;
64115
}
65116
curr = curr->next();
66117
} while (curr != buf.get());
67118

68119
Base::writeChain(cb, std::move(buf), flags);
69120
}
121+
122+
private:
123+
std::function<bool(const uint8_t*)> inArena_;
70124
};
71125

72126
} // namespace
73127

74128
TEST(IOBufFactoryIntegrationTest, FrameInArena) {
75129
constexpr size_t kArenaSize = 4 * 1024 * 1024;
76-
if (!iua::ioUringArenaSupported()) {
77-
GTEST_SKIP() << "IoUringArena not supported";
78-
}
79-
if (!iua::init(kArenaSize)) {
80-
GTEST_SKIP() << "IoUringArena initialization not supported";
130+
131+
// Prefer the real io_uring arena; fall back to a malloc-backed tracking arena
132+
// on hosts without io_uring support. Both exercise the same contract: frames
133+
// written by RocketClientChannel are allocated through our IOBufFactory.
134+
folly::IOBufFactory factoryFn;
135+
std::function<bool(const uint8_t*)> inArena;
136+
if (iua::ioUringArenaSupported() && iua::init(kArenaSize)) {
137+
factoryFn = folly::memory::makeIOBufArenaFactory<iua>();
138+
inArena = [](const uint8_t* p) {
139+
return iua::addressInArena(const_cast<uint8_t*>(p));
140+
};
141+
} else {
142+
factoryFn = folly::memory::makeIOBufArenaFactory<TrackingArena>();
143+
inArena = [](const uint8_t* p) { return TrackingArena::addressInArena(p); };
81144
}
145+
auto factory = std::make_shared<folly::IOBufFactory>(std::move(factoryFn));
82146

83147
auto server = ScopedServerInterfaceThread(std::make_shared<TestHandler>());
84-
auto factory = std::make_shared<folly::IOBufFactory>(
85-
folly::memory::makeIOBufArenaFactory<iua>());
86148

87149
folly::EventBase evb;
88150
auto socket = folly::AsyncSocket::newSocket(&evb, server.getAddress());
89151
auto transport = ArenaCheckingTransport::UniquePtr(
90-
new ArenaCheckingTransport(std::move(socket)));
152+
new ArenaCheckingTransport(std::move(socket), std::move(inArena)));
91153
auto* checker = static_cast<ArenaCheckingTransport*>(transport.get());
92154

93155
auto channel = RocketClientChannel::newChannel(std::move(transport));

0 commit comments

Comments
 (0)