@@ -65,15 +65,22 @@ class ClientConnectionTest : public ::testing::Test
6565 engine_.reset ();
6666 }
6767
68- void CatchImmediateConnectEndpointRegistrationCommand ()
68+ void CatchImmediateConnectCommand ()
6969 {
7070 EXPECT_CALL (*engine_, EnqueueCommand (_, ISharedResourceEngine::TimePoint{}, _, _))
7171 .WillOnce ([&](auto &, auto , ISharedResourceEngine::CommandCallback callback, auto ) {
72- // reusing the connect callback in case ow queued endpoint registration
7372 connect_command_callback_ = std::move (callback);
7473 });
7574 }
7675
76+ void CatchEndpointRegistrationCommand ()
77+ {
78+ EXPECT_CALL (*engine_, EnqueueCommand (_, ISharedResourceEngine::TimePoint{}, _, _))
79+ .WillOnce ([&](auto &, auto , ISharedResourceEngine::CommandCallback callback, auto ) {
80+ endpoint_command_callback_ = std::move (callback);
81+ });
82+ }
83+
7784 void CatchTimedConnectCommand ()
7885 {
7986 EXPECT_CALL (*engine_, EnqueueCommand (_, Gt (ISharedResourceEngine::Clock::now ()), _, _))
@@ -126,6 +133,17 @@ class ClientConnectionTest : public ::testing::Test
126133 on_callback_thread_ = false ;
127134 }
128135
136+ void InvokeEndpointRegistrationCommand ()
137+ {
138+ on_callback_thread_ = true ;
139+ {
140+ auto callback = std::move (endpoint_command_callback_);
141+ callback (ISharedResourceEngine::Clock::now ());
142+ // the destructor for callback capture, if any, is called now
143+ }
144+ on_callback_thread_ = false ;
145+ }
146+
129147 void InvokeDisconnectCommand ()
130148 {
131149 on_callback_thread_ = true ;
@@ -200,13 +218,26 @@ class ClientConnectionTest : public ::testing::Test
200218 IClientConnection::StateCallback state_callback = {},
201219 IClientConnection::NotifyCallback notify_callback = {})
202220 {
203- AtTryOpenCall_Return (kValidFd );
204- CatchImmediateConnectEndpointRegistrationCommand ();
221+ if (client_config_.sync_first_connect )
222+ {
223+ AtTryOpenCall_Return (kValidFd );
224+ CatchEndpointRegistrationCommand ();
205225
206- connection.Start (std::move (state_callback), std::move (notify_callback));
226+ connection.Start (std::move (state_callback), std::move (notify_callback));
207227
208- CatchPosixEndpointRegistration ();
209- InvokeConnectCommand ();
228+ CatchPosixEndpointRegistration ();
229+ InvokeEndpointRegistrationCommand ();
230+ }
231+ else
232+ {
233+ CatchImmediateConnectCommand ();
234+ connection.Start (std::move (state_callback), std::move (notify_callback));
235+ EXPECT_EQ (connection.GetState (), State::kStarting );
236+
237+ AtTryOpenCall_Return (kValidFd );
238+ CatchPosixEndpointRegistration ();
239+ InvokeConnectCommand ();
240+ }
210241
211242 EXPECT_EQ (connection.GetState (), State::kReady );
212243 EXPECT_EQ (posix_endpoint_->fd , kValidFd );
@@ -216,12 +247,20 @@ class ClientConnectionTest : public ::testing::Test
216247
217248 void StopConnectionInProgress (detail::ClientConnection& connection)
218249 {
219- CatchDisconnectCommand ();
220- connection.Stop ();
221- EXPECT_EQ (connection.GetState (), State::kStopping );
222- EXPECT_EQ (connection.GetStopReason (), StopReason::kUserRequested );
250+ if (client_config_.sync_first_connect )
251+ {
252+ // for the immediate stop on the user thread
253+ CatchDisconnectCommand ();
254+ connection.Stop ();
255+ EXPECT_EQ (connection.GetState (), State::kStopping );
256+ EXPECT_EQ (connection.GetStopReason (), StopReason::kUserRequested );
223257
224- InvokeDisconnectCommand ();
258+ InvokeDisconnectCommand ();
259+ }
260+ else
261+ {
262+ connection.Stop ();
263+ }
225264 EXPECT_EQ (connection.GetState (), State::kStopped );
226265 EXPECT_EQ (connection.GetStopReason (), StopReason::kUserRequested );
227266 }
@@ -259,8 +298,9 @@ class ClientConnectionTest : public ::testing::Test
259298 std::shared_ptr<StrictMock<SharedResourceEngineMock>> engine_{};
260299 const std::string service_identifier_{" test_identifier" };
261300 const ServiceProtocolConfig protocol_config_{service_identifier_, kMaxSendSize , kMaxReplySize , kMaxNotifySize };
262- IClientFactory::ClientConfig client_config_{0 , 1 , false , false };
301+ IClientFactory::ClientConfig client_config_{0 , 1 , false , false , false };
263302 ISharedResourceEngine::CommandCallback connect_command_callback_{};
303+ ISharedResourceEngine::CommandCallback endpoint_command_callback_{};
264304 ISharedResourceEngine::CommandCallback disconnect_command_callback_{};
265305 ISharedResourceEngine::CommandCallback send_queue_command_callback_{};
266306 ISharedResourceEngine::PosixEndpointEntry* posix_endpoint_{};
@@ -287,6 +327,27 @@ TEST_F(ClientConnectionTest, TryingToConnectOnceStoppingWhileConnecting)
287327{
288328 detail::ClientConnection connection (engine_, protocol_config_, client_config_);
289329
330+ CatchImmediateConnectCommand ();
331+ connection.Start (IClientConnection::StateCallback (), IClientConnection::NotifyCallback ());
332+ EXPECT_EQ (connection.GetState (), State::kStarting );
333+
334+ EXPECT_CALL (*engine_, TryOpenClientConnection (std::string_view{service_identifier_}))
335+ .WillOnce ([this , &connection](auto &&) {
336+ StopConnectionInProgress (connection);
337+ return score::cpp::make_unexpected (score::os::Error::createFromErrno (EIO)); // this error code would be ignored
338+ });
339+ ExpectCleanUpOwner (connection);
340+ InvokeConnectCommand ();
341+
342+ EXPECT_EQ (connection.GetState (), State::kStopped );
343+ EXPECT_EQ (connection.GetStopReason (), StopReason::kUserRequested );
344+ }
345+
346+ TEST_F (ClientConnectionTest, TryingToSyncConnectOnceStoppingWhileConnecting)
347+ {
348+ client_config_.sync_first_connect = true ;
349+ detail::ClientConnection connection (engine_, protocol_config_, client_config_);
350+
290351 EXPECT_CALL (*engine_, TryOpenClientConnection (std::string_view{service_identifier_}))
291352 .WillOnce ([this , &connection](auto &&) {
292353 StopConnectionInProgress (connection);
@@ -301,6 +362,30 @@ TEST_F(ClientConnectionTest, TryingToConnectOnceStoppingWhileConnecting)
301362
302363TEST_F (ClientConnectionTest, TryingToConnectOnceStoppingOnHardError)
303364{
365+ const auto error_list_to_test = {std::make_pair (EACCES, StopReason::kPermission ),
366+ std::make_pair (EPIPE, StopReason::kIoError )};
367+
368+ for (auto entry : error_list_to_test)
369+ {
370+ detail::ClientConnection connection (engine_, protocol_config_, client_config_);
371+
372+ CatchImmediateConnectCommand ();
373+ connection.Start (IClientConnection::StateCallback (), IClientConnection::NotifyCallback ());
374+ EXPECT_EQ (connection.GetState (), State::kStarting );
375+
376+ AtTryOpenCall_Return (score::cpp::make_unexpected (score::os::Error::createFromErrno (entry.first )));
377+ ExpectCleanUpOwner (connection);
378+ InvokeConnectCommand ();
379+
380+ EXPECT_EQ (connection.GetState (), State::kStopped );
381+ EXPECT_EQ (connection.GetStopReason (), entry.second );
382+ }
383+ }
384+
385+ TEST_F (ClientConnectionTest, TryingToSyncConnectOnceStoppingOnHardError)
386+ {
387+ client_config_.sync_first_connect = true ;
388+
304389 const auto error_list_to_test = {std::make_pair (EACCES, StopReason::kPermission ),
305390 std::make_pair (EPIPE, StopReason::kIoError )};
306391
@@ -323,6 +408,38 @@ TEST_F(ClientConnectionTest, TryingToConnectMultipleTimesStoppingOnPermissionErr
323408
324409 detail::ClientConnection connection (engine_, protocol_config_, client_config_);
325410
411+ for (auto entry : error_list_to_test)
412+ {
413+ if (entry == *error_list_to_test.begin ())
414+ {
415+ CatchImmediateConnectCommand ();
416+ connection.Start (IClientConnection::StateCallback (), IClientConnection::NotifyCallback ());
417+ }
418+ else
419+ {
420+ AtTryOpenCall_Return (score::cpp::make_unexpected (score::os::Error::createFromErrno (entry)));
421+ CatchTimedConnectCommand ();
422+ InvokeConnectCommand ();
423+ }
424+ EXPECT_EQ (connection.GetState (), State::kStarting );
425+ }
426+
427+ AtTryOpenCall_Return (score::cpp::make_unexpected (score::os::Error::createFromErrno (EACCES)));
428+ ExpectCleanUpOwner (connection);
429+ InvokeConnectCommand ();
430+
431+ EXPECT_EQ (connection.GetState (), State::kStopped );
432+ EXPECT_EQ (connection.GetStopReason (), StopReason::kPermission );
433+ }
434+
435+ TEST_F (ClientConnectionTest, TryingToSyncConnectMultipleTimesStoppingOnPermissionError)
436+ {
437+ client_config_.sync_first_connect = true ;
438+
439+ const auto error_list_to_test = {EAGAIN, ECONNREFUSED, ENOENT};
440+
441+ detail::ClientConnection connection (engine_, protocol_config_, client_config_);
442+
326443 for (auto entry : error_list_to_test)
327444 {
328445 AtTryOpenCall_Return (score::cpp::make_unexpected (score::os::Error::createFromErrno (entry)));
@@ -350,8 +467,7 @@ TEST_F(ClientConnectionTest, TryingToConnectMultipleTimesFinallyConnectingAndImp
350467{
351468 detail::ClientConnection connection (engine_, protocol_config_, client_config_);
352469
353- AtTryOpenCall_Return (score::cpp::make_unexpected (score::os::Error::createFromErrno (ENOENT)));
354- CatchTimedConnectCommand ();
470+ CatchImmediateConnectCommand ();
355471 connection.Start (IClientConnection::StateCallback (), IClientConnection::NotifyCallback ());
356472 EXPECT_EQ (connection.GetState (), State::kStarting );
357473
@@ -383,6 +499,15 @@ TEST_F(ClientConnectionTest, SuccessfullyConnectingAtFirstAttemptThenExplicitlyS
383499 StopCurrentConnection (connection);
384500}
385501
502+ TEST_F (ClientConnectionTest, SuccessfullySyncConnectingAtFirstAttemptThenExplicitlyStopping)
503+ {
504+ client_config_.sync_first_connect = true ;
505+ detail::ClientConnection connection (engine_, protocol_config_, client_config_);
506+ MakeSuccessfulConnection (connection);
507+
508+ StopCurrentConnection (connection);
509+ }
510+
386511TEST_F (ClientConnectionTest, SuccessfullyConnectingAtFirstAttemptThenExplicitlyStoppingAsIfFromCallback)
387512{
388513 detail::ClientConnection connection (engine_, protocol_config_, client_config_);
@@ -391,6 +516,15 @@ TEST_F(ClientConnectionTest, SuccessfullyConnectingAtFirstAttemptThenExplicitlyS
391516 StopCurrentConnectionAsIfInCallback (connection);
392517}
393518
519+ TEST_F (ClientConnectionTest, SuccessfullySyncConnectingAtFirstAttemptThenExplicitlyStoppingAsIfFromCallback)
520+ {
521+ client_config_.sync_first_connect = true ;
522+ detail::ClientConnection connection (engine_, protocol_config_, client_config_);
523+ MakeSuccessfulConnection (connection);
524+
525+ StopCurrentConnectionAsIfInCallback (connection);
526+ }
527+
394528TEST_F (ClientConnectionTest, SuccessfullyConnectingAtFirstAttemptThenFirstReadDisconnected)
395529{
396530 detail::ClientConnection connection (engine_, protocol_config_, client_config_);
0 commit comments