refactor: fix issue #10

- add StabilityTest.cs: test app is stable across startup and teardowns within the UnityTestRunner environment
- add RaindropLoader.cs: provides UnityTests a easy API to 'startup' the game and 'teardown' the game.
- the above code changes caused regressions (NRE) in UIBootstrapper.cs, UIService, and some camera thingy so I changed them.

I feel like I am just mixing the spaghetti in a pot, and the only way to know it is done is to check if the tests are passing better. lol.
This commit is contained in:
alexiscatnip
2022-08-06 02:43:06 +08:00
committed by alexiscatnip
parent cd6a027eda
commit 827ecfea77
9 changed files with 139 additions and 21 deletions
@@ -32,10 +32,19 @@ namespace Raindrop.Bootstrap
StartUIScene();
}
}
public void OnDestroy()
{
Quit_Application();
}
#region Bootstrap functions
private void StartUIScene()
{
SceneManager.LoadScene("Raindrop/Bootstrap/MainScene");
SceneManager.LoadScene(
"Raindrop/Bootstrap/MainScene",
LoadSceneMode.Additive);
}
// prep user file system for LMV's usage, by copying static files.
@@ -45,13 +54,18 @@ namespace Raindrop.Bootstrap
var copy_result = copier.Work();
if (copy_result == -1)
{
Logger.Log("static files copier failed", Helpers.LogLevel.Error);
Logger.Log(
"static files copier failed",
Helpers.LogLevel.Error);
}
}
private static void SendStartupMessageToLogger()
{
Logger.Log("RaindropBootstrapper.cs : RaindropInstance Started and succesfully linked to servicelocator.", Helpers.LogLevel.Info);
Logger.Log("RaindropBootstrapper.cs : " +
"RaindropInstance Started and " +
"succesfully linked to servicelocator.",
Helpers.LogLevel.Info);
}
public static void Start_Raindrop_CoreDependencies()
@@ -106,10 +120,6 @@ namespace Raindrop.Bootstrap
}
public void OnApplicationQuit()
{
Quit_Application();
}
// globally-accessible quit method.
public void Quit_Application()
@@ -157,10 +167,14 @@ namespace Raindrop.Bootstrap
}
frmMain_Disposed(instance);
Unregister_RaindropInstance();
Debug.Log("disposed netcom and client! :) This marks the end of the app.");
}
//wraps up the netcom and client.
// wraps up the netcom (synchronisation context) ,
// followed by the client instance.
void frmMain_Disposed(RaindropInstance instance)
{
RaindropNetcom netcom = instance.Netcom;
@@ -182,5 +196,15 @@ namespace Raindrop.Bootstrap
instance.CleanUp();
}
public static void Unregister_RaindropInstance()
{
if (ServiceLocator.Instance.IsRegistered<RaindropInstance>())
{
ServiceLocator.Instance.Unregister<RaindropInstance>();
}
}
#endregion
}
}
@@ -0,0 +1,24 @@
using UnityEngine.SceneManagement;
namespace Raindrop.Bootstrap
{
// call these methods to load the game.
public static class RaindropLoader
{
public static void Load()
{
SceneManager.LoadScene(
"Raindrop/Bootstrap/BootstrapScene",
LoadSceneMode.Single);
}
public static void Unload()
{
// calling with LoadSceneMode.Single will call Destroy() on
// RaindropBootstrapper, causing a cascade of teardown,
// similar to what happens in the actual device
var emptyScene = "Scenes/empty";
SceneManager.LoadScene(emptyScene, LoadSceneMode.Single);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 37bdc91a50854f16a60547b011c4e1e1
timeCreated: 1657735609
+17 -2
View File
@@ -1,4 +1,5 @@
using Plugins.CommonDependencies;
using System;
using Plugins.CommonDependencies;
using Raindrop.Map.Model;
using Raindrop.Netcom;
using Raindrop.Services;
@@ -20,13 +21,26 @@ namespace Raindrop.Bootstrap
// has a funny role; in that it will register itself to the UIservice on start/awake.
// this should really be the other way round - that the UIservice
// creates/has dependency on the UIrootGO!!!
private void Awake()
private void Start()
{
//RaindropBootstrapper.Start_Raindrop_CoreDependencies(); // hacky - to ensure that the UI's dependencies are ready.
OpenMetaverse.Logger.Log("UI layer of application Started. Logging Started.", OpenMetaverse.Helpers.LogLevel.Info);
InitialiseUIVariant();
}
private void OnDestroy()
{
if (ServiceLocator.Instance.IsRegistered<MapService>())
{
ServiceLocator.Instance.Unregister<MapService>();
}
if (ServiceLocator.Instance.IsRegistered<UIService>())
{
ServiceLocator.Instance.Unregister<UIService>();
}
}
//warn: if this init method is called too early, there can be issues.
private void InitialiseUIVariant()
{
@@ -49,6 +63,7 @@ namespace Raindrop.Bootstrap
references.ll.Init();
var uisrv = new UIService(
instance,
references.sm,
references.mm,
references.ll,
+4 -2
View File
@@ -20,7 +20,7 @@ namespace Raindrop.Services
// Notification - manages app-wide notifications.
// <deprecated> LoadingCanvasPresenter - this particular modal/screen is tricky; it appears only when the scene is loading.
private RaindropInstance instance => ServiceLocator.Instance.Get<RaindropInstance>();
private RaindropInstance instance;
private RaindropNetcom netcom { get { return instance.Netcom; } }
private GridClient client { get { return instance.Client; } }
@@ -45,9 +45,11 @@ namespace Raindrop.Services
* +UIService.showScreen(UIBuilder(CanvasType.Login))
* +UIService.showModal
*/
public UIService(ScreenStackManager cm, ModalsManager mm, LoadingView loadingView,
public UIService(RaindropInstance raindropInstance,
ScreenStackManager cm, ModalsManager mm, LoadingView loadingView,
ChatPresenter ChatPresenter)
{
instance = raindropInstance;
ScreenStackManager = cm;
ModalsManager = mm;
_loadingController = new LoadingController(loadingView);
+4 -2
View File
@@ -12,13 +12,15 @@ using Camera = UnityEngine.Camera;
[RequireComponent(typeof(Camera))]
public class UpdateCameraBackend : MonoBehaviour
{
private RaindropInstance instance { get { return ServiceLocator.Instance.Get<RaindropInstance>(); } }
bool Active => instance.Client.Network.Connected && (instance.Client.Network.CurrentSim != null);
private RaindropInstance instance;
bool Active => instance.Client.Network.Connected &&
(instance.Client.Network.CurrentSim != null);
public Camera cam;
void Start()
{
cam = GetComponent<Camera>();
instance = ServiceLocator.Instance.Get<RaindropInstance>();
}
private void Update()
@@ -5,6 +5,7 @@ using NUnit.Framework;
using OpenMetaverse;
using Plugins.CommonDependencies;
using Raindrop;
using Raindrop.Bootstrap;
using Raindrop.Media;
using UnityEngine;
using UnityEngine.SceneManagement;
@@ -15,11 +16,19 @@ namespace Tests.Raindrop.SoundTests
[TestFixture()]
public class SoundTests
{
// TODO: note that current soundtests is not failing on warnings of the type:
// Failed to initialize the sound system: Raindrop.Media.MediaException: FMOD error! ERR_MEMORY - Not enough memory or resources.
[SetUp]
public void Setup()
{
SceneManager.LoadScene("Raindrop/Bootstrap/BootstrapScene");
RaindropLoader.Load();
}
[TearDown]
public void TearDown()
{
RaindropLoader.Unload();
}
// copy sample audio to cache.
@@ -63,9 +72,9 @@ namespace Tests.Raindrop.SoundTests
{
File.Copy(fromPath, toPath);
}
catch
catch (Exception e)
{
Debug.Log("failed to copy sample sound file for the test.");
Debug.Log("failed to copy sample sound file for the test: " + e.ToString());
}
}
}
@@ -107,7 +116,4 @@ namespace Tests.Raindrop.SoundTests
}
}
}
@@ -0,0 +1,39 @@
using System.Collections;
using NUnit.Framework;
using Raindrop.Bootstrap;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.TestTools;
namespace Tests.Raindrop.RaindropFullIntegrationTests
{
[TestFixture()]
public class StabilityTest
{
// Check if we can load and unload game in the test environment,
// consecutively.
// Addresses github issue #10
[UnityTest]
public IEnumerator StabilityTest_Restart_RaindropApp()
{
int iterations = 3;
for (int i = 0; i < iterations; i++)
{
Debug.Log($"scene iteration {i} start");
Debug.Log("Load bootstrap scene: ");
RaindropLoader.Load();
yield return new WaitForSeconds(8);
Debug.Log("unload entire scene: ");
RaindropLoader.Unload();
yield return new WaitForSeconds(2);
Debug.Log($"scene iteration {i} done");
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f103b30862a14c5abd9f2bb68f8223c6
timeCreated: 1657735870