@@ -13,6 +13,8 @@ namespace TestProject.RuntimeTests
1313 public class SceneEventProgressTests : NetcodeIntegrationTest
1414 {
1515 private const string k_SceneUsedToGetAsyncOperation = "EmptyScene" ;
16+ private const string k_SceneUsedToGetClientAsyncOperation = "UnitTestBaseScene" ;
17+
1618 protected override int NumberOfClients => 4 ;
1719
1820 private bool m_SceneEventProgressCompleted ;
@@ -51,6 +53,7 @@ private void StartNewSceneEventProgress()
5153 m_CurrentSceneEventProgress . SetAsyncOperation ( SceneManager . LoadSceneAsync ( k_SceneUsedToGetAsyncOperation , LoadSceneMode . Additive ) ) ;
5254 }
5355
56+
5457 private void MockServerLoadedSene ( Scene scene , LoadSceneMode loadSceneMode )
5558 {
5659 if ( scene . name == k_SceneUsedToGetAsyncOperation )
@@ -155,6 +158,31 @@ public IEnumerator ClientsDisconnectDuring()
155158 VerifyClientsThatCompleted ( ) ;
156159 }
157160
161+ [ UnityTest ]
162+ public IEnumerator ClientsShutdownDuring ( )
163+ {
164+ StartNewSceneEventProgress ( ) ;
165+
166+ for ( int i = 0 ; i < NumberOfClients ; i ++ )
167+ {
168+ var currentClientNetworkManager = m_ClientNetworkManagers [ i ] ;
169+ // Two clients will shutdown
170+ var clientFinished = i % 2 == 0 ;
171+ SetClientFinished ( currentClientNetworkManager . LocalClientId , clientFinished ) ;
172+
173+ if ( ! clientFinished )
174+ {
175+ currentClientNetworkManager . Shutdown ( ) ;
176+ }
177+ // wait anywhere from 100-500ms until processing next client
178+ var randomWaitPeriod = Random . Range ( 0.1f , 0.5f ) ;
179+ yield return new WaitForSeconds ( randomWaitPeriod ) ;
180+ }
181+ yield return WaitForConditionOrTimeOut ( ( ) => m_SceneEventProgressCompleted ) ;
182+ AssertOnTimeout ( $ "Timed out waiting for SceneEventProgress to time out!") ;
183+ VerifyClientsThatCompleted ( ) ;
184+ }
185+
158186 /// <summary>
159187 /// This verifies that SceneEventProgress will still complete
160188 /// even when clients late join.
@@ -163,16 +191,13 @@ public IEnumerator ClientsDisconnectDuring()
163191 public IEnumerator ClientsLateJoinDuring ( )
164192 {
165193 StartNewSceneEventProgress ( ) ;
166-
167194 for ( int i = 0 ; i < NumberOfClients ; i ++ )
168195 {
169196 // Two clients will connect during a SceneEventProgress
170197 var shouldNewClientJoin = i % 2 == 0 ;
171198 var currentClientNetworkManager = m_ClientNetworkManagers [ i ] ;
172-
173199 // All connected clients will finish their SceneEventProgress
174200 SetClientFinished ( currentClientNetworkManager . LocalClientId , true ) ;
175-
176201 if ( shouldNewClientJoin )
177202 {
178203 yield return CreateAndStartNewClient ( ) ;
@@ -181,11 +206,84 @@ public IEnumerator ClientsLateJoinDuring()
181206 var randomWaitPeriod = Random . Range ( 0.1f , 0.5f ) ;
182207 yield return new WaitForSeconds ( randomWaitPeriod ) ;
183208 }
184-
185209 yield return WaitForConditionOrTimeOut ( ( ) => m_SceneEventProgressCompleted ) ;
186210 AssertOnTimeout ( $ "Timed out waiting for SceneEventProgress to finish!") ;
211+ VerifyClientsThatCompleted ( ) ;
212+ }
213+
214+ private List < ulong > m_ClientsThatTimedOutAndFinished = new List < ulong > ( ) ;
215+
216+ private SceneEventProgress StartClientSceneEventProgress ( NetworkManager networkManager )
217+ {
218+ var sceneEventProgress = new SceneEventProgress ( networkManager , SceneEventProgressStatus . Started ) ;
187219
220+ // Mock Scene Loading Event for mocking timed out client
221+ m_CurrentSceneEventProgress . SceneEventId = ( uint ) networkManager . LocalClientId ;
222+ var asyncOperation = SceneManager . LoadSceneAsync ( k_SceneUsedToGetClientAsyncOperation , LoadSceneMode . Additive ) ;
223+ asyncOperation . completed += new System . Action < AsyncOperation > ( asyncOp2 =>
224+ {
225+ m_ClientsThatTimedOutAndFinished . Add ( networkManager . LocalClientId ) ;
226+ } ) ;
227+
228+ m_CurrentSceneEventProgress . SetAsyncOperation ( asyncOperation ) ;
229+ return sceneEventProgress ;
230+ }
231+
232+ private Dictionary < NetworkManager , SceneEventProgress > m_ClientsToFinishAfterDisconnecting = new Dictionary < NetworkManager , SceneEventProgress > ( ) ;
233+ private bool TimedOutClientsFinishedSceneEventProgress ( )
234+ {
235+ // Now, verify all "mock timed out" clients still finished their SceneEventProgress
236+ foreach ( var entry in m_ClientsToFinishAfterDisconnecting )
237+ {
238+ if ( ! m_ClientsThatTimedOutAndFinished . Contains ( entry . Key . LocalClientId ) )
239+ {
240+ return false ;
241+ }
242+ }
243+ return true ;
244+ }
245+
246+ /// <summary>
247+ /// This mocks a client timing out during a SceneEventProgress
248+ /// </summary>
249+ [ UnityTest ]
250+ public IEnumerator ClientsMockTimeOutDuring ( )
251+ {
252+ m_ClientsThatTimedOutAndFinished . Clear ( ) ;
253+ m_ClientsToFinishAfterDisconnecting . Clear ( ) ;
254+ StartNewSceneEventProgress ( ) ;
255+
256+ for ( int i = 0 ; i < NumberOfClients ; i ++ )
257+ {
258+ // Two clients will mock timing out during a SceneEventProgress
259+ var shouldClientFinish = i % 2 == 0 ;
260+ var currentClientNetworkManager = m_ClientNetworkManagers [ i ] ;
261+
262+ // Set whether the client should or should not have finished
263+ SetClientFinished ( currentClientNetworkManager . LocalClientId , shouldClientFinish ) ;
264+ if ( ! shouldClientFinish )
265+ {
266+ var sceneEventProgress = StartClientSceneEventProgress ( currentClientNetworkManager ) ;
267+ m_ClientsToFinishAfterDisconnecting . Add ( currentClientNetworkManager , sceneEventProgress ) ;
268+ currentClientNetworkManager . Shutdown ( ) ;
269+ }
270+ }
271+
272+ yield return WaitForConditionOrTimeOut ( ( ) => m_SceneEventProgressCompleted ) ;
273+ AssertOnTimeout ( $ "Timed out waiting for SceneEventProgress to finish!") ;
188274 VerifyClientsThatCompleted ( ) ;
275+
276+ yield return WaitForConditionOrTimeOut ( TimedOutClientsFinishedSceneEventProgress ) ;
277+ if ( s_GlobalTimeoutHelper . TimedOut )
278+ {
279+ foreach ( var entry in m_ClientsToFinishAfterDisconnecting )
280+ {
281+ Assert . IsTrue ( m_ClientsThatTimedOutAndFinished . Contains ( entry . Key . LocalClientId ) , $ "Client-{ entry . Key . LocalClientId } did not complete its { nameof ( SceneEventProgress ) } !") ;
282+ // Now, as a final check we try to finish the "mock" timed out client's scene event progress
283+ entry . Value . TryFinishingSceneEventProgress ( ) ;
284+ }
285+ }
286+ m_ClientsToFinishAfterDisconnecting . Clear ( ) ;
189287 }
190288 }
191289}
0 commit comments