@@ -18,6 +18,8 @@ import { fileURLToPath } from "node:url";
1818const rootDir = path . resolve ( path . dirname ( fileURLToPath ( import . meta. url ) ) , ".." ) ;
1919const curlTimingFormat =
2020 "http_code=%{http_code}\\ntime_connect=%{time_connect}\\ntime_starttransfer=%{time_starttransfer}\\ntime_total=%{time_total}\\nsize_download=%{size_download}\\nsize_upload=%{size_upload}\\n" ;
21+ const coldMissPurgeAttempts = 5 ;
22+ const coldMissRetryDelayMs = 1_000 ;
2123
2224const defaultThresholds = {
2325 upload_response_ms : { warn : 5_000 , fail : 15_000 } ,
@@ -709,8 +711,11 @@ async function measurePlayback(config, edge, assetId, artifact, expectedCache, p
709711 throw new SafeError ( `${ edge . edge_id } ${ artifact . label } expected HTTP 200, got ${ response . http_code } ` ) ;
710712 }
711713 const cache = response . headers . get ( "x-rend-cache" ) || "" ;
712- if ( cache !== expectedCache ) {
713- throw new SafeError ( `${ edge . edge_id } ${ artifact . label } expected X-Rend-Cache ${ expectedCache } , got ${ cache || "missing" } ` ) ;
714+ if ( expectedCache ) {
715+ const expectedValues = Array . isArray ( expectedCache ) ? expectedCache : [ expectedCache ] ;
716+ if ( ! expectedValues . includes ( cache ) ) {
717+ throw new SafeError ( `${ edge . edge_id } ${ artifact . label } expected X-Rend-Cache ${ expectedValues . join ( " or " ) } , got ${ cache || "missing" } ` ) ;
718+ }
714719 }
715720 const contentType = ( response . headers . get ( "content-type" ) || "" ) . split ( ";" , 1 ) [ 0 ] ;
716721 if ( contentType !== artifact . content_type ) {
@@ -734,6 +739,28 @@ async function measurePlayback(config, edge, assetId, artifact, expectedCache, p
734739 } ;
735740}
736741
742+ async function purgeAndMeasureColdPlayback ( config , edge , assetId , artifact , cookieJar ) {
743+ const purgeSummaries = [ ] ;
744+ let lastCacheStatus = "" ;
745+ for ( let attempt = 1 ; attempt <= coldMissPurgeAttempts ; attempt += 1 ) {
746+ purgeSummaries . push ( await purgeEdge ( config , edge , assetId , [ artifact . artifact_path ] ) ) ;
747+ const result = await measurePlayback ( config , edge , assetId , artifact , null , "cold_miss" , cookieJar ) ;
748+ lastCacheStatus = result . cache_status ;
749+ if ( result . cache_status === "MISS" ) {
750+ return { result, purgeSummaries } ;
751+ }
752+ if ( result . cache_status !== "HIT" ) {
753+ throw new SafeError ( `${ edge . edge_id } ${ artifact . label } expected X-Rend-Cache MISS after purge, got ${ result . cache_status || "missing" } ` ) ;
754+ }
755+ if ( attempt < coldMissPurgeAttempts ) {
756+ await sleep ( coldMissRetryDelayMs ) ;
757+ }
758+ }
759+ throw new SafeError ( `${ edge . edge_id } ${ artifact . label } expected X-Rend-Cache MISS after purge, got ${ lastCacheStatus || "missing" } ` , {
760+ purge_attempts : coldMissPurgeAttempts ,
761+ } ) ;
762+ }
763+
737764async function fetchEdgeMetrics ( config , edge ) {
738765 const response = await curlRequest ( {
739766 method : "GET" ,
@@ -1073,8 +1100,9 @@ async function runFixture(config, fixtureName, thresholds, warnings, failures, c
10731100 const warmSummaries = [ ] ;
10741101 const purgeSummaries = [ ] ;
10751102 for ( const artifact of artifacts ) {
1076- purgeSummaries . push ( await purgeEdge ( config , edge , assetId , [ artifact . artifact_path ] ) ) ;
1077- const miss = await measurePlayback ( config , edge , assetId , artifact , "MISS" , "cold_miss" , cookieJar ) ;
1103+ const cold = await purgeAndMeasureColdPlayback ( config , edge , assetId , artifact , cookieJar ) ;
1104+ purgeSummaries . push ( ...cold . purgeSummaries ) ;
1105+ const miss = cold . result ;
10781106 miss . fixture = fixtureName ;
10791107 edgeResults . push ( miss ) ;
10801108 expectedTelemetryEvents += 1 ;
0 commit comments