@@ -16,7 +16,7 @@ import (
1616 "github.com/Azure/AppConfiguration-GoProvider/azureappconfiguration/internal/fm"
1717 "github.com/Azure/AppConfiguration-GoProvider/azureappconfiguration/internal/tracing"
1818 "github.com/Azure/azure-sdk-for-go/sdk/azcore"
19- "github.com/Azure/azure-sdk-for-go/sdk/data/azappconfig"
19+ "github.com/Azure/azure-sdk-for-go/sdk/data/azappconfig/v2 "
2020 "github.com/stretchr/testify/assert"
2121 "github.com/stretchr/testify/mock"
2222)
@@ -128,7 +128,7 @@ func TestLoadFeatureFlags_Success(t *testing.T) {
128128 {Key : toPtr (".appconfig.featureflag/Beta" ), Value : & value1 , ContentType : toPtr (featureFlagContentType )},
129129 {Key : toPtr (".appconfig.featureflag/Alpha" ), Value : & value2 , ContentType : toPtr (featureFlagContentType )},
130130 },
131- pageETags : map [Selector ][]* azcore.ETag {},
131+ pageETags : map [comparableSelector ][]* azcore.ETag {},
132132 }
133133
134134 mockClient .On ("getSettings" , ctx ).Return (mockResponse , nil )
@@ -1545,7 +1545,7 @@ func TestLoadFeatureFlags_TracingUpdated(t *testing.T) {
15451545 ContentType : toPtr (featureFlagContentType ),
15461546 },
15471547 },
1548- pageETags : map [Selector ][]* azcore.ETag {},
1548+ pageETags : map [comparableSelector ][]* azcore.ETag {},
15491549 }
15501550
15511551 mockClient .On ("getSettings" , ctx ).Return (mockResponse , nil )
@@ -1601,3 +1601,203 @@ func TestLoadFeatureFlags_TracingUpdated(t *testing.T) {
16011601 // Verify max variants is included
16021602 assert .Contains (t , correlationCtx , tracing .FFMaxVariantsKey + "=3" )
16031603}
1604+
1605+ func TestLoadKeyValues_WithTagFilter (t * testing.T ) {
1606+ ctx := context .Background ()
1607+ mockClient := new (mockSettingsClient )
1608+
1609+ // Create mock settings with different tags
1610+ value1 := "value1"
1611+ value3 := "value3"
1612+ value4 := "value4"
1613+
1614+ mockResponse := & settingsResponse {
1615+ settings : []azappconfig.Setting {
1616+ {
1617+ Key : toPtr ("app:key1" ),
1618+ Value : & value1 ,
1619+ Tags : map [string ]* string {
1620+ "env" : toPtr ("production" ),
1621+ "team" : toPtr ("backend" ),
1622+ },
1623+ },
1624+ {
1625+ Key : toPtr ("app:key3" ),
1626+ Value : & value3 ,
1627+ Tags : map [string ]* string {
1628+ "env" : toPtr ("production" ),
1629+ "team" : toPtr ("frontend" ),
1630+ },
1631+ },
1632+ {
1633+ Key : toPtr ("app:key4" ),
1634+ Value : & value4 ,
1635+ Tags : map [string ]* string {
1636+ "env" : toPtr ("production" ),
1637+ "team" : toPtr ("backend" ),
1638+ "feature" : toPtr ("new" ),
1639+ },
1640+ },
1641+ },
1642+ pageETags : map [comparableSelector ][]* azcore.ETag {},
1643+ }
1644+
1645+ mockClient .On ("getSettings" , ctx ).Return (mockResponse , nil )
1646+
1647+ // Test with single tag filter
1648+ azappcfg := & AzureAppConfiguration {
1649+ clientManager : & configurationClientManager {
1650+ staticClient : & configurationClientWrapper {client : & azappconfig.Client {}},
1651+ },
1652+ kvSelectors : []Selector {
1653+ {
1654+ KeyFilter : "*" ,
1655+ TagFilters : []string {"env=production" },
1656+ },
1657+ },
1658+ keyValues : make (map [string ]any ),
1659+ }
1660+
1661+ err := azappcfg .loadKeyValues (ctx , mockClient )
1662+ assert .NoError (t , err )
1663+
1664+ // Should load keys with env=production tag (key1, key3, key4)
1665+ assert .Equal (t , & value1 , azappcfg .keyValues ["app:key1" ])
1666+ assert .Equal (t , & value3 , azappcfg .keyValues ["app:key3" ])
1667+ assert .Equal (t , & value4 , azappcfg .keyValues ["app:key4" ])
1668+ assert .NotContains (t , azappcfg .keyValues , "app:key2" ) // staging env, should be filtered out
1669+ }
1670+
1671+ func TestLoadKeyValues_WithMultipleTagFilters (t * testing.T ) {
1672+ ctx := context .Background ()
1673+ mockClient := new (mockSettingsClient )
1674+
1675+ value1 := "value1"
1676+ value4 := "value4"
1677+
1678+ mockResponse := & settingsResponse {
1679+ settings : []azappconfig.Setting {
1680+ {
1681+ Key : toPtr ("app:key1" ),
1682+ Value : & value1 ,
1683+ Tags : map [string ]* string {
1684+ "env" : toPtr ("production" ),
1685+ "team" : toPtr ("backend" ),
1686+ },
1687+ },
1688+ {
1689+ Key : toPtr ("app:key4" ),
1690+ Value : & value4 ,
1691+ Tags : map [string ]* string {
1692+ "env" : toPtr ("production" ),
1693+ "team" : toPtr ("backend" ),
1694+ "feature" : toPtr ("new" ),
1695+ },
1696+ },
1697+ },
1698+ pageETags : map [comparableSelector ][]* azcore.ETag {},
1699+ }
1700+
1701+ mockClient .On ("getSettings" , ctx ).Return (mockResponse , nil )
1702+
1703+ // Test with multiple tag filters (must match ALL)
1704+ azappcfg := & AzureAppConfiguration {
1705+ clientManager : & configurationClientManager {
1706+ staticClient : & configurationClientWrapper {client : & azappconfig.Client {}},
1707+ },
1708+ kvSelectors : []Selector {
1709+ {
1710+ KeyFilter : "*" ,
1711+ TagFilters : []string {"env=production" , "team=backend" },
1712+ },
1713+ },
1714+ keyValues : make (map [string ]any ),
1715+ }
1716+
1717+ err := azappcfg .loadKeyValues (ctx , mockClient )
1718+ assert .NoError (t , err )
1719+
1720+ // Should load only keys that match BOTH env=production AND team=backend (key1, key4)
1721+ assert .Equal (t , & value1 , azappcfg .keyValues ["app:key1" ])
1722+ assert .Equal (t , & value4 , azappcfg .keyValues ["app:key4" ])
1723+ }
1724+
1725+ func TestSelectorComparableKey_WithTagFilter (t * testing.T ) {
1726+ // Test that selectors with same TagFilter (but different order) produce the same comparable key
1727+ selector1 := Selector {
1728+ KeyFilter : "app*" ,
1729+ LabelFilter : "prod" ,
1730+ TagFilters : []string {"env=production" , "team=backend" },
1731+ }
1732+
1733+ selector2 := Selector {
1734+ KeyFilter : "app*" ,
1735+ LabelFilter : "prod" ,
1736+ TagFilters : []string {"team=backend" , "env=production" }, // Different order
1737+ }
1738+
1739+ key1 := selector1 .comparableKey ()
1740+ key2 := selector2 .comparableKey ()
1741+
1742+ // Should produce the same comparable key due to sorting
1743+ assert .Equal (t , key1 , key2 )
1744+ assert .Equal (t , `["env=production","team=backend"]` , key1 .TagFilters )
1745+ assert .Equal (t , `["env=production","team=backend"]` , key2 .TagFilters )
1746+ }
1747+
1748+ func TestSelectorComparableKey_WithSpecialCharacters (t * testing.T ) {
1749+ // Test that selectors handle special characters in tag values correctly
1750+ selector := Selector {
1751+ KeyFilter : "app*" ,
1752+ LabelFilter : "prod" ,
1753+ TagFilters : []string {
1754+ `env=prod,staging` , // Comma in value
1755+ `description="test,with,quotes"` , // Quotes and commas
1756+ `path=c:\windows\system32` , // Backslashes
1757+ `json={"key":"value"}` , // JSON in value
1758+ },
1759+ }
1760+
1761+ key := selector .comparableKey ()
1762+
1763+ // Verify JSON encoding handles all special characters properly
1764+ expected := `["description=\"test,with,quotes\"","env=prod,staging","json={\"key\":\"value\"}","path=c:\\windows\\system32"]`
1765+ assert .Equal (t , expected , key .TagFilters )
1766+ }
1767+
1768+ func TestSelectorComparableKey_WithEmptyAndNilTagFilter (t * testing.T ) {
1769+ // Test empty TagFilter
1770+ selector1 := Selector {
1771+ KeyFilter : "app*" ,
1772+ LabelFilter : "prod" ,
1773+ TagFilters : []string {},
1774+ }
1775+
1776+ key1 := selector1 .comparableKey ()
1777+ assert .Equal (t , "" , key1 .TagFilters )
1778+
1779+ // Test nil TagFilter (should be handled the same as empty)
1780+ selector2 := Selector {
1781+ KeyFilter : "app*" ,
1782+ LabelFilter : "prod" ,
1783+ TagFilters : nil ,
1784+ }
1785+
1786+ key2 := selector2 .comparableKey ()
1787+ assert .Equal (t , "" , key2 .TagFilters )
1788+ }
1789+
1790+ func TestSelectorComparableKey_Deterministic (t * testing.T ) {
1791+ // Test that the same selector always produces the same key
1792+ selector := Selector {
1793+ KeyFilter : "app*" ,
1794+ LabelFilter : "prod" ,
1795+ TagFilters : []string {"z=last" , "a=first" , "m=middle" },
1796+ }
1797+
1798+ key1 := selector .comparableKey ()
1799+ key2 := selector .comparableKey ()
1800+
1801+ assert .Equal (t , key1 , key2 )
1802+ assert .Equal (t , `["a=first","m=middle","z=last"]` , key1 .TagFilters ) // Should be sorted
1803+ }
0 commit comments