@@ -81,12 +81,24 @@ const mockedKVs = [{
8181 tags : { "tag1" : "someValue" , "tag2" : "someValue" }
8282} , {
8383 key : "keyWithTag1" ,
84- value : "someValue " ,
84+ value : "someValue1 " ,
8585 tags : { "tag1" : "someValue" }
8686} , {
8787 key : "keyWithTag2" ,
88- value : "someValue " ,
88+ value : "someValue2 " ,
8989 tags : { "tag2" : "someValue" }
90+ } , {
91+ key : "keyWithNullTag" ,
92+ value : "valueWithNullTag" ,
93+ tags : { "nullTag" : "\0" }
94+ } , {
95+ key : "keyWithEscapedComma" ,
96+ value : "valueWithEscapedComma" ,
97+ tags : { "tag" : "value\\,with\\,commas" }
98+ } , {
99+ key : "keyWithEmptyTag" ,
100+ value : "valueWithEmptyTag" ,
101+ tags : { "emptyTag" : "" }
90102}
91103] . map ( createMockedKeyValue ) ;
92104
@@ -188,7 +200,7 @@ describe("load", function () {
188200 } ]
189201 } ) ;
190202 expect ( loadWithTag1 . has ( "keyWithTag1" ) ) . true ;
191- expect ( loadWithTag1 . get ( "keyWithTag1" ) ) . eq ( "someValue " ) ;
203+ expect ( loadWithTag1 . get ( "keyWithTag1" ) ) . eq ( "someValue1 " ) ;
192204 expect ( loadWithTag1 . has ( "keyWithTag2" ) ) . false ;
193205 expect ( loadWithTag1 . has ( "keyWithMultipleTags" ) ) . true ;
194206 expect ( loadWithTag1 . get ( "keyWithMultipleTags" ) ) . eq ( "someValue" ) ;
@@ -205,6 +217,53 @@ describe("load", function () {
205217 expect ( loadWithMultipleTags . get ( "keyWithMultipleTags" ) ) . eq ( "someValue" ) ;
206218 } ) ;
207219
220+ it ( "should filter by nullTag to load key values with null tag" , async ( ) => {
221+ const connectionString = createMockedConnectionString ( ) ;
222+ const loadWithNullTag = await load ( connectionString , {
223+ selectors : [ {
224+ keyFilter : "*" ,
225+ tagFilters : [ "nullTag=\0" ]
226+ } ]
227+ } ) ;
228+
229+ // Should include only key values with nullTag=\0
230+ expect ( loadWithNullTag . has ( "keyWithNullTag" ) ) . true ;
231+ expect ( loadWithNullTag . get ( "keyWithNullTag" ) ) . eq ( "valueWithNullTag" ) ;
232+
233+ // Should exclude key values with other tags
234+ expect ( loadWithNullTag . has ( "keyWithEmptyTag" ) ) . false ;
235+ } ) ;
236+
237+ it ( "should filter by tags with escaped comma characters" , async ( ) => {
238+ const connectionString = createMockedConnectionString ( ) ;
239+ const loadWithEscapedComma = await load ( connectionString , {
240+ selectors : [ {
241+ keyFilter : "*" ,
242+ tagFilters : [ "tag=value\\,with\\,commas" ]
243+ } ]
244+ } ) ;
245+
246+ expect ( loadWithEscapedComma . has ( "keyWithEscapedComma" ) ) . true ;
247+ expect ( loadWithEscapedComma . get ( "keyWithEscapedComma" ) ) . eq ( "valueWithEscapedComma" ) ;
248+ } ) ;
249+
250+ it ( "should filter by empty tag value to load key values with empty tag" , async ( ) => {
251+ const connectionString = createMockedConnectionString ( ) ;
252+ const loadWithEmptyTag = await load ( connectionString , {
253+ selectors : [ {
254+ keyFilter : "*" ,
255+ tagFilters : [ "emptyTag=" ]
256+ } ]
257+ } ) ;
258+
259+ // Should include key values with emptyTag=""
260+ expect ( loadWithEmptyTag . has ( "keyWithEmptyTag" ) ) . true ;
261+ expect ( loadWithEmptyTag . get ( "keyWithEmptyTag" ) ) . eq ( "valueWithEmptyTag" ) ;
262+
263+ // Should exclude key values with other tags
264+ expect ( loadWithEmptyTag . has ( "keyWithNullTag" ) ) . false ;
265+ } ) ;
266+
208267 it ( "should also work with other ReadonlyMap APIs" , async ( ) => {
209268 const connectionString = createMockedConnectionString ( ) ;
210269 const settings = await load ( connectionString , {
@@ -319,12 +378,40 @@ describe("load", function () {
319378 const loadWithInvalidTagFilter = load ( connectionString , {
320379 selectors : [ {
321380 keyFilter : "*" ,
322- tagFilters : [ "testTag " ]
381+ tagFilters : [ "emptyTag " ]
323382 } ]
324383 } ) ;
325384 return expect ( loadWithInvalidTagFilter ) . to . eventually . rejectedWith ( "Tag filter must follow the format \"tagName=tagValue\"" ) ;
326385 } ) ;
327386
387+ it ( "should throw exception when too many tag filters are provided" , async ( ) => {
388+ const connectionString = createMockedConnectionString ( ) ;
389+
390+ // Create a list with more than the maximum allowed tag filters (assuming max is 5)
391+ const tooManyTagFilters = [
392+ "Environment=Development" ,
393+ "Team=Backend" ,
394+ "Priority=High" ,
395+ "Version=1.0" ,
396+ "Stage=Testing" ,
397+ "Region=EastUS" // This should exceed the limit
398+ ] ;
399+ try {
400+ await load ( connectionString , {
401+ selectors : [ {
402+ keyFilter : "*" ,
403+ tagFilters : tooManyTagFilters
404+ } ]
405+ } ) ;
406+ } catch ( error ) {
407+ expect ( error . message ) . eq ( "Failed to load." ) ;
408+ expect ( error . cause . message ) . eq ( "Invalid request parameter 'tags'. Maximum number of tag filters is 5." ) ;
409+ return ;
410+ }
411+ // we should never reach here, load should throw an error
412+ throw new Error ( "Expected load to throw." ) ;
413+ } ) ;
414+
328415 it ( "should override config settings with same key but different label" , async ( ) => {
329416 const connectionString = createMockedConnectionString ( ) ;
330417 const settings = await load ( connectionString , {
0 commit comments