Files
AIC-Project/Client/PackageLocal/com.unity.pipeline@0.4.0-exp.1/Tests/Editor/SecurityTokenTests.cs
T

132 lines
5.3 KiB
C#

using NUnit.Framework;
using Unity.Pipeline.Security;
namespace Unity.Pipeline.Tests.Editor
{
/// <summary>
/// Tests for security token generation and comparison.
/// </summary>
public class SecurityTokenTests
{
[SetUp]
public void SetUp() => SecurityTokenManager.ClearCache();
[TearDown]
public void TearDown() => SecurityTokenManager.ClearCache();
[Test]
public void GetOrCreateToken_FirstCall_GeneratesToken()
{
var token = SecurityTokenManager.GetOrCreateToken();
Assert.IsNotNull(token, "Token should not be null");
Assert.IsNotEmpty(token, "Token should not be empty");
Assert.GreaterOrEqual(token.Length, 32, "Token should be at least 32 characters (256-bit base64)");
}
[Test]
public void GetOrCreateToken_SecondCall_ReturnsSameToken()
{
var firstToken = SecurityTokenManager.GetOrCreateToken();
var secondToken = SecurityTokenManager.GetOrCreateToken();
Assert.AreEqual(firstToken, secondToken, "Should return the same token on subsequent calls");
}
[Test]
public void ClearCache_AfterTokenGeneration_GeneratesDifferentToken()
{
var originalToken = SecurityTokenManager.GetOrCreateToken();
SecurityTokenManager.ClearCache();
var newToken = SecurityTokenManager.GetOrCreateToken();
Assert.IsNotNull(newToken);
Assert.AreNotEqual(originalToken, newToken, "A fresh token should be generated after the cache is cleared");
}
[Test]
public void GetOrCreateToken_AfterSimulatedDomainReload_ReturnsSameToken()
{
var before = SecurityTokenManager.GetOrCreateToken();
// A domain reload clears in-memory statics but leaves SessionState intact.
SecurityTokenManager.ResetInMemoryCacheForTests();
var after = SecurityTokenManager.GetOrCreateToken();
Assert.AreEqual(before, after,
"Token must survive a domain reload (rehydrated from SessionState) so long-lived clients don't get 401.");
}
[Test]
public void ClearCache_ThenSimulatedReload_GeneratesDifferentToken()
{
var original = SecurityTokenManager.GetOrCreateToken();
// Explicit rotation erases the persisted copy, so even the reload rehydrate path
// cannot bring the old token back.
SecurityTokenManager.ClearCache();
SecurityTokenManager.ResetInMemoryCacheForTests();
var rotated = SecurityTokenManager.GetOrCreateToken();
Assert.AreNotEqual(original, rotated,
"ClearCache must erase the persisted token so a fresh one is generated, not rehydrated.");
}
[Test]
public void RotateToken_GeneratesNewTokenAndPersistsIt()
{
var original = SecurityTokenManager.GetOrCreateToken();
var rotated = SecurityTokenManager.RotateToken();
Assert.AreNotEqual(original, rotated, "RotateToken should produce a new token.");
Assert.AreEqual(rotated, SecurityTokenManager.GetOrCreateToken(),
"The rotated token should be the one served on subsequent calls.");
// And it must survive a subsequent domain reload like any session token.
SecurityTokenManager.ResetInMemoryCacheForTests();
Assert.AreEqual(rotated, SecurityTokenManager.GetOrCreateToken(),
"The rotated token should persist across domain reloads.");
}
[Test]
public void GetOrCreateToken_WarmedThenConcurrentReads_AreConsistent()
{
// Warm on the main thread, then hammer the fast path from background threads — warmed
// reads must be consistent and must not touch SessionState off-thread.
var expected = SecurityTokenManager.GetOrCreateToken();
Assert.IsNotEmpty(expected);
var results = new System.Collections.Concurrent.ConcurrentBag<string>();
System.Threading.Tasks.Parallel.For(0, 32, _ => results.Add(SecurityTokenManager.GetOrCreateToken()));
Assert.AreEqual(32, results.Count);
CollectionAssert.AreEquivalent(System.Linq.Enumerable.Repeat(expected, 32), results,
"All concurrent reads should return the single warmed token.");
}
[Test]
public void ConstantTimeEquals_IdenticalTokens_ReturnsTrue()
{
var token = SecurityTokenManager.GetOrCreateToken();
Assert.IsTrue(SecurityTokenManager.ConstantTimeEquals(token, token));
}
[Test]
public void ConstantTimeEquals_DifferentTokens_ReturnsFalse()
{
var token = SecurityTokenManager.GetOrCreateToken();
Assert.IsFalse(SecurityTokenManager.ConstantTimeEquals(token, "not-the-token"));
}
[TestCase(null, TestName = "ConstantTimeEquals_NullToken_ReturnsFalse")]
[TestCase("", TestName = "ConstantTimeEquals_EmptyToken_ReturnsFalse")]
public void ConstantTimeEquals_NullOrEmpty_ReturnsFalse(string token)
{
var expected = SecurityTokenManager.GetOrCreateToken();
Assert.IsFalse(SecurityTokenManager.ConstantTimeEquals(token, expected));
}
}
}