Skip to content

Commit

Permalink
Fix agents do not output exit log if canceled
Browse files Browse the repository at this point in the history
  • Loading branch information
nowsprinting committed Apr 21, 2024
1 parent fb09e6e commit d9f2984
Show file tree
Hide file tree
Showing 17 changed files with 248 additions and 140 deletions.
17 changes: 11 additions & 6 deletions Runtime/Agents/DoNothingAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,21 @@ public override async UniTask Run(CancellationToken token)
{
Logger.Log($"Enter {this.name}.Run()");

if (lifespanSec > 0)
try
{
await UniTask.Delay(TimeSpan.FromSeconds(lifespanSec), cancellationToken: token);
if (lifespanSec > 0)
{
await UniTask.Delay(TimeSpan.FromSeconds(lifespanSec), cancellationToken: token);
}
else
{
await UniTask.WaitWhile(() => true, cancellationToken: token); // Wait indefinitely
}
}
else
finally
{
await UniTask.WaitWhile(() => true, cancellationToken: token); // 無期限に待機
Logger.Log($"Exit {this.name}.Run()");
}

Logger.Log($"Exit {this.name}.Run()");
}
}
}
33 changes: 19 additions & 14 deletions Runtime/Agents/EmergencyExitAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,32 @@ public override async UniTask Run(CancellationToken token)
Logger.Log($"Enter {this.name}.Run()");

var selectables = new Selectable[20];
while (true)
try
{
var allSelectableCount = Selectable.allSelectableCount;
if (selectables.Length < allSelectableCount)
while (true) // Note: This agent is not terminate myself
{
selectables = new Selectable[allSelectableCount];
}
var allSelectableCount = Selectable.allSelectableCount;
if (selectables.Length < allSelectableCount)
{
selectables = new Selectable[allSelectableCount];
}

Selectable.AllSelectablesNoAlloc(selectables);
for (var i = 0; i < allSelectableCount; i++)
{
if (selectables[i].TryGetComponent<EmergencyExit>(out var emergencyExit))
Selectable.AllSelectablesNoAlloc(selectables);
for (var i = 0; i < allSelectableCount; i++)
{
ClickEmergencyExitButton(emergencyExit);
if (selectables[i].TryGetComponent<EmergencyExit>(out var emergencyExit))
{
ClickEmergencyExitButton(emergencyExit);
}
}
}

await UniTask.NextFrame(token);
await UniTask.NextFrame(token);
}
}
finally
{
Logger.Log($"Exit {this.name}.Run()");
}

// Note: This agent is not terminate myself
}

[SuppressMessage("ReSharper", "SuggestBaseTypeForParameter")]
Expand Down
11 changes: 8 additions & 3 deletions Runtime/Agents/OneTimeAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,14 @@ public override async UniTask Run(CancellationToken token)

agent.Logger = Logger;
agent.Random = Random; // This Agent does not consume pseudo-random numbers, so passed on as is.
await agent.Run(token);

Logger.Log($"Exit {this.name}.Run()");
try
{
await agent.Run(token);
}
finally
{
Logger.Log($"Exit {this.name}.Run()");
}
}
}
}
11 changes: 8 additions & 3 deletions Runtime/Agents/ParallelCompositeAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,14 @@ public override async UniTask Run(CancellationToken token)
tasks[i] = agent.Run(token);
}

await UniTask.WhenAll(tasks);

