@@ -1302,3 +1302,104 @@ func TestPrometheusMetricsStartTimestamp(t *testing.T) {
13021302 checkMetric (`skipper_serve_host_count{code="201",host="bar_test",method="POST",start="(\d+)"} 2` )
13031303 checkMetric (`skipper_route_error_total{start="(\d+)"} 3` )
13041304}
1305+
1306+ func TestRouteValidationMetricsRealRoutingBehavior (t * testing.T ) {
1307+ pm := metrics .NewPrometheus (metrics.Options {})
1308+ path := "/metrics"
1309+
1310+ mux := http .NewServeMux ()
1311+ pm .RegisterHandler (path , mux )
1312+
1313+ getMetricsOutput := func () string {
1314+ req := httptest .NewRequest ("GET" , path , nil )
1315+ w := httptest .NewRecorder ()
1316+ mux .ServeHTTP (w , req )
1317+
1318+ resp := w .Result ()
1319+ require .Equal (t , http .StatusOK , resp .StatusCode )
1320+
1321+ body , err := io .ReadAll (resp .Body )
1322+ require .NoError (t , err )
1323+ return string (body )
1324+ }
1325+
1326+ t .Log ("Phase 1: Initial state - no metrics present" )
1327+ output1 := getMetricsOutput ()
1328+ assert .NotContains (t , output1 , `skipper_route_invalid{reason="unknown_filter"}` )
1329+ assert .NotContains (t , output1 , `skipper_route_invalid{reason="invalid_matcher"}` )
1330+
1331+ t .Log ("Phase 2: Routes with validation errors (simulating receiveRouteMatcher)" )
1332+ reasonCounts2 := map [string ]int {
1333+ "unknown_filter" : 2 ,
1334+ "invalid_matcher" : 1 ,
1335+ }
1336+ pm .UpdateInvalidRoute (reasonCounts2 )
1337+
1338+ output2 := getMetricsOutput ()
1339+ assert .Contains (t , output2 , `skipper_route_invalid{reason="unknown_filter"} 2` )
1340+ assert .Contains (t , output2 , `skipper_route_invalid{reason="invalid_matcher"} 1` )
1341+
1342+ t .Log ("Phase 3: Routes are fixed - receiveRouteMatcher calls UpdateInvalidRoute with fresh empty/nil map" )
1343+ reasonCounts3 := map [string ]int {}
1344+ pm .UpdateInvalidRoute (reasonCounts3 )
1345+
1346+ output3 := getMetricsOutput ()
1347+ assert .Contains (t , output3 , `skipper_route_invalid{reason="unknown_filter"} 0` )
1348+ assert .Contains (t , output3 , `skipper_route_invalid{reason="invalid_matcher"} 0` )
1349+
1350+ t .Log ("Key insight: Metrics are now properly set to 0 when routes are fixed" )
1351+ t .Log ("Previously seen invalid routes are tracked and reset to 0 when not present in new counts" )
1352+ }
1353+
1354+ func TestRouteValidationMetricsLifecycleBehavior (t * testing.T ) {
1355+ pm := metrics .NewPrometheus (metrics.Options {})
1356+ path := "/metrics"
1357+
1358+ mux := http .NewServeMux ()
1359+ pm .RegisterHandler (path , mux )
1360+
1361+ getMetricsOutput := func () string {
1362+ req := httptest .NewRequest ("GET" , path , nil )
1363+ w := httptest .NewRecorder ()
1364+ mux .ServeHTTP (w , req )
1365+
1366+ resp := w .Result ()
1367+ require .Equal (t , http .StatusOK , resp .StatusCode )
1368+
1369+ body , err := io .ReadAll (resp .Body )
1370+ require .NoError (t , err )
1371+ return string (body )
1372+ }
1373+
1374+ t .Log ("Scenario 1: Initial route errors" )
1375+ pm .UpdateInvalidRoute (map [string ]int {
1376+ "unknown_filter" : 3 ,
1377+ "invalid_matcher" : 2 ,
1378+ })
1379+
1380+ output1 := getMetricsOutput ()
1381+ assert .Contains (t , output1 , `skipper_route_invalid{reason="unknown_filter"} 3` )
1382+ assert .Contains (t , output1 , `skipper_route_invalid{reason="invalid_matcher"} 2` )
1383+
1384+ t .Log ("Scenario 2: Some routes fixed, some errors increase, new errors appear" )
1385+ pm .UpdateInvalidRoute (map [string ]int {
1386+ "unknown_filter" : 5 ,
1387+ "invalid_predicate" : 1 ,
1388+ })
1389+
1390+ output2 := getMetricsOutput ()
1391+ assert .Contains (t , output2 , `skipper_route_invalid{reason="unknown_filter"} 5` )
1392+ assert .Contains (t , output2 , `skipper_route_invalid{reason="invalid_predicate"} 1` )
1393+ assert .Contains (t , output2 , `skipper_route_invalid{reason="invalid_matcher"} 0` )
1394+
1395+ t .Log ("Scenario 3: All routes become valid" )
1396+ pm .UpdateInvalidRoute (map [string ]int {})
1397+
1398+ output3 := getMetricsOutput ()
1399+ assert .Contains (t , output3 , `skipper_route_invalid{reason="unknown_filter"} 0` )
1400+ assert .Contains (t , output3 , `skipper_route_invalid{reason="invalid_predicate"} 0` )
1401+ assert .Contains (t , output3 , `skipper_route_invalid{reason="invalid_matcher"} 0` )
1402+
1403+ t .Log ("Answer: When routes are fixed, metrics are properly set to 0" )
1404+ t .Log ("This happens because UpdateInvalidRoute now tracks previously seen reasons and resets them" )
1405+ }
0 commit comments