mirror of
				https://kkgithub.com/actions/setup-python.git
				synced 2025-11-04 04:31:51 +08:00 
			
		
		
		
	
		
			
	
	
		
			238 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			238 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| 
								 | 
							
								import fs from 'fs';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import * as utils from '../src/utils';
							 | 
						||
| 
								 | 
							
								import {HttpClient} from '@actions/http-client';
							 | 
						||
| 
								 | 
							
								import * as ifm from '@actions/http-client/interfaces';
							 | 
						||
| 
								 | 
							
								import * as tc from '@actions/tool-cache';
							 | 
						||
| 
								 | 
							
								import * as exec from '@actions/exec';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import * as path from 'path';
							 | 
						||
| 
								 | 
							
								import * as semver from 'semver';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import * as finder from '../src/find-pypy';
							 | 
						||
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
								  IPyPyManifestRelease,
							 | 
						||
| 
								 | 
							
								  IS_WINDOWS,
							 | 
						||
| 
								 | 
							
								  validateVersion,
							 | 
						||
| 
								 | 
							
								  getPyPyVersionFromPath
							 | 
						||
| 
								 | 
							
								} from '../src/utils';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const manifestData = require('./data/pypy.json');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								let architecture: string;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if (IS_WINDOWS) {
							 | 
						||
| 
								 | 
							
								  architecture = 'x86';
							 | 
						||
| 
								 | 
							
								} else {
							 | 
						||
| 
								 | 
							
								  architecture = 'x64';
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const toolDir = path.join(__dirname, 'runner', 'tools');
							 | 
						||
| 
								 | 
							
								const tempDir = path.join(__dirname, 'runner', 'temp');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('parsePyPyVersion', () => {
							 | 
						||
| 
								 | 
							
								  it.each([
							 | 
						||
| 
								 | 
							
								    ['pypy-3.6-v7.3.3', {pythonVersion: '3.6', pypyVersion: 'v7.3.3'}],
							 | 
						||
| 
								 | 
							
								    ['pypy-3.6-v7.3.x', {pythonVersion: '3.6', pypyVersion: 'v7.3.x'}],
							 | 
						||
| 
								 | 
							
								    ['pypy-3.6-v7.x', {pythonVersion: '3.6', pypyVersion: 'v7.x'}],
							 | 
						||
| 
								 | 
							
								    ['pypy-3.6', {pythonVersion: '3.6', pypyVersion: 'x'}],
							 | 
						||
| 
								 | 
							
								    ['pypy-3.6-nightly', {pythonVersion: '3.6', pypyVersion: 'nightly'}],
							 | 
						||
| 
								 | 
							
								    ['pypy-3.6-v7.3.3rc1', {pythonVersion: '3.6', pypyVersion: 'v7.3.3-rc.1'}]
							 | 
						||
| 
								 | 
							
								  ])('%s -> %s', (input, expected) => {
							 | 
						||
| 
								 | 
							
								    expect(finder.parsePyPyVersion(input)).toEqual(expected);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('throw on invalid input', () => {
							 | 
						||
| 
								 | 
							
								    expect(() => finder.parsePyPyVersion('pypy-')).toThrowError(
							 | 
						||
| 
								 | 
							
								      "Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy-<python-version>'. See README for examples and documentation."
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('getPyPyVersionFromPath', () => {
							 | 
						||
| 
								 | 
							
								  it('/fake/toolcache/PyPy/3.6.5/x64 -> 3.6.5', () => {
							 | 
						||
| 
								 | 
							
								    expect(getPyPyVersionFromPath('/fake/toolcache/PyPy/3.6.5/x64')).toEqual(
							 | 
						||
| 
								 | 
							
								      '3.6.5'
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('findPyPyToolCache', () => {
							 | 
						||
| 
								 | 
							
								  const actualPythonVersion = '3.6.17';
							 | 
						||
| 
								 | 
							
								  const actualPyPyVersion = '7.5.4';
							 | 
						||
| 
								 | 
							
								  const pypyPath = path.join('PyPy', actualPythonVersion, architecture);
							 | 
						||
| 
								 | 
							
								  let tcFind: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spyReadExactPyPyVersion: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    tcFind = jest.spyOn(tc, 'find');
							 | 
						||
| 
								 | 
							
								    tcFind.mockImplementation((toolname: string, pythonVersion: string) => {
							 | 
						||
| 
								 | 
							
								      const semverVersion = new semver.Range(pythonVersion);
							 | 
						||
| 
								 | 
							
								      return semver.satisfies(actualPythonVersion, semverVersion)
							 | 
						||
| 
								 | 
							
								        ? pypyPath
							 | 
						||
| 
								 | 
							
								        : '';
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    spyReadExactPyPyVersion = jest.spyOn(utils, 'readExactPyPyVersionFile');
							 | 
						||
| 
								 | 
							
								    spyReadExactPyPyVersion.mockImplementation(() => actualPyPyVersion);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  afterEach(() => {
							 | 
						||
| 
								 | 
							
								    jest.resetAllMocks();
							 | 
						||
| 
								 | 
							
								    jest.clearAllMocks();
							 | 
						||
| 
								 | 
							
								    jest.restoreAllMocks();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('PyPy exists on the path and versions are satisfied', () => {
							 | 
						||
| 
								 | 
							
								    expect(finder.findPyPyToolCache('3.6.17', 'v7.5.4', architecture)).toEqual({
							 | 
						||
| 
								 | 
							
								      installDir: pypyPath,
							 | 
						||
| 
								 | 
							
								      resolvedPythonVersion: actualPythonVersion,
							 | 
						||
| 
								 | 
							
								      resolvedPyPyVersion: actualPyPyVersion
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('PyPy exists on the path and versions are satisfied with semver', () => {
							 | 
						||
| 
								 | 
							
								    expect(finder.findPyPyToolCache('3.6', 'v7.5.x', architecture)).toEqual({
							 | 
						||
| 
								 | 
							
								      installDir: pypyPath,
							 | 
						||
| 
								 | 
							
								      resolvedPythonVersion: actualPythonVersion,
							 | 
						||
| 
								 | 
							
								      resolvedPyPyVersion: actualPyPyVersion
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it("PyPy exists on the path, but Python version doesn't match", () => {
							 | 
						||
| 
								 | 
							
								    expect(finder.findPyPyToolCache('3.7', 'v7.5.4', architecture)).toEqual({
							 | 
						||
| 
								 | 
							
								      installDir: '',
							 | 
						||
| 
								 | 
							
								      resolvedPythonVersion: '',
							 | 
						||
| 
								 | 
							
								      resolvedPyPyVersion: ''
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it("PyPy exists on the path, but PyPy version doesn't match", () => {
							 | 
						||
| 
								 | 
							
								    expect(finder.findPyPyToolCache('3.6', 'v7.5.1', architecture)).toEqual({
							 | 
						||
| 
								 | 
							
								      installDir: null,
							 | 
						||
| 
								 | 
							
								      resolvedPythonVersion: '',
							 | 
						||
| 
								 | 
							
								      resolvedPyPyVersion: ''
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('findPyPyVersion', () => {
							 | 
						||
| 
								 | 
							
								  let tcFind: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spyExtractZip: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spyExtractTar: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spyHttpClient: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spyExistsSync: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spyExec: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spySymlinkSync: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spyDownloadTool: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spyReadExactPyPyVersion: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spyFsReadDir: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spyWriteExactPyPyVersionFile: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spyCacheDir: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								  let spyChmodSync: jest.SpyInstance;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  beforeEach(() => {
							 | 
						||
| 
								 | 
							
								    tcFind = jest.spyOn(tc, 'find');
							 | 
						||
| 
								 | 
							
								    tcFind.mockImplementation((tool: string, version: string) => {
							 | 
						||
| 
								 | 
							
								      const semverRange = new semver.Range(version);
							 | 
						||
| 
								 | 
							
								      let pypyPath = '';
							 | 
						||
| 
								 | 
							
								      if (semver.satisfies('3.6.12', semverRange)) {
							 | 
						||
| 
								 | 
							
								        pypyPath = path.join(toolDir, 'PyPy', '3.6.12', architecture);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      return pypyPath;
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    spyWriteExactPyPyVersionFile = jest.spyOn(
							 | 
						||
| 
								 | 
							
								      utils,
							 | 
						||
| 
								 | 
							
								      'writeExactPyPyVersionFile'
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    spyWriteExactPyPyVersionFile.mockImplementation(() => null);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    spyReadExactPyPyVersion = jest.spyOn(utils, 'readExactPyPyVersionFile');
							 | 
						||
| 
								 | 
							
								    spyReadExactPyPyVersion.mockImplementation(() => '7.3.3');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    spyDownloadTool = jest.spyOn(tc, 'downloadTool');
							 | 
						||
| 
								 | 
							
								    spyDownloadTool.mockImplementation(() => path.join(tempDir, 'PyPy'));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    spyExtractZip = jest.spyOn(tc, 'extractZip');
							 | 
						||
| 
								 | 
							
								    spyExtractZip.mockImplementation(() => tempDir);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    spyExtractTar = jest.spyOn(tc, 'extractTar');
							 | 
						||
| 
								 | 
							
								    spyExtractTar.mockImplementation(() => tempDir);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    spyFsReadDir = jest.spyOn(fs, 'readdirSync');
							 | 
						||
| 
								 | 
							
								    spyFsReadDir.mockImplementation((directory: string) => ['PyPyTest']);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
							 | 
						||
| 
								 | 
							
								    spyHttpClient.mockImplementation(
							 | 
						||
| 
								 | 
							
								      async (): Promise<ifm.ITypedResponse<IPyPyManifestRelease[]>> => {
							 | 
						||
| 
								 | 
							
								        const result = JSON.stringify(manifestData);
							 | 
						||
| 
								 | 
							
								        return {
							 | 
						||
| 
								 | 
							
								          statusCode: 200,
							 | 
						||
| 
								 | 
							
								          headers: {},
							 | 
						||
| 
								 | 
							
								          result: JSON.parse(result) as IPyPyManifestRelease[]
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    spyExec = jest.spyOn(exec, 'exec');
							 | 
						||
| 
								 | 
							
								    spyExec.mockImplementation(() => undefined);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    spySymlinkSync = jest.spyOn(fs, 'symlinkSync');
							 | 
						||
| 
								 | 
							
								    spySymlinkSync.mockImplementation(() => undefined);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    spyExistsSync = jest.spyOn(fs, 'existsSync');
							 | 
						||
| 
								 | 
							
								    spyExistsSync.mockReturnValue(true);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  afterEach(() => {
							 | 
						||
| 
								 | 
							
								    jest.resetAllMocks();
							 | 
						||
| 
								 | 
							
								    jest.clearAllMocks();
							 | 
						||
| 
								 | 
							
								    jest.restoreAllMocks();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('found PyPy in toolcache', async () => {
							 | 
						||
| 
								 | 
							
								    await expect(
							 | 
						||
| 
								 | 
							
								      finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture)
							 | 
						||
| 
								 | 
							
								    ).resolves.toEqual({
							 | 
						||
| 
								 | 
							
								      resolvedPythonVersion: '3.6.12',
							 | 
						||
| 
								 | 
							
								      resolvedPyPyVersion: '7.3.3'
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('throw on invalid input format', async () => {
							 | 
						||
| 
								 | 
							
								    await expect(
							 | 
						||
| 
								 | 
							
								      finder.findPyPyVersion('pypy3.7-v7.3.x', architecture)
							 | 
						||
| 
								 | 
							
								    ).rejects.toThrow();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('throw on invalid input format pypy3.7-7.3.x', async () => {
							 | 
						||
| 
								 | 
							
								    await expect(
							 | 
						||
| 
								 | 
							
								      finder.findPyPyVersion('pypy3.7-v7.3.x', architecture)
							 | 
						||
| 
								 | 
							
								    ).rejects.toThrow();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('found and install successfully', async () => {
							 | 
						||
| 
								 | 
							
								    spyCacheDir = jest.spyOn(tc, 'cacheDir');
							 | 
						||
| 
								 | 
							
								    spyCacheDir.mockImplementation(() =>
							 | 
						||
| 
								 | 
							
								      path.join(toolDir, 'PyPy', '3.7.7', architecture)
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    spyChmodSync = jest.spyOn(fs, 'chmodSync');
							 | 
						||
| 
								 | 
							
								    spyChmodSync.mockImplementation(() => undefined);
							 | 
						||
| 
								 | 
							
								    await expect(
							 | 
						||
| 
								 | 
							
								      finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture)
							 | 
						||
| 
								 | 
							
								    ).resolves.toEqual({
							 | 
						||
| 
								 | 
							
								      resolvedPythonVersion: '3.7.9',
							 | 
						||
| 
								 | 
							
								      resolvedPyPyVersion: '7.3.3'
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('throw if release is not found', async () => {
							 | 
						||
| 
								 | 
							
								    await expect(
							 | 
						||
| 
								 | 
							
								      finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture)
							 | 
						||
| 
								 | 
							
								    ).rejects.toThrowError(
							 | 
						||
| 
								 | 
							
								      `PyPy version 3.7 (v7.5.x) with arch ${architecture} not found`
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 |