Logger.Log($"Exit {this.name}.Run()");
try
{
await UniTask.WhenAll(tasks);
}
finally
{
Logger.Log($"Exit {this.name}.Run()");
}
}
}
}
17 changes: 11 additions & 6 deletions Runtime/Agents/RepeatAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,19 @@ public override async UniTask Run(CancellationToken token)
{
Logger.Log($"Enter {this.name}.Run()");

while (true)
agent.Logger = Logger;
agent.Random = Random; // This Agent does not consume pseudo-random numbers, so passed on as is.
try
{
agent.Logger = Logger;
agent.Random = Random; // This Agent does not consume pseudo-random numbers, so passed on as is.
await agent.Run(token);
while (true) // Note: This agent is not terminate myself
{
await agent.Run(token);
}
}
finally
{
Logger.Log($"Exit {this.name}.Run()");
}

// Note: This agent is not terminate myself
}
}
}
17 changes: 11 additions & 6 deletions Runtime/Agents/SerialCompositeAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,19 @@ public override async UniTask Run(CancellationToken token)
{
Logger.Log($"Enter {this.name}.Run()");

foreach (var agent in agents)
try
{
agent.Logger = Logger;
agent.Random = RandomFactory.CreateRandom();
await agent.Run(token);
foreach (var agent in agents)
{
agent.Logger = Logger;
agent.Random = RandomFactory.CreateRandom();
await agent.Run(token);
}
}
finally
{
Logger.Log($"Exit {this.name}.Run()");
}

Logger.Log($"Exit {this.name}.Run()");
}
}
}
42 changes: 24 additions & 18 deletions Runtime/Agents/TimeBombAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,34 +63,40 @@ public override async UniTask Run(CancellationToken token)
{
Logger.Log($"Enter {this.name}.Run()");

using (var agentCts = new CancellationTokenSource()) // To cancel only the Working Agent.
try
{
_cts = agentCts;

using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(token, agentCts.Token))
using (var agentCts = new CancellationTokenSource()) // To cancel only the Working Agent.
{
try
{
agent.Logger = Logger;
agent.Random = Random; // This Agent does not consume pseudo-random numbers, so passed on as is.
await agent.Run(linkedCts.Token);
_cts = agentCts;

throw new TimeoutException(
$"Could not receive defuse message `{defuseMessage}` before the agent terminated.");
}
catch (OperationCanceledException e)
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(token, agentCts.Token))
{
if (token.IsCancellationRequested) // The parent was cancelled.
try
{
throw;
agent.Logger = Logger;
agent.Random = Random;
// Note: This Agent does not consume pseudo-random numbers, so passed on as is.
await agent.Run(linkedCts.Token);

throw new TimeoutException(
$"Could not receive defuse message `{defuseMessage}` before the agent terminated.");
}
catch (OperationCanceledException e)
{
if (token.IsCancellationRequested) // The parent was cancelled.
{
throw;
}

Logger.Log($"Working agent {agent.name} was cancelled.");
Logger.Log($"Working agent {agent.name} was cancelled.");
}
}
}
}

Logger.Log($"Exit {this.name}.Run()");
finally
{
Logger.Log($"Exit {this.name}.Run()");
}
}
}
}
10 changes: 8 additions & 2 deletions Runtime/Agents/UGUIMonkeyAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,15 @@ public override async UniTask Run(CancellationToken token)
randomString: new RandomStringImpl(random)),
},
};
await Monkey.Run(config, token);

Logger.Log($"Exit {this.name}.Run()");
try
{
await Monkey.Run(config, token);
}
finally
{
Logger.Log($"Exit {this.name}.Run()");
}
}

private RandomStringParameters GetRandomStringParameters(GameObject gameObject)
Expand Down
16 changes: 10 additions & 6 deletions Tests/Runtime/Agents/DoNothingAgentTest.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Copyright (c) 2023 DeNA Co., Ltd.
// This software is released under the MIT License.

using System;
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using DeNA.Anjin.Utilities;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Object = UnityEngine.Object;

namespace DeNA.Anjin.Agents
Expand All @@ -23,17 +23,18 @@ public async Task Run_cancelTask_stopAgent()
agent.name = nameof(Run_cancelTask_stopAgent);
agent.lifespanSec = 0; // Expect indefinite execution

var agentName = agent.GetType().Name;
var gameObject = new GameObject(agentName);
var gameObject = new GameObject();
var token = gameObject.GetCancellationTokenOnDestroy();
var task = agent.Run(token);
await UniTask.Delay(TimeSpan.FromSeconds(1), cancellationToken: token);
await UniTask.NextFrame();

Object.DestroyImmediate(gameObject);
// ReSharper disable once MethodSupportsCancellation
await UniTask.NextFrame();

Assert.That(task.Status, Is.EqualTo(UniTaskStatus.Canceled));

LogAssert.Expect(LogType.Log, $"Enter {agent.name}.Run()");
LogAssert.Expect(LogType.Log, $"Exit {agent.name}.Run()");
}

