Skip to content

Commit

Permalink
add skip docker image deletion option to test-runner
Browse files Browse the repository at this point in the history
  • Loading branch information
busma13 committed Nov 7, 2024
1 parent 622680f commit 148e5d2
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 17 deletions.
8 changes: 8 additions & 0 deletions packages/scripts/src/cmds/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Options = {
packages?: PackageInfo[];
'ignore-mount': boolean;
'test-platform': string;
'skip-image-deletion': boolean;
};

const jestArgs = getExtraArgs();
Expand Down Expand Up @@ -101,6 +102,11 @@ const cmd: CommandModule<GlobalCMDOptions, Options> = {
default: config.TEST_PLATFORM,
choices: ['native', 'kubernetes', 'kubernetesV2']
})
.option('skip-image-deletion', {
description: 'Skip the deletion of docker images from cache after loading into docker.\n This is useful if a CI job calls `ts-scripts test` more than once.',
type: 'boolean',
default: config.SKIP_IMAGE_DELETION,
})
.positional('packages', {
description: 'Runs the tests for one or more package and/or an asset, if none specified it will run all of the tests',
coerce(arg) {
Expand All @@ -126,6 +132,7 @@ const cmd: CommandModule<GlobalCMDOptions, Options> = {
const ignoreMount = hoistJestArg(argv, 'ignore-mount', 'boolean');
const testPlatform = hoistJestArg(argv, 'test-platform', 'string') as 'native' | 'kubernetes' | 'kubernetesV2';
const kindClusterName = testPlatform === 'native' ? 'default' : 'k8s-e2e';
const skipImageDeletion = hoistJestArg(argv, 'skip-image-deletion', 'boolean');

if (debug && watch) {
throw new Error('--debug and --watch conflict, please set one or the other');
Expand All @@ -147,6 +154,7 @@ const cmd: CommandModule<GlobalCMDOptions, Options> = {
ignoreMount,
testPlatform,
kindClusterName,
skipImageDeletion
});
},
};
Expand Down
1 change: 1 addition & 0 deletions packages/scripts/src/helpers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,4 @@ export const {
export const DOCKER_IMAGES_PATH = './images';
export const DOCKER_IMAGE_LIST_PATH = `${DOCKER_IMAGES_PATH}/image-list.txt`;
export const DOCKER_CACHE_PATH = '/tmp/docker_cache';
export const SKIP_IMAGE_DELETION = toBoolean(process.env.SKIP_IMAGE_DELETION) || false;
3 changes: 2 additions & 1 deletion packages/scripts/src/helpers/k8s-env/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ export async function launchK8sEnv(options: K8sEnvOptions) {
reportCoverage: false,
useExistingServices: false,
ignoreMount: false,
testPlatform: options.clusteringType
testPlatform: options.clusteringType,
skipImageDeletion: false
});

try {
Expand Down
6 changes: 4 additions & 2 deletions packages/scripts/src/helpers/kind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export class Kind {

// TODO: check that image is loaded before we continue
async loadServiceImage(
serviceName: string, serviceImage: string, version: string
serviceName: string, serviceImage: string, version: string, skipDelete: boolean
): Promise<void> {
let subprocess;
try {
Expand All @@ -95,7 +95,9 @@ export class Kind {
subprocess = await execaCommand(`gunzip -d ${filePath}`);
signale.info(`${subprocess.command}: successful`);
subprocess = await execaCommand(`kind load --name ${this.clusterName} image-archive ${tarPath}`);
fs.rmSync(tarPath);
if (!skipDelete) {
fs.rmSync(tarPath);
}
} else {
subprocess = await execaCommand(`kind load --name ${this.clusterName} docker-image ${serviceImage}:${version}`);
}
Expand Down
14 changes: 11 additions & 3 deletions packages/scripts/src/helpers/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,11 +456,15 @@ async function dockerImageRm(image: string): Promise<void> {

/**
* Unzips and loads a Docker image from a Docker cache
* If successful the image will be deleted from the cache
* If successful and skipDelete is false the image will be deleted from the cache
* @param {string} imageName Name of the image to load
* @param {boolean} skipDelete Skip removal of docker image from cache
* @returns {Promise<boolean>} Whether or not the image loaded successfully
*/
export async function loadThenDeleteImageFromCache(imageName: string): Promise<boolean> {
export async function loadThenDeleteImageFromCache(
imageName: string,
skipDelete = false
): Promise<boolean> {
signale.time(`unzip and load ${imageName}`);
const fileName = imageName.trim().replace(/[/:]/g, '_');
const filePath = path.join(config.DOCKER_CACHE_PATH, `${fileName}.tar.gz`);
Expand All @@ -478,7 +482,11 @@ export async function loadThenDeleteImageFromCache(imageName: string): Promise<b
return false;
}

fs.rmSync(filePath);
if (!skipDelete) {
signale.info(`Deleting ${imageName} from docker image cache.`);
fs.rmSync(filePath);
}

signale.timeEnd(`unzip and load ${imageName}`);

return true;
Expand Down
13 changes: 7 additions & 6 deletions packages/scripts/src/helpers/test-runner/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ async function runTestSuite(

if (isCI) {
// load the services from cache in CI
await loadOrPullServiceImages(suite);
await loadOrPullServiceImages(suite, options.skipImageDeletion);
}

const CHUNK_SIZE = options.debug ? 1 : MAX_PROJECTS_PER_BATCH;
Expand Down Expand Up @@ -219,7 +219,7 @@ async function runE2ETest(
kind = new Kind(K8S_VERSION, options.kindClusterName);
try {
if (isCI) {
await loadThenDeleteImageFromCache('kindest/node:v1.30.0');
await loadThenDeleteImageFromCache('kindest/node:v1.30.0', options.skipImageDeletion);
}
await kind.createCluster();
} catch (err) {
Expand All @@ -240,12 +240,11 @@ async function runE2ETest(
if (isCI) {
// load service if in native. In k8s services will be loaded directly to kind
if (options.testPlatform === 'native') {
await loadOrPullServiceImages(suite);
await deleteDockerImageCache();
await loadOrPullServiceImages(suite, options.skipImageDeletion);
}

// load the base docker image
await loadThenDeleteImageFromCache(`${BASE_DOCKER_IMAGE}:${NODE_VERSION}`);
await loadThenDeleteImageFromCache(`${BASE_DOCKER_IMAGE}:${NODE_VERSION}`, options.skipImageDeletion);
}

try {
Expand Down Expand Up @@ -283,7 +282,9 @@ async function runE2ETest(
tracker.addError(err);
}

await deleteDockerImageCache();
if (!options.skipImageDeletion) {
await deleteDockerImageCache();
}

if (!tracker.hasErrors()) {
const timeLabel = `test suite "${suite}"`;
Expand Down
1 change: 1 addition & 0 deletions packages/scripts/src/helpers/test-runner/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type TestOptions = {
ignoreMount: boolean;
testPlatform: 'native' | 'kubernetes' | 'kubernetesV2';
kindClusterName: string;
skipImageDeletion: boolean;
};

export type GroupedPackages = {
Expand Down
14 changes: 11 additions & 3 deletions packages/scripts/src/helpers/test-runner/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,10 @@ const services: Readonly<Record<Service, Readonly<DockerRunOptions>>> = {
}
};

export async function loadOrPullServiceImages(suite: string): Promise<void> {
export async function loadOrPullServiceImages(
suite: string,
skipImageDeletion: boolean
): Promise<void> {
const launchServices = getServicesForSuite(suite);

try {
Expand Down Expand Up @@ -209,7 +212,7 @@ export async function loadOrPullServiceImages(suite: string): Promise<void> {

if (fs.existsSync(config.DOCKER_CACHE_PATH)) {
await Promise.all(images.map(async (imageName) => {
const success = await loadThenDeleteImageFromCache(imageName);
const success = await loadThenDeleteImageFromCache(imageName, skipImageDeletion);
if (!success) {
loadFailedList.push(imageName);
}
Expand Down Expand Up @@ -834,7 +837,12 @@ async function startService(options: TestOptions, service: Service): Promise<()

if (options.testPlatform === 'kubernetes' || options.testPlatform === 'kubernetesV2') {
const kind = new Kind(config.K8S_VERSION, options.kindClusterName);
await kind.loadServiceImage(service, services[service].image, version);
await kind.loadServiceImage(
service,
services[service].image,
version,
options.skipImageDeletion
);
await k8sStopService(service);
await k8sStartService(service, services[service].image, version, kind);
return () => { };
Expand Down
3 changes: 2 additions & 1 deletion packages/scripts/test/service-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ describe('services', () => {
encryptMinio: false,
ignoreMount: false,
testPlatform: 'native',
kindClusterName: 'default'
kindClusterName: 'default',
skipImageDeletion: false
};
let services: any;

Expand Down
3 changes: 2 additions & 1 deletion packages/scripts/test/test-runner-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ describe('Test Runner Helpers', () => {
encryptMinio: false,
ignoreMount: true,
testPlatform: 'native',
kindClusterName: 'default'
kindClusterName: 'default',
skipImageDeletion: false
};

function makeTestOptions(input: Partial<TestOptions>): TestOptions {
Expand Down

0 comments on commit 148e5d2

Please sign in to comment.