2021-12-14 19:50:52 +00:00
"use strict" ;
var _ _importDefault = ( this && this . _ _importDefault ) || function ( mod ) {
return ( mod && mod . _ _esModule ) ? mod : { "default" : mod } ;
} ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
const ava _1 = _ _importDefault ( require ( "ava" ) ) ;
const feature _flags _1 = require ( "./feature-flags" ) ;
2021-12-15 16:29:34 +00:00
const logging _1 = require ( "./logging" ) ;
2021-12-15 17:03:43 +00:00
const repository _1 = require ( "./repository" ) ;
2021-12-14 19:50:52 +00:00
const testing _utils _1 = require ( "./testing-utils" ) ;
const util _1 = require ( "./util" ) ;
( 0 , testing _utils _1 . setupTests ) ( ava _1 . default ) ;
ava _1 . default . beforeEach ( ( ) => {
2022-11-14 16:37:48 +00:00
( 0 , util _1 . initializeEnvironment ) ( "1.2.3" ) ;
2021-12-14 19:50:52 +00:00
} ) ;
2021-12-15 17:03:43 +00:00
const testRepositoryNwo = ( 0 , repository _1 . parseRepositoryNwo ) ( "github/example" ) ;
2022-10-11 18:56:15 +01:00
const ALL _FEATURES _DISABLED _VARIANTS = [
2021-12-14 19:50:52 +00:00
{
description : "GHES" ,
gitHubVersion : { type : util _1 . GitHubVariant . GHES , version : "3.0.0" } ,
} ,
{ description : "GHAE" , gitHubVersion : { type : util _1 . GitHubVariant . GHAE } } ,
] ;
2022-10-11 18:56:15 +01:00
for ( const variant of ALL _FEATURES _DISABLED _VARIANTS ) {
( 0 , ava _1 . default ) ( ` All features are disabled if running against ${ variant . description } ` , async ( t ) => {
2021-12-14 19:50:52 +00:00
await ( 0 , util _1 . withTmpDir ) ( async ( tmpDir ) => {
const loggedMessages = [ ] ;
2022-10-11 10:39:40 -07:00
const featureEnablement = setUpTests ( tmpDir , ( 0 , testing _utils _1 . getRecordingLogger ) ( loggedMessages ) , variant . gitHubVersion ) ;
2022-10-11 18:56:15 +01:00
for ( const feature of Object . values ( feature _flags _1 . Feature ) ) {
t . false ( await featureEnablement . getValue ( feature , includeCodeQlIfRequired ( feature ) ) ) ;
2021-12-16 13:14:32 +00:00
}
2021-12-14 19:50:52 +00:00
t . assert ( loggedMessages . find ( ( v ) => v . type === "debug" &&
v . message ===
2022-10-07 13:41:50 -07:00
"Not running against github.com. Disabling all toggleable features." ) !== undefined ) ;
2021-12-14 19:50:52 +00:00
} ) ;
} ) ;
}
2022-07-18 10:37:04 +00:00
( 0 , ava _1 . default ) ( "API response missing" , async ( t ) => {
await ( 0 , util _1 . withTmpDir ) ( async ( tmpDir ) => {
const loggedMessages = [ ] ;
2022-10-11 10:39:40 -07:00
const featureEnablement = setUpTests ( tmpDir , ( 0 , testing _utils _1 . getRecordingLogger ) ( loggedMessages ) ) ;
2022-07-18 10:37:04 +00:00
( 0 , testing _utils _1 . mockFeatureFlagApiEndpoint ) ( 403 , { } ) ;
2022-10-11 18:56:15 +01:00
for ( const feature of Object . values ( feature _flags _1 . Feature ) ) {
t . assert ( ( await featureEnablement . getValue ( feature , includeCodeQlIfRequired ( feature ) ) ) === false ) ;
2022-07-18 10:37:04 +00:00
}
2022-10-06 12:29:58 -07:00
assertAllFeaturesUndefinedInApi ( t , loggedMessages ) ;
2022-07-18 10:37:04 +00:00
} ) ;
} ) ;
2022-10-11 18:56:15 +01:00
( 0 , ava _1 . default ) ( "Features are disabled if they're not returned in API response" , async ( t ) => {
2021-12-14 19:50:52 +00:00
await ( 0 , util _1 . withTmpDir ) ( async ( tmpDir ) => {
const loggedMessages = [ ] ;
2022-10-11 10:39:40 -07:00
const featureEnablement = setUpTests ( tmpDir , ( 0 , testing _utils _1 . getRecordingLogger ) ( loggedMessages ) ) ;
2021-12-16 13:30:31 +00:00
( 0 , testing _utils _1 . mockFeatureFlagApiEndpoint ) ( 200 , { } ) ;
2022-10-11 18:56:15 +01:00
for ( const feature of Object . values ( feature _flags _1 . Feature ) ) {
t . assert ( ( await featureEnablement . getValue ( feature , includeCodeQlIfRequired ( feature ) ) ) === false ) ;
2021-12-14 19:50:52 +00:00
}
2022-10-06 12:29:58 -07:00
assertAllFeaturesUndefinedInApi ( t , loggedMessages ) ;
2021-12-14 19:50:52 +00:00
} ) ;
} ) ;
2021-12-15 16:29:34 +00:00
( 0 , ava _1 . default ) ( "Feature flags exception is propagated if the API request errors" , async ( t ) => {
2021-12-14 19:50:52 +00:00
await ( 0 , util _1 . withTmpDir ) ( async ( tmpDir ) => {
2022-10-11 10:39:40 -07:00
const featureEnablement = setUpTests ( tmpDir ) ;
2021-12-16 13:30:31 +00:00
( 0 , testing _utils _1 . mockFeatureFlagApiEndpoint ) ( 500 , { } ) ;
2022-10-11 10:39:40 -07:00
await t . throwsAsync ( async ( ) => featureEnablement . getValue ( feature _flags _1 . Feature . MlPoweredQueriesEnabled , includeCodeQlIfRequired ( feature _flags _1 . Feature . MlPoweredQueriesEnabled ) ) , {
2022-10-07 13:41:50 -07:00
message : "Encountered an error while trying to determine feature enablement: Error: some error message" ,
2021-12-15 16:29:34 +00:00
} ) ;
2021-12-14 19:50:52 +00:00
} ) ;
} ) ;
2022-10-11 10:39:40 -07:00
for ( const feature of Object . keys ( feature _flags _1 . featureConfig ) ) {
2022-10-11 18:56:15 +01:00
( 0 , ava _1 . default ) ( ` Only feature ' ${ feature } ' is enabled if enabled in the API response. Other features disabled ` , async ( t ) => {
2021-12-14 19:50:52 +00:00
await ( 0 , util _1 . withTmpDir ) ( async ( tmpDir ) => {
2022-10-11 10:39:40 -07:00
const featureEnablement = setUpTests ( tmpDir ) ;
2022-10-11 18:56:15 +01:00
// set all features to false except the one we're testing
2022-10-11 10:39:40 -07:00
const expectedFeatureEnablement = { } ;
2022-10-06 12:31:08 -07:00
for ( const f of Object . keys ( feature _flags _1 . featureConfig ) ) {
2022-10-11 10:39:40 -07:00
expectedFeatureEnablement [ f ] = f === feature ;
2021-12-14 19:50:52 +00:00
}
2022-10-11 10:39:40 -07:00
( 0 , testing _utils _1 . mockFeatureFlagApiEndpoint ) ( 200 , expectedFeatureEnablement ) ;
2022-10-11 18:56:15 +01:00
// retrieve the values of the actual features
2022-10-11 10:39:40 -07:00
const actualFeatureEnablement = { } ;
2022-10-06 12:31:08 -07:00
for ( const f of Object . keys ( feature _flags _1 . featureConfig ) ) {
2022-10-11 10:39:40 -07:00
actualFeatureEnablement [ f ] = await featureEnablement . getValue ( f , includeCodeQlIfRequired ( f ) ) ;
2022-10-05 15:54:07 -07:00
}
2022-10-11 18:56:15 +01:00
// All features should be false except the one we're testing
2022-10-11 10:39:40 -07:00
t . deepEqual ( actualFeatureEnablement , expectedFeatureEnablement ) ;
2021-12-14 19:50:52 +00:00
} ) ;
} ) ;
2022-10-11 18:56:15 +01:00
( 0 , ava _1 . default ) ( ` Only feature ' ${ feature } ' is enabled if the associated environment variable is true. Others disabled. ` , async ( t ) => {
2022-10-05 15:54:07 -07:00
await ( 0 , util _1 . withTmpDir ) ( async ( tmpDir ) => {
2022-10-11 10:39:40 -07:00
const featureEnablement = setUpTests ( tmpDir ) ;
const expectedFeatureEnablement = initializeFeatures ( false ) ;
( 0 , testing _utils _1 . mockFeatureFlagApiEndpoint ) ( 200 , expectedFeatureEnablement ) ;
2022-10-11 18:56:15 +01:00
// feature should be disabled initially
2022-10-11 10:39:40 -07:00
t . assert ( ! ( await featureEnablement . getValue ( feature , includeCodeQlIfRequired ( feature ) ) ) ) ;
2022-10-11 18:56:15 +01:00
// set env var to true and check that the feature is now enabled
2022-10-11 10:39:40 -07:00
process . env [ feature _flags _1 . featureConfig [ feature ] . envVar ] = "true" ;
t . assert ( await featureEnablement . getValue ( feature , includeCodeQlIfRequired ( feature ) ) ) ;
2022-10-05 15:54:07 -07:00
} ) ;
} ) ;
2022-10-11 18:56:15 +01:00
( 0 , ava _1 . default ) ( ` Feature ' ${ feature } ' is disabled if the associated environment variable is false, even if enabled in API ` , async ( t ) => {
2022-10-05 15:54:07 -07:00
await ( 0 , util _1 . withTmpDir ) ( async ( tmpDir ) => {
2022-10-11 10:39:40 -07:00
const featureEnablement = setUpTests ( tmpDir ) ;
const expectedFeatureEnablement = initializeFeatures ( true ) ;
( 0 , testing _utils _1 . mockFeatureFlagApiEndpoint ) ( 200 , expectedFeatureEnablement ) ;
2022-10-11 18:56:15 +01:00
// feature should be enabled initially
2022-10-11 10:39:40 -07:00
t . assert ( await featureEnablement . getValue ( feature , includeCodeQlIfRequired ( feature ) ) ) ;
2022-10-11 18:56:15 +01:00
// set env var to false and check that the feature is now disabled
2022-10-11 10:39:40 -07:00
process . env [ feature _flags _1 . featureConfig [ feature ] . envVar ] = "false" ;
t . assert ( ! ( await featureEnablement . getValue ( feature , includeCodeQlIfRequired ( feature ) ) ) ) ;
2022-10-05 15:54:07 -07:00
} ) ;
} ) ;
2022-10-11 10:39:40 -07:00
if ( feature _flags _1 . featureConfig [ feature ] . minimumVersion !== undefined ) {
2022-10-11 18:56:15 +01:00
( 0 , ava _1 . default ) ( ` Getting feature ' ${ feature } should throw if no codeql is provided ` , async ( t ) => {
2022-10-06 12:29:58 -07:00
await ( 0 , util _1 . withTmpDir ) ( async ( tmpDir ) => {
2022-10-11 10:39:40 -07:00
const featureEnablement = setUpTests ( tmpDir ) ;
const expectedFeatureEnablement = initializeFeatures ( true ) ;
( 0 , testing _utils _1 . mockFeatureFlagApiEndpoint ) ( 200 , expectedFeatureEnablement ) ;
await t . throwsAsync ( async ( ) => featureEnablement . getValue ( feature ) , {
message : ` Internal error: A minimum version is specified for feature ${ feature } , but no instance of CodeQL was provided. ` ,
2022-10-06 12:29:58 -07:00
} ) ;
} ) ;
} ) ;
}
2022-10-11 10:39:40 -07:00
if ( feature _flags _1 . featureConfig [ feature ] . minimumVersion !== undefined ) {
2022-10-11 18:56:15 +01:00
( 0 , ava _1 . default ) ( ` Feature ' ${ feature } ' is disabled if the minimum CLI version is below ${ feature _flags _1 . featureConfig [ feature ] . minimumVersion } ` , async ( t ) => {
2022-10-05 15:54:07 -07:00
await ( 0 , util _1 . withTmpDir ) ( async ( tmpDir ) => {
2022-10-11 10:39:40 -07:00
const featureEnablement = setUpTests ( tmpDir ) ;
const expectedFeatureEnablement = initializeFeatures ( true ) ;
( 0 , testing _utils _1 . mockFeatureFlagApiEndpoint ) ( 200 , expectedFeatureEnablement ) ;
2022-10-11 18:56:15 +01:00
// feature should be disabled when an old CLI version is set
2022-10-05 15:54:07 -07:00
let codeql = ( 0 , testing _utils _1 . mockCodeQLVersion ) ( "2.0.0" ) ;
2022-10-11 10:39:40 -07:00
t . assert ( ! ( await featureEnablement . getValue ( feature , codeql ) ) ) ;
2022-10-11 18:56:15 +01:00
// even setting the env var to true should not enable the feature if
2022-10-05 15:54:07 -07:00
// the minimum CLI version is not met
2022-10-11 10:39:40 -07:00
process . env [ feature _flags _1 . featureConfig [ feature ] . envVar ] = "true" ;
t . assert ( ! ( await featureEnablement . getValue ( feature , codeql ) ) ) ;
2022-10-11 18:56:15 +01:00
// feature should be enabled when a new CLI version is set
2022-10-05 15:54:07 -07:00
// and env var is not set
2022-10-11 10:39:40 -07:00
process . env [ feature _flags _1 . featureConfig [ feature ] . envVar ] = "" ;
codeql = ( 0 , testing _utils _1 . mockCodeQLVersion ) ( feature _flags _1 . featureConfig [ feature ] . minimumVersion ) ;
t . assert ( await featureEnablement . getValue ( feature , codeql ) ) ;
2022-10-11 18:56:15 +01:00
// set env var to false and check that the feature is now disabled
2022-10-11 10:39:40 -07:00
process . env [ feature _flags _1 . featureConfig [ feature ] . envVar ] = "false" ;
t . assert ( ! ( await featureEnablement . getValue ( feature , codeql ) ) ) ;
2022-10-05 15:54:07 -07:00
} ) ;
} ) ;
}
}
2022-10-11 18:56:15 +01:00
// If we ever run into a situation where we no longer have any features that
2022-10-07 11:33:32 -07:00
// specify a minimum version, then we will have a bunch of code no longer being
// tested. This is unlikely, and this test will fail if that happens.
// If we do end up in that situation, then we should consider adding a synthetic
2022-10-11 18:56:15 +01:00
// feature with a minimum version that is only used for tests.
2022-10-07 11:33:32 -07:00
( 0 , ava _1 . default ) ( "At least one feature has a minimum version specified" , ( t ) => {
2022-10-11 18:56:15 +01:00
t . assert ( Object . values ( feature _flags _1 . featureConfig ) . some ( ( f ) => f . minimumVersion !== undefined ) , "At least one feature should have a minimum version specified" ) ;
// An even less likely scenario is that we no longer have any features.
t . assert ( Object . values ( feature _flags _1 . featureConfig ) . length > 0 , "There should be at least one feature" ) ;
2022-10-07 11:33:32 -07:00
} ) ;
2022-10-06 12:29:58 -07:00
function assertAllFeaturesUndefinedInApi ( t , loggedMessages ) {
2022-10-11 10:39:40 -07:00
for ( const feature of Object . keys ( feature _flags _1 . featureConfig ) ) {
2022-10-06 12:29:58 -07:00
t . assert ( loggedMessages . find ( ( v ) => v . type === "debug" &&
2022-10-11 10:39:40 -07:00
v . message . includes ( feature ) &&
2022-10-06 12:29:58 -07:00
v . message . includes ( "considering it disabled" ) ) !== undefined ) ;
}
}
function initializeFeatures ( initialValue ) {
2022-10-06 12:31:08 -07:00
return Object . keys ( feature _flags _1 . featureConfig ) . reduce ( ( features , key ) => {
2022-10-06 12:29:58 -07:00
features [ key ] = initialValue ;
return features ;
} , { } ) ;
}
function setUpTests ( tmpDir , logger = ( 0 , logging _1 . getRunnerLogger ) ( true ) , gitHubVersion = { type : util _1 . GitHubVariant . DOTCOM } ) {
2022-10-05 15:54:07 -07:00
( 0 , testing _utils _1 . setupActionsVars ) ( tmpDir , tmpDir ) ;
2022-11-14 19:48:27 +00:00
return new feature _flags _1 . Features ( gitHubVersion , testRepositoryNwo , logger ) ;
2021-12-14 19:50:52 +00:00
}
2022-10-11 18:56:15 +01:00
function includeCodeQlIfRequired ( feature ) {
return feature _flags _1 . featureConfig [ feature ] . minimumVersion !== undefined
2022-10-06 12:29:58 -07:00
? ( 0 , testing _utils _1 . mockCodeQLVersion ) ( "9.9.9" )
: undefined ;
}
2021-12-14 19:50:52 +00:00
//# sourceMappingURL=feature-flags.test.js.map