@@ -1236,3 +1236,158 @@ func TestCustomClientOptionsShoudPanic(t *testing.T) {
12361236 })
12371237 }
12381238}
1239+
1240+ func TestExtractNextPage (t * testing.T ) {
1241+ client := flagsmith .NewClient ("test-key" )
1242+
1243+ testCases := []struct {
1244+ name string
1245+ header string
1246+ expected string
1247+ }{
1248+ {
1249+ name : "valid link header with encoded page_id" ,
1250+ header : "</api/v1/environment-document/?page_id=" + fixtures .PageIDEncoded + ">; rel=\" next\" " ,
1251+ expected : fixtures .PageID ,
1252+ },
1253+ {
1254+ name : "empty header returns empty string" ,
1255+ header : "" ,
1256+ expected : "" ,
1257+ },
1258+ {
1259+ name : "header without page_id returns empty string" ,
1260+ header : "</api/v1/environment-document/>; rel=\" next\" " ,
1261+ expected : "" ,
1262+ },
1263+ }
1264+
1265+ for _ , tc := range testCases {
1266+ t .Run (tc .name , func (t * testing.T ) {
1267+ result := client .ExtractNextPage (tc .header )
1268+ assert .Equal (t , tc .expected , result )
1269+ })
1270+ }
1271+ }
1272+
1273+ func TestUpdateEnvironmentPaginatesIdentityOverrides (t * testing.T ) {
1274+ // Given
1275+ ctx := context .Background ()
1276+ server := httptest .NewServer (http .HandlerFunc (fixtures .PaginatedEnvironmentDocumentHandler ))
1277+ defer server .Close ()
1278+
1279+ client := flagsmith .NewClient (fixtures .EnvironmentAPIKey , flagsmith .WithLocalEvaluation (ctx ),
1280+ flagsmith .WithBaseURL (server .URL + "/api/v1/" ))
1281+
1282+ // When
1283+ err := client .UpdateEnvironment (ctx )
1284+
1285+ // Then
1286+ assert .NoError (t , err )
1287+
1288+ // Identity from page 1 should be found
1289+ flags , err := client .GetIdentityFlags (ctx , fixtures .OverriddenIdentifier , nil )
1290+ assert .NoError (t , err )
1291+ enabled , err := flags .IsFeatureEnabled (fixtures .Feature1Name )
1292+ assert .NoError (t , err )
1293+ assert .False (t , enabled , "identity from page 1 should have overridden feature disabled" )
1294+
1295+ // Identity from page 2 should also be found
1296+ flags2 , err := client .GetIdentityFlags (ctx , fixtures .OverriddenIdentifierPage2 , nil )
1297+ assert .NoError (t , err )
1298+ enabled2 , err := flags2 .IsFeatureEnabled (fixtures .Feature1Name )
1299+ assert .NoError (t , err )
1300+ assert .False (t , enabled2 , "identity from page 2 should have overridden feature disabled" )
1301+ }
1302+
1303+ func TestUpdateEnvironmentSinglePageNoLinkHeader (t * testing.T ) {
1304+ // Given
1305+ ctx := context .Background ()
1306+ server := httptest .NewServer (http .HandlerFunc (fixtures .EnvironmentDocumentHandler ))
1307+ defer server .Close ()
1308+
1309+ client := flagsmith .NewClient (fixtures .EnvironmentAPIKey , flagsmith .WithLocalEvaluation (ctx ),
1310+ flagsmith .WithBaseURL (server .URL + "/api/v1/" ))
1311+
1312+ // When
1313+ err := client .UpdateEnvironment (ctx )
1314+
1315+ // Then — no pagination, identity from page 1 should still work
1316+ assert .NoError (t , err )
1317+
1318+ flags , err := client .GetIdentityFlags (ctx , fixtures .OverriddenIdentifier , nil )
1319+ assert .NoError (t , err )
1320+ enabled , err := flags .IsFeatureEnabled (fixtures .Feature1Name )
1321+ assert .NoError (t , err )
1322+ assert .False (t , enabled , "identity override should have feature disabled" )
1323+ }
1324+
1325+ func TestUpdateEnvironmentLogsWarningWhenSlowerThanRefreshInterval (t * testing.T ) {
1326+ // Given: handler delays the response so the fetch takes longer than the
1327+ // refresh interval; we capture logs to assert the warning is emitted.
1328+ ctx := context .Background ()
1329+ server := httptest .NewServer (http .HandlerFunc (func (rw http.ResponseWriter , req * http.Request ) {
1330+ time .Sleep (20 * time .Millisecond )
1331+ fixtures .EnvironmentDocumentHandler (rw , req )
1332+ }))
1333+ defer server .Close ()
1334+
1335+ var logOutput strings.Builder
1336+ var logMu sync.Mutex
1337+ slogLogger := slog .New (slog .NewTextHandler (writerFunc (func (p []byte ) (n int , err error ) {
1338+ logMu .Lock ()
1339+ defer logMu .Unlock ()
1340+ return logOutput .Write (p )
1341+ }), & slog.HandlerOptions {Level : slog .LevelWarn }))
1342+
1343+ client := flagsmith .NewClient (fixtures .EnvironmentAPIKey ,
1344+ flagsmith .WithSlogLogger (slogLogger ),
1345+ flagsmith .WithBaseURL (server .URL + "/api/v1/" ),
1346+ flagsmith .WithEnvironmentRefreshInterval (1 * time .Millisecond ))
1347+
1348+ // When
1349+ err := client .UpdateEnvironment (ctx )
1350+
1351+ // Then
1352+ assert .NoError (t , err )
1353+
1354+ logMu .Lock ()
1355+ logStr := logOutput .String ()
1356+ logMu .Unlock ()
1357+
1358+ assert .Contains (t , logStr , "fetching environment took longer than the configured refresh interval" )
1359+ assert .Contains (t , logStr , "refresh_interval=1ms" )
1360+ assert .Contains (t , logStr , "elapsed=" )
1361+ }
1362+
1363+ func TestUpdateEnvironmentDoesNotLogWarningWhenWithinRefreshInterval (t * testing.T ) {
1364+ // Given
1365+ ctx := context .Background ()
1366+ server := httptest .NewServer (http .HandlerFunc (fixtures .EnvironmentDocumentHandler ))
1367+ defer server .Close ()
1368+
1369+ var logOutput strings.Builder
1370+ var logMu sync.Mutex
1371+ slogLogger := slog .New (slog .NewTextHandler (writerFunc (func (p []byte ) (n int , err error ) {
1372+ logMu .Lock ()
1373+ defer logMu .Unlock ()
1374+ return logOutput .Write (p )
1375+ }), & slog.HandlerOptions {Level : slog .LevelWarn }))
1376+
1377+ client := flagsmith .NewClient (fixtures .EnvironmentAPIKey ,
1378+ flagsmith .WithSlogLogger (slogLogger ),
1379+ flagsmith .WithBaseURL (server .URL + "/api/v1/" ),
1380+ flagsmith .WithEnvironmentRefreshInterval (10 * time .Second ))
1381+
1382+ // When
1383+ err := client .UpdateEnvironment (ctx )
1384+
1385+ // Then
1386+ assert .NoError (t , err )
1387+
1388+ logMu .Lock ()
1389+ logStr := logOutput .String ()
1390+ logMu .Unlock ()
1391+
1392+ assert .NotContains (t , logStr , "fetching environment took longer" )
1393+ }
0 commit comments