Skip to content

Commit

Permalink
Fix not stopping and reporting when error occurred
Browse files Browse the repository at this point in the history
  • Loading branch information
Kuniwak committed Nov 9, 2023
1 parent f5eaf92 commit 9af66be
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 15 deletions.
1 change: 1 addition & 0 deletions Editor/DeNA.Anjin.Editor.asmdef
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "DeNA.Anjin.Editor",
"rootNamespace": "DeNA.Anjin",
"references": [
"UniTask",
"DeNA.Anjin",
"TestHelper.Monkey.Annotations",
"TestHelper.Monkey"
Expand Down
7 changes: 4 additions & 3 deletions Editor/UI/Settings/AutopilotSettingsEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// This software is released under the MIT License.

using System.Diagnostics.CodeAnalysis;
using Cysharp.Threading.Tasks;
using DeNA.Anjin.Settings;
using UnityEditor;
using UnityEngine;
Expand Down Expand Up @@ -137,7 +138,7 @@ public override void OnInspectorGUI()
{
if (GUILayout.Button(s_stopButton))
{
Stop();
Stop().Forget();
}
}
else
Expand All @@ -157,10 +158,10 @@ private static void DrawHeader(string label)
}

[SuppressMessage("ApiDesign", "RS0030")]
internal void Stop()
internal async UniTask Stop()
{
var autopilot = FindObjectOfType<Autopilot>();
autopilot.Terminate(Autopilot.ExitCode.Normally);
await autopilot.TerminateAsync(Autopilot.ExitCode.Normally);
}

internal void Launch(AutopilotState state)
Expand Down
15 changes: 12 additions & 3 deletions Runtime/AgentDispatcher.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) 2023 DeNA Co., Ltd.
// This software is released under the MIT License.

using System;
using DeNA.Anjin.Agents;
using DeNA.Anjin.Settings;
using DeNA.Anjin.Utilities;
Expand Down Expand Up @@ -106,9 +107,17 @@ private void DispatchAgent(AbstractAgent agent)

agent.Logger = _logger;
agent.Random = _randomFactory.CreateRandom();
agent.Run(token).Forget();

_logger.Log($"Agent {agentName} dispatched!");

try
{
agent.Run(token).Forget();
_logger.Log($"Agent {agentName} dispatched!");
}
catch (Exception e)
{
Debug.LogException(e);
_logger.Log($"Agent {agentName} dispatched but immediately threw an error!");
}
}
}
}
35 changes: 29 additions & 6 deletions Runtime/Autopilot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

using System;
using System.Collections;
using System.Threading;
using Cysharp.Threading.Tasks;
using DeNA.Anjin.Reporters;
using DeNA.Anjin.Settings;
using DeNA.Anjin.Utilities;
Expand Down Expand Up @@ -62,15 +64,18 @@ private void Start()

_randomFactory = new RandomFactory(seed);
_logger.Log($"Random seed is {seed}");

// NOTE: Registering logMessageReceived must be placed before DispatchByScene.
// Because some agent can throw an error immediately, so reporter can miss the error if
// registering logMessageReceived is placed after DispatchByScene.
_reporter = new SlackReporter(_settings, new SlackAPI());
_logMessageHandler = new LogMessageHandler(_settings, _reporter);
Application.logMessageReceived += _logMessageHandler.HandleLog;

_dispatcher = new AgentDispatcher(_settings, _logger, _randomFactory);
_dispatcher.DispatchByScene(SceneManager.GetActiveScene());
SceneManager.activeSceneChanged += _dispatcher.DispatchByScene;

_reporter = new SlackReporter(_settings, new SlackAPI());
_logMessageHandler = new LogMessageHandler(_settings, _reporter);
Application.logMessageReceived += _logMessageHandler.HandleLog;

