-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #106 from nowsprinting/feature/terminate_agent
Add TerminateAgent
- Loading branch information
Showing
9 changed files
with
295 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright (c) 2023-2024 DeNA Co., Ltd. | ||
// This software is released under the MIT License. | ||
|
||
using DeNA.Anjin.Agents; | ||
using UnityEditor; | ||
using UnityEngine; | ||
|
||
namespace DeNA.Anjin.Editor.UI.Agents | ||
{ | ||
/// <summary> | ||
/// Editor GUI for TerminateAgent. | ||
/// </summary> | ||
[CustomEditor(typeof(TerminateAgent))] | ||
public class TerminateAgentEditor : UnityEditor.Editor | ||
{ | ||
// @formatter:off | ||
private static readonly string s_description = L10n.Tr("Description"); | ||
private static readonly string s_descriptionTooltip = L10n.Tr("Description about this agent instance"); | ||
|
||
private static readonly string s_exitCode = L10n.Tr("Exit Code"); | ||
private static readonly string s_exitCodeTooltip = L10n.Tr("Select the exit code used when this agent terminates the Autopilot."); | ||
private static readonly string s_customExitCode = L10n.Tr("Custom Exit Code"); | ||
private static readonly string s_customExitCodeTooltip = L10n.Tr("Input exit code by integer value."); | ||
private static readonly string s_exitMessage = L10n.Tr("Message"); | ||
private static readonly string s_exitMessageTooltip = L10n.Tr("Message sent by the Reporter when this agent terminates the Autopilot."); | ||
// @formatter:on | ||
|
||
private const float SpacerPixels = 10f; | ||
|
||
/// <inheritdoc/> | ||
public override void OnInspectorGUI() | ||
{ | ||
serializedObject.Update(); | ||
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(TerminateAgent.description)), | ||
new GUIContent(s_description, s_descriptionTooltip)); | ||
GUILayout.Space(SpacerPixels); | ||
|
||
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(TerminateAgent.exitCode)), | ||
new GUIContent(s_exitCode, s_exitCodeTooltip)); | ||
EditorGUI.BeginDisabledGroup(((TerminateAgent)target).exitCode != ExitCodeByTerminateAgent.Custom); | ||
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(TerminateAgent.customExitCode)), | ||
new GUIContent(s_customExitCode, s_customExitCodeTooltip)); | ||
EditorGUI.EndDisabledGroup(); | ||
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(TerminateAgent.exitMessage)), | ||
new GUIContent(s_exitMessage, s_exitMessageTooltip)); | ||
|
||
serializedObject.ApplyModifiedProperties(); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// Copyright (c) 2023-2024 DeNA Co., Ltd. | ||
// This software is released under the MIT License. | ||
|
||
using System.Threading; | ||
using Cysharp.Threading.Tasks; | ||
using DeNA.Anjin.Attributes; | ||
using UnityEngine; | ||
|
||
namespace DeNA.Anjin.Agents | ||
{ | ||
/// <summary> | ||
/// Autopilot exit code that terminates by <c>TerminateAgent</c>. | ||
/// </summary> | ||
public enum ExitCodeByTerminateAgent | ||
{ | ||
/// <summary> | ||
/// Normally terminated. | ||
/// </summary> | ||
Normally = ExitCode.Normally, | ||
|
||
/// <summary> | ||
/// Terminate by Autopilot scenario running failure. | ||
/// By default, the exit code at expiration will be <c>Normally</c>. | ||
/// This exit code is only used if set by the user. | ||
/// </summary> | ||
AutopilotFailed = ExitCode.AutopilotFailed, | ||
|
||
/// <summary> | ||
/// Input custom exit code by integer value. | ||
/// </summary> | ||
Custom = 1024, | ||
} | ||
|
||
/// <summary> | ||
/// An Agent that terminates the Autopilot running when the scenario goal is achieved. | ||
/// </summary> | ||
[CreateAssetMenu(fileName = "New TerminateAgent", menuName = "Anjin/Terminate Agent", order = 22)] | ||
public class TerminateAgent : AbstractAgent | ||
{ | ||
/// <summary> | ||
/// Exit Code when terminated by this Agent. | ||
/// When using it from within code, use the <code>ExitCode</code> property. | ||
/// </summary> | ||
public ExitCodeByTerminateAgent exitCode = ExitCodeByTerminateAgent.Normally; | ||
|
||
/// <summary> | ||
/// Custom exit code to be used if <code>Custom</code> is selected for <c>exitCode</c>. | ||
/// Please enter an integer value. | ||
/// </summary> | ||
public string customExitCode; | ||
|
||
public ExitCode ExitCode | ||
{ | ||
get | ||
{ | ||
if (exitCode == ExitCodeByTerminateAgent.Custom) | ||
{ | ||
return int.TryParse(customExitCode, out var intExitCode) | ||
? (ExitCode)intExitCode | ||
: (ExitCode)exitCode; | ||
} | ||
|
||
return (ExitCode)exitCode; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Message used by Reporter. | ||
/// </summary> | ||
[Multiline] | ||
public string exitMessage = "Terminated by TerminateAgent"; | ||
|
||
internal ITerminatable _autopilot; // can inject for testing | ||
|
||
[InitializeOnLaunchAutopilot] | ||
private static void ResetInstances() | ||
{ | ||
// Reset runtime instances | ||
var agents = Resources.FindObjectsOfTypeAll<TerminateAgent>(); | ||
foreach (var agent in agents) | ||
{ | ||
agent._autopilot = null; | ||
} | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override async UniTask Run(CancellationToken token) | ||
{ | ||
try | ||
{ | ||
Logger.Log($"Enter {this.name}.Run()"); | ||
|
||
_autopilot = _autopilot ?? Autopilot.Instance; | ||
|
||
// ReSharper disable once MethodSupportsCancellation | ||
_autopilot.TerminateAsync(ExitCode, exitMessage).Forget(); | ||
// Note: Do not use this Agent's CancellationToken. | ||
} | ||
finally | ||
{ | ||
Logger.Log($"Exit {this.name}.Run()"); | ||
} | ||
|
||
await UniTask.CompletedTask; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Copyright (c) 2023-2024 DeNA Co., Ltd. | ||
// This software is released under the MIT License. | ||
|
||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Cysharp.Threading.Tasks; | ||
using DeNA.Anjin.TestDoubles; | ||
using NUnit.Framework; | ||
using UnityEngine; | ||
using UnityEngine.TestTools; | ||
|
||
namespace DeNA.Anjin.Agents | ||
{ | ||
[TestFixture] | ||
public class TerminateAgentTest | ||
{ | ||
[Test] | ||
public void ExitCode_NotCustom_ReturnsExitCode() | ||
{ | ||
var sut = ScriptableObject.CreateInstance<TerminateAgent>(); | ||
sut.exitCode = ExitCodeByTerminateAgent.AutopilotFailed; | ||
sut.customExitCode = "100"; // dummy | ||
|
||
Assert.That(sut.ExitCode, Is.EqualTo(ExitCode.AutopilotFailed)); | ||
} | ||
|
||
[Test] | ||
public void ExitCode_Custom_ReturnsCustomExitCode() | ||
{ | ||
var sut = ScriptableObject.CreateInstance<TerminateAgent>(); | ||
sut.exitCode = ExitCodeByTerminateAgent.Custom; | ||
sut.customExitCode = "100"; | ||
|
||
Assert.That(sut.ExitCode, Is.EqualTo((ExitCode)100)); | ||
} | ||
|
||
[Test] | ||
public void ExitCode_CustomButNotValid_ReturnsExitCodeByTerminateAgentCustom() | ||
{ | ||
var sut = ScriptableObject.CreateInstance<TerminateAgent>(); | ||
sut.exitCode = ExitCodeByTerminateAgent.Custom; | ||
sut.customExitCode = "not valid"; | ||
|
||
Assert.That(sut.ExitCode, Is.EqualTo((ExitCode)ExitCodeByTerminateAgent.Custom)); | ||
} | ||
|
||
[Test] | ||
public async Task Run_CallTerminateAsync() | ||
{ | ||
var agent = ScriptableObject.CreateInstance<TerminateAgent>(); | ||
agent.Logger = Debug.unityLogger; | ||
agent.name = TestContext.CurrentContext.Test.Name; | ||
agent.exitCode = ExitCodeByTerminateAgent.Custom; | ||
agent.customExitCode = "100"; | ||
agent.exitMessage = "Terminated!"; | ||
|
||
var spyTerminatable = new SpyTerminatable(); | ||
agent._autopilot = spyTerminatable; | ||
|
||
using (var cts = new CancellationTokenSource()) | ||
{ | ||
await agent.Run(cts.Token); | ||
await UniTask.NextFrame(); | ||
} | ||
|
||
Assert.That(spyTerminatable.IsCalled, Is.True); | ||
Assert.That(spyTerminatable.CapturedExitCode, Is.EqualTo((ExitCode)100)); | ||
Assert.That(spyTerminatable.CapturedMessage, Is.EqualTo("Terminated!")); | ||
Assert.That(spyTerminatable.CapturedReporting, Is.True); | ||
|
||
LogAssert.Expect(LogType.Log, $"Enter {agent.name}.Run()"); | ||
LogAssert.Expect(LogType.Log, $"Exit {agent.name}.Run()"); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.