@@ -1601,3 +1601,267 @@ func TestLoadFeatureFlags_TracingUpdated(t *testing.T) {
16011601 // Verify max variants is included
16021602 assert .Contains (t , correlationCtx , tracing .FFMaxVariantsKey + "=3" )
16031603}
1604+
1605+ func TestLoadFeatureFlags_WithTelemetryEnabled (t * testing.T ) {
1606+ ctx := context .Background ()
1607+ mockClient := new (mockSettingsClient )
1608+
1609+ // Feature flag with telemetry enabled
1610+ value1 := `{
1611+ "id": "TelemetryFlag",
1612+ "description": "Feature flag with telemetry",
1613+ "enabled": true,
1614+ "telemetry": {
1615+ "enabled": true
1616+ }
1617+ }`
1618+
1619+ // Feature flag with telemetry disabled
1620+ value2 := `{
1621+ "id": "NoTelemetryFlag",
1622+ "description": "Feature flag without telemetry",
1623+ "enabled": false,
1624+ "telemetry": {
1625+ "enabled": false
1626+ }
1627+ }`
1628+
1629+ // Feature flag without telemetry section
1630+ value3 := `{
1631+ "id": "BasicFlag",
1632+ "description": "Basic feature flag",
1633+ "enabled": true
1634+ }`
1635+
1636+ eTag1 := "W/\" etag-1\" "
1637+ eTag2 := "W/\" etag-2\" "
1638+ eTag3 := "W/\" etag-3\" "
1639+
1640+ mockResponse := & settingsResponse {
1641+ settings : []azappconfig.Setting {
1642+ {
1643+ Key : toPtr (".appconfig.featureflag/TelemetryFlag" ),
1644+ Value : & value1 ,
1645+ ContentType : toPtr (featureFlagContentType ),
1646+ ETag : (* azcore .ETag )(& eTag1 ),
1647+ Label : toPtr ("production" ),
1648+ },
1649+ {
1650+ Key : toPtr (".appconfig.featureflag/NoTelemetryFlag" ),
1651+ Value : & value2 ,
1652+ ContentType : toPtr (featureFlagContentType ),
1653+ ETag : (* azcore .ETag )(& eTag2 ),
1654+ },
1655+ {
1656+ Key : toPtr (".appconfig.featureflag/BasicFlag" ),
1657+ Value : & value3 ,
1658+ ContentType : toPtr (featureFlagContentType ),
1659+ ETag : (* azcore .ETag )(& eTag3 ),
1660+ },
1661+ },
1662+ pageETags : map [Selector ][]* azcore.ETag {},
1663+ }
1664+
1665+ mockClient .On ("getSettings" , ctx ).Return (mockResponse , nil )
1666+
1667+ azappcfg := & AzureAppConfiguration {
1668+ clientManager : & configurationClientManager {
1669+ staticClient : & configurationClientWrapper {client : & azappconfig.Client {}},
1670+ endpoint : "https://mystore.azconfig.io" ,
1671+ },
1672+ ffSelectors : getFeatureFlagSelectors ([]Selector {}),
1673+ featureFlags : make (map [string ]any ),
1674+ tracingOptions : tracing.Options {
1675+ Enabled : true ,
1676+ FeatureFlagTracing : & tracing.FeatureFlagTracing {},
1677+ },
1678+ }
1679+
1680+ err := azappcfg .loadFeatureFlags (ctx , mockClient )
1681+ assert .NoError (t , err )
1682+
1683+ // Verify feature flags structure
1684+ featureManagement := azappcfg .featureFlags [featureManagementSectionKey ].(map [string ]any )
1685+ featureFlags := featureManagement [featureFlagSectionKey ].([]any )
1686+ assert .Len (t , featureFlags , 3 )
1687+
1688+ // Find and verify TelemetryFlag
1689+ var telemetryFlag map [string ]any
1690+ var noTelemetryFlag map [string ]any
1691+ var basicFlag map [string ]any
1692+
1693+ for _ , flag := range featureFlags {
1694+ flagMap := flag .(map [string ]any )
1695+ switch flagMap ["id" ] {
1696+ case "TelemetryFlag" :
1697+ telemetryFlag = flagMap
1698+ case "NoTelemetryFlag" :
1699+ noTelemetryFlag = flagMap
1700+ case "BasicFlag" :
1701+ basicFlag = flagMap
1702+ }
1703+ }
1704+
1705+ // Verify TelemetryFlag has telemetry metadata populated
1706+ assert .NotNil (t , telemetryFlag , "TelemetryFlag should exist" )
1707+ telemetry , ok := telemetryFlag [telemetryKey ].(map [string ]any )
1708+ assert .True (t , ok , "TelemetryFlag should have telemetry section" )
1709+ assert .True (t , telemetry [enabledKey ].(bool ), "Telemetry should be enabled" )
1710+
1711+ metadata , ok := telemetry [metadataKey ].(map [string ]any )
1712+ assert .True (t , ok , "Telemetry should have metadata" )
1713+ assert .Equal (t , "https://mystore.azconfig.io/kv/.appconfig.featureflag/TelemetryFlag?label=production" ,
1714+ metadata [featureFlagReferenceKey ], "Feature flag reference should be populated with label" )
1715+
1716+ // Verify NoTelemetryFlag does not have metadata populated
1717+ assert .NotNil (t , noTelemetryFlag , "NoTelemetryFlag should exist" )
1718+ noTelemetry , ok := noTelemetryFlag [telemetryKey ].(map [string ]any )
1719+ assert .True (t , ok , "NoTelemetryFlag should have telemetry section" )
1720+ assert .False (t , noTelemetry [enabledKey ].(bool ), "Telemetry should be disabled" )
1721+
1722+ // Should not have metadata since telemetry is disabled
1723+ _ , hasMetadata := noTelemetry [metadataKey ]
1724+ assert .False (t , hasMetadata , "NoTelemetryFlag should not have metadata when telemetry is disabled" )
1725+
1726+ // Verify BasicFlag does not have telemetry section modified
1727+ assert .NotNil (t , basicFlag , "BasicFlag should exist" )
1728+ _ , hasTelemetry := basicFlag [telemetryKey ]
1729+ assert .False (t , hasTelemetry , "BasicFlag should not have telemetry section" )
1730+
1731+ // Verify tracing was updated
1732+ assert .True (t , azappcfg .tracingOptions .FeatureFlagTracing .UsesTelemetry , "Should detect telemetry usage" )
1733+ }
1734+
1735+ func TestLoadFeatureFlags_TelemetryWithExistingMetadata (t * testing.T ) {
1736+ ctx := context .Background ()
1737+ mockClient := new (mockSettingsClient )
1738+
1739+ // Feature flag with telemetry enabled and existing metadata
1740+ value1 := `{
1741+ "id": "ExistingMetadataFlag",
1742+ "description": "Feature flag with existing metadata",
1743+ "enabled": true,
1744+ "telemetry": {
1745+ "enabled": true,
1746+ "metadata": {
1747+ "customKey": "customValue",
1748+ "version": "1.0"
1749+ }
1750+ }
1751+ }`
1752+
1753+ eTag1 := "W/\" existing-etag\" "
1754+
1755+ mockResponse := & settingsResponse {
1756+ settings : []azappconfig.Setting {
1757+ {
1758+ Key : toPtr (".appconfig.featureflag/ExistingMetadataFlag" ),
1759+ Value : & value1 ,
1760+ ContentType : toPtr (featureFlagContentType ),
1761+ ETag : (* azcore .ETag )(& eTag1 ),
1762+ },
1763+ },
1764+ pageETags : map [Selector ][]* azcore.ETag {},
1765+ }
1766+
1767+ mockClient .On ("getSettings" , ctx ).Return (mockResponse , nil )
1768+
1769+ azappcfg := & AzureAppConfiguration {
1770+ clientManager : & configurationClientManager {
1771+ staticClient : & configurationClientWrapper {client : & azappconfig.Client {}},
1772+ endpoint : "https://test.azconfig.io" ,
1773+ },
1774+ ffSelectors : getFeatureFlagSelectors ([]Selector {}),
1775+ featureFlags : make (map [string ]any ),
1776+ tracingOptions : tracing.Options {
1777+ Enabled : true ,
1778+ FeatureFlagTracing : & tracing.FeatureFlagTracing {},
1779+ },
1780+ }
1781+
1782+ err := azappcfg .loadFeatureFlags (ctx , mockClient )
1783+ assert .NoError (t , err )
1784+
1785+ // Verify feature flags structure
1786+ featureManagement := azappcfg .featureFlags [featureManagementSectionKey ].(map [string ]any )
1787+ featureFlags := featureManagement [featureFlagSectionKey ].([]any )
1788+ assert .Len (t , featureFlags , 1 )
1789+
1790+ flag := featureFlags [0 ].(map [string ]any )
1791+ assert .Equal (t , "ExistingMetadataFlag" , flag ["id" ])
1792+
1793+ telemetry := flag [telemetryKey ].(map [string ]any )
1794+ assert .True (t , telemetry [enabledKey ].(bool ))
1795+
1796+ metadata := telemetry [metadataKey ].(map [string ]any )
1797+
1798+ // Verify existing metadata is preserved
1799+ assert .Equal (t , "customValue" , metadata ["customKey" ], "Existing custom metadata should be preserved" )
1800+ assert .Equal (t , "1.0" , metadata ["version" ], "Existing version metadata should be preserved" )
1801+
1802+ // Verify new metadata is added
1803+ assert .Equal (t , "https://test.azconfig.io/kv/.appconfig.featureflag/ExistingMetadataFlag" ,
1804+ metadata [featureFlagReferenceKey ], "Feature flag reference should be added to metadata" )
1805+ }
1806+
1807+ func TestGenerateFeatureFlagReference (t * testing.T ) {
1808+ tests := []struct {
1809+ name string
1810+ setting azappconfig.Setting
1811+ endpoint string
1812+ expected string
1813+ }{
1814+ {
1815+ name : "feature flag without label" ,
1816+ setting : azappconfig.Setting {
1817+ Key : toPtr (".appconfig.featureflag/TestFlag" ),
1818+ Label : nil ,
1819+ },
1820+ endpoint : "https://mystore.azconfig.io" ,
1821+ expected : "https://mystore.azconfig.io/kv/.appconfig.featureflag/TestFlag" ,
1822+ },
1823+ {
1824+ name : "feature flag with empty label" ,
1825+ setting : azappconfig.Setting {
1826+ Key : toPtr (".appconfig.featureflag/TestFlag" ),
1827+ Label : toPtr ("" ),
1828+ },
1829+ endpoint : "https://mystore.azconfig.io" ,
1830+ expected : "https://mystore.azconfig.io/kv/.appconfig.featureflag/TestFlag" ,
1831+ },
1832+ {
1833+ name : "feature flag with whitespace-only label" ,
1834+ setting : azappconfig.Setting {
1835+ Key : toPtr (".appconfig.featureflag/TestFlag" ),
1836+ Label : toPtr (" " ),
1837+ },
1838+ endpoint : "https://mystore.azconfig.io" ,
1839+ expected : "https://mystore.azconfig.io/kv/.appconfig.featureflag/TestFlag" ,
1840+ },
1841+ {
1842+ name : "feature flag with valid label" ,
1843+ setting : azappconfig.Setting {
1844+ Key : toPtr (".appconfig.featureflag/TestFlag" ),
1845+ Label : toPtr ("production" ),
1846+ },
1847+ endpoint : "https://mystore.azconfig.io" ,
1848+ expected : "https://mystore.azconfig.io/kv/.appconfig.featureflag/TestFlag?label=production" ,
1849+ },
1850+ {
1851+ name : "feature flag with label containing spaces" ,
1852+ setting : azappconfig.Setting {
1853+ Key : toPtr (".appconfig.featureflag/TestFlag" ),
1854+ Label : toPtr ("staging" ),
1855+ },
1856+ endpoint : "https://test.azconfig.io" ,
1857+ expected : "https://test.azconfig.io/kv/.appconfig.featureflag/TestFlag?label=staging" ,
1858+ },
1859+ }
1860+
1861+ for _ , test := range tests {
1862+ t .Run (test .name , func (t * testing.T ) {
1863+ result := generateFeatureFlagReference (test .setting , test .endpoint )
1864+ assert .Equal (t , test .expected , result )
1865+ })
1866+ }
1867+ }
0 commit comments