[Test]
Expand All @@ -49,10 +50,13 @@ public async Task Run_lifespanPassed_stopAgent()
{
var token = cancellationTokenSource.Token;
var task = agent.Run(token);
await UniTask.Delay(TimeSpan.FromSeconds(2), cancellationToken: token); // Consider overhead
await UniTask.Delay(2000); // Consider overhead

Assert.That(task.Status, Is.EqualTo(UniTaskStatus.Succeeded));
}

LogAssert.Expect(LogType.Log, $"Enter {agent.name}.Run()");
LogAssert.Expect(LogType.Log, $"Exit {agent.name}.Run()");
}
}
}
39 changes: 26 additions & 13 deletions Tests/Runtime/Agents/EmergencyExitAgentTest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) 2023 DeNA Co., Ltd.
// This software is released under the MIT License.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -11,6 +10,7 @@
using DeNA.Anjin.Utilities;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using UnityEngine.UI;
using Object = UnityEngine.Object;

Expand All @@ -27,24 +27,26 @@ public async Task Run_cancelTask_stopAgent()
agent.Random = new RandomFactory(0).CreateRandom();
agent.name = nameof(Run_cancelTask_stopAgent);

var agentName = agent.GetType().Name;
var gameObject = new GameObject(agentName);
var gameObject = new GameObject();
var token = gameObject.GetCancellationTokenOnDestroy();
var task = agent.Run(token);
await UniTask.Delay(TimeSpan.FromMilliseconds(500), cancellationToken: token);
await UniTask.NextFrame();

Object.DestroyImmediate(gameObject);
// ReSharper disable once MethodSupportsCancellation
await UniTask.NextFrame();

Assert.That(task.Status, Is.EqualTo(UniTaskStatus.Canceled));

LogAssert.Expect(LogType.Log, $"Enter {agent.name}.Run()");
LogAssert.Expect(LogType.Log, $"Exit {agent.name}.Run()");
}

private static SpyButton CreateButtonWithEmergencyExitAnnotation()
private static SpyButton CreateButtonWithEmergencyExitAnnotation(bool interactable = true)
{
var button = new GameObject();
button.AddComponent<EmergencyExit>();
return button.AddComponent<SpyButton>();
var button = new GameObject().AddComponent<SpyButton>();
button.GetComponent<Selectable>().interactable = interactable;
button.gameObject.AddComponent<EmergencyExit>();
return button;
}

[Test]
Expand All @@ -59,14 +61,20 @@ public async Task Run_existEmergencyExitButton_ClickEmergencyExitButton()
{
var token = cancellationTokenSource.Token;
var task = agent.Run(token);
await UniTask.Delay(TimeSpan.FromMilliseconds(500), cancellationToken: token);
await UniTask.NextFrame();

var emergencyButton = CreateButtonWithEmergencyExitAnnotation();
await UniTask.NextFrame(token);

Assert.That(emergencyButton.IsClicked, Is.True, "Clicked button with EmergencyExit annotation");
Assert.That(task.Status, Is.EqualTo(UniTaskStatus.Pending), "Keep agent running");

cancellationTokenSource.Cancel();
await UniTask.NextFrame();
}

LogAssert.Expect(LogType.Log, $"Enter {agent.name}.Run()");
LogAssert.Expect(LogType.Log, $"Exit {agent.name}.Run()");
}

[Test]
Expand All @@ -81,15 +89,20 @@ public async Task Run_existNotInteractableEmergencyExitButton_DoesNotClickEmerge
{
var token = cancellationTokenSource.Token;
var task = agent.Run(token);
await UniTask.Delay(TimeSpan.FromMilliseconds(500), cancellationToken: token);
await UniTask.NextFrame();

var emergencyButton = CreateButtonWithEmergencyExitAnnotation();
emergencyButton.gameObject.GetComponent<Button>().interactable = false;
var emergencyButton = CreateButtonWithEmergencyExitAnnotation(false);
await UniTask.NextFrame(token);

Assert.That(emergencyButton.IsClicked, Is.False, "Does not click button with EmergencyExit annotation");
Assert.That(task.Status, Is.EqualTo(UniTaskStatus.Pending), "Keep agent running");

cancellationTokenSource.Cancel();
await UniTask.NextFrame();
}

LogAssert.Expect(LogType.Log, $"Enter {agent.name}.Run()");
LogAssert.Expect(LogType.Log, $"Exit {agent.name}.Run()");
}
}
}
Loading

0 comments on commit d9f2984

Please sign in to comment.