if (_settings.lifespanSec > 0)
{
StartCoroutine(Lifespan(_settings.lifespanSec));
Expand All @@ -92,7 +97,7 @@ private void Start()
private IEnumerator Lifespan(int timeoutSec)
{
yield return new WaitForSecondsRealtime(timeoutSec);
Terminate(ExitCode.Normally);
yield return UniTask.ToCoroutine(() => TerminateAsync(ExitCode.Normally));
}

/// <summary>
Expand All @@ -101,7 +106,8 @@ private IEnumerator Lifespan(int timeoutSec)
/// <param name="exitCode">Exit code for Unity Editor</param>
/// <param name="logString">Log message string when terminate by the log message</param>
/// <param name="stackTrace">Stack trace when terminate by the log message</param>
public void Terminate(ExitCode exitCode, string logString = null, string stackTrace = null)
/// <returns>A task awaits termination get completed</returns>
public async UniTask TerminateAsync(ExitCode exitCode, string logString = null, string stackTrace = null, CancellationToken token = default)
{
if (_dispatcher != null)
{
Expand Down Expand Up @@ -132,12 +138,29 @@ public void Terminate(ExitCode exitCode, string logString = null, string stackTr
// Terminate when ran specified time.
_logger.Log("Stop playing by autopilot");
_state.exitCode = exitCode;
// XXX: Avoid a problem that Editor stay playing despite isPlaying get assigned false.
// SEE: https://github.com/DeNA/Anjin/issues/20
await UniTask.DelayFrame(1, cancellationToken: token);
UnityEditor.EditorApplication.isPlaying = false;
// Call Launcher.OnChangePlayModeState() so terminates Unity editor, when launch from CLI.
#else
_logger.Log($"Exit Unity-editor by autopilot, exit code={exitCode}");
Application.Quit((int)exitCode);
await UniTask.CompletedTask;
#endif
}


/// <summary>
/// Terminate autopilot
/// </summary>
/// <param name="exitCode">Exit code for Unity Editor</param>
/// <param name="logString">Log message string when terminate by the log message</param>
/// <param name="stackTrace">Stack trace when terminate by the log message</param>
[Obsolete("Use " + nameof(TerminateAsync))]
public void Terminate(ExitCode exitCode, string logString = null, string stackTrace = null)
{
TerminateAsync(exitCode, logString, stackTrace).Forget();
}
}
}
2 changes: 1 addition & 1 deletion Runtime/Utilities/LogMessageHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public async void HandleLog(string logString, string stackTrace, LogType type)
var autopilot = Object.FindObjectOfType<Autopilot>();
if (autopilot != null)
{
autopilot.Terminate(Autopilot.ExitCode.AutopilotFailed, logString, stackTrace);
await autopilot.TerminateAsync(Autopilot.ExitCode.AutopilotFailed, logString, stackTrace);
}
}

Expand Down
4 changes: 2 additions & 2 deletions Tests/Runtime/LauncherTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public async Task Launch_InPlayMode_RunAutopilot()
var autopilot = Object.FindObjectOfType<Autopilot>();
Assert.That((bool)autopilot, Is.True, "Autopilot object is alive");

autopilot.Terminate(Autopilot.ExitCode.Normally);
await autopilot.TerminateAsync(Autopilot.ExitCode.Normally);
}

[Test]
Expand All @@ -66,7 +66,7 @@ public async Task Stop_TerminateAutopilotAndKeepPlayMode()
var state = AutopilotState.Instance;
editor.Launch(state);
await Task.Delay(2000);
editor.Stop(); // Note: If Autopilot stops for life before Stop, a NullReference exception is raised here.
await editor.Stop(); // Note: If Autopilot stops for life before Stop, a NullReference exception is raised here.

Assert.That(state.IsRunning, Is.False, "AutopilotState is terminated");
Assert.That(EditorApplication.isPlaying, Is.True, "Keep play mode");
Expand Down
9 changes: 9 additions & 0 deletions Tests/Runtime/TestDoubles/StubClickAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,18 @@

namespace DeNA.Anjin.TestDoubles
{
/// <summary>
/// A test double for agent. This agent immediately click game objects that have the name specified
/// </summary>
public class StubClickAgent : AbstractAgent
{
/// <summary>
/// A name of game objects to click
/// </summary>
[SerializeField] public string targetName;


/// <inheritdoc />
public override UniTask Run(CancellationToken token)
{
foreach (var obj in FindObjectsByType<GameObject>(FindObjectsSortMode.None))
Expand All @@ -33,6 +41,7 @@ public override UniTask Run(CancellationToken token)

handler.OnPointerClick(new PointerEventData(EventSystem.current));
}

return UniTask.CompletedTask;
}
}
Expand Down

0 comments on commit 9af66be

Please sign in to comment.