mirror of
				https://github.com/actions/setup-node.git
				synced 2025-10-26 07:16:44 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			363 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			363 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import * as core from '@actions/core';
 | |
| import * as cache from '@actions/cache';
 | |
| import path from 'path';
 | |
| import * as utils from '../src/cache-utils';
 | |
| import {
 | |
|   PackageManagerInfo,
 | |
|   isCacheFeatureAvailable,
 | |
|   supportedPackageManagers,
 | |
|   getProjectDirectoriesFromCacheDependencyPath
 | |
| } from '../src/cache-utils';
 | |
| import fs from 'fs';
 | |
| import * as cacheUtils from '../src/cache-utils';
 | |
| import * as glob from '@actions/glob';
 | |
| import {Globber} from '@actions/glob';
 | |
| import {MockGlobber} from './mock/glob-mock';
 | |
| 
 | |
| describe('cache-utils', () => {
 | |
|   const versionYarn1 = '1.2.3';
 | |
| 
 | |
|   let debugSpy: jest.SpyInstance;
 | |
|   let getCommandOutputSpy: jest.SpyInstance;
 | |
|   let isFeatureAvailable: jest.SpyInstance;
 | |
|   let info: jest.SpyInstance;
 | |
|   let warningSpy: jest.SpyInstance;
 | |
|   let fsRealPathSyncSpy: jest.SpyInstance;
 | |
| 
 | |
|   beforeEach(() => {
 | |
|     console.log('::stop-commands::stoptoken');
 | |
|     process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data');
 | |
|     debugSpy = jest.spyOn(core, 'debug');
 | |
|     debugSpy.mockImplementation(msg => {});
 | |
| 
 | |
|     info = jest.spyOn(core, 'info');
 | |
|     warningSpy = jest.spyOn(core, 'warning');
 | |
| 
 | |
|     isFeatureAvailable = jest.spyOn(cache, 'isFeatureAvailable');
 | |
| 
 | |
|     getCommandOutputSpy = jest.spyOn(utils, 'getCommandOutput');
 | |
| 
 | |
|     fsRealPathSyncSpy = jest.spyOn(fs, 'realpathSync');
 | |
|     fsRealPathSyncSpy.mockImplementation(dirName => {
 | |
|       return dirName;
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   afterEach(() => {
 | |
|     jest.resetAllMocks();
 | |
|     jest.clearAllMocks();
 | |
|     //jest.restoreAllMocks();
 | |
|   });
 | |
| 
 | |
|   afterAll(async () => {
 | |
|     console.log('::stoptoken::');
 | |
|     jest.restoreAllMocks();
 | |
|   }, 100000);
 | |
| 
 | |
|   describe('getPackageManagerInfo', () => {
 | |
|     it.each<[string, PackageManagerInfo | null]>([
 | |
|       ['npm', utils.supportedPackageManagers.npm],
 | |
|       ['pnpm', utils.supportedPackageManagers.pnpm],
 | |
|       ['yarn', utils.supportedPackageManagers.yarn],
 | |
|       ['yarn1', null],
 | |
|       ['yarn2', null],
 | |
|       ['npm7', null]
 | |
|     ])('getPackageManagerInfo for %s is %o', async (packageManager, result) => {
 | |
|       getCommandOutputSpy.mockImplementationOnce(() => versionYarn1);
 | |
|       await expect(utils.getPackageManagerInfo(packageManager)).resolves.toBe(
 | |
|         result
 | |
|       );
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   it('isCacheFeatureAvailable for GHES is false', () => {
 | |
|     isFeatureAvailable.mockImplementation(() => false);
 | |
|     process.env['GITHUB_SERVER_URL'] = 'https://www.test.com';
 | |
| 
 | |
|     expect(isCacheFeatureAvailable()).toBeFalsy();
 | |
|     expect(warningSpy).toHaveBeenCalledWith(
 | |
|       'Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if Actions cache service is enabled or not.'
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   it('isCacheFeatureAvailable for GHES has an interhal error', () => {
 | |
|     isFeatureAvailable.mockImplementation(() => false);
 | |
|     process.env['GITHUB_SERVER_URL'] = '';
 | |
|     isCacheFeatureAvailable();
 | |
|     expect(warningSpy).toHaveBeenCalledWith(
 | |
|       'The runner was not able to contact the cache service. Caching will be skipped'
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   it('isCacheFeatureAvailable for GHES is available', () => {
 | |
|     isFeatureAvailable.mockImplementation(() => true);
 | |
| 
 | |
|     expect(isCacheFeatureAvailable()).toStrictEqual(true);
 | |
|   });
 | |
| 
 | |
|   afterEach(() => {
 | |
|     process.env['GITHUB_SERVER_URL'] = '';
 | |
|     jest.resetAllMocks();
 | |
|     jest.clearAllMocks();
 | |
|   });
 | |
| 
 | |
|   describe('getCacheDirectoriesPaths', () => {
 | |
|     let existsSpy: jest.SpyInstance;
 | |
|     let lstatSpy: jest.SpyInstance;
 | |
|     let globCreateSpy: jest.SpyInstance;
 | |
| 
 | |
|     beforeEach(() => {
 | |
|       existsSpy = jest.spyOn(fs, 'existsSync');
 | |
|       existsSpy.mockImplementation(() => true);
 | |
| 
 | |
|       lstatSpy = jest.spyOn(fs, 'lstatSync');
 | |
|       lstatSpy.mockImplementation(arg => ({
 | |
|         isDirectory: () => true
 | |
|       }));
 | |
| 
 | |
|       globCreateSpy = jest.spyOn(glob, 'create');
 | |
| 
 | |
|       globCreateSpy.mockImplementation(
 | |
|         (pattern: string): Promise<Globber> =>
 | |
|           MockGlobber.create(['/foo', '/bar'])
 | |
|       );
 | |
| 
 | |
|       getProjectDirectoriesFromCacheDependencyPath.cache.clear?.();
 | |
|     });
 | |
| 
 | |
|     afterEach(() => {
 | |
|       existsSpy.mockRestore();
 | |
|       lstatSpy.mockRestore();
 | |
|       globCreateSpy.mockRestore();
 | |
|     });
 | |
| 
 | |
|     it.each([
 | |
|       [supportedPackageManagers.npm, ''],
 | |
|       [supportedPackageManagers.npm, '/dir/file.lock'],
 | |
|       [supportedPackageManagers.npm, '/**/file.lock'],
 | |
|       [supportedPackageManagers.pnpm, ''],
 | |
|       [supportedPackageManagers.pnpm, '/dir/file.lock'],
 | |
|       [supportedPackageManagers.pnpm, '/**/file.lock']
 | |
|     ])(
 | |
|       'getCacheDirectoriesPaths should return one dir for non yarn',
 | |
|       async (packageManagerInfo, cacheDependency) => {
 | |
|         getCommandOutputSpy.mockImplementation(() => 'foo');
 | |
| 
 | |
|         const dirs = await cacheUtils.getCacheDirectories(
 | |
|           packageManagerInfo,
 | |
|           cacheDependency
 | |
|         );
 | |
|         expect(dirs).toEqual(['foo']);
 | |
|         // to do not call for a version
 | |
|         // call once for get cache folder
 | |
|         expect(getCommandOutputSpy).toHaveBeenCalledTimes(1);
 | |
|       }
 | |
|     );
 | |
| 
 | |
|     it('getCacheDirectoriesPaths should return one dir for yarn without cacheDependency', async () => {
 | |
|       getCommandOutputSpy.mockImplementation(() => 'foo');
 | |
| 
 | |
|       const dirs = await cacheUtils.getCacheDirectories(
 | |
|         supportedPackageManagers.yarn,
 | |
|         ''
 | |
|       );
 | |
|       expect(dirs).toEqual(['foo']);
 | |
|     });
 | |
| 
 | |
|     it.each([
 | |
|       [supportedPackageManagers.npm, ''],
 | |
|       [supportedPackageManagers.npm, '/dir/file.lock'],
 | |
|       [supportedPackageManagers.npm, '/**/file.lock'],
 | |
|       [supportedPackageManagers.pnpm, ''],
 | |
|       [supportedPackageManagers.pnpm, '/dir/file.lock'],
 | |
|       [supportedPackageManagers.pnpm, '/**/file.lock'],
 | |
|       [supportedPackageManagers.yarn, ''],
 | |
|       [supportedPackageManagers.yarn, '/dir/file.lock'],
 | |
|       [supportedPackageManagers.yarn, '/**/file.lock']
 | |
|     ])(
 | |
|       'getCacheDirectoriesPaths should throw for getCommandOutput returning empty',
 | |
|       async (packageManagerInfo, cacheDependency) => {
 | |
|         getCommandOutputSpy.mockImplementation((command: string) =>
 | |
|           // return empty string to indicate getCacheFolderPath failed
 | |
|           //        --version still works
 | |
|           command.includes('version') ? '1.' : ''
 | |
|         );
 | |
| 
 | |
|         await expect(
 | |
|           cacheUtils.getCacheDirectories(packageManagerInfo, cacheDependency)
 | |
|         ).rejects.toThrow(); //'Could not get cache folder path for /dir');
 | |
|       }
 | |
|     );
 | |
| 
 | |
|     it.each([
 | |
|       [supportedPackageManagers.yarn, '/dir/file.lock'],
 | |
|       [supportedPackageManagers.yarn, '/**/file.lock']
 | |
|     ])(
 | |
|       'getCacheDirectoriesPaths should nothrow in case of having not directories',
 | |
|       async (packageManagerInfo, cacheDependency) => {
 | |
|         lstatSpy.mockImplementation(arg => ({
 | |
|           isDirectory: () => false
 | |
|         }));
 | |
| 
 | |
|         await cacheUtils.getCacheDirectories(
 | |
|           packageManagerInfo,
 | |
|           cacheDependency
 | |
|         );
 | |
|         expect(warningSpy).toHaveBeenCalledTimes(1);
 | |
|         expect(warningSpy).toHaveBeenCalledWith(
 | |
|           `No existing directories found containing cache-dependency-path="${cacheDependency}"`
 | |
|         );
 | |
|       }
 | |
|     );
 | |
| 
 | |
|     it.each(['1.1.1', '2.2.2'])(
 | |
|       'getCacheDirectoriesPaths yarn v%s should return one dir without cacheDependency',
 | |
|       async version => {
 | |
|         getCommandOutputSpy.mockImplementationOnce(() => version);
 | |
|         getCommandOutputSpy.mockImplementationOnce(() => `foo${version}`);
 | |
| 
 | |
|         const dirs = await cacheUtils.getCacheDirectories(
 | |
|           supportedPackageManagers.yarn,
 | |
|           ''
 | |
|         );
 | |
|         expect(dirs).toEqual([`foo${version}`]);
 | |
|       }
 | |
|     );
 | |
| 
 | |
|     it.each(['1.1.1', '2.2.2'])(
 | |
|       'getCacheDirectoriesPaths yarn v%s should return 2 dirs with globbed cacheDependency',
 | |
|       async version => {
 | |
|         let dirNo = 1;
 | |
|         getCommandOutputSpy.mockImplementation((command: string) =>
 | |
|           command.includes('version') ? version : `file_${version}_${dirNo++}`
 | |
|         );
 | |
|         globCreateSpy.mockImplementation(
 | |
|           (pattern: string): Promise<Globber> =>
 | |
|             MockGlobber.create(['/tmp/dir1/file', '/tmp/dir2/file'])
 | |
|         );
 | |
| 
 | |
|         const dirs = await cacheUtils.getCacheDirectories(
 | |
|           supportedPackageManagers.yarn,
 | |
|           '/tmp/**/file'
 | |
|         );
 | |
|         expect(dirs).toEqual([`file_${version}_1`, `file_${version}_2`]);
 | |
|       }
 | |
|     );
 | |
| 
 | |
|     it.each(['1.1.1', '2.2.2'])(
 | |
|       'getCacheDirectoriesPaths yarn v%s should return 2 dirs  with globbed cacheDependency expanding to duplicates',
 | |
|       async version => {
 | |
|         let dirNo = 1;
 | |
|         getCommandOutputSpy.mockImplementation((command: string) =>
 | |
|           command.includes('version') ? version : `file_${version}_${dirNo++}`
 | |
|         );
 | |
|         globCreateSpy.mockImplementation(
 | |
|           (pattern: string): Promise<Globber> =>
 | |
|             MockGlobber.create([
 | |
|               '/tmp/dir1/file',
 | |
|               '/tmp/dir2/file',
 | |
|               '/tmp/dir1/file'
 | |
|             ])
 | |
|         );
 | |
| 
 | |
|         const dirs = await cacheUtils.getCacheDirectories(
 | |
|           supportedPackageManagers.yarn,
 | |
|           '/tmp/**/file'
 | |
|         );
 | |
|         expect(dirs).toEqual([`file_${version}_1`, `file_${version}_2`]);
 | |
|       }
 | |
|     );
 | |
| 
 | |
|     it.each(['1.1.1', '2.2.2'])(
 | |
|       'getCacheDirectoriesPaths yarn v%s should return 2 uniq dirs despite duplicate cache directories',
 | |
|       async version => {
 | |
|         let dirNo = 1;
 | |
|         getCommandOutputSpy.mockImplementation((command: string) =>
 | |
|           command.includes('version')
 | |
|             ? version
 | |
|             : `file_${version}_${dirNo++ % 2}`
 | |
|         );
 | |
|         globCreateSpy.mockImplementation(
 | |
|           (pattern: string): Promise<Globber> =>
 | |
|             MockGlobber.create([
 | |
|               '/tmp/dir1/file',
 | |
|               '/tmp/dir2/file',
 | |
|               '/tmp/dir3/file'
 | |
|             ])
 | |
|         );
 | |
| 
 | |
|         const dirs = await cacheUtils.getCacheDirectories(
 | |
|           supportedPackageManagers.yarn,
 | |
|           '/tmp/**/file'
 | |
|         );
 | |
|         expect(dirs).toEqual([`file_${version}_1`, `file_${version}_0`]);
 | |
|         expect(getCommandOutputSpy).toHaveBeenCalledTimes(6);
 | |
|         expect(getCommandOutputSpy).toHaveBeenCalledWith(
 | |
|           'yarn --version',
 | |
|           '/tmp/dir1'
 | |
|         );
 | |
|         expect(getCommandOutputSpy).toHaveBeenCalledWith(
 | |
|           'yarn --version',
 | |
|           '/tmp/dir2'
 | |
|         );
 | |
|         expect(getCommandOutputSpy).toHaveBeenCalledWith(
 | |
|           'yarn --version',
 | |
|           '/tmp/dir3'
 | |
|         );
 | |
|         expect(getCommandOutputSpy).toHaveBeenCalledWith(
 | |
|           version.startsWith('1.')
 | |
|             ? 'yarn cache dir'
 | |
|             : 'yarn config get cacheFolder',
 | |
|           '/tmp/dir1'
 | |
|         );
 | |
|         expect(getCommandOutputSpy).toHaveBeenCalledWith(
 | |
|           version.startsWith('1.')
 | |
|             ? 'yarn cache dir'
 | |
|             : 'yarn config get cacheFolder',
 | |
|           '/tmp/dir2'
 | |
|         );
 | |
|         expect(getCommandOutputSpy).toHaveBeenCalledWith(
 | |
|           version.startsWith('1.')
 | |
|             ? 'yarn cache dir'
 | |
|             : 'yarn config get cacheFolder',
 | |
|           '/tmp/dir3'
 | |
|         );
 | |
|       }
 | |
|     );
 | |
| 
 | |
|     it.each(['1.1.1', '2.2.2'])(
 | |
|       'getCacheDirectoriesPaths yarn v%s should return 4 dirs with multiple globs',
 | |
|       async version => {
 | |
|         // simulate wrong indents
 | |
|         const cacheDependencyPath = `/tmp/dir1/file
 | |
|           /tmp/dir2/file
 | |
| /tmp/**/file
 | |
|           `;
 | |
|         globCreateSpy.mockImplementation(
 | |
|           (pattern: string): Promise<Globber> =>
 | |
|             MockGlobber.create([
 | |
|               '/tmp/dir1/file',
 | |
|               '/tmp/dir2/file',
 | |
|               '/tmp/dir3/file',
 | |
|               '/tmp/dir4/file'
 | |
|             ])
 | |
|         );
 | |
|         let dirNo = 1;
 | |
|         getCommandOutputSpy.mockImplementation((command: string) =>
 | |
|           command.includes('version') ? version : `file_${version}_${dirNo++}`
 | |
|         );
 | |
|         const dirs = await cacheUtils.getCacheDirectories(
 | |
|           supportedPackageManagers.yarn,
 | |
|           cacheDependencyPath
 | |
|         );
 | |
|         expect(dirs).toEqual([
 | |
|           `file_${version}_1`,
 | |
|           `file_${version}_2`,
 | |
|           `file_${version}_3`,
 | |
|           `file_${version}_4`
 | |
|         ]);
 | |
|       }
 | |
|     );
 | |
|   });
 | |
| });
 |