2023-03-27 11:14:23 +00:00
|
|
|
import CloudRunner from '../../cloud-runner';
|
|
|
|
|
import { ImageTag } from '../../..';
|
|
|
|
|
import UnityVersioning from '../../../unity-versioning';
|
|
|
|
|
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
2022-11-07 20:41:00 +00:00
|
|
|
import { v4 as uuidv4 } from 'uuid';
|
2023-03-27 11:14:23 +00:00
|
|
|
import CloudRunnerOptions from '../../options/cloud-runner-options';
|
|
|
|
|
import setups from './../cloud-runner-suite.test';
|
|
|
|
|
import * as fs from 'node:fs';
|
2023-03-04 00:25:40 +00:00
|
|
|
import path from 'node:path';
|
2023-03-27 11:14:23 +00:00
|
|
|
import { CloudRunnerFolders } from '../../options/cloud-runner-folders';
|
|
|
|
|
import SharedWorkspaceLocking from '../../services/core/shared-workspace-locking';
|
|
|
|
|
import { CreateParameters } from '../create-test-parameter';
|
|
|
|
|
import { CloudRunnerSystem } from '../../services/core/cloud-runner-system';
|
2022-11-07 20:41:00 +00:00
|
|
|
|
|
|
|
|
describe('Cloud Runner Retain Workspace', () => {
|
|
|
|
|
it('Responds', () => {});
|
|
|
|
|
setups();
|
|
|
|
|
if (CloudRunnerOptions.cloudRunnerDebug) {
|
|
|
|
|
it('Run one build it should not already be retained, run subsequent build which should use retained workspace', async () => {
|
|
|
|
|
const overrides = {
|
|
|
|
|
versioning: 'None',
|
|
|
|
|
projectPath: 'test-project',
|
|
|
|
|
unityVersion: UnityVersioning.determineUnityVersion('test-project', UnityVersioning.read('test-project')),
|
|
|
|
|
targetPlatform: 'StandaloneLinux64',
|
|
|
|
|
cacheKey: `test-case-${uuidv4()}`,
|
2023-03-27 11:14:23 +00:00
|
|
|
maxRetainedWorkspaces: 1,
|
2025-08-28 05:48:50 +00:00
|
|
|
cloudRunnerDebug: true,
|
2022-11-07 20:41:00 +00:00
|
|
|
};
|
|
|
|
|
const buildParameter = await CreateParameters(overrides);
|
|
|
|
|
expect(buildParameter.projectPath).toEqual(overrides.projectPath);
|
|
|
|
|
|
|
|
|
|
const baseImage = new ImageTag(buildParameter);
|
2024-02-06 23:46:31 +00:00
|
|
|
const resultsObject = await CloudRunner.run(buildParameter, baseImage.toString());
|
|
|
|
|
const results = resultsObject.BuildResults;
|
2022-11-07 20:41:00 +00:00
|
|
|
const libraryString = 'Rebuilding Library because the asset database could not be found!';
|
|
|
|
|
const cachePushFail = 'Did not push source folder to cache because it was empty Library';
|
|
|
|
|
|
2025-09-03 19:49:52 +00:00
|
|
|
expect(resultsObject.BuildSucceeded).toBe(true);
|
|
|
|
|
|
|
|
|
|
// Keep minimal assertions to reduce brittleness
|
2022-11-07 20:41:00 +00:00
|
|
|
expect(results).not.toContain(cachePushFail);
|
|
|
|
|
|
2023-03-27 11:14:23 +00:00
|
|
|
if (CloudRunnerOptions.providerStrategy === `local-docker`) {
|
Cloud runner develop - better parameterization of s3 usage, improved async workflow and GC, github checks early integration (#479)
* custom steps may leave value undefined, will be pulled from env vars
* custom steps may leave value undefined, will be pulled from env vars
* custom steps may leave value undefined, will be pulled from env vars
* add 3 new premade steps, steam-deploy-client, steam-deploy-project, aws-s3-pull-build
* fix
* fix
* fix
* continue building async-workflow support
* test checks
* test checks
* test checks
* move github checks within build workflow
* async workflow test
* async workflow test
* async workflow test
* async workflow test
* async workflow test
* async workflow test
* async workflow test
* async workflow test for aws only
* async workflow test for aws only
* async workflow test for aws only
* async workflow test for aws only
* cleanup logging
* disable lz4 compression by default
* disable lz4 compression by default
* AWS BASE STACK for tests
* AWS BASE STACK for tests
* AWS BASE STACK for tests
* AWS BASE STACK for tests
* AWS BASE STACK for tests
* AWS BASE STACK for tests
* disable lz4 compression by default
* disable lz4 compression by default
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* workflow
* workflow
* workflow
* workflow
* workflow
* workflow
* workflow
* workflow
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
2023-01-20 17:40:57 +00:00
|
|
|
const cacheFolderExists = fs.existsSync(`cloud-runner-cache/cache/${overrides.cacheKey}`);
|
|
|
|
|
expect(cacheFolderExists).toBeTruthy();
|
2023-03-27 11:14:23 +00:00
|
|
|
await CloudRunnerSystem.Run(`tree -d ./cloud-runner-cache`);
|
Cloud runner develop - better parameterization of s3 usage, improved async workflow and GC, github checks early integration (#479)
* custom steps may leave value undefined, will be pulled from env vars
* custom steps may leave value undefined, will be pulled from env vars
* custom steps may leave value undefined, will be pulled from env vars
* add 3 new premade steps, steam-deploy-client, steam-deploy-project, aws-s3-pull-build
* fix
* fix
* fix
* continue building async-workflow support
* test checks
* test checks
* test checks
* move github checks within build workflow
* async workflow test
* async workflow test
* async workflow test
* async workflow test
* async workflow test
* async workflow test
* async workflow test
* async workflow test for aws only
* async workflow test for aws only
* async workflow test for aws only
* async workflow test for aws only
* cleanup logging
* disable lz4 compression by default
* disable lz4 compression by default
* AWS BASE STACK for tests
* AWS BASE STACK for tests
* AWS BASE STACK for tests
* AWS BASE STACK for tests
* AWS BASE STACK for tests
* AWS BASE STACK for tests
* disable lz4 compression by default
* disable lz4 compression by default
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* Update github check with aws log
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* kinesis and subscription filter for logs creation skipped when watchToEnd false
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* cleanup local pipeline, log aws formation
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* async pipeline
* workflow
* workflow
* workflow
* workflow
* workflow
* workflow
* workflow
* workflow
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
* parameterize s3
2023-01-20 17:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
2022-11-07 20:41:00 +00:00
|
|
|
CloudRunnerLogger.log(`run 1 succeeded`);
|
2023-03-27 11:14:23 +00:00
|
|
|
|
2026-01-17 04:52:35 +00:00
|
|
|
// Clean up k3d node between builds to free space, but preserve Unity image
|
|
|
|
|
if (CloudRunnerOptions.providerStrategy === 'k8s') {
|
|
|
|
|
try {
|
|
|
|
|
CloudRunnerLogger.log('Cleaning up k3d node between builds (preserving Unity image)...');
|
|
|
|
|
const K3D_NODE_CONTAINERS = ['k3d-unity-builder-agent-0', 'k3d-unity-builder-server-0'];
|
|
|
|
|
for (const NODE of K3D_NODE_CONTAINERS) {
|
|
|
|
|
// Remove stopped containers but keep images
|
|
|
|
|
await CloudRunnerSystem.Run(
|
|
|
|
|
`docker exec ${NODE} sh -c "crictl rm --all 2>/dev/null || true" || true`,
|
|
|
|
|
true,
|
|
|
|
|
true,
|
|
|
|
|
);
|
2026-01-17 05:48:22 +00:00
|
|
|
// Only remove specific known system images, preserve Unity and everything else
|
|
|
|
|
// DO NOT use --prune as it might remove Unity image
|
2026-01-17 04:52:35 +00:00
|
|
|
await CloudRunnerSystem.Run(
|
2026-01-17 05:48:22 +00:00
|
|
|
`docker exec ${NODE} sh -c "crictl images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -vE 'unityci/editor|unity' | grep -E 'rancher/|curlimages/|amazon/aws-cli|rclone/rclone|steamcmd/steamcmd|ubuntu:|alpine:' | xargs -r -I {} crictl rmi {} 2>/dev/null || true" || true`,
|
2026-01-17 04:52:35 +00:00
|
|
|
true,
|
|
|
|
|
true,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
CloudRunnerLogger.log('Cleanup between builds completed');
|
|
|
|
|
} catch (cleanupError) {
|
|
|
|
|
CloudRunnerLogger.logWarning(`Failed to cleanup between builds: ${cleanupError}`);
|
|
|
|
|
// Continue anyway
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-27 11:14:23 +00:00
|
|
|
// await CloudRunnerSystem.Run(`tree -d ./cloud-runner-cache/${}`);
|
2022-11-07 20:41:00 +00:00
|
|
|
const buildParameter2 = await CreateParameters(overrides);
|
|
|
|
|
|
|
|
|
|
buildParameter2.cacheKey = buildParameter.cacheKey;
|
|
|
|
|
const baseImage2 = new ImageTag(buildParameter2);
|
2024-02-06 23:46:31 +00:00
|
|
|
const results2Object = await CloudRunner.run(buildParameter2, baseImage2.toString());
|
|
|
|
|
const results2 = results2Object.BuildResults;
|
2022-11-07 20:41:00 +00:00
|
|
|
CloudRunnerLogger.log(`run 2 succeeded`);
|
|
|
|
|
|
|
|
|
|
const build2ContainsCacheKey = results2.includes(buildParameter.cacheKey);
|
|
|
|
|
const build2ContainsBuildGuid1FromRetainedWorkspace = results2.includes(buildParameter.buildGuid);
|
|
|
|
|
const build2ContainsRetainedWorkspacePhrase = results2.includes(`Retained Workspace:`);
|
|
|
|
|
const build2ContainsWorkspaceExistsAlreadyPhrase = results2.includes(`Retained Workspace Already Exists!`);
|
|
|
|
|
const build2NotContainsZeroLibraryCacheFilesMessage = !results2.includes(
|
|
|
|
|
'There is 0 files/dir in the cache pulled contents for Library',
|
|
|
|
|
);
|
|
|
|
|
const build2NotContainsZeroLFSCacheFilesMessage = !results2.includes(
|
|
|
|
|
'There is 0 files/dir in the cache pulled contents for LFS',
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
expect(build2ContainsCacheKey).toBeTruthy();
|
|
|
|
|
expect(build2ContainsRetainedWorkspacePhrase).toBeTruthy();
|
|
|
|
|
expect(build2ContainsWorkspaceExistsAlreadyPhrase).toBeTruthy();
|
|
|
|
|
expect(build2ContainsBuildGuid1FromRetainedWorkspace).toBeTruthy();
|
2025-09-03 19:49:52 +00:00
|
|
|
expect(results2Object.BuildSucceeded).toBe(true);
|
2022-11-07 20:41:00 +00:00
|
|
|
expect(build2NotContainsZeroLibraryCacheFilesMessage).toBeTruthy();
|
|
|
|
|
expect(build2NotContainsZeroLFSCacheFilesMessage).toBeTruthy();
|
2024-02-06 23:46:31 +00:00
|
|
|
const splitResults = results2.split('Activation successful');
|
|
|
|
|
expect(splitResults[splitResults.length - 1]).not.toContain(libraryString);
|
2022-11-07 20:41:00 +00:00
|
|
|
}, 1_000_000_000);
|
|
|
|
|
afterAll(async () => {
|
|
|
|
|
await SharedWorkspaceLocking.CleanupWorkspace(CloudRunner.lockedWorkspace || ``, CloudRunner.buildParameters);
|
|
|
|
|
if (
|
|
|
|
|
fs.existsSync(`./cloud-runner-cache/${path.basename(CloudRunnerFolders.uniqueCloudRunnerJobFolderAbsolute)}`)
|
|
|
|
|
) {
|
|
|
|
|
CloudRunnerLogger.log(
|
|
|
|
|
`Cleaning up ./cloud-runner-cache/${path.basename(CloudRunnerFolders.uniqueCloudRunnerJobFolderAbsolute)}`,
|
|
|
|
|
);
|
2025-12-05 16:20:31 +00:00
|
|
|
try {
|
2025-12-15 02:49:27 +00:00
|
|
|
const workspaceCachePath = `./cloud-runner-cache/${path.basename(
|
|
|
|
|
CloudRunnerFolders.uniqueCloudRunnerJobFolderAbsolute,
|
|
|
|
|
)}`;
|
|
|
|
|
// Try to fix permissions first to avoid permission denied errors
|
2025-12-05 16:20:31 +00:00
|
|
|
await CloudRunnerSystem.Run(
|
2025-12-15 02:49:27 +00:00
|
|
|
`chmod -R u+w ${workspaceCachePath} 2>/dev/null || chown -R $(whoami) ${workspaceCachePath} 2>/dev/null || true`,
|
2025-12-05 16:20:31 +00:00
|
|
|
);
|
2025-12-15 02:49:27 +00:00
|
|
|
// Try regular rm first
|
|
|
|
|
await CloudRunnerSystem.Run(`rm -rf ${workspaceCachePath} 2>/dev/null || true`);
|
|
|
|
|
// If that fails, try with sudo if available
|
|
|
|
|
await CloudRunnerSystem.Run(`sudo rm -rf ${workspaceCachePath} 2>/dev/null || true`);
|
|
|
|
|
// As last resort, try to remove files one by one, ignoring permission errors
|
|
|
|
|
await CloudRunnerSystem.Run(
|
|
|
|
|
`find ${workspaceCachePath} -type f -exec rm -f {} + 2>/dev/null || find ${workspaceCachePath} -type f -delete 2>/dev/null || true`,
|
|
|
|
|
);
|
|
|
|
|
// Remove empty directories
|
|
|
|
|
await CloudRunnerSystem.Run(`find ${workspaceCachePath} -type d -empty -delete 2>/dev/null || true`);
|
2025-12-05 16:20:31 +00:00
|
|
|
} catch (error: any) {
|
|
|
|
|
CloudRunnerLogger.log(`Failed to cleanup workspace: ${error.message}`);
|
2025-12-15 02:49:27 +00:00
|
|
|
// Don't throw - cleanup failures shouldn't fail the test suite
|
2025-12-05 16:20:31 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-12-06 23:00:43 +00:00
|
|
|
|
2025-12-05 16:20:31 +00:00
|
|
|
// Clean up cache files to prevent disk space issues
|
|
|
|
|
const cachePath = `./cloud-runner-cache`;
|
|
|
|
|
if (fs.existsSync(cachePath)) {
|
|
|
|
|
try {
|
|
|
|
|
CloudRunnerLogger.log(`Cleaning up cache directory: ${cachePath}`);
|
2025-12-15 02:49:27 +00:00
|
|
|
// Try to change ownership first (if running as root or with sudo)
|
|
|
|
|
// Then try multiple cleanup methods to handle permission issues
|
|
|
|
|
await CloudRunnerSystem.Run(
|
|
|
|
|
`chmod -R u+w ${cachePath} 2>/dev/null || chown -R $(whoami) ${cachePath} 2>/dev/null || true`,
|
|
|
|
|
);
|
|
|
|
|
// Try regular rm first
|
|
|
|
|
await CloudRunnerSystem.Run(`rm -rf ${cachePath}/* 2>/dev/null || true`);
|
|
|
|
|
// If that fails, try with sudo if available
|
|
|
|
|
await CloudRunnerSystem.Run(`sudo rm -rf ${cachePath}/* 2>/dev/null || true`);
|
|
|
|
|
// As last resort, try to remove files one by one, ignoring permission errors
|
|
|
|
|
await CloudRunnerSystem.Run(
|
|
|
|
|
`find ${cachePath} -type f -exec rm -f {} + 2>/dev/null || find ${cachePath} -type f -delete 2>/dev/null || true`,
|
|
|
|
|
);
|
|
|
|
|
// Remove empty directories
|
|
|
|
|
await CloudRunnerSystem.Run(`find ${cachePath} -type d -empty -delete 2>/dev/null || true`);
|
2025-12-05 16:20:31 +00:00
|
|
|
} catch (error: any) {
|
|
|
|
|
CloudRunnerLogger.log(`Failed to cleanup cache: ${error.message}`);
|
2025-12-15 02:49:27 +00:00
|
|
|
// Don't throw - cleanup failures shouldn't fail the test suite
|
2025-12-05 16:20:31 +00:00
|
|
|
}
|
2022-11-07 20:41:00 +00:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|