mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Test] (P11 B1): the broker's PairBind templates against the encoder, a pair presented at hand-off whose Hello comes 5 s later, a pair presented only at program start refused by name, and the reserved core on lone-prime, symmetric and unreadable topologies
This commit is contained in:
@@ -7,30 +7,39 @@
|
||||
// End of Source File Header
|
||||
|
||||
// P11 B1 (CONTRACT-P11 B1): the apply thread's affinity and spin, selected per session from the
|
||||
// peer's Hello dial mode and data plane. Every row of ApplyThreadPolicy.h's table, with the Redmi's
|
||||
// topology (cpu0-5 performance, cpu6-7 prime: big 0xc0 of 0xff) and the shapes that must not be read
|
||||
// as one.
|
||||
// peer's Hello dial mode and data plane, and the core reserved for a dialled-in shared-segment peer
|
||||
// on every topology shape that matters - the Redmi's (cpu0-5 performance, cpu6-7 prime: big 0xc0,
|
||||
// prime 0xc0 of 0xff), a lone prime core beside other big cores, a lone prime core alone, symmetric
|
||||
// machines, an unreadable topology.
|
||||
|
||||
#include <MG_Remote/Server/ApplyThreadPolicy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
using namespace MobileGL;
|
||||
using namespace MobileGL::MG_Remote::Server;
|
||||
|
||||
namespace {
|
||||
constexpr Uint64 kRedmiBig = 0xc0;
|
||||
constexpr Uint64 kRedmiPrime = 0xc0;
|
||||
constexpr Uint64 kRedmiOnline = 0xff;
|
||||
constexpr Uint32 kConfigured = 50;
|
||||
constexpr Bool kShm = true;
|
||||
constexpr Bool kStream = false;
|
||||
|
||||
ApplyThreadPolicy Connected(const char* affinity, Uint64 big, Uint64 prime, Uint64 online) {
|
||||
return SelectApplyThreadPolicy(affinity, false, kConfigured, ApplyPeer::Connected, kShm, big, prime, online);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(ApplyThreadPolicy, AutoKeepsEveryBigCoreAndTheConfiguredSpinForAnInProcessOrForkedPeer) {
|
||||
// inproc and the same-app fork spawn: exactly the pre-B1 `auto` (A4's measured shapes).
|
||||
for (const ApplyPeer peer : {ApplyPeer::InProcess, ApplyPeer::Forked}) {
|
||||
const auto policy =
|
||||
SelectApplyThreadPolicy("auto", false, kConfigured, peer, kShm, kRedmiBig, kRedmiOnline);
|
||||
const auto policy = SelectApplyThreadPolicy("auto", false, kConfigured, peer, kShm, kRedmiBig, kRedmiPrime,
|
||||
kRedmiOnline);
|
||||
EXPECT_TRUE(policy.recognised);
|
||||
EXPECT_EQ(policy.requestedMask, kRedmiBig) << ApplyPeerName(peer);
|
||||
EXPECT_EQ(policy.spinUs, kConfigured) << ApplyPeerName(peer);
|
||||
@@ -39,80 +48,107 @@ TEST(ApplyThreadPolicy, AutoKeepsEveryBigCoreAndTheConfiguredSpinForAnInProcessO
|
||||
|
||||
TEST(ApplyThreadPolicy, AutoKeepsEveryBigCoreForADialledInPeerOnTheStreamPlane) {
|
||||
// tcp: an io thread feeds the apply thread; nothing changes for a TCP client.
|
||||
const auto policy =
|
||||
SelectApplyThreadPolicy("auto", false, kConfigured, ApplyPeer::Connected, kStream, kRedmiBig, kRedmiOnline);
|
||||
const auto policy = SelectApplyThreadPolicy("auto", false, kConfigured, ApplyPeer::Connected, kStream, kRedmiBig,
|
||||
kRedmiPrime, kRedmiOnline);
|
||||
EXPECT_EQ(policy.requestedMask, kRedmiBig);
|
||||
EXPECT_EQ(policy.spinUs, kConfigured);
|
||||
}
|
||||
|
||||
TEST(ApplyThreadPolicy, AutoGivesADialledInSharedSegmentPeerTheLowestPrimeCoreOnly) {
|
||||
const auto policy =
|
||||
SelectApplyThreadPolicy("auto", false, kConfigured, ApplyPeer::Connected, kShm, kRedmiBig, kRedmiOnline);
|
||||
TEST(ApplyThreadPolicy, SeveralPrimeCoresGiveTheApplyThreadTheLowestOfThem) {
|
||||
const auto policy = Connected("auto", kRedmiBig, kRedmiPrime, kRedmiOnline);
|
||||
EXPECT_TRUE(policy.recognised);
|
||||
EXPECT_EQ(policy.requestedMask, 0x40u)
|
||||
<< "the LOWEST big core: the scheduler puts a foreground client's GL thread on the highest";
|
||||
<< "the LOWEST prime core: the scheduler puts a foreground client's GL thread on the highest";
|
||||
EXPECT_EQ(policy.spinUs, kConnectedPeerSpinUs);
|
||||
EXPECT_NE(std::string(policy.rule).find("lowest of the prime cores"), std::string::npos) << policy.rule;
|
||||
// A non-contiguous prime set: still exactly one core, the lowest.
|
||||
EXPECT_EQ(SelectApplyThreadPolicy("auto", false, kConfigured, ApplyPeer::Connected, kShm, 0x0a, 0xff).requestedMask,
|
||||
0x02u);
|
||||
EXPECT_EQ(ReservedApplyCore(kRedmiBig, kRedmiOnline), 0x40u) << "the core the broker tells the helper to avoid";
|
||||
EXPECT_EQ(Connected("auto", 0x0a, 0x0a, 0xff).requestedMask, 0x02u);
|
||||
}
|
||||
|
||||
TEST(ApplyThreadPolicy, ALonePrimeCoreIsNeverTheApplyThreadsItTakesABigCoreBesideIt) {
|
||||
// cpu0-3 little, cpu4 the only core at the peak (3.3 GHz), cpu5-7 big (3.0, within 15%): the
|
||||
// lowest-numbered big core IS the prime here, and it stays the client's - the apply thread takes cpu5.
|
||||
ReservedCoreReason reason = ReservedCoreReason::NoAsymmetry;
|
||||
EXPECT_EQ(ReservedApplyCore(0xf0, 0x10, 0xff, &reason), 0x20u);
|
||||
EXPECT_EQ(reason, ReservedCoreReason::BigCoreBesideTheOnlyPrime);
|
||||
const auto policy = Connected("auto", 0xf0, 0x10, 0xff);
|
||||
EXPECT_EQ(policy.requestedMask, 0x20u);
|
||||
EXPECT_NE(std::string(policy.rule).find("beside the only prime core"), std::string::npos) << policy.rule;
|
||||
// A Snapdragon 8 Gen 2 shape: cpu0-2 little, cpu3-6 big within 15%, cpu7 the lone prime.
|
||||
EXPECT_EQ(ReservedApplyCore(0xf8, 0x80, 0xff), 0x08u);
|
||||
}
|
||||
|
||||
TEST(ApplyThreadPolicy, ALonePrimeCoreWithNoOtherBigCoreLeavesTheApplyThreadUnpinned) {
|
||||
// A Tensor-G3-like shape read at 85%: only cpu8 is big, and it is the prime. Pinning the spinning
|
||||
// apply thread there would take the one core the client wants; it stays unpinned, and says so.
|
||||
ReservedCoreReason reason = ReservedCoreReason::NoAsymmetry;
|
||||
EXPECT_EQ(ReservedApplyCore(0x100, 0x100, 0x1ff, &reason), 0u);
|
||||
EXPECT_EQ(reason, ReservedCoreReason::OnlyPrimeCoreLeftAlone);
|
||||
const auto policy = Connected("auto", 0x80, 0x80, 0xff);
|
||||
EXPECT_EQ(policy.requestedMask, 0u);
|
||||
EXPECT_NE(std::string(policy.rule).find("unpinned - the only prime core"), std::string::npos) << policy.rule;
|
||||
EXPECT_EQ(policy.spinUs, kConnectedPeerSpinUs);
|
||||
}
|
||||
|
||||
TEST(ApplyThreadPolicy, NoAsymmetryLeavesTheApplyThreadUnpinned) {
|
||||
// A symmetric machine (every cpu big and prime) and an unreadable topology (0): nothing to split.
|
||||
for (const auto& shape : {std::pair<Uint64, Uint64>{0xff, 0xff}, std::pair<Uint64, Uint64>{0, 0}}) {
|
||||
ReservedCoreReason reason = ReservedCoreReason::LowestOfSeveralPrimeCores;
|
||||
EXPECT_EQ(ReservedApplyCore(shape.first, shape.second, 0xff, &reason), 0u) << shape.first;
|
||||
EXPECT_EQ(reason, ReservedCoreReason::NoAsymmetry) << shape.first;
|
||||
EXPECT_NE(std::string(Connected("auto", shape.first, shape.second, 0xff).rule).find("no asymmetric"),
|
||||
std::string::npos);
|
||||
}
|
||||
// ...and the in-process / forked rows keep the whole (symmetric) big set as before.
|
||||
EXPECT_EQ(SelectApplyThreadPolicy("auto", false, kConfigured, ApplyPeer::Forked, kShm, 0xff, 0xff, 0xff)
|
||||
.requestedMask,
|
||||
0xffu);
|
||||
}
|
||||
|
||||
TEST(ApplyThreadPolicy, AnEmptyOrMissingAffinityIsAuto) {
|
||||
for (const char* text : {static_cast<const char*>(nullptr), ""}) {
|
||||
EXPECT_EQ(SelectApplyThreadPolicy(text, false, kConfigured, ApplyPeer::Connected, kShm, kRedmiBig,
|
||||
EXPECT_EQ(Connected(text, kRedmiBig, kRedmiPrime, kRedmiOnline).requestedMask, 0x40u);
|
||||
EXPECT_EQ(SelectApplyThreadPolicy(text, false, kConfigured, ApplyPeer::Forked, kShm, kRedmiBig, kRedmiPrime,
|
||||
kRedmiOnline)
|
||||
.requestedMask,
|
||||
0x40u);
|
||||
EXPECT_EQ(SelectApplyThreadPolicy(text, false, kConfigured, ApplyPeer::Forked, kShm, kRedmiBig, kRedmiOnline)
|
||||
.requestedMask,
|
||||
kRedmiBig);
|
||||
EXPECT_EQ(ReservedApplyCoreForConfig(text, kRedmiBig, kRedmiPrime, kRedmiOnline), 0x40u);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ApplyThreadPolicy, ADialledInPeerGetsNoAffinityWhereThereIsNoPrimePairToSplit) {
|
||||
// A symmetric machine (every cpu is "big"), a single prime core, an unreadable topology: none
|
||||
// has a second prime core to leave to the client, so the scheduler places both threads.
|
||||
for (const Uint64 big : {Uint64{0xff}, Uint64{0x80}, Uint64{0}}) {
|
||||
EXPECT_EQ(SelectApplyThreadPolicy("auto", false, kConfigured, ApplyPeer::Connected, kShm, big, 0xff)
|
||||
.requestedMask,
|
||||
0u)
|
||||
<< big;
|
||||
EXPECT_EQ(ReservedApplyCore(big, 0xff), 0u) << big;
|
||||
}
|
||||
// ...and the in-process / forked rows keep the whole (symmetric) big set as before.
|
||||
EXPECT_EQ(SelectApplyThreadPolicy("auto", false, kConfigured, ApplyPeer::Forked, kShm, 0xff, 0xff).requestedMask,
|
||||
0xffu);
|
||||
}
|
||||
|
||||
TEST(ApplyThreadPolicy, AnExplicitSpinWinsForADialledInPeer) {
|
||||
const auto policy =
|
||||
SelectApplyThreadPolicy("auto", true, 7, ApplyPeer::Connected, kShm, kRedmiBig, kRedmiOnline);
|
||||
const auto policy = SelectApplyThreadPolicy("auto", true, 7, ApplyPeer::Connected, kShm, kRedmiBig, kRedmiPrime,
|
||||
kRedmiOnline);
|
||||
EXPECT_EQ(policy.spinUs, 7u);
|
||||
EXPECT_EQ(policy.requestedMask, 0x40u);
|
||||
}
|
||||
|
||||
TEST(ApplyThreadPolicy, AnExplicitMaskOrOffWinsForEveryPeerAndPlane) {
|
||||
TEST(ApplyThreadPolicy, AnExplicitMaskOrOffWinsForEveryPeerAndPlaneAndReservesNothing) {
|
||||
for (const ApplyPeer peer : {ApplyPeer::InProcess, ApplyPeer::Forked, ApplyPeer::Connected}) {
|
||||
for (const Bool plane : {kShm, kStream}) {
|
||||
const auto off = SelectApplyThreadPolicy("off", false, kConfigured, peer, plane, kRedmiBig, kRedmiOnline);
|
||||
const auto off = SelectApplyThreadPolicy("off", false, kConfigured, peer, plane, kRedmiBig, kRedmiPrime,
|
||||
kRedmiOnline);
|
||||
EXPECT_TRUE(off.recognised);
|
||||
EXPECT_EQ(off.requestedMask, 0u) << ApplyPeerName(peer);
|
||||
EXPECT_EQ(off.spinUs, kConfigured) << "an operator's affinity keeps the configured spin";
|
||||
const auto mask = SelectApplyThreadPolicy("0x80", false, kConfigured, peer, plane, kRedmiBig, kRedmiOnline);
|
||||
const auto mask = SelectApplyThreadPolicy("0x80", false, kConfigured, peer, plane, kRedmiBig,
|
||||
kRedmiPrime, kRedmiOnline);
|
||||
EXPECT_TRUE(mask.recognised);
|
||||
EXPECT_EQ(mask.requestedMask, 0x80u) << ApplyPeerName(peer);
|
||||
EXPECT_EQ(SelectApplyThreadPolicy("12", false, kConfigured, peer, plane, kRedmiBig, kRedmiOnline)
|
||||
EXPECT_EQ(SelectApplyThreadPolicy("12", false, kConfigured, peer, plane, kRedmiBig, kRedmiPrime,
|
||||
kRedmiOnline)
|
||||
.requestedMask,
|
||||
12u);
|
||||
}
|
||||
}
|
||||
// What the supervisor announces (and the helper avoids) under an operator's affinity: nothing.
|
||||
EXPECT_EQ(ReservedApplyCoreForConfig("0x80", kRedmiBig, kRedmiPrime, kRedmiOnline), 0u);
|
||||
EXPECT_EQ(ReservedApplyCoreForConfig("off", kRedmiBig, kRedmiPrime, kRedmiOnline), 0u);
|
||||
}
|
||||
|
||||
TEST(ApplyThreadPolicy, UnrecognisedAffinityTextAppliesNothingAndSaysSo) {
|
||||
for (const char* text : {"big", "0xzz", "auto ", "3cores"}) {
|
||||
const auto policy =
|
||||
SelectApplyThreadPolicy(text, false, kConfigured, ApplyPeer::Connected, kShm, kRedmiBig, kRedmiOnline);
|
||||
const auto policy = Connected(text, kRedmiBig, kRedmiPrime, kRedmiOnline);
|
||||
EXPECT_FALSE(policy.recognised) << text;
|
||||
EXPECT_EQ(policy.requestedMask, 0u) << text;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,10 @@ foreach (test IN LISTS MOBILEGL_WIRE_TESTS)
|
||||
GTest::gtest_main
|
||||
${LINK_LIBRARIES}
|
||||
)
|
||||
if (test STREQUAL "ServerSpawnTest")
|
||||
# P11 B1: reads the broker's PairBind templates out of android-plugin/.../PairBindFrames.java.
|
||||
target_compile_definitions(${test} PRIVATE MOBILEGL_SOURCE_ROOT="${MGL_ROOT}")
|
||||
endif ()
|
||||
|
||||
if (test STREQUAL "ServerSpawnTest" OR test STREQUAL "PeerLatchTest" OR test STREQUAL "InProcessServerTest" OR
|
||||
test STREQUAL "ServerOwnedSurfaceTest" OR test STREQUAL "AdoptTierStreamTest")
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#include <vector>
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <MG_Remote/Transport/Framing.h>
|
||||
#include <MG_Remote/Transport/PairBind.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
@@ -1388,8 +1389,135 @@ namespace {
|
||||
return "fd:" + std::to_string(control) + "," + std::to_string(aux);
|
||||
}
|
||||
|
||||
// ---- ID-P11-12: the broker's hand-off PairBinds, byte for byte ---------------------------------
|
||||
//
|
||||
// The server app's broker (Java) writes the PairBind pair itself, from two prefixes in
|
||||
// PairBindFrames.java. These read them out of that source file, so the tests below send exactly
|
||||
// what the broker sends - and the template test pins them to the native encoder.
|
||||
std::string ReadJavaHexConstant(const std::string& source, const char* name) {
|
||||
const auto at = source.find(std::string(name) + " =");
|
||||
if (at == std::string::npos) return {};
|
||||
const auto open = source.find('"', at);
|
||||
const auto close = open == std::string::npos ? open : source.find('"', open + 1);
|
||||
if (close == std::string::npos) return {};
|
||||
return source.substr(open + 1, close - open - 1);
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> HexBytes(const std::string& hex) {
|
||||
std::vector<std::uint8_t> out;
|
||||
for (std::size_t i = 0; i + 1 < hex.size(); i += 2) {
|
||||
out.push_back(static_cast<std::uint8_t>(std::stoul(hex.substr(i, 2), nullptr, 16)));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
struct BrokerTemplates {
|
||||
std::vector<std::uint8_t> control;
|
||||
std::vector<std::uint8_t> aux;
|
||||
};
|
||||
|
||||
BrokerTemplates LoadBrokerTemplates() {
|
||||
const std::string path = std::string(MOBILEGL_SOURCE_ROOT) +
|
||||
"/android-plugin/app/src/main/java/top/mobilegl/plugin/PairBindFrames.java";
|
||||
std::ifstream file(path);
|
||||
const std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||
return {HexBytes(ReadJavaHexConstant(source, "CONTROL_PREFIX_HEX")),
|
||||
HexBytes(ReadJavaHexConstant(source, "AUX_PREFIX_HEX"))};
|
||||
}
|
||||
|
||||
// PairBindFrames.frame(nonce, aux), in C++: header (magic, length) + prefix + nonce.
|
||||
std::vector<std::uint8_t> BrokerFrame(const BrokerTemplates& templates, const std::uint8_t (&nonce)[16], bool aux) {
|
||||
const auto& prefix = aux ? templates.aux : templates.control;
|
||||
std::vector<std::uint8_t> payload(prefix);
|
||||
payload.insert(payload.end(), nonce, nonce + 16);
|
||||
std::vector<std::uint8_t> framed;
|
||||
(void)Transport::AppendFrame(framed, payload.data(), payload.size());
|
||||
return framed;
|
||||
}
|
||||
|
||||
bool WriteAll(int fd, const std::vector<std::uint8_t>& bytes) {
|
||||
std::size_t done = 0;
|
||||
while (done < bytes.size()) {
|
||||
const ssize_t n = ::send(fd, bytes.data() + done, bytes.size() - done, MSG_NOSIGNAL);
|
||||
if (n <= 0) return false;
|
||||
done += static_cast<std::size_t>(n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(ServerSpawnTest, TheBrokersPairBindTemplatesAreTheEncoders) {
|
||||
// The broker cannot link the flatbuffers encoder; its bytes are the encoder's up to the nonce, and
|
||||
// this is what keeps them so. A schema change that moves one byte of a PairBind turns this red.
|
||||
const auto templates = LoadBrokerTemplates();
|
||||
ASSERT_FALSE(templates.control.empty()) << "CONTROL_PREFIX_HEX not found in PairBindFrames.java";
|
||||
ASSERT_FALSE(templates.aux.empty()) << "AUX_PREFIX_HEX not found in PairBindFrames.java";
|
||||
std::uint8_t nonce[Transport::kPairNonceBytes];
|
||||
for (int round = 0; round < 32; ++round) {
|
||||
ASSERT_EQ(Transport::SocketTransport::MintNonce(nonce, sizeof(nonce)), MOBILEGL_OK);
|
||||
for (const bool aux : {false, true}) {
|
||||
const auto encoded = Transport::EncodePairBind(nonce, aux);
|
||||
std::vector<std::uint8_t> expected;
|
||||
ASSERT_EQ(Transport::AppendFrame(expected, encoded.data(), encoded.size()), MOBILEGL_OK);
|
||||
EXPECT_EQ(BrokerFrame(templates, nonce, aux), expected) << (aux ? "aux" : "control") << " round " << round;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ServerSpawnTest, APairTheBrokerPresentedAtHandoffWaitsForAHelloThatComesSecondsLater) {
|
||||
// ID-P11-12 end to end: the broker connects AND presents the PairBind pair at hand-off; the
|
||||
// program it was for starts slowly (assets first) and says Hello five seconds later - past the
|
||||
// 2000 ms pairing budget, which the broker's PairBinds already met. The paired session waits for that
|
||||
// Hello (until EOF, ServerMain.cpp kPairedUnixHelloWaitMs) and comes up; the program, told by the
|
||||
// helper's MOBILEGL_IPC_FD_PAIRED=1, does not present a second pair.
|
||||
const auto templates = LoadBrokerTemplates();
|
||||
ASSERT_FALSE(templates.control.empty());
|
||||
const std::string endpoint = Endpoint("handoff");
|
||||
Session session;
|
||||
ASSERT_EQ(Server::LaunchServer(ServerImage(), endpoint, &session.server), MOBILEGL_OK);
|
||||
ScopedSessionCleanup cleanup{session};
|
||||
int control = -1, aux = -1;
|
||||
ASSERT_TRUE(BrokerConnectsTwice(endpoint, &control, &aux)) << "the server never listened on " << endpoint;
|
||||
std::uint8_t nonce[Transport::kPairNonceBytes];
|
||||
ASSERT_EQ(Transport::SocketTransport::MintNonce(nonce, sizeof(nonce)), MOBILEGL_OK);
|
||||
ASSERT_TRUE(WriteAll(control, BrokerFrame(templates, nonce, false)));
|
||||
ASSERT_TRUE(WriteAll(aux, BrokerFrame(templates, nonce, true)));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5)); // the program loading its assets
|
||||
const ScopedEnvironment paired("MOBILEGL_IPC_FD_PAIRED", "1");
|
||||
const ScopedIpcEndpoint configured(FdSpec(control, aux), "auto");
|
||||
ASSERT_EQ(Client::ClientSessionInstance().StartSpawned(), MOBILEGL_OK)
|
||||
<< "a pair presented at hand-off did not become a session when its Hello came 5 s later";
|
||||
EXPECT_TRUE(Client::ClientSession::Active() != nullptr);
|
||||
Client::ClientSessionInstance().Stop();
|
||||
int exitCode = -1;
|
||||
ASSERT_EQ(Server::ReapServer(session.server, 5000, &exitCode), MOBILEGL_OK);
|
||||
EXPECT_EQ(exitCode, 0);
|
||||
session.server.pid = -1;
|
||||
}
|
||||
|
||||
TEST(ServerSpawnTest, APairPresentedOnlyWhenTheProgramStartsIsRefusedByNameOnceThePairingBudgetIsGone) {
|
||||
// Why the broker presents the pair: the flow before ID-P11-12's follow-up - the broker connects and
|
||||
// writes nothing, the program presents the PairBinds only when it reaches its first EGL call - is
|
||||
// refused by the server's PairAcceptor once 2000 ms have passed since the connect, and the program
|
||||
// hears it by name rather than hanging.
|
||||
const std::string endpoint = Endpoint("latepair");
|
||||
Session session;
|
||||
ASSERT_EQ(Server::LaunchServer(ServerImage(), endpoint, &session.server), MOBILEGL_OK);
|
||||
ScopedSessionCleanup cleanup{session};
|
||||
int control = -1, aux = -1;
|
||||
ASSERT_TRUE(BrokerConnectsTwice(endpoint, &control, &aux));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
|
||||
const ScopedIpcEndpoint configured(FdSpec(control, aux), "auto");
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
EXPECT_NE(Client::ClientSessionInstance().StartSpawned(), MOBILEGL_OK)
|
||||
<< "a pair presented after the pairing budget became a session";
|
||||
EXPECT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count(),
|
||||
4000)
|
||||
<< "the refusal must be answered, not waited out";
|
||||
EXPECT_TRUE(Client::ClientSession::Active() == nullptr);
|
||||
}
|
||||
|
||||
TEST(ServerSpawnTest, AnFdPairTheBrokerConnectedBringsASharedSegmentSessionUp) {
|
||||
// THE B1 CLIENT PATH END TO END against a real server process: the pair was connected by
|
||||
// somebody else, the client adopts it, presents its own PairBind pair (the server's
|
||||
|
||||
Reference in New Issue
Block a user