RemoteObjectLayerTest.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. //===---------------------- RemoteObjectLayerTest.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-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
  9. #include "llvm/ExecutionEngine/Orc/NullResolver.h"
  10. #include "llvm/ExecutionEngine/Orc/RemoteObjectLayer.h"
  11. #include "OrcTestCommon.h"
  12. #include "QueueChannel.h"
  13. #include "gtest/gtest.h"
  14. using namespace llvm;
  15. using namespace llvm::orc;
  16. namespace {
  17. class MockObjectLayer {
  18. public:
  19. using ObjHandleT = uint64_t;
  20. using ObjectPtr = std::unique_ptr<MemoryBuffer>;
  21. using LookupFn = std::function<JITSymbol(StringRef, bool)>;
  22. using SymbolLookupTable = std::map<ObjHandleT, LookupFn>;
  23. using AddObjectFtor =
  24. std::function<Expected<ObjHandleT>(ObjectPtr, SymbolLookupTable&)>;
  25. class ObjectNotFound : public remote::ResourceNotFound<ObjHandleT> {
  26. public:
  27. ObjectNotFound(ObjHandleT H) : ResourceNotFound(H, "Object handle") {}
  28. };
  29. MockObjectLayer(AddObjectFtor AddObject)
  30. : AddObject(std::move(AddObject)) {}
  31. Expected<ObjHandleT> addObject(ObjectPtr Obj,
  32. std::shared_ptr<JITSymbolResolver> Resolver) {
  33. return AddObject(std::move(Obj), SymTab);
  34. }
  35. Error removeObject(ObjHandleT H) {
  36. if (SymTab.count(H))
  37. return Error::success();
  38. else
  39. return make_error<ObjectNotFound>(H);
  40. }
  41. JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
  42. for (auto KV : SymTab) {
  43. if (auto Sym = KV.second(Name, ExportedSymbolsOnly))
  44. return Sym;
  45. else if (auto Err = Sym.takeError())
  46. return std::move(Err);
  47. }
  48. return JITSymbol(nullptr);
  49. }
  50. JITSymbol findSymbolIn(ObjHandleT H, StringRef Name,
  51. bool ExportedSymbolsOnly) {
  52. auto LI = SymTab.find(H);
  53. if (LI != SymTab.end())
  54. return LI->second(Name, ExportedSymbolsOnly);
  55. else
  56. return make_error<ObjectNotFound>(H);
  57. }
  58. Error emitAndFinalize(ObjHandleT H) {
  59. if (SymTab.count(H))
  60. return Error::success();
  61. else
  62. return make_error<ObjectNotFound>(H);
  63. }
  64. private:
  65. AddObjectFtor AddObject;
  66. SymbolLookupTable SymTab;
  67. };
  68. using RPCEndpoint = rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>;
  69. MockObjectLayer::ObjectPtr createTestObject() {
  70. OrcNativeTarget::initialize();
  71. auto TM = std::unique_ptr<TargetMachine>(EngineBuilder().selectTarget());
  72. if (!TM)
  73. return nullptr;
  74. LLVMContext Ctx;
  75. ModuleBuilder MB(Ctx, TM->getTargetTriple().str(), "TestModule");
  76. MB.getModule()->setDataLayout(TM->createDataLayout());
  77. auto *Main = MB.createFunctionDecl(
  78. FunctionType::get(Type::getInt32Ty(Ctx),
  79. {Type::getInt32Ty(Ctx),
  80. Type::getInt8PtrTy(Ctx)->getPointerTo()},
  81. false),
  82. "main");
  83. Main->getBasicBlockList().push_back(BasicBlock::Create(Ctx));
  84. IRBuilder<> B(&Main->back());
  85. B.CreateRet(ConstantInt::getSigned(Type::getInt32Ty(Ctx), 42));
  86. SimpleCompiler IRCompiler(*TM);
  87. return IRCompiler(*MB.getModule());
  88. }
  89. TEST(RemoteObjectLayer, AddObject) {
  90. llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
  91. auto TestObject = createTestObject();
  92. if (!TestObject)
  93. return;
  94. auto Channels = createPairedQueueChannels();
  95. auto ReportError = [](Error Err) {
  96. logAllUnhandledErrors(std::move(Err), llvm::errs());
  97. };
  98. // Copy the bytes out of the test object: the copy will be used to verify
  99. // that the original is correctly transmitted over RPC to the mock layer.
  100. StringRef ObjBytes = TestObject->getBuffer();
  101. std::vector<char> ObjContents(ObjBytes.size());
  102. std::copy(ObjBytes.begin(), ObjBytes.end(), ObjContents.begin());
  103. RPCEndpoint ClientEP(*Channels.first, true);
  104. RemoteObjectClientLayer<RPCEndpoint> Client(AcknowledgeORCv1Deprecation,
  105. ClientEP, ReportError);
  106. RPCEndpoint ServerEP(*Channels.second, true);
  107. MockObjectLayer BaseLayer(
  108. [&ObjContents](MockObjectLayer::ObjectPtr Obj,
  109. MockObjectLayer::SymbolLookupTable &SymTab) {
  110. // Check that the received object file content matches the original.
  111. StringRef RPCObjContents = Obj->getBuffer();
  112. EXPECT_EQ(RPCObjContents.size(), ObjContents.size())
  113. << "RPC'd object file has incorrect size";
  114. EXPECT_TRUE(std::equal(RPCObjContents.begin(), RPCObjContents.end(),
  115. ObjContents.begin()))
  116. << "RPC'd object file content does not match original content";
  117. return 1;
  118. });
  119. RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(
  120. AcknowledgeORCv1Deprecation, BaseLayer, ServerEP, ReportError);
  121. bool Finished = false;
  122. ServerEP.addHandler<remote::utils::TerminateSession>(
  123. [&]() { Finished = true; }
  124. );
  125. auto ServerThread =
  126. std::thread([&]() {
  127. while (!Finished)
  128. cantFail(ServerEP.handleOne());
  129. });
  130. cantFail(Client.addObject(std::move(TestObject),
  131. std::make_shared<NullLegacyResolver>()));
  132. cantFail(ClientEP.callB<remote::utils::TerminateSession>());
  133. ServerThread.join();
  134. }
  135. TEST(RemoteObjectLayer, AddObjectFailure) {
  136. llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
  137. auto TestObject = createTestObject();
  138. if (!TestObject)
  139. return;
  140. auto Channels = createPairedQueueChannels();
  141. auto ReportError =
  142. [](Error Err) {
  143. auto ErrMsg = toString(std::move(Err));
  144. EXPECT_EQ(ErrMsg, "AddObjectFailure - Test Message")
  145. << "Expected error string to be \"AddObjectFailure - Test Message\"";
  146. };
  147. RPCEndpoint ClientEP(*Channels.first, true);
  148. RemoteObjectClientLayer<RPCEndpoint> Client(AcknowledgeORCv1Deprecation,
  149. ClientEP, ReportError);
  150. RPCEndpoint ServerEP(*Channels.second, true);
  151. MockObjectLayer BaseLayer(
  152. [](MockObjectLayer::ObjectPtr Obj,
  153. MockObjectLayer::SymbolLookupTable &SymTab)
  154. -> Expected<MockObjectLayer::ObjHandleT> {
  155. return make_error<StringError>("AddObjectFailure - Test Message",
  156. inconvertibleErrorCode());
  157. });
  158. RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(
  159. AcknowledgeORCv1Deprecation, BaseLayer, ServerEP, ReportError);
  160. bool Finished = false;
  161. ServerEP.addHandler<remote::utils::TerminateSession>(
  162. [&]() { Finished = true; }
  163. );
  164. auto ServerThread =
  165. std::thread([&]() {
  166. while (!Finished)
  167. cantFail(ServerEP.handleOne());
  168. });
  169. auto HandleOrErr = Client.addObject(std::move(TestObject),
  170. std::make_shared<NullLegacyResolver>());
  171. EXPECT_FALSE(HandleOrErr) << "Expected error from addObject";
  172. auto ErrMsg = toString(HandleOrErr.takeError());
  173. EXPECT_EQ(ErrMsg, "AddObjectFailure - Test Message")
  174. << "Expected error string to be \"AddObjectFailure - Test Message\"";
  175. cantFail(ClientEP.callB<remote::utils::TerminateSession>());
  176. ServerThread.join();
  177. }
  178. TEST(RemoteObjectLayer, RemoveObject) {
  179. llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
  180. auto TestObject = createTestObject();
  181. if (!TestObject)
  182. return;
  183. auto Channels = createPairedQueueChannels();
  184. auto ReportError = [](Error Err) {
  185. logAllUnhandledErrors(std::move(Err), llvm::errs());
  186. };
  187. RPCEndpoint ClientEP(*Channels.first, true);
  188. RemoteObjectClientLayer<RPCEndpoint> Client(AcknowledgeORCv1Deprecation,
  189. ClientEP, ReportError);
  190. RPCEndpoint ServerEP(*Channels.second, true);
  191. MockObjectLayer BaseLayer(
  192. [](MockObjectLayer::ObjectPtr Obj,
  193. MockObjectLayer::SymbolLookupTable &SymTab) {
  194. SymTab[1] = MockObjectLayer::LookupFn();
  195. return 1;
  196. });
  197. RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(
  198. AcknowledgeORCv1Deprecation, BaseLayer, ServerEP, ReportError);
  199. bool Finished = false;
  200. ServerEP.addHandler<remote::utils::TerminateSession>(
  201. [&]() { Finished = true; }
  202. );
  203. auto ServerThread =
  204. std::thread([&]() {
  205. while (!Finished)
  206. cantFail(ServerEP.handleOne());
  207. });
  208. auto H = cantFail(Client.addObject(std::move(TestObject),
  209. std::make_shared<NullLegacyResolver>()));
  210. cantFail(Client.removeObject(H));
  211. cantFail(ClientEP.callB<remote::utils::TerminateSession>());
  212. ServerThread.join();
  213. }
  214. TEST(RemoteObjectLayer, RemoveObjectFailure) {
  215. llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
  216. auto TestObject = createTestObject();
  217. if (!TestObject)
  218. return;
  219. auto Channels = createPairedQueueChannels();
  220. auto ReportError =
  221. [](Error Err) {
  222. auto ErrMsg = toString(std::move(Err));
  223. EXPECT_EQ(ErrMsg, "Object handle 42 not found")
  224. << "Expected error string to be \"Object handle 42 not found\"";
  225. };
  226. RPCEndpoint ClientEP(*Channels.first, true);
  227. RemoteObjectClientLayer<RPCEndpoint> Client(AcknowledgeORCv1Deprecation,
  228. ClientEP, ReportError);
  229. RPCEndpoint ServerEP(*Channels.second, true);
  230. // AddObject lambda does not update symbol table, so removeObject will treat
  231. // this as a bad object handle.
  232. MockObjectLayer BaseLayer(
  233. [](MockObjectLayer::ObjectPtr Obj,
  234. MockObjectLayer::SymbolLookupTable &SymTab) {
  235. return 42;
  236. });
  237. RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(
  238. AcknowledgeORCv1Deprecation, BaseLayer, ServerEP, ReportError);
  239. bool Finished = false;
  240. ServerEP.addHandler<remote::utils::TerminateSession>(
  241. [&]() { Finished = true; }
  242. );
  243. auto ServerThread =
  244. std::thread([&]() {
  245. while (!Finished)
  246. cantFail(ServerEP.handleOne());
  247. });
  248. auto H = cantFail(Client.addObject(std::move(TestObject),
  249. std::make_shared<NullLegacyResolver>()));
  250. auto Err = Client.removeObject(H);
  251. EXPECT_TRUE(!!Err) << "Expected error from removeObject";
  252. auto ErrMsg = toString(std::move(Err));
  253. EXPECT_EQ(ErrMsg, "Object handle 42 not found")
  254. << "Expected error string to be \"Object handle 42 not found\"";
  255. cantFail(ClientEP.callB<remote::utils::TerminateSession>());
  256. ServerThread.join();
  257. }
  258. TEST(RemoteObjectLayer, FindSymbol) {
  259. llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
  260. auto TestObject = createTestObject();
  261. if (!TestObject)
  262. return;
  263. auto Channels = createPairedQueueChannels();
  264. auto ReportError =
  265. [](Error Err) {
  266. auto ErrMsg = toString(std::move(Err));
  267. EXPECT_EQ(ErrMsg, "Could not find symbol 'badsymbol'")
  268. << "Expected error string to be \"Object handle 42 not found\"";
  269. };
  270. RPCEndpoint ClientEP(*Channels.first, true);
  271. RemoteObjectClientLayer<RPCEndpoint> Client(AcknowledgeORCv1Deprecation,
  272. ClientEP, ReportError);
  273. RPCEndpoint ServerEP(*Channels.second, true);
  274. // AddObject lambda does not update symbol table, so removeObject will treat
  275. // this as a bad object handle.
  276. MockObjectLayer BaseLayer(
  277. [](MockObjectLayer::ObjectPtr Obj,
  278. MockObjectLayer::SymbolLookupTable &SymTab) {
  279. SymTab[42] =
  280. [](StringRef Name, bool ExportedSymbolsOnly) -> JITSymbol {
  281. if (Name == "foobar")
  282. return JITSymbol(0x12348765, JITSymbolFlags::Exported);
  283. if (Name == "badsymbol")
  284. return make_error<JITSymbolNotFound>(Name);
  285. return nullptr;
  286. };
  287. return 42;
  288. });
  289. RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(
  290. AcknowledgeORCv1Deprecation, BaseLayer, ServerEP, ReportError);
  291. bool Finished = false;
  292. ServerEP.addHandler<remote::utils::TerminateSession>(
  293. [&]() { Finished = true; }
  294. );
  295. auto ServerThread =
  296. std::thread([&]() {
  297. while (!Finished)
  298. cantFail(ServerEP.handleOne());
  299. });
  300. cantFail(Client.addObject(std::move(TestObject),
  301. std::make_shared<NullLegacyResolver>()));
  302. // Check that we can find and materialize a valid symbol.
  303. auto Sym1 = Client.findSymbol("foobar", true);
  304. EXPECT_TRUE(!!Sym1) << "Symbol 'foobar' should be findable";
  305. EXPECT_EQ(cantFail(Sym1.getAddress()), 0x12348765ULL)
  306. << "Symbol 'foobar' does not return the correct address";
  307. {
  308. // Check that we can return a symbol containing an error.
  309. auto Sym2 = Client.findSymbol("badsymbol", true);
  310. EXPECT_FALSE(!!Sym2) << "Symbol 'badsymbol' should not be findable";
  311. auto Err = Sym2.takeError();
  312. EXPECT_TRUE(!!Err) << "Sym2 should contain an error value";
  313. auto ErrMsg = toString(std::move(Err));
  314. EXPECT_EQ(ErrMsg, "Could not find symbol 'badsymbol'")
  315. << "Expected symbol-not-found error for Sym2";
  316. }
  317. {
  318. // Check that we can return a 'null' symbol.
  319. auto Sym3 = Client.findSymbol("baz", true);
  320. EXPECT_FALSE(!!Sym3) << "Symbol 'baz' should convert to false";
  321. auto Err = Sym3.takeError();
  322. EXPECT_FALSE(!!Err) << "Symbol 'baz' should not contain an error";
  323. }
  324. cantFail(ClientEP.callB<remote::utils::TerminateSession>());
  325. ServerThread.join();
  326. }
  327. TEST(RemoteObjectLayer, FindSymbolIn) {
  328. llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
  329. auto TestObject = createTestObject();
  330. if (!TestObject)
  331. return;
  332. auto Channels = createPairedQueueChannels();
  333. auto ReportError =
  334. [](Error Err) {
  335. auto ErrMsg = toString(std::move(Err));
  336. EXPECT_EQ(ErrMsg, "Could not find symbol 'barbaz'")
  337. << "Expected error string to be \"Object handle 42 not found\"";
  338. };
  339. RPCEndpoint ClientEP(*Channels.first, true);
  340. RemoteObjectClientLayer<RPCEndpoint> Client(AcknowledgeORCv1Deprecation,
  341. ClientEP, ReportError);
  342. RPCEndpoint ServerEP(*Channels.second, true);
  343. // AddObject lambda does not update symbol table, so removeObject will treat
  344. // this as a bad object handle.
  345. MockObjectLayer BaseLayer(
  346. [](MockObjectLayer::ObjectPtr Obj,
  347. MockObjectLayer::SymbolLookupTable &SymTab) {
  348. SymTab[42] =
  349. [](StringRef Name, bool ExportedSymbolsOnly) -> JITSymbol {
  350. if (Name == "foobar")
  351. return JITSymbol(0x12348765, JITSymbolFlags::Exported);
  352. return make_error<JITSymbolNotFound>(Name);
  353. };
  354. // Dummy symbol table entry - this should not be visible to
  355. // findSymbolIn.
  356. SymTab[43] =
  357. [](StringRef Name, bool ExportedSymbolsOnly) -> JITSymbol {
  358. if (Name == "barbaz")
  359. return JITSymbol(0xdeadbeef, JITSymbolFlags::Exported);
  360. return make_error<JITSymbolNotFound>(Name);
  361. };
  362. return 42;
  363. });
  364. RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(
  365. AcknowledgeORCv1Deprecation, BaseLayer, ServerEP, ReportError);
  366. bool Finished = false;
  367. ServerEP.addHandler<remote::utils::TerminateSession>(
  368. [&]() { Finished = true; }
  369. );
  370. auto ServerThread =
  371. std::thread([&]() {
  372. while (!Finished)
  373. cantFail(ServerEP.handleOne());
  374. });
  375. auto H = cantFail(Client.addObject(std::move(TestObject),
  376. std::make_shared<NullLegacyResolver>()));
  377. auto Sym1 = Client.findSymbolIn(H, "foobar", true);
  378. EXPECT_TRUE(!!Sym1) << "Symbol 'foobar' should be findable";
  379. EXPECT_EQ(cantFail(Sym1.getAddress()), 0x12348765ULL)
  380. << "Symbol 'foobar' does not return the correct address";
  381. auto Sym2 = Client.findSymbolIn(H, "barbaz", true);
  382. EXPECT_FALSE(!!Sym2) << "Symbol 'barbaz' should not be findable";
  383. auto Err = Sym2.takeError();
  384. EXPECT_TRUE(!!Err) << "Sym2 should contain an error value";
  385. auto ErrMsg = toString(std::move(Err));
  386. EXPECT_EQ(ErrMsg, "Could not find symbol 'barbaz'")
  387. << "Expected symbol-not-found error for Sym2";
  388. cantFail(ClientEP.callB<remote::utils::TerminateSession>());
  389. ServerThread.join();
  390. }
  391. TEST(RemoteObjectLayer, EmitAndFinalize) {
  392. llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
  393. auto TestObject = createTestObject();
  394. if (!TestObject)
  395. return;
  396. auto Channels = createPairedQueueChannels();
  397. auto ReportError = [](Error Err) {
  398. logAllUnhandledErrors(std::move(Err), llvm::errs());
  399. };
  400. RPCEndpoint ClientEP(*Channels.first, true);
  401. RemoteObjectClientLayer<RPCEndpoint> Client(AcknowledgeORCv1Deprecation,
  402. ClientEP, ReportError);
  403. RPCEndpoint ServerEP(*Channels.second, true);
  404. MockObjectLayer BaseLayer(
  405. [](MockObjectLayer::ObjectPtr Obj,
  406. MockObjectLayer::SymbolLookupTable &SymTab) {
  407. SymTab[1] = MockObjectLayer::LookupFn();
  408. return 1;
  409. });
  410. RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(
  411. AcknowledgeORCv1Deprecation, BaseLayer, ServerEP, ReportError);
  412. bool Finished = false;
  413. ServerEP.addHandler<remote::utils::TerminateSession>(
  414. [&]() { Finished = true; }
  415. );
  416. auto ServerThread =
  417. std::thread([&]() {
  418. while (!Finished)
  419. cantFail(ServerEP.handleOne());
  420. });
  421. auto H = cantFail(Client.addObject(std::move(TestObject),
  422. std::make_shared<NullLegacyResolver>()));
  423. auto Err = Client.emitAndFinalize(H);
  424. EXPECT_FALSE(!!Err) << "emitAndFinalize should work";
  425. cantFail(ClientEP.callB<remote::utils::TerminateSession>());
  426. ServerThread.join();
  427. }
  428. TEST(RemoteObjectLayer, EmitAndFinalizeFailure) {
  429. llvm::orc::rpc::registerStringError<rpc::RawByteChannel>();
  430. auto TestObject = createTestObject();
  431. if (!TestObject)
  432. return;
  433. auto Channels = createPairedQueueChannels();
  434. auto ReportError =
  435. [](Error Err) {
  436. auto ErrMsg = toString(std::move(Err));
  437. EXPECT_EQ(ErrMsg, "Object handle 1 not found")
  438. << "Expected bad handle error";
  439. };
  440. RPCEndpoint ClientEP(*Channels.first, true);
  441. RemoteObjectClientLayer<RPCEndpoint> Client(AcknowledgeORCv1Deprecation,
  442. ClientEP, ReportError);
  443. RPCEndpoint ServerEP(*Channels.second, true);
  444. MockObjectLayer BaseLayer(
  445. [](MockObjectLayer::ObjectPtr Obj,
  446. MockObjectLayer::SymbolLookupTable &SymTab) {
  447. return 1;
  448. });
  449. RemoteObjectServerLayer<MockObjectLayer, RPCEndpoint> Server(
  450. AcknowledgeORCv1Deprecation, BaseLayer, ServerEP, ReportError);
  451. bool Finished = false;
  452. ServerEP.addHandler<remote::utils::TerminateSession>(
  453. [&]() { Finished = true; }
  454. );
  455. auto ServerThread =
  456. std::thread([&]() {
  457. while (!Finished)
  458. cantFail(ServerEP.handleOne());
  459. });
  460. auto H = cantFail(Client.addObject(std::move(TestObject),
  461. std::make_shared<NullLegacyResolver>()));
  462. auto Err = Client.emitAndFinalize(H);
  463. EXPECT_TRUE(!!Err) << "emitAndFinalize should work";
  464. auto ErrMsg = toString(std::move(Err));
  465. EXPECT_EQ(ErrMsg, "Object handle 1 not found")
  466. << "emitAndFinalize returned incorrect error";
  467. cantFail(ClientEP.callB<remote::utils::TerminateSession>());
  468. ServerThread.join();
  469. }
  470. }