977 lines
51 KiB
C#
977 lines
51 KiB
C#
#if (ENABLE_CCD && ENABLE_MOQ)
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text.RegularExpressions;
|
|
using NUnit.Framework;
|
|
using System.Threading.Tasks;
|
|
using Moq;
|
|
using Unity.Services.Ccd.Management;
|
|
using Unity.Services.Ccd.Management.Models;
|
|
using UnityEngine;
|
|
using UnityEngine.TestTools;
|
|
using UnityEditor.AddressableAssets;
|
|
using UnityEditor.AddressableAssets.Build;
|
|
using UnityEditor.AddressableAssets.Settings;
|
|
using UnityEditor;
|
|
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
|
|
using UnityEngine.AddressableAssets;
|
|
using System.Net.Sockets;
|
|
using System.Net;
|
|
using System.Threading;
|
|
using System.Runtime.Remoting.Contexts;
|
|
using static UnityEngine.Networking.UnityWebRequest;
|
|
using static UnityEditor.MaterialProperty;
|
|
using UnityEditor.PackageManager;
|
|
using UnityEngine.AddressableAssets.ResourceLocators;
|
|
|
|
namespace UnityEditor.AddressableAssets.Tests.OptionalPackages.Ccd
|
|
{
|
|
public class CcdBuildMenuTests
|
|
{
|
|
public enum RemoteCatalogType
|
|
{
|
|
None,
|
|
Local,
|
|
Remote
|
|
};
|
|
static RemoteCatalogType[] remoteCatalogTypes = new RemoteCatalogType[] { RemoteCatalogType.None, RemoteCatalogType.Local, RemoteCatalogType.Remote};
|
|
|
|
private const int k_SleepTime = 30000;
|
|
|
|
// this is all cribbed from AddressableAssetTestsBase
|
|
protected const string k_TestConfigName = "CcdBuildAddressableAssetSettings.Tests";
|
|
protected const string k_ProfileDefault = "Default";
|
|
protected const string k_ProfileAutomaticAndLocal = "CCD - Automatic and Local Hosting";
|
|
protected const string k_ProfileStaticAndLocal = "CCD - Static and Local Hosting";
|
|
protected const string k_ProfileAutomaticAndStatic = "CCD - Automatic and Static Hosting";
|
|
protected const string k_SecondBuildPath = "Second.BuildPath";
|
|
protected const string k_SecondLoadPath = "Second.LoadPath";
|
|
protected const char k_PrefixSeparator = '.';
|
|
protected const string k_ProfileSettingsPath = "Assets/AddressableAssetsData/ProfileDataSourceSettings.asset";
|
|
protected string k_CcdAutomaticBuildPath = $"{AddressableAssetSettings.kCCDBuildDataPath}/ManagedEnvironment/ManagedBucket/ManagedBadge";
|
|
|
|
protected string k_CcdAutomaticLoadPath =
|
|
$"https://{CloudProjectSettings.projectId}.client-api.unity3dusercontent.com/client_api/v1/environments/{{CcdManager.EnvironmentName}}/buckets/{{CcdManager.BucketId}}/release_by_badge/{{CcdManager.Badge}}/entry_by_path/content/?path=";
|
|
|
|
|
|
protected string TestFolder => $"Assets/{TestFolderName}";
|
|
protected string TestFolderName => $"{GetType()}_Tests";
|
|
protected string ConfigFolder => TestFolder + "/Config";
|
|
private AddressableAssetSettings m_Settings;
|
|
private static string m_ProjectId;
|
|
private static string m_EnvironmentName = "production";
|
|
private static string m_EnvironmentId = "14069e00-c1e1-4b63-8d4c-0739213540fb";
|
|
private static string m_DevEnvironmentId = "14069e00-c1e1-4b63-8d4c-0739213540fb";
|
|
private static string m_ManagedBucketId = "05bb444b-5c7e-40ad-a123-fd7596f60784";
|
|
private static string m_StaticBucketId = "ce62fde2-1451-4e0c-adee-1924e95b48e7";
|
|
private static string m_SecondBucketId = "98476627-3c9d-49a2-ac79-b84e3e2b6913";
|
|
// this is used to queue up subsequent calls to ListBuckets
|
|
private Queue<List<CcdBucket>> m_listBucketCalls = new Queue<List<CcdBucket>>();
|
|
|
|
|
|
|
|
private AddressablesDataBuilderInput m_Input;
|
|
|
|
|
|
object m_CcdManagementInstance;
|
|
|
|
CcdManagementServiceSdkMock m_CcdManagementMock;
|
|
|
|
string m_ContentStatePath;
|
|
|
|
bool m_IsHttpRunning;
|
|
|
|
Thread m_HttpServer;
|
|
|
|
|
|
public static void ListenerCallback(IAsyncResult result)
|
|
{
|
|
HttpListener listener = (HttpListener)result.AsyncState;
|
|
// Call EndGetContext to complete the asynchronous operation.
|
|
HttpListenerContext context = listener.EndGetContext(result);
|
|
HttpListenerResponse response = context.Response;
|
|
|
|
|
|
string output;
|
|
var path = context.Request.Url.LocalPath;
|
|
// can't use a switch here due to interpolated path
|
|
if (path == $"/api/unity/legacy/v1/projects/{m_ProjectId}/environments")
|
|
{
|
|
output = "{\"results\": [" +
|
|
"{\"id\": \"" + m_EnvironmentId + "\", \"name\": \"production\", \"is_default\": true}," +
|
|
"{\"id\": \"" + m_DevEnvironmentId + "\", \"name\": \"development\", \"is_default\": true}" +
|
|
"]}";
|
|
}
|
|
else if (path == "/api/auth/v1/genesis-token-exchange/unity/")
|
|
{
|
|
output = "{\"token\": \"mock-token\"}";
|
|
}
|
|
else
|
|
{
|
|
throw new Exception($"Unknown path: {context.Request.Url.LocalPath}");
|
|
}
|
|
|
|
Stream stream = response.OutputStream;
|
|
var writer = new StreamWriter(stream);
|
|
writer.Write(output);
|
|
writer.Close();
|
|
}
|
|
|
|
private string startHttpServer()
|
|
{
|
|
// get unused port
|
|
var tcpListener = new TcpListener(IPAddress.Loopback, 0);
|
|
tcpListener.Start();
|
|
var port = ((IPEndPoint)tcpListener.LocalEndpoint).Port;
|
|
tcpListener.Stop();
|
|
|
|
var prefix = "http://" + IPAddress.Loopback + ":" + port;
|
|
Debug.Log(prefix);
|
|
|
|
HttpListener listener = new HttpListener();
|
|
listener.Prefixes.Add(prefix + "/");
|
|
listener.Start();
|
|
Assert.True(listener.IsListening);
|
|
|
|
m_IsHttpRunning = true;
|
|
m_HttpServer = new Thread(() =>
|
|
{
|
|
while (m_IsHttpRunning)
|
|
{
|
|
// GetContext method blocks while waiting for a request.
|
|
IAsyncResult result = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
|
|
// only wait 500ms before we check if we're still running
|
|
result.AsyncWaitHandle.WaitOne(500);
|
|
// HttpListenerContext context = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
|
|
}
|
|
|
|
listener.Close();
|
|
});
|
|
m_HttpServer.Start();
|
|
return prefix;
|
|
}
|
|
|
|
private void stopHttpServer()
|
|
{
|
|
m_IsHttpRunning = false;
|
|
if (m_HttpServer != null)
|
|
{
|
|
m_HttpServer.Join(k_SleepTime);
|
|
}
|
|
}
|
|
|
|
private void deleteContentStateBin()
|
|
{
|
|
if (File.Exists(m_ContentStatePath))
|
|
{
|
|
File.Delete(m_ContentStatePath);
|
|
}
|
|
}
|
|
|
|
private void createContentStateBin()
|
|
{
|
|
deleteContentStateBin();
|
|
Directory.CreateDirectory(Path.GetDirectoryName(m_ContentStatePath));
|
|
File.Create(m_ContentStatePath).Close();
|
|
}
|
|
|
|
[OneTimeSetUp]
|
|
public void Init()
|
|
{
|
|
AssetDatabase.DeleteAsset(k_ProfileSettingsPath);
|
|
|
|
if (Directory.Exists(TestFolder))
|
|
{
|
|
Debug.Log($"{GetType()} (init) - deleting {TestFolder}");
|
|
if (!AssetDatabase.DeleteAsset(TestFolder))
|
|
Directory.Delete(TestFolder);
|
|
}
|
|
|
|
Debug.Log($"{GetType()} (init) - creating {TestFolder}");
|
|
AssetDatabase.CreateFolder("Assets", TestFolderName);
|
|
AssetDatabase.CreateFolder(TestFolder, "Config");
|
|
|
|
m_Settings = AddressableAssetSettings.Create(ConfigFolder, k_TestConfigName, true, true);
|
|
// ProfileDataSourceSettings::UpdateCCDDataSourcesAsync uses AddressableAssetSettingsDefaultObject so we have to set it
|
|
if (!Directory.Exists("Assets/AddressableAssetsData"))
|
|
Directory.CreateDirectory("Assets/AddressableAssetsData");
|
|
AddressableAssetSettingsDefaultObject.Settings = m_Settings;
|
|
|
|
m_Input = new AddressablesDataBuilderInput(m_Settings);
|
|
|
|
// we cannot get the projectId inside of our http server thread so set it as a static value
|
|
m_ProjectId = CloudProjectSettings.projectId;
|
|
var prefix = startHttpServer();
|
|
|
|
// We need to override ProfileDataSourceSettings.m_ServicesBasePath with our test http server
|
|
var field = typeof(ProfileDataSourceSettings).GetField("m_ServicesBasePath", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
|
|
field.SetValue(null, prefix);
|
|
|
|
// we reset all profiles in here
|
|
buildLocalGroup();
|
|
|
|
// now we can create a new profile
|
|
var defaultProfileId = m_Settings.profileSettings.GetProfileId("Default");
|
|
buildGroup1();
|
|
buildGroup2();
|
|
|
|
// create ccd automatic profile
|
|
var ccdAutomaticAndLocal = m_Settings.profileSettings.AddProfile(k_ProfileAutomaticAndLocal, defaultProfileId);
|
|
m_Settings.profileSettings.SetValue(ccdAutomaticAndLocal, AddressableAssetSettings.kRemoteBuildPath, k_CcdAutomaticBuildPath);
|
|
m_Settings.profileSettings.SetValue(ccdAutomaticAndLocal, AddressableAssetSettings.kRemoteLoadPath, k_CcdAutomaticLoadPath);
|
|
m_Settings.profileSettings.SetValue(ccdAutomaticAndLocal, k_SecondBuildPath, AddressableAssetSettings.kLocalBuildPathValue);
|
|
m_Settings.profileSettings.SetValue(ccdAutomaticAndLocal, k_SecondLoadPath, AddressableAssetSettings.kLocalLoadPathValue);
|
|
m_Settings.profileSettings.SetValue(ccdAutomaticAndLocal, ProfileDataSourceSettings.ENVIRONMENT_NAME, "production");
|
|
|
|
|
|
var ccdStaticAndLocal = m_Settings.profileSettings.AddProfile(k_ProfileStaticAndLocal, defaultProfileId);
|
|
m_Settings.profileSettings.SetValue(ccdStaticAndLocal, AddressableAssetSettings.kRemoteBuildPath,
|
|
$"{AddressableAssetSettings.kCCDBuildDataPath}/{m_EnvironmentId}/{m_StaticBucketId}/latest");
|
|
m_Settings.profileSettings.SetValue(ccdStaticAndLocal, AddressableAssetSettings.kRemoteLoadPath,
|
|
$"https://{m_ProjectId}.client-api.unity3dusercontent.com/client_api/v1/environments/production/buckets/{m_StaticBucketId}/release_by_badge/latest/entry_by_path/content/?path=");
|
|
m_Settings.profileSettings.SetValue(ccdStaticAndLocal, k_SecondBuildPath, AddressableAssetSettings.kLocalBuildPathValue);
|
|
m_Settings.profileSettings.SetValue(ccdStaticAndLocal, k_SecondLoadPath, AddressableAssetSettings.kLocalLoadPathValue);
|
|
m_Settings.profileSettings.SetValue(ccdStaticAndLocal, ProfileDataSourceSettings.ENVIRONMENT_NAME, "production");
|
|
|
|
var ccdStaticAndAutomatic = m_Settings.profileSettings.AddProfile(k_ProfileAutomaticAndStatic, defaultProfileId);
|
|
m_Settings.profileSettings.SetValue(ccdStaticAndAutomatic, AddressableAssetSettings.kRemoteBuildPath, k_CcdAutomaticBuildPath);
|
|
m_Settings.profileSettings.SetValue(ccdStaticAndAutomatic, AddressableAssetSettings.kRemoteLoadPath, k_CcdAutomaticLoadPath);
|
|
m_Settings.profileSettings.SetValue(ccdStaticAndAutomatic, k_SecondBuildPath, $"{AddressableAssetSettings.kCCDBuildDataPath}/{m_EnvironmentId}/{m_SecondBucketId}/latest");
|
|
m_Settings.profileSettings.SetValue(ccdStaticAndAutomatic, k_SecondLoadPath,
|
|
$"https://{m_ProjectId}.client-api.unity3dusercontent.com/client_api/v1/environments/production/buckets/{m_SecondBucketId}/release_by_badge/latest/entry_by_path/content/?path=");
|
|
m_Settings.profileSettings.SetValue(ccdStaticAndAutomatic, ProfileDataSourceSettings.ENVIRONMENT_NAME, "production");
|
|
|
|
setManagedBucketManually("", "", "");
|
|
}
|
|
|
|
[SetUp]
|
|
public async Task SetUp()
|
|
{
|
|
// clear out the build directory
|
|
if (Directory.Exists(AddressableAssetSettings.kCCDBuildDataPath))
|
|
{
|
|
Directory.Delete(AddressableAssetSettings.kCCDBuildDataPath, true);
|
|
}
|
|
|
|
// Setup fake CcdManagementService
|
|
m_CcdManagementMock = new CcdManagementServiceSdkMock();
|
|
m_CcdManagementMock.Init();
|
|
|
|
#if CCD_3_OR_NEWER
|
|
m_CcdManagementMock.Setup(client => client.ListBucketsAsync(It.IsAny<PageOptions>(), It.IsAny<ListBucketsOptions>())).Returns<PageOptions, ListBucketsOptions>((v, bucketsOptions) =>
|
|
#else
|
|
m_CcdManagementMock.Setup(client => client.ListBucketsAsync(It.IsAny<PageOptions>())).Returns<PageOptions>((v) =>
|
|
#endif
|
|
{
|
|
if (v.Page == 1)
|
|
{
|
|
if (m_listBucketCalls.Count == 0)
|
|
{
|
|
throw new Exception("no list bucket data found for call");
|
|
}
|
|
|
|
return Task.FromResult(m_listBucketCalls.Dequeue());
|
|
}
|
|
if (v.Page == 2)
|
|
throw new CcdManagementException(CcdManagementErrorCodes.OutOfRange, "out of range");
|
|
return null;
|
|
});
|
|
|
|
// Refresh data sources to populate our profiles
|
|
Assert.True(await refreshDataSources());
|
|
|
|
// Setup ContentStatePath
|
|
var getContentStateBuildPathMethod = m_Input.AddressableSettings.GetType().GetMethod("GetContentStateBuildPath", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
var contentStateBuildPath = (string)getContentStateBuildPathMethod.Invoke(m_Input.AddressableSettings, null);
|
|
m_ContentStatePath = Path.Combine(contentStateBuildPath, "addressables_content_state.bin");
|
|
resetManagedBucket();
|
|
}
|
|
|
|
[TearDown]
|
|
public void Teardown()
|
|
{
|
|
m_CcdManagementMock.VerifyAll();
|
|
AssetDatabase.DeleteAsset(k_ProfileSettingsPath);
|
|
deleteContentStateBin();
|
|
if (m_listBucketCalls.Count > 0)
|
|
{
|
|
throw new Exception("not all list bucket calls were made");
|
|
}
|
|
}
|
|
|
|
[OneTimeTearDown]
|
|
public void Cleanup()
|
|
{
|
|
if (Directory.Exists(TestFolder))
|
|
{
|
|
Debug.Log($"{GetType()} - (cleanup) deleting {TestFolder}");
|
|
AssetDatabase.DeleteAsset(TestFolder);
|
|
}
|
|
|
|
|
|
if (File.Exists(k_ProfileSettingsPath))
|
|
{
|
|
File.Delete(k_ProfileSettingsPath);
|
|
}
|
|
|
|
EditorBuildSettings.RemoveConfigObject(k_TestConfigName);
|
|
|
|
stopHttpServer();
|
|
}
|
|
|
|
private void createFile(string fileName)
|
|
{
|
|
if (!File.Exists(fileName))
|
|
{
|
|
if (!Directory.Exists(fileName))
|
|
Directory.CreateDirectory(Path.GetDirectoryName(fileName));
|
|
var fs = File.Create(fileName);
|
|
fs.Dispose();
|
|
}
|
|
|
|
Assert.True(File.Exists(fileName));
|
|
}
|
|
|
|
private void setupRemoteCatalog(RemoteCatalogType remoteCatalogType)
|
|
{
|
|
switch(remoteCatalogType)
|
|
{
|
|
case RemoteCatalogType.None:
|
|
m_Settings.BuildRemoteCatalog = false;
|
|
m_Settings.RemoteCatalogBuildPath = new ProfileValueReference();
|
|
break;
|
|
case RemoteCatalogType.Local:
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.RemoteCatalogBuildPath = new ProfileValueReference();
|
|
m_Settings.RemoteCatalogBuildPath.SetVariableByName(m_Settings, "Local.BuildPath");
|
|
m_Settings.RemoteCatalogLoadPath.SetVariableByName(m_Settings, "Local.LoadPath");
|
|
break;
|
|
case RemoteCatalogType.Remote:
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.RemoteCatalogBuildPath = new ProfileValueReference();
|
|
m_Settings.RemoteCatalogBuildPath.SetVariableByName(m_Settings, "Remote.BuildPath");
|
|
m_Settings.RemoteCatalogLoadPath.SetVariableByName(m_Settings, "Remote.LoadPath");
|
|
break;
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AutomaticAndStaticProfileUploadAndReleaseSuccess()
|
|
{
|
|
const string managedFileName = AddressableAssetSettings.kCCDBuildDataPath + "/ManagedEnvironment/ManagedBucket/ManagedBadge/managed_file.txt";
|
|
createFile(managedFileName);
|
|
string staticFileName = $"{AddressableAssetSettings.kCCDBuildDataPath}/{m_EnvironmentId}/{m_StaticBucketId}/latest/static_file.txt";
|
|
createFile(staticFileName);
|
|
|
|
var buildResult = new AddressablesPlayerBuildResult
|
|
{
|
|
FileRegistry = new FileRegistry()
|
|
};
|
|
buildResult.FileRegistry.AddFile(managedFileName);
|
|
buildResult.FileRegistry.AddFile(staticFileName);
|
|
|
|
var managedEntryId = Guid.Parse("678fcf3b-203c-4c95-9142-3c774de50f94");
|
|
var staticEntryId = Guid.Parse("ca7e45ab-6f51-4286-adbd-d061b14af614");
|
|
m_CcdManagementMock.Setup(client => client.CreateOrUpdateEntryByPathAsync(It.Is<EntryByPathOptions>((v) => v.Path == "managed_file.txt"), It.IsAny<EntryModelOptions>()))
|
|
.Returns(Task.FromResult(new CcdEntry(entryid: managedEntryId)));
|
|
m_CcdManagementMock.Setup(client => client.UploadContentAsync(It.Is<UploadContentOptions>((v) => v.EntryId == managedEntryId))).Returns(Task.FromResult(Task.CompletedTask));
|
|
m_CcdManagementMock.Setup(client => client.CreateOrUpdateEntryByPathAsync(It.Is<EntryByPathOptions>((v) => v.Path == "static_file.txt"), It.IsAny<EntryModelOptions>()))
|
|
.Returns(Task.FromResult(new CcdEntry(entryid: staticEntryId)));
|
|
m_CcdManagementMock.Setup(client => client.UploadContentAsync(It.Is<UploadContentOptions>((v) => v.EntryId == staticEntryId))).Returns(Task.FromResult(Task.CompletedTask));
|
|
m_CcdManagementMock.Setup(client => client.CreateReleaseAsync(It.IsAny<CreateReleaseOptions>())).Returns(Task.FromResult(new CcdRelease()));
|
|
m_CcdManagementMock.Setup(client => client.GetEntryByPathAsync(It.Is<EntryByPathOptions>((v) => v.Path == "addressables_content_state.bin")))
|
|
.Throws(new CcdManagementException(54, "not found"));
|
|
|
|
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setManagedBucketManually(m_EnvironmentId, m_EnvironmentName, m_ManagedBucketId);
|
|
var result = await CcdBuildEvents.Instance.UploadAndRelease(m_Input, buildResult);
|
|
Assert.True(result);
|
|
|
|
File.Delete(managedFileName);
|
|
File.Delete(staticFileName);
|
|
}
|
|
|
|
|
|
[Test]
|
|
public async Task AutomaticProfileUploadAndReleaseSuccess()
|
|
{
|
|
const string fileName = AddressableAssetSettings.kCCDBuildDataPath + "/ManagedEnvironment/ManagedBucket/ManagedBadge/ccd_file.txt";
|
|
createFile(fileName);
|
|
|
|
var buildResult = new AddressablesPlayerBuildResult
|
|
{
|
|
FileRegistry = new FileRegistry()
|
|
};
|
|
buildResult.FileRegistry.AddFile(fileName);
|
|
|
|
m_CcdManagementMock.Setup(client => client.CreateOrUpdateEntryByPathAsync(It.IsAny<EntryByPathOptions>(), It.IsAny<EntryModelOptions>())).Returns(Task.FromResult(new CcdEntry()));
|
|
m_CcdManagementMock.Setup(client => client.UploadContentAsync(It.IsAny<UploadContentOptions>())).Returns(Task.FromResult(Task.CompletedTask));
|
|
m_CcdManagementMock.Setup(client => client.GetEntryByPathAsync(It.IsAny<EntryByPathOptions>())).Returns(Task.FromResult(new CcdEntry()));
|
|
m_CcdManagementMock.Setup(client => client.CreateReleaseAsync(It.IsAny<CreateReleaseOptions>())).Returns(Task.FromResult(new CcdRelease()));
|
|
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setManagedBucketManually(m_EnvironmentId, m_EnvironmentName, m_ManagedBucketId);
|
|
var result = await CcdBuildEvents.Instance.UploadAndRelease(m_Input, buildResult);
|
|
Assert.True(result);
|
|
|
|
File.Delete(fileName);
|
|
}
|
|
|
|
[Test]
|
|
public async Task StaticProfileUploadAndReleaseSuccess()
|
|
{
|
|
string fileName = $"{AddressableAssetSettings.kCCDBuildDataPath}/{m_EnvironmentId}/{m_StaticBucketId}/latest/ccd_file.txt";
|
|
createFile(fileName);
|
|
|
|
var buildResult = new AddressablesPlayerBuildResult
|
|
{
|
|
FileRegistry = new FileRegistry()
|
|
};
|
|
buildResult.FileRegistry.AddFile(fileName);
|
|
|
|
m_CcdManagementMock.Setup(client => client.CreateOrUpdateEntryByPathAsync(It.IsAny<EntryByPathOptions>(), It.IsAny<EntryModelOptions>())).Returns(Task.FromResult(new CcdEntry()));
|
|
m_CcdManagementMock.Setup(client => client.UploadContentAsync(It.IsAny<UploadContentOptions>())).Returns(Task.FromResult(Task.CompletedTask));
|
|
m_CcdManagementMock.Setup(client => client.GetEntryByPathAsync(It.IsAny<EntryByPathOptions>())).Returns(Task.FromResult(new CcdEntry()));
|
|
m_CcdManagementMock.Setup(client => client.CreateReleaseAsync(It.IsAny<CreateReleaseOptions>())).Returns(Task.FromResult(new CcdRelease()));
|
|
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileStaticAndLocal);
|
|
setManagedBucketManually(null, "", null);
|
|
var result = await CcdBuildEvents.Instance.UploadAndRelease(m_Input, buildResult);
|
|
Assert.True(result);
|
|
|
|
File.Delete(fileName);
|
|
}
|
|
|
|
[Test]
|
|
public async Task UploadAndReleaseNoFile()
|
|
{
|
|
var result = await CcdBuildEvents.Instance.UploadAndRelease(m_Input, new AddressablesPlayerBuildResult());
|
|
Assert.False(result);
|
|
}
|
|
|
|
[Test]
|
|
public async Task UploadAndReleaseCreateEntryError()
|
|
{
|
|
|
|
string fileName = $"{AddressableAssetSettings.kCCDBuildDataPath}/{m_EnvironmentId}/{m_StaticBucketId}/latest/ccd_file.txt";
|
|
createFile(fileName);
|
|
|
|
var buildResult = new AddressablesPlayerBuildResult
|
|
{
|
|
FileRegistry = new FileRegistry()
|
|
};
|
|
buildResult.FileRegistry.AddFile(fileName);
|
|
|
|
m_CcdManagementMock.Setup(client => client.CreateOrUpdateEntryByPathAsync(It.IsAny<EntryByPathOptions>(), It.IsAny<EntryModelOptions>())).Throws(InternalErrorException());
|
|
LogAssert.Expect(LogType.Error, new Regex($".*Unable to create entry for ccd_file.txt: crash.*", RegexOptions.Singleline));
|
|
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileStaticAndLocal);
|
|
setManagedBucketManually(null, "", null);
|
|
var result = await CcdBuildEvents.Instance.UploadAndRelease(m_Input, buildResult);
|
|
Assert.False(result);
|
|
|
|
File.Delete(fileName);
|
|
}
|
|
|
|
[Test]
|
|
public async Task UploadContentStateNoBin()
|
|
{
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setManagedBucketManually(m_EnvironmentId, m_EnvironmentName, m_ManagedBucketId);
|
|
|
|
var result = await CcdBuildEvents.Instance.UploadContentState(m_Input, new AddressablesPlayerBuildResult());
|
|
Assert.False(result);
|
|
LogAssert.Expect(LogType.Error, new Regex("^(Content state file is missing)"));
|
|
}
|
|
|
|
[Test]
|
|
public async Task UploadContentStateNoBucketSet()
|
|
{
|
|
createContentStateBin();
|
|
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setManagedBucketManually(m_EnvironmentId, m_EnvironmentName, null);
|
|
|
|
var result = await CcdBuildEvents.Instance.UploadContentState(m_Input, new AddressablesPlayerBuildResult());
|
|
Assert.False(result);
|
|
LogAssert.Expect(LogType.Error, "Content state could not be uploaded as no bucket was specified. This is populated for managed profiles in the VerifyBucket event.");
|
|
}
|
|
|
|
[Test]
|
|
public async Task UploadContentStateNoRemoteCatalog()
|
|
{
|
|
m_Settings.BuildRemoteCatalog = false;
|
|
|
|
var result = await CcdBuildEvents.Instance.UploadContentState(m_Input, new AddressablesPlayerBuildResult());
|
|
Assert.True(result);
|
|
LogAssert.Expect(LogType.Warning, "Not uploading content state, because 'Build Remote Catalog' is not checked in Addressable Asset Settings. This will disable content updates");
|
|
}
|
|
|
|
[Test]
|
|
public async Task UploadContentStateRemoteCatalogPathsLocalHosting()
|
|
{
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileDefault);
|
|
var result = await CcdBuildEvents.Instance.UploadContentState(m_Input, new AddressablesPlayerBuildResult());
|
|
Assert.False(result);
|
|
LogAssert.Expect(LogType.Error, "Content state could not be uploaded as the remote catalog is not targeting CCD");
|
|
}
|
|
|
|
[Test]
|
|
public async Task UploadContentStateSuccess()
|
|
{
|
|
createContentStateBin();
|
|
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setManagedBucketManually(m_EnvironmentId, m_EnvironmentName, m_ManagedBucketId);
|
|
|
|
m_CcdManagementMock.Setup(client => client.CreateOrUpdateEntryByPathAsync(It.IsAny<EntryByPathOptions>(), It.IsAny<EntryModelOptions>())).Returns(Task.FromResult(new CcdEntry()));
|
|
m_CcdManagementMock.Setup(client => client.UploadContentAsync(It.IsAny<UploadContentOptions>())).Returns(Task.FromResult(Task.CompletedTask));
|
|
|
|
var result = await CcdBuildEvents.Instance.UploadContentState(m_Input, new AddressablesPlayerBuildResult());
|
|
Assert.True(result);
|
|
}
|
|
|
|
[Test]
|
|
public async Task UploadContentUploadFailure()
|
|
{
|
|
createContentStateBin();
|
|
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setManagedBucketManually(m_EnvironmentId, m_EnvironmentName, m_ManagedBucketId);
|
|
|
|
m_CcdManagementMock.Setup(client => client.CreateOrUpdateEntryByPathAsync(It.IsAny<EntryByPathOptions>(), It.IsAny<EntryModelOptions>())).Returns(Task.FromResult(new CcdEntry()));
|
|
m_CcdManagementMock.Setup(client => client.UploadContentAsync(It.IsAny<UploadContentOptions>())).Throws(InternalErrorException());
|
|
|
|
var result = await CcdBuildEvents.Instance.UploadContentState(m_Input, new AddressablesPlayerBuildResult());
|
|
Assert.False(result);
|
|
LogAssert.Expect(LogType.Error, $"Unable to upload content state: crash");
|
|
}
|
|
|
|
[Test]
|
|
public async Task UploadContentCreateEntryFailure()
|
|
{
|
|
createContentStateBin();
|
|
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setManagedBucketManually(m_EnvironmentId, m_EnvironmentName, m_ManagedBucketId);
|
|
|
|
m_CcdManagementMock.Setup(client => client.CreateOrUpdateEntryByPathAsync(It.IsAny<EntryByPathOptions>(), It.IsAny<EntryModelOptions>())).Throws(InternalErrorException());
|
|
|
|
var result = await CcdBuildEvents.Instance.UploadContentState(m_Input, new AddressablesPlayerBuildResult());
|
|
Assert.False(result);
|
|
LogAssert.Expect(LogType.Error, $"Unable to create entry for content state: crash");
|
|
}
|
|
|
|
|
|
[Test]
|
|
public async Task DownloadContentStateNoRemoteCatalog()
|
|
{
|
|
m_Input.AddressableSettings.BuildRemoteCatalog = false;
|
|
var result = await CcdBuildEvents.Instance.DownloadContentStateBin(m_Input);
|
|
Assert.True(result);
|
|
LogAssert.Expect(LogType.Warning, "Not downloading content state because 'Build Remote Catalog' is not checked in Addressable Asset Settings. This will disable content updates");
|
|
}
|
|
|
|
[Test]
|
|
public async Task DownloadContentStateRemoteCatalogPathsLocalHosting()
|
|
{
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileDefault);
|
|
;
|
|
|
|
var result = await CcdBuildEvents.Instance.DownloadContentStateBin(m_Input);
|
|
Assert.False(result);
|
|
LogAssert.Expect(LogType.Error, "Content state could not be downloaded as the remote catalog is not targeting CCD");
|
|
}
|
|
|
|
[Test]
|
|
public async Task DownloadContentStateNoBin()
|
|
{
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setManagedBucketManually(m_EnvironmentId, m_EnvironmentName, m_ManagedBucketId);
|
|
|
|
var error = new CcdManagementException(54, "not found");
|
|
m_CcdManagementMock.Setup(client => client.GetEntryByPathAsync(It.IsAny<EntryByPathOptions>())).Throws(error);
|
|
|
|
var result = await CcdBuildEvents.Instance.DownloadContentStateBin(m_Input);
|
|
Assert.True(result);
|
|
}
|
|
|
|
[Test]
|
|
public async Task DownloadContentStateNoBucketSet()
|
|
{
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setManagedBucketManually(m_EnvironmentId, m_EnvironmentName, null);
|
|
|
|
var result = await CcdBuildEvents.Instance.DownloadContentStateBin(m_Input);
|
|
Assert.False(result);
|
|
LogAssert.Expect(LogType.Error, "Content state could not be downloaded as no bucket was specified. This is populated for managed profiles in the VerifyTargetBucket event.");
|
|
}
|
|
|
|
[Test]
|
|
public async Task DownloadContentStateSuccess()
|
|
{
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setManagedBucketManually(m_EnvironmentId, m_EnvironmentName, m_ManagedBucketId);
|
|
|
|
|
|
m_CcdManagementMock.Setup(client => client.GetEntryByPathAsync(It.IsAny<EntryByPathOptions>())).Returns(Task.FromResult(new CcdEntry()));
|
|
m_CcdManagementMock.Setup(client => client.GetContentAsync(It.IsAny<EntryOptions>())).Returns(Task.FromResult((Stream)new MemoryStream()));
|
|
|
|
var result = await CcdBuildEvents.Instance.DownloadContentStateBin(m_Input);
|
|
Assert.True(result);
|
|
Assert.True(File.Exists(m_ContentStatePath));
|
|
}
|
|
|
|
[Test]
|
|
public async Task DownloadContentStateGetEntryFailure()
|
|
{
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setManagedBucketManually(m_EnvironmentId, m_EnvironmentName, m_ManagedBucketId);
|
|
|
|
|
|
m_CcdManagementMock.Setup(client => client.GetEntryByPathAsync(It.IsAny<EntryByPathOptions>())).Throws(this.InternalErrorException());
|
|
|
|
var result = await CcdBuildEvents.Instance.DownloadContentStateBin(m_Input);
|
|
Assert.False(result);
|
|
Assert.False(File.Exists(m_ContentStatePath));
|
|
LogAssert.Expect(LogType.Error, $"Unable to get entry for content state addressables_content_state.bin: crash");
|
|
}
|
|
|
|
[Test]
|
|
public async Task DownloadContentStateUploadFailure()
|
|
{
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setManagedBucketManually(m_EnvironmentId, m_EnvironmentName, m_ManagedBucketId);
|
|
|
|
|
|
m_CcdManagementMock.Setup(client => client.GetEntryByPathAsync(It.IsAny<EntryByPathOptions>())).Returns(Task.FromResult(new CcdEntry()));
|
|
m_CcdManagementMock.Setup(client => client.GetContentAsync(It.IsAny<EntryOptions>())).Throws(InternalErrorException);
|
|
|
|
var result = await CcdBuildEvents.Instance.DownloadContentStateBin(m_Input);
|
|
Assert.False(result);
|
|
Assert.False(File.Exists(m_ContentStatePath));
|
|
LogAssert.Expect(LogType.Error, $"Unable to upload content state addressables_content_state.bin: crash");
|
|
}
|
|
|
|
private void resetManagedBucket()
|
|
{
|
|
var ccdManagedDataField = m_Input.AddressableSettings.GetType().GetField("m_CcdManagedData", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
ccdManagedDataField.SetValue(m_Input.AddressableSettings, new CcdManagedData());
|
|
}
|
|
|
|
|
|
// the bucket ID is set in VerifyBucket so if you are testing another method in isolation you'll probably need to call this to set the bucket
|
|
private void setManagedBucketManually(string environmentId, string environmentName, string bucketId)
|
|
{
|
|
// VerifyBucket sets the BucketId in m_CcdManagedData which we need to manually populate since it's only
|
|
var ccdManagedDataField = m_Input.AddressableSettings.GetType().GetField("m_CcdManagedData", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
var ccdManagedDataInstance = ccdManagedDataField.GetValue(m_Input.AddressableSettings);
|
|
var bucketIdField = ccdManagedDataInstance.GetType().GetField("BucketId", BindingFlags.Public | BindingFlags.Instance);
|
|
bucketIdField.SetValue(ccdManagedDataInstance, bucketId);
|
|
|
|
var environmentIdField = ccdManagedDataInstance.GetType().GetField("EnvironmentId", BindingFlags.Public | BindingFlags.Instance);
|
|
environmentIdField.SetValue(ccdManagedDataInstance, environmentId);
|
|
|
|
var environmentNameField = ccdManagedDataInstance.GetType().GetField("EnvironmentName", BindingFlags.Public | BindingFlags.Instance);
|
|
environmentNameField.SetValue(ccdManagedDataInstance, environmentName);
|
|
}
|
|
|
|
public void buildLocalGroup()
|
|
{
|
|
m_Settings.profileSettings.CreateValue(ProfileDataSourceSettings.ENVIRONMENT_NAME, "production");
|
|
m_Settings.profileSettings.CreateValue(k_SecondBuildPath, AddressableAssetSettings.kRemoteBuildPathValue);
|
|
m_Settings.profileSettings.CreateValue(k_SecondLoadPath, AddressableAssetSettings.kRemoteLoadPathValue);
|
|
|
|
|
|
GameObject testObject = new GameObject("DrabCube");
|
|
PrefabUtility.SaveAsPrefabAsset(testObject, TestFolder + "/drab.prefab");
|
|
var assetGUID = AssetDatabase.AssetPathToGUID(TestFolder + "/drab.prefab");
|
|
|
|
var group = m_Settings.FindGroup("Default Local Group");
|
|
m_Settings.CreateOrMoveEntry(assetGUID, group);
|
|
}
|
|
|
|
public void buildGroup1()
|
|
{
|
|
var group = m_Settings.CreateGroup("First Group", false, false, false, null);
|
|
|
|
var schema = group.AddSchema<BundledAssetGroupSchema>();
|
|
schema.BuildPath.SetVariableByName(m_Settings, AddressableAssetSettings.kRemoteBuildPath);
|
|
schema.LoadPath.SetVariableByName(m_Settings, AddressableAssetSettings.kRemoteLoadPath);
|
|
schema.BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackTogether;
|
|
|
|
group.AddSchema<ContentUpdateGroupSchema>().StaticContent = true;
|
|
|
|
GameObject testObject = new GameObject("RedCube");
|
|
PrefabUtility.SaveAsPrefabAsset(testObject, TestFolder + "/red.prefab");
|
|
var assetGUID = AssetDatabase.AssetPathToGUID(TestFolder + "/red.prefab");
|
|
m_Settings.CreateOrMoveEntry(assetGUID, group);
|
|
}
|
|
|
|
public void buildGroup2()
|
|
{
|
|
var group = m_Settings.CreateGroup("Second Group", false, false, false, null);
|
|
|
|
var schema = group.AddSchema<BundledAssetGroupSchema>();
|
|
schema.BuildPath.SetVariableByName(m_Settings, k_SecondBuildPath);
|
|
schema.LoadPath.SetVariableByName(m_Settings, k_SecondLoadPath);
|
|
schema.BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackTogether;
|
|
|
|
group.AddSchema<ContentUpdateGroupSchema>().StaticContent = true;
|
|
|
|
GameObject testObject = new GameObject("BlueCube");
|
|
PrefabUtility.SaveAsPrefabAsset(testObject, TestFolder + "/blue.prefab");
|
|
var assetGUID = AssetDatabase.AssetPathToGUID(TestFolder + "/blue.prefab");
|
|
m_Settings.CreateOrMoveEntry(assetGUID, group);
|
|
}
|
|
|
|
public async Task<bool> refreshDataSources()
|
|
{
|
|
var managedBucket = new CcdBucket(id: Guid.Parse(m_ManagedBucketId), name: EditorUserBuildSettings.activeBuildTarget.ToString(), attributes: new CcdBucketAttributes(promoteOnly: false));
|
|
var staticBucket = new CcdBucket(id: Guid.Parse(m_StaticBucketId), name: "Static Bucket", attributes: new CcdBucketAttributes(promoteOnly: false));
|
|
var secondBucket = new CcdBucket(id: Guid.Parse(m_SecondBucketId), name: "Second Bucket", attributes: new CcdBucketAttributes(promoteOnly: false));
|
|
var buckets = new List<CcdBucket>();
|
|
buckets.Add(managedBucket);
|
|
buckets.Add(staticBucket);
|
|
buckets.Add(secondBucket);
|
|
|
|
m_CcdManagementMock.Setup(client => client.ListBadgesAsync(managedBucket.Id, It.IsAny<PageOptions>()))
|
|
.Throws(new CcdManagementException(CcdManagementErrorCodes.OutOfRange, "out of range"));
|
|
m_CcdManagementMock.Setup(client => client.ListBadgesAsync(staticBucket.Id, It.IsAny<PageOptions>()))
|
|
.Throws(new CcdManagementException(CcdManagementErrorCodes.OutOfRange, "out of range"));
|
|
m_CcdManagementMock.Setup(client => client.ListBadgesAsync(secondBucket.Id, It.IsAny<PageOptions>()))
|
|
.Throws(new CcdManagementException(CcdManagementErrorCodes.OutOfRange, "out of range"));
|
|
return await refreshDataSources(buckets);
|
|
}
|
|
public async Task<bool> refreshDataSources(List<CcdBucket> buckets)
|
|
{
|
|
// this is refresh data
|
|
// production
|
|
m_listBucketCalls.Enqueue(buckets);
|
|
// development
|
|
m_listBucketCalls.Enqueue(new List<CcdBucket>());
|
|
|
|
// I can't add group types directly as it's internal. So adding my test group types by calling
|
|
var result = await CcdBuildEvents.Instance.RefreshDataSources(m_Input);
|
|
|
|
// we have to set the currentEnvironment as that is only set through the GUI by default
|
|
var currentEnvironmentField = ProfileDataSourceSettings.GetSettings().GetType().GetField("currentEnvironment", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
var currentEnvironment = currentEnvironmentField.GetValue(ProfileDataSourceSettings.GetSettings());
|
|
var currentEnvironmentIdField = currentEnvironment.GetType().GetField("id", BindingFlags.Public | BindingFlags.Instance);
|
|
currentEnvironmentIdField.SetValue(currentEnvironment, m_EnvironmentId);
|
|
var currentEnvironmentNameField = currentEnvironment.GetType().GetField("name", BindingFlags.Public | BindingFlags.Instance);
|
|
currentEnvironmentNameField.SetValue(currentEnvironment, "production");
|
|
var currentEnvironmentProjectField = currentEnvironment.GetType().GetField("projectGenesisId", BindingFlags.Public | BindingFlags.Instance);
|
|
currentEnvironmentProjectField.SetValue(currentEnvironment, m_ProjectId);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
[Test]
|
|
public async Task VerifyTargetBucketAllLocal([ValueSource(nameof(remoteCatalogTypes))] RemoteCatalogType remoteCatalogType)
|
|
{
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileDefault);
|
|
setupRemoteCatalog(remoteCatalogType);
|
|
var success = await CcdBuildEvents.Instance.VerifyTargetBucket(m_Input);
|
|
Assert.True(success);
|
|
#if !ADDRESSABLES_WITHOUT_GROUP_FIXES
|
|
LogAssert.Expect(LogType.Warning, "No Addressable Asset Groups have been marked remote or the current profile is not using CCD.");
|
|
#endif
|
|
|
|
m_Settings.BuildRemoteCatalog = true;
|
|
success = await CcdBuildEvents.Instance.VerifyTargetBucket(m_Input);
|
|
Assert.True(success);
|
|
#if !ADDRESSABLES_WITHOUT_GROUP_FIXES
|
|
LogAssert.Expect(LogType.Warning, "No Addressable Asset Groups have been marked remote or the current profile is not using CCD.");
|
|
LogAssert.Expect(LogType.Warning, "A remote catalog will be built without any remote Asset Bundles.");
|
|
#endif
|
|
}
|
|
|
|
private CcdManagementException AlreadyExistsException()
|
|
{
|
|
return new CcdManagementException(CcdManagementErrorCodes.AlreadyExists, "already exists");
|
|
}
|
|
|
|
private CcdManagementException InternalErrorException()
|
|
{
|
|
return new CcdManagementException(CcdManagementErrorCodes.InternalError, "crash");
|
|
}
|
|
|
|
[Test]
|
|
public async Task VerifyTargetBucketAutomaticAndStaticProfile([ValueSource(nameof(remoteCatalogTypes))] RemoteCatalogType remoteCatalogType)
|
|
{
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndStatic);
|
|
setupRemoteCatalog(remoteCatalogType);
|
|
var success = await CcdBuildEvents.Instance.VerifyTargetBucket(m_Input);
|
|
Assert.True(success);
|
|
|
|
var ccdManagedDataField = m_Input.AddressableSettings.GetType().GetField("m_CcdManagedData", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
var ccdManagedDataInstance = ccdManagedDataField.GetValue(m_Input.AddressableSettings);
|
|
var bucketIdField = ccdManagedDataInstance.GetType().GetField("BucketId", BindingFlags.Public | BindingFlags.Instance);
|
|
var verifiedBucketId = bucketIdField.GetValue(ccdManagedDataInstance);
|
|
Assert.AreEqual(m_ManagedBucketId, verifiedBucketId);
|
|
}
|
|
|
|
[Test]
|
|
public async Task VerifyTargetBucketAutomaticProfile([ValueSource(nameof(remoteCatalogTypes))] RemoteCatalogType remoteCatalogType)
|
|
{
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setupRemoteCatalog(remoteCatalogType);
|
|
|
|
var success = await CcdBuildEvents.Instance.VerifyTargetBucket(m_Input);
|
|
Assert.True(success);
|
|
|
|
var ccdManagedDataField = m_Input.AddressableSettings.GetType().GetField("m_CcdManagedData", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
var ccdManagedDataInstance = ccdManagedDataField.GetValue(m_Input.AddressableSettings);
|
|
var bucketIdField = ccdManagedDataInstance.GetType().GetField("BucketId", BindingFlags.Public | BindingFlags.Instance);
|
|
var verifiedBucketId = bucketIdField.GetValue(ccdManagedDataInstance);
|
|
Assert.AreEqual(m_ManagedBucketId, verifiedBucketId);
|
|
}
|
|
|
|
[Test]
|
|
public async Task VerifyTargetBucketAutomaticProfileNoManagedData([ValueSource(nameof(remoteCatalogTypes))] RemoteCatalogType remoteCatalogType)
|
|
{
|
|
var managedBucket = new CcdBucket(id: Guid.Parse(m_ManagedBucketId), name: EditorUserBuildSettings.activeBuildTarget.ToString(), attributes: new CcdBucketAttributes(promoteOnly: false));
|
|
m_CcdManagementMock.Setup(client => client.CreateBucketAsync(It.Is<CreateBucketOptions>((v) => v.Name == EditorUserBuildSettings.activeBuildTarget.ToString())))
|
|
.Returns(Task.FromResult(managedBucket));
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setupRemoteCatalog(remoteCatalogType);
|
|
|
|
resetManagedBucket();
|
|
|
|
// this should be a completely new remote project
|
|
await refreshDataSources(new List<CcdBucket>());
|
|
|
|
var success = await CcdBuildEvents.Instance.VerifyTargetBucket(m_Input);
|
|
Assert.True(success);
|
|
|
|
var ccdManagedDataField = m_Input.AddressableSettings.GetType().GetField("m_CcdManagedData", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
var ccdManagedDataInstance = ccdManagedDataField.GetValue(m_Input.AddressableSettings);
|
|
var bucketIdField = ccdManagedDataInstance.GetType().GetField("BucketId", BindingFlags.Public | BindingFlags.Instance);
|
|
var verifiedBucketId = bucketIdField.GetValue(ccdManagedDataInstance);
|
|
Assert.AreEqual(m_ManagedBucketId, verifiedBucketId);
|
|
}
|
|
|
|
[Test]
|
|
public async Task VerifyTargetBucketAutomaticProfileNoManagedDataBucketExists([ValueSource(nameof(remoteCatalogTypes))] RemoteCatalogType remoteCatalogType)
|
|
{
|
|
var managedBucket = new CcdBucket(id: Guid.Parse(m_ManagedBucketId), name: EditorUserBuildSettings.activeBuildTarget.ToString(), attributes: new CcdBucketAttributes(promoteOnly: false));
|
|
m_CcdManagementMock.Setup(client => client.CreateBucketAsync(It.Is<CreateBucketOptions>((v) => v.Name == EditorUserBuildSettings.activeBuildTarget.ToString())))
|
|
.Throws(AlreadyExistsException());
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setupRemoteCatalog(remoteCatalogType);
|
|
|
|
resetManagedBucket();
|
|
|
|
// this should be a completely new remote project
|
|
await refreshDataSources(new List<CcdBucket>());
|
|
// since the bucket already exists we should load the bucket
|
|
m_listBucketCalls.Enqueue(new List<CcdBucket>(){managedBucket});
|
|
|
|
var success = await CcdBuildEvents.Instance.VerifyTargetBucket(m_Input);
|
|
Assert.True(success);
|
|
|
|
var ccdManagedDataField = m_Input.AddressableSettings.GetType().GetField("m_CcdManagedData", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
var ccdManagedDataInstance = ccdManagedDataField.GetValue(m_Input.AddressableSettings);
|
|
var bucketIdField = ccdManagedDataInstance.GetType().GetField("BucketId", BindingFlags.Public | BindingFlags.Instance);
|
|
var verifiedBucketId = bucketIdField.GetValue(ccdManagedDataInstance);
|
|
Assert.AreEqual(m_ManagedBucketId, verifiedBucketId);
|
|
}
|
|
|
|
|
|
[Test]
|
|
public async Task VerifyTargetBucketStaticProfile([ValueSource(nameof(remoteCatalogTypes))] RemoteCatalogType remoteCatalogType)
|
|
{
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileStaticAndLocal);
|
|
setupRemoteCatalog(remoteCatalogType);
|
|
var success = await CcdBuildEvents.Instance.VerifyTargetBucket(m_Input);
|
|
Assert.True(success);
|
|
}
|
|
|
|
[Test]
|
|
public async Task VerifyTargetBucketOverride([ValueSource(nameof(remoteCatalogTypes))] RemoteCatalogType remoteCatalogType)
|
|
{
|
|
var ccdManagedDataField = m_Input.AddressableSettings.GetType().GetField("m_CcdManagedData", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
var ccdManagedDataInstance = ccdManagedDataField.GetValue(m_Input.AddressableSettings);
|
|
|
|
var stateField = ccdManagedDataInstance.GetType().GetField("State", BindingFlags.Public | BindingFlags.Instance);
|
|
var stateEnumValues = stateField.GetValue(ccdManagedDataInstance).GetType().GetEnumValues();
|
|
stateField.SetValue(ccdManagedDataInstance, stateEnumValues.GetValue(2));
|
|
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
setupRemoteCatalog(remoteCatalogType);
|
|
m_Settings.RemoteCatalogBuildPath.SetVariableByName(m_Settings, "Remote.BuildPath");
|
|
m_Settings.RemoteCatalogLoadPath.SetVariableByName(m_Settings, "Remote.LoadPath");
|
|
|
|
var success = await CcdBuildEvents.Instance.VerifyTargetBucket(m_Input);
|
|
Assert.True(success);
|
|
}
|
|
|
|
static Tuple<bool, string>[] buildRemoteCatalogValues = new Tuple<bool, string>[]
|
|
{
|
|
new Tuple<bool, string>(true, "Remote Catalog"),
|
|
new Tuple<bool, string>(false, "First Group")
|
|
};
|
|
|
|
[Test]
|
|
public async Task VerifyTargetEnvironmentNotFound([ValueSource(nameof(buildRemoteCatalogValues))] Tuple<bool, string> remoteCatalogPair)
|
|
{
|
|
LogAssert.Expect(LogType.Error, new Regex(".*Unable to find remote environment badenvironment.*", RegexOptions.Singleline));
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
m_Settings.profileSettings.SetValue(m_Settings.activeProfileId, ProfileDataSourceSettings.ENVIRONMENT_NAME, "badenvironment");
|
|
m_Settings.BuildRemoteCatalog = remoteCatalogPair.Item1;
|
|
var success = await CcdBuildEvents.Instance.VerifyTargetBucket(m_Input);
|
|
Assert.False(success);
|
|
}
|
|
|
|
|
|
[Test]
|
|
public async Task VerifyTargetEnvironmentInternalError([ValueSource(nameof(buildRemoteCatalogValues))] Tuple<bool, string> remoteCatalogPair)
|
|
{
|
|
// we have to delete the automatic profile bucket from the cache so CreateBucketAsync is called
|
|
DeleteBucketFromCache(EditorUserBuildSettings.activeBuildTarget.ToString());
|
|
|
|
LogAssert.Expect(LogType.Error, $"Unable to verify target bucket for {remoteCatalogPair.Item2}: crash");
|
|
m_CcdManagementMock.Setup(client => client.CreateBucketAsync(It.Is<CreateBucketOptions>((v) => v.Name == EditorUserBuildSettings.activeBuildTarget.ToString())))
|
|
.Throws<CcdManagementException>(InternalErrorException);
|
|
m_Settings.activeProfileId = m_Settings.profileSettings.GetProfileId(k_ProfileAutomaticAndLocal);
|
|
m_Settings.BuildRemoteCatalog = remoteCatalogPair.Item1;
|
|
var success = await CcdBuildEvents.Instance.VerifyTargetBucket(m_Input);
|
|
Assert.False(success);
|
|
}
|
|
|
|
private void DeleteBucketFromCache(string bucketName)
|
|
{
|
|
ProfileGroupType automaticProfileType = null;
|
|
foreach (ProfileGroupType profileType in ProfileDataSourceSettings.GetSettings().profileGroupTypes)
|
|
{
|
|
var bucketNameVariable = profileType.GetVariableBySuffix($"{nameof(CcdBucket)}{nameof(CcdBucket.Name)}");
|
|
if (bucketNameVariable != null && bucketNameVariable.Value == bucketName)
|
|
{
|
|
automaticProfileType = profileType;
|
|
}
|
|
}
|
|
Assert.IsNotNull(automaticProfileType);
|
|
Assert.True(ProfileDataSourceSettings.GetSettings().profileGroupTypes.Remove(automaticProfileType));
|
|
}
|
|
}
|
|
}
|
|
#endif
|