2022-09-27 20:47:12 +08:00
import each from 'jest-each' ;
2023-05-15 20:09:29 +08:00
import semver from 'semver' ;
2023-05-29 18:43:18 +08:00
import fs from 'fs' ;
import fspromises from 'fs/promises' ;
2023-05-15 20:09:29 +08:00
import * as exec from '@actions/exec' ;
import * as core from '@actions/core' ;
import * as io from '@actions/io' ;
2022-09-27 20:47:12 +08:00
import * as installer from '../src/installer' ;
import { IS_WINDOWS } from '../src/utils' ;
2023-05-15 20:09:29 +08:00
import { QualityOptions } from '../src/setup-dotnet' ;
describe ( 'installer tests' , ( ) = > {
const env = process . env ;
beforeEach ( ( ) = > {
jest . resetModules ( ) ;
process . env = { . . . env } ;
} ) ;
describe ( 'DotnetCoreInstaller tests' , ( ) = > {
const getExecOutputSpy = jest . spyOn ( exec , 'getExecOutput' ) ;
const warningSpy = jest . spyOn ( core , 'warning' ) ;
const whichSpy = jest . spyOn ( io , 'which' ) ;
const maxSatisfyingSpy = jest . spyOn ( semver , 'maxSatisfying' ) ;
2023-05-29 18:43:18 +08:00
const chmodSyncSpy = jest . spyOn ( fs , 'chmodSync' ) ;
const readdirSpy = jest . spyOn ( fspromises , 'readdir' ) ;
2023-05-15 20:09:29 +08:00
describe ( 'installDotnet() tests' , ( ) = > {
2023-05-29 18:43:18 +08:00
beforeAll ( ( ) = > {
whichSpy . mockImplementation ( ( ) = > Promise . resolve ( 'PathToShell' ) ) ;
chmodSyncSpy . mockImplementation ( ( ) = > { } ) ;
readdirSpy . mockImplementation ( ( ) = > Promise . resolve ( [ ] ) ) ;
} ) ;
afterAll ( ( ) = > {
jest . resetAllMocks ( ) ;
} ) ;
2023-05-15 20:09:29 +08:00
it ( 'should throw the error in case of non-zero exit code of the installation script. The error message should contain logs.' , async ( ) = > {
const inputVersion = '3.1.100' ;
const inputQuality = '' as QualityOptions ;
const errorMessage = 'fictitious error message!' ;
2023-05-29 18:43:18 +08:00
2023-05-15 20:09:29 +08:00
getExecOutputSpy . mockImplementation ( ( ) = > {
return Promise . resolve ( {
exitCode : 1 ,
stdout : '' ,
stderr : errorMessage
} ) ;
} ) ;
2023-05-29 18:43:18 +08:00
2023-05-15 20:09:29 +08:00
const dotnetInstaller = new installer . DotnetCoreInstaller (
inputVersion ,
inputQuality
) ;
await expect ( dotnetInstaller . installDotnet ( ) ) . rejects . toThrow (
` Failed to install dotnet, exit code: 1. ${ errorMessage } `
) ;
} ) ;
it ( 'should return version of .NET SDK after installation complete' , async ( ) = > {
const inputVersion = '3.1.100' ;
const inputQuality = '' as QualityOptions ;
2023-05-15 20:24:28 +08:00
const stdout = ` Fictitious dotnet version ${ inputVersion } is installed ` ;
2023-05-15 20:09:29 +08:00
getExecOutputSpy . mockImplementation ( ( ) = > {
2023-05-15 20:24:28 +08:00
return Promise . resolve ( {
exitCode : 0 ,
stdout : ` ${ stdout } ` ,
stderr : ''
} ) ;
2023-05-15 20:09:29 +08:00
} ) ;
maxSatisfyingSpy . mockImplementation ( ( ) = > inputVersion ) ;
const dotnetInstaller = new installer . DotnetCoreInstaller (
inputVersion ,
inputQuality
) ;
const installedVersion = await dotnetInstaller . installDotnet ( ) ;
expect ( installedVersion ) . toBe ( inputVersion ) ;
} ) ;
it ( ` should supply 'version' argument to the installation script if supplied version is in A.B.C syntax ` , async ( ) = > {
const inputVersion = '6.0.300' ;
const inputQuality = '' as QualityOptions ;
2023-05-15 20:24:28 +08:00
const stdout = ` Fictitious dotnet version ${ inputVersion } is installed ` ;
2023-05-15 20:09:29 +08:00
getExecOutputSpy . mockImplementation ( ( ) = > {
2023-05-15 20:24:28 +08:00
return Promise . resolve ( {
exitCode : 0 ,
stdout : ` ${ stdout } ` ,
stderr : ''
} ) ;
2023-05-15 20:09:29 +08:00
} ) ;
maxSatisfyingSpy . mockImplementation ( ( ) = > inputVersion ) ;
const dotnetInstaller = new installer . DotnetCoreInstaller (
inputVersion ,
inputQuality
) ;
await dotnetInstaller . installDotnet ( ) ;
2023-05-24 23:57:28 +08:00
/ * *
* First time script would be called to
* install runtime , here we checking only the
* second one that installs actual SDK . i . e . 1
* /
const callIndex = 1 ;
2023-05-15 20:09:29 +08:00
const scriptArguments = (
2023-05-24 23:57:28 +08:00
getExecOutputSpy . mock . calls [ callIndex ] [ 1 ] as string [ ]
2023-05-15 20:09:29 +08:00
) . join ( ' ' ) ;
const expectedArgument = IS_WINDOWS
? ` -Version ${ inputVersion } `
: ` --version ${ inputVersion } ` ;
expect ( scriptArguments ) . toContain ( expectedArgument ) ;
} ) ;
it ( ` should warn if the 'quality' input is set and the supplied version is in A.B.C syntax ` , async ( ) = > {
const inputVersion = '6.0.300' ;
const inputQuality = 'ga' as QualityOptions ;
2023-05-15 20:24:28 +08:00
const stdout = ` Fictitious dotnet version ${ inputVersion } is installed ` ;
2023-05-15 20:09:29 +08:00
getExecOutputSpy . mockImplementation ( ( ) = > {
2023-05-15 20:24:28 +08:00
return Promise . resolve ( {
exitCode : 0 ,
stdout : ` ${ stdout } ` ,
stderr : ''
} ) ;
2023-05-15 20:09:29 +08:00
} ) ;
maxSatisfyingSpy . mockImplementation ( ( ) = > inputVersion ) ;
const dotnetInstaller = new installer . DotnetCoreInstaller (
inputVersion ,
inputQuality
) ;
await dotnetInstaller . installDotnet ( ) ;
expect ( warningSpy ) . toHaveBeenCalledWith (
2023-05-18 18:39:22 +08:00
` The 'dotnet-quality' input can be used only with .NET SDK version in A.B, A.B.x, A, A.x and A.B.Cxx formats where the major tag is higher than 5. You specified: ${ inputVersion } . 'dotnet-quality' input is ignored. `
2023-05-15 20:09:29 +08:00
) ;
} ) ;
it ( ` should warn if the 'quality' input is set and version isn't in A.B.C syntax but major tag is lower then 6 ` , async ( ) = > {
const inputVersion = '3.1' ;
const inputQuality = 'ga' as QualityOptions ;
2023-05-15 20:24:28 +08:00
const stdout = ` Fictitious dotnet version 3.1.100 is installed ` ;
2023-05-15 20:09:29 +08:00
getExecOutputSpy . mockImplementation ( ( ) = > {
2023-05-15 20:24:28 +08:00
return Promise . resolve ( {
exitCode : 0 ,
stdout : ` ${ stdout } ` ,
stderr : ''
} ) ;
2023-05-15 20:09:29 +08:00
} ) ;
maxSatisfyingSpy . mockImplementation ( ( ) = > inputVersion ) ;
const dotnetInstaller = new installer . DotnetCoreInstaller (
inputVersion ,
inputQuality
) ;
await dotnetInstaller . installDotnet ( ) ;
expect ( warningSpy ) . toHaveBeenCalledWith (
2023-05-18 18:39:22 +08:00
` The 'dotnet-quality' input can be used only with .NET SDK version in A.B, A.B.x, A, A.x and A.B.Cxx formats where the major tag is higher than 5. You specified: ${ inputVersion } . 'dotnet-quality' input is ignored. `
2023-05-15 20:09:29 +08:00
) ;
} ) ;
each ( [ '6' , '6.0' , '6.0.x' , '6.0.*' , '6.0.X' ] ) . test (
` should supply 'quality' argument to the installation script if quality input is set and version (%s) is not in A.B.C syntax ` ,
async inputVersion = > {
const inputQuality = 'ga' as QualityOptions ;
const exitCode = 0 ;
2023-05-15 20:24:28 +08:00
const stdout = ` Fictitious dotnet version 6.0.0 is installed ` ;
2023-05-15 20:09:29 +08:00
getExecOutputSpy . mockImplementation ( ( ) = > {
return Promise . resolve ( {
exitCode : exitCode ,
2023-05-15 20:24:28 +08:00
stdout : ` ${ stdout } ` ,
2023-05-15 20:09:29 +08:00
stderr : ''
} ) ;
} ) ;
maxSatisfyingSpy . mockImplementation ( ( ) = > inputVersion ) ;
const dotnetInstaller = new installer . DotnetCoreInstaller (
inputVersion ,
inputQuality
) ;
await dotnetInstaller . installDotnet ( ) ;
2023-05-24 23:57:28 +08:00
/ * *
* First time script would be called to
* install runtime , here we checking only the
* second one that installs actual SDK . i . e . 1
* /
const callIndex = 1 ;
2023-05-15 20:09:29 +08:00
const scriptArguments = (
2023-05-24 23:57:28 +08:00
getExecOutputSpy . mock . calls [ callIndex ] [ 1 ] as string [ ]
2023-05-15 20:09:29 +08:00
) . join ( ' ' ) ;
const expectedArgument = IS_WINDOWS
? ` -Quality ${ inputQuality } `
: ` --quality ${ inputQuality } ` ;
expect ( scriptArguments ) . toContain ( expectedArgument ) ;
}
2023-05-05 16:44:54 +08:00
) ;
2023-05-15 20:09:29 +08:00
each ( [ '6' , '6.0' , '6.0.x' , '6.0.*' , '6.0.X' ] ) . test (
` should supply 'channel' argument to the installation script if version (%s) isn't in A.B.C syntax ` ,
async inputVersion = > {
const inputQuality = '' as QualityOptions ;
const exitCode = 0 ;
2023-05-15 20:24:28 +08:00
const stdout = ` Fictitious dotnet version 6.0.0 is installed ` ;
2023-05-15 20:09:29 +08:00
getExecOutputSpy . mockImplementation ( ( ) = > {
return Promise . resolve ( {
exitCode : exitCode ,
2023-05-15 20:24:28 +08:00
stdout : ` ${ stdout } ` ,
2023-05-15 20:09:29 +08:00
stderr : ''
} ) ;
} ) ;
maxSatisfyingSpy . mockImplementation ( ( ) = > inputVersion ) ;
const dotnetInstaller = new installer . DotnetCoreInstaller (
inputVersion ,
inputQuality
) ;
await dotnetInstaller . installDotnet ( ) ;
2023-05-24 23:57:28 +08:00
/ * *
* First time script would be called to
* install runtime , here we checking only the
* second one that installs actual SDK . i . e . 1
* /
const callIndex = 1 ;
2023-05-15 20:09:29 +08:00
const scriptArguments = (
2023-05-24 23:57:28 +08:00
getExecOutputSpy . mock . calls [ callIndex ] [ 1 ] as string [ ]
2023-05-15 20:09:29 +08:00
) . join ( ' ' ) ;
const expectedArgument = IS_WINDOWS
? ` -Channel 6.0 `
: ` --channel 6.0 ` ;
expect ( scriptArguments ) . toContain ( expectedArgument ) ;
}
2023-05-05 16:44:54 +08:00
) ;
2023-05-15 20:09:29 +08:00
if ( IS_WINDOWS ) {
it ( ` should supply '-ProxyAddress' argument to the installation script if env.variable 'https_proxy' is set ` , async ( ) = > {
process . env [ 'https_proxy' ] = 'https://proxy.com' ;
const inputVersion = '6.0.100' ;
const inputQuality = '' as QualityOptions ;
2023-05-15 20:24:28 +08:00
const stdout = ` Fictitious dotnet version ${ inputVersion } is installed ` ;
2023-05-15 20:09:29 +08:00
getExecOutputSpy . mockImplementation ( ( ) = > {
2023-05-15 20:24:28 +08:00
return Promise . resolve ( {
exitCode : 0 ,
stdout : ` ${ stdout } ` ,
stderr : ''
} ) ;
2023-05-15 20:09:29 +08:00
} ) ;
maxSatisfyingSpy . mockImplementation ( ( ) = > inputVersion ) ;
const dotnetInstaller = new installer . DotnetCoreInstaller (
inputVersion ,
inputQuality
) ;
await dotnetInstaller . installDotnet ( ) ;
2023-05-24 23:57:28 +08:00
/ * *
* First time script would be called to
* install runtime , here we checking only the
* second one that installs actual SDK . i . e . 1
* /
const callIndex = 1 ;
2023-05-15 20:09:29 +08:00
const scriptArguments = (
2023-05-24 23:57:28 +08:00
getExecOutputSpy . mock . calls [ callIndex ] [ 1 ] as string [ ]
2023-05-15 20:09:29 +08:00
) . join ( ' ' ) ;
expect ( scriptArguments ) . toContain (
` -ProxyAddress ${ process . env [ 'https_proxy' ] } `
) ;
} ) ;
it ( ` should supply '-ProxyBypassList' argument to the installation script if env.variable 'no_proxy' is set ` , async ( ) = > {
process . env [ 'no_proxy' ] = 'first.url,second.url' ;
const inputVersion = '6.0.100' ;
const inputQuality = '' as QualityOptions ;
2023-05-15 20:24:28 +08:00
const stdout = ` Fictitious dotnet version 6.0.0 is installed ` ;
2023-05-15 20:09:29 +08:00
getExecOutputSpy . mockImplementation ( ( ) = > {
2023-05-15 20:24:28 +08:00
return Promise . resolve ( {
exitCode : 0 ,
stdout : ` ${ stdout } ` ,
stderr : ''
} ) ;
2023-05-15 20:09:29 +08:00
} ) ;
maxSatisfyingSpy . mockImplementation ( ( ) = > inputVersion ) ;
const dotnetInstaller = new installer . DotnetCoreInstaller (
inputVersion ,
inputQuality
) ;
await dotnetInstaller . installDotnet ( ) ;
2023-05-24 23:57:28 +08:00
/ * *
* First time script would be called to
* install runtime , here we checking only the
* second one that installs actual SDK . i . e . 1
* /
const callIndex = 1 ;
2023-05-15 20:09:29 +08:00
const scriptArguments = (
2023-05-24 23:57:28 +08:00
getExecOutputSpy . mock . calls [ callIndex ] [ 1 ] as string [ ]
2023-05-15 20:09:29 +08:00
) . join ( ' ' ) ;
expect ( scriptArguments ) . toContain (
` -ProxyBypassList ${ process . env [ 'no_proxy' ] } `
) ;
} ) ;
}
2020-01-26 14:37:54 +08:00
} ) ;
2019-06-21 20:21:08 +08:00
2023-05-15 20:09:29 +08:00
describe ( 'addToPath() tests' , ( ) = > {
it ( ` should export DOTNET_ROOT env.var with value from DOTNET_INSTALL_DIR env.var ` , async ( ) = > {
process . env [ 'DOTNET_INSTALL_DIR' ] = 'fictitious/dotnet/install/dir' ;
2023-05-30 18:45:38 +08:00
installer . DotnetInstallDir . addToPath ( ) ;
2023-05-15 20:09:29 +08:00
const dotnet_root = process . env [ 'DOTNET_ROOT' ] ;
expect ( dotnet_root ) . toBe ( process . env [ 'DOTNET_INSTALL_DIR' ] ) ;
} ) ;
it ( ` should export value from DOTNET_INSTALL_DIR env.var to the PATH ` , async ( ) = > {
process . env [ 'DOTNET_INSTALL_DIR' ] = 'fictitious/dotnet/install/dir' ;
2023-05-30 18:45:38 +08:00
installer . DotnetInstallDir . addToPath ( ) ;
2023-05-15 20:09:29 +08:00
const path = process . env [ 'PATH' ] ;
expect ( path ) . toContain ( process . env [ 'DOTNET_INSTALL_DIR' ] ) ;
} ) ;
} ) ;
} ) ;
describe ( 'DotnetVersionResolver tests' , ( ) = > {
2023-05-24 22:59:05 +08:00
describe ( 'createDotnetVersion() tests' , ( ) = > {
2023-05-15 20:09:29 +08:00
each ( [
'3.1' ,
'3.x' ,
'3.1.x' ,
'3.1.*' ,
'3.1.X' ,
'3.1.2' ,
2023-05-18 17:11:51 +08:00
'3.1.0-preview1' ,
'6.0.2xx'
2023-05-15 20:09:29 +08:00
] ) . test (
'if valid version is supplied (%s), it should return version object with some value' ,
async version = > {
const dotnetVersionResolver = new installer . DotnetVersionResolver (
version
) ;
const versionObject =
2023-05-24 22:59:05 +08:00
await dotnetVersionResolver . createDotnetVersion ( ) ;
2023-05-15 20:09:29 +08:00
expect ( ! ! versionObject . value ) . toBe ( true ) ;
}
2023-05-05 16:44:54 +08:00
) ;
2023-05-15 20:09:29 +08:00
each ( [
'.' ,
'..' ,
' . ' ,
'. ' ,
' .' ,
' . . ' ,
' .. ' ,
' . ' ,
'-1.-1' ,
'-1' ,
'-1.-1.-1' ,
'..3' ,
'1..3' ,
'1..' ,
'.2.3' ,
'.2.x' ,
'*.' ,
'1.2.' ,
'1.2.-abc' ,
'a.b' ,
'a.b.c' ,
'a.b.c-preview' ,
' 0 . 1 . 2 ' ,
'invalid'
] ) . test (
'if invalid version is supplied (%s), it should throw' ,
async version = > {
const dotnetVersionResolver = new installer . DotnetVersionResolver (
version
) ;
await expect (
2023-05-24 22:59:05 +08:00
async ( ) = > await dotnetVersionResolver . createDotnetVersion ( )
2023-05-15 20:09:29 +08:00
) . rejects . toThrow ( ) ;
}
2023-03-09 20:43:05 +08:00
) ;
2023-05-05 16:44:54 +08:00
2023-05-18 17:46:40 +08:00
each ( [ '3' , '3.1' , '3.1.x' , '3.1.*' , '3.1.X' , '6.0.2xx' ] ) . test (
2023-05-15 20:09:29 +08:00
"if version that can be resolved to 'channel' option is supplied (%s), it should set type to 'channel' in version object" ,
async version = > {
const dotnetVersionResolver = new installer . DotnetVersionResolver (
version
) ;
const versionObject =
2023-05-24 22:59:05 +08:00
await dotnetVersionResolver . createDotnetVersion ( ) ;
2023-05-15 20:09:29 +08:00
expect ( versionObject . type . toLowerCase ( ) . includes ( 'channel' ) ) . toBe (
true
) ;
}
2023-05-05 16:44:54 +08:00
) ;
2023-05-15 20:09:29 +08:00
2023-05-18 17:46:40 +08:00
each ( [ '6.0' , '6.0.x' , '6.0.*' , '6.0.X' , '6.0.2xx' ] ) . test (
2023-05-15 20:09:29 +08:00
"if version that can be resolved to 'channel' option is supplied and its major tag is >= 6 (%s), it should set type to 'channel' and qualityFlag to 'true' in version object" ,
async version = > {
const dotnetVersionResolver = new installer . DotnetVersionResolver (
version
) ;
const versionObject =
2023-05-24 22:59:05 +08:00
await dotnetVersionResolver . createDotnetVersion ( ) ;
2023-05-15 20:09:29 +08:00
expect ( versionObject . type . toLowerCase ( ) . includes ( 'channel' ) ) . toBe (
true
) ;
expect ( versionObject . qualityFlag ) . toBe ( true ) ;
}
2023-05-05 16:44:54 +08:00
) ;
2023-05-15 20:09:29 +08:00
each ( [ '3.1.2' , '3.1.0-preview1' ] ) . test (
"if version that can be resolved to 'version' option is supplied (%s), it should set quality flag to 'false' and type to 'version' in version object" ,
async version = > {
const dotnetVersionResolver = new installer . DotnetVersionResolver (
version
) ;
const versionObject =
2023-05-24 22:59:05 +08:00
await dotnetVersionResolver . createDotnetVersion ( ) ;
2023-05-15 20:09:29 +08:00
expect ( versionObject . type . toLowerCase ( ) . includes ( 'version' ) ) . toBe (
true
) ;
expect ( versionObject . qualityFlag ) . toBe ( false ) ;
}
2023-05-05 16:44:54 +08:00
) ;
2023-05-15 20:09:29 +08:00
each ( [ '3.1.2' , '3.1' ] ) . test (
'it should create proper line arguments for powershell/bash installation scripts' ,
async version = > {
const dotnetVersionResolver = new installer . DotnetVersionResolver (
version
) ;
const versionObject =
2023-05-24 22:59:05 +08:00
await dotnetVersionResolver . createDotnetVersion ( ) ;
2023-05-15 20:09:29 +08:00
const windowsRegEx = new RegExp ( /^-(Version|Channel)/ ) ;
const nonWindowsRegEx = new RegExp ( /^--(version|channel)/ ) ;
if ( IS_WINDOWS ) {
expect ( windowsRegEx . test ( versionObject . type ) ) . toBe ( true ) ;
expect ( nonWindowsRegEx . test ( versionObject . type ) ) . toBe ( false ) ;
} else {
expect ( nonWindowsRegEx . test ( versionObject . type ) ) . toBe ( true ) ;
expect ( windowsRegEx . test ( versionObject . type ) ) . toBe ( false ) ;
}
}
) ;
2023-05-18 17:11:51 +08:00
it ( ` should throw if dotnet-version is supplied in A.B.Cxx syntax with major tag lower that 5 ` , async ( ) = > {
const version = '3.0.1xx' ;
const dotnetVersionResolver = new installer . DotnetVersionResolver (
version
) ;
await expect (
2023-05-24 22:59:05 +08:00
async ( ) = > await dotnetVersionResolver . createDotnetVersion ( )
2023-05-18 17:11:51 +08:00
) . rejects . toThrow (
` 'dotnet-version' was supplied in invalid format: ${ version } ! The A.B.Cxx syntax is available since the .NET 5.0 release. `
) ;
} ) ;
2023-05-15 20:09:29 +08:00
} ) ;
} ) ;
2023-05-15 20:24:28 +08:00
} ) ;