@@ -6,6 +6,7 @@ const featureTogglesModule = require("../src/featureToggles");
66const { FeatureToggles, readConfigFromFile, SCOPE_ROOT_KEY } = featureTogglesModule ;
77const { CONFIG_KEY , CONFIG_INFO_KEY } = featureTogglesModule . _ ;
88
9+ const { cfEnv } = require ( "../src/env" ) ;
910const { FEATURE , mockConfig, redisKey, redisChannel } = require ( "./mockdata" ) ;
1011
1112const { readFile : readFileSpy } = require ( "fs" ) ;
@@ -45,7 +46,7 @@ describe("feature toggles test", () => {
4546
4647 describe ( "enums" , ( ) => {
4748 it ( "config info consistency" , ( ) => {
48- const internalKeys = [ CONFIG_KEY . VALIDATION_REG_EXP ] ;
49+ const internalKeys = [ CONFIG_KEY . VALIDATION_REG_EXP , CONFIG_KEY . ALLOWED_SCOPES_CHECK_MAP ] ;
4950 const configKeysCheck = [ ] . concat ( Object . keys ( CONFIG_INFO_KEY ) , internalKeys ) . sort ( ) ;
5051 const configKeys = Object . values ( CONFIG_KEY ) . sort ( ) ;
5152
@@ -353,6 +354,12 @@ describe("feature toggles test", () => {
353354 const inputArgsList = [
354355 [ FEATURE . A , 1 , { a : 1 } ] ,
355356 [ FEATURE . A , 1 , "a::1" ] ,
357+ [ FEATURE . AA , true ] ,
358+ [ FEATURE . AA , true , { tenant : "t1" , user : "u1" } ] ,
359+ [ FEATURE . AA , true , { tenant : "t1" } ] ,
360+ [ FEATURE . AA , true , { user : "u1" } ] ,
361+ [ FEATURE . AA , true , { usr : "u1" } ] ,
362+ [ FEATURE . AA , true , { Tenant : "t1" } ] ,
356363 ] ;
357364
358365 let i = 0 ;
@@ -384,6 +391,34 @@ describe("feature toggles test", () => {
384391 },
385392 ]
386393 ` ) ;
394+ expect ( await featureToggles . validateFeatureValue ( ...inputArgsList [ i ++ ] ) ) . toMatchInlineSnapshot ( `[]` ) ;
395+ expect ( await featureToggles . validateFeatureValue ( ...inputArgsList [ i ++ ] ) ) . toMatchInlineSnapshot ( `[]` ) ;
396+ expect ( await featureToggles . validateFeatureValue ( ...inputArgsList [ i ++ ] ) ) . toMatchInlineSnapshot ( `[]` ) ;
397+ expect ( await featureToggles . validateFeatureValue ( ...inputArgsList [ i ++ ] ) ) . toMatchInlineSnapshot ( `[]` ) ;
398+ expect ( await featureToggles . validateFeatureValue ( ...inputArgsList [ i ++ ] ) ) . toMatchInlineSnapshot ( `
399+ [
400+ {
401+ "errorMessage": "scope "{0}" is not allowed",
402+ "errorMessageValues": [
403+ "usr",
404+ ],
405+ "featureKey": "test/feature_aa",
406+ "scopeKey": "usr::u1",
407+ },
408+ ]
409+ ` ) ;
410+ expect ( await featureToggles . validateFeatureValue ( ...inputArgsList [ i ++ ] ) ) . toMatchInlineSnapshot ( `
411+ [
412+ {
413+ "errorMessage": "scope "{0}" is not allowed",
414+ "errorMessageValues": [
415+ "Tenant",
416+ ],
417+ "featureKey": "test/feature_aa",
418+ "scopeKey": "Tenant::t1",
419+ },
420+ ]
421+ ` ) ;
387422 expect ( i ) . toBe ( inputArgsList . length ) ;
388423
389424 expect ( loggerSpy . warning ) . not . toHaveBeenCalled ( ) ;
@@ -462,6 +497,7 @@ describe("feature toggles test", () => {
462497 it ( "getFeatureValue" , async ( ) => {
463498 const mockFeatureValuesEntries = [
464499 [ [ FEATURE . A ] , { [ SCOPE_ROOT_KEY ] : true } ] ,
500+ [ [ FEATURE . AA ] , { [ SCOPE_ROOT_KEY ] : true } ] ,
465501 [ [ FEATURE . B ] , { [ SCOPE_ROOT_KEY ] : 0 } ] ,
466502 [ [ FEATURE . C ] , { [ SCOPE_ROOT_KEY ] : "cvalue" } ] ,
467503 ] ;
@@ -471,7 +507,7 @@ describe("feature toggles test", () => {
471507 [ "e" , "bvalue" ] ,
472508 [ "f" , "cvalue" ] ,
473509 ] ;
474- for ( let i = 0 ; i < 3 ; i ++ ) {
510+ for ( let i = 0 ; i < mockFeatureValuesEntries . length ; i ++ ) {
475511 redisWrapperMock . watchedHashGetSetObject . mockImplementationOnce ( ( key , field ) => mockFeatureValues [ field ] ) ;
476512 }
477513 await featureToggles . initializeFeatures ( { config : mockConfig } ) ;
@@ -492,6 +528,7 @@ describe("feature toggles test", () => {
492528 const testScopeKey = FeatureToggles . getScopeKey ( testScopeMap ) ;
493529 const mockFeatureValuesEntries = [
494530 [ [ FEATURE . A ] , { [ SCOPE_ROOT_KEY ] : true , [ testScopeKey ] : false } ] ,
531+ [ [ FEATURE . AA ] , { [ SCOPE_ROOT_KEY ] : true , [ testScopeKey ] : false } ] ,
495532 [ [ FEATURE . B ] , { [ SCOPE_ROOT_KEY ] : 0 , [ testScopeKey ] : 10 } ] ,
496533 [ [ FEATURE . C ] , { [ SCOPE_ROOT_KEY ] : "cvalue" , [ testScopeKey ] : "" } ] ,
497534 ] ;
@@ -501,7 +538,7 @@ describe("feature toggles test", () => {
501538 [ "e" , "bvalue" ] ,
502539 [ "f" , "cvalue" ] ,
503540 ] ;
504- for ( let i = 0 ; i < 3 ; i ++ ) {
541+ for ( let i = 0 ; i < mockFeatureValuesEntries . length ; i ++ ) {
505542 redisWrapperMock . watchedHashGetSetObject . mockImplementationOnce ( ( key , field ) => mockFeatureValues [ field ] ) ;
506543 }
507544 await featureToggles . initializeFeatures ( { config : mockConfig } ) ;
@@ -775,6 +812,41 @@ describe("feature toggles test", () => {
775812 expect ( featureToggles . getFeatureValue ( FEATURE . G ) ) . toBe ( oldValue ) ;
776813 } ) ;
777814
815+ it ( "FeatureValueValidation and appUrl working" , async ( ) => {
816+ jest . spyOn ( cfEnv , "cfApp" ) . mockReturnValueOnce ( { uris : [ "https://it.cfapps.sap.hana.ondemand.com" ] } ) ;
817+ const newValue = "newValue" ;
818+ await featureToggles . initializeFeatures ( { config : mockConfig } ) ;
819+ const featureConfig = featureToggles . getFeatureInfo ( FEATURE . H ) . config ;
820+
821+ expect ( featureConfig . APP_URL ) . toMatchInlineSnapshot ( `"\\.cfapps\\.sap\\.hana\\.ondemand\\.com$"` ) ;
822+ expect ( featureConfig . APP_URL_ACTIVE ) . toBe ( true ) ;
823+ expect ( await featureToggles . changeFeatureValue ( FEATURE . H , newValue ) ) . toBeUndefined ( ) ;
824+ expect ( featureToggles . getFeatureValue ( FEATURE . H ) ) . toBe ( newValue ) ;
825+ } ) ;
826+
827+ it ( "FeatureValueValidation and appUrl failing" , async ( ) => {
828+ jest . spyOn ( cfEnv , "cfApp" ) . mockReturnValueOnce ( { uris : [ "https://not-it.com" ] } ) ;
829+ const newValue = "newValue" ;
830+ await featureToggles . initializeFeatures ( { config : mockConfig } ) ;
831+ const oldValue = featureToggles . getFeatureValue ( FEATURE . H ) ;
832+ const featureConfig = featureToggles . getFeatureInfo ( FEATURE . H ) . config ;
833+
834+ expect ( featureConfig . APP_URL ) . toMatchInlineSnapshot ( `"\\.cfapps\\.sap\\.hana\\.ondemand\\.com$"` ) ;
835+ expect ( featureConfig . APP_URL_ACTIVE ) . toBe ( false ) ;
836+ expect ( await featureToggles . changeFeatureValue ( FEATURE . H , newValue ) ) . toMatchInlineSnapshot ( `
837+ [
838+ {
839+ "errorMessage": "feature key is not active because app url does not match regular expression {0}",
840+ "errorMessageValues": [
841+ "\\.cfapps\\.sap\\.hana\\.ondemand\\.com$",
842+ ],
843+ "featureKey": "test/feature_h",
844+ },
845+ ]
846+ ` ) ;
847+ expect ( featureToggles . getFeatureValue ( FEATURE . H ) ) . toBe ( oldValue ) ;
848+ } ) ;
849+
778850 it ( "validateInput throws error" , async ( ) => {
779851 const error = new Error ( "bad validator" ) ;
780852 const validator = jest . fn ( ) . mockRejectedValue ( error ) ;
0 commit comments