@@ -1159,6 +1159,228 @@ describe('AgentClient', () => {
11591159 expect ( storeContainer . deleteContainer ) . toHaveBeenCalledWith ( 'c1' ) ;
11601160 } ) ;
11611161
1162+ test ( 'should ignore watcher-cycle cleanup for invalid container ids' , ( ) => {
1163+ ( client as any ) . pendingWatcherCycleReports . set (
1164+ 'watcher' ,
1165+ new Map ( [
1166+ [
1167+ 'c1' ,
1168+ {
1169+ container : {
1170+ id : 'c1' ,
1171+ name : 'test' ,
1172+ watcher : 'watcher' ,
1173+ } ,
1174+ changed : true ,
1175+ } ,
1176+ ] ,
1177+ ] ) ,
1178+ ) ;
1179+
1180+ ( client as any ) . clearPendingWatcherCycleReportByContainerId ( '' ) ;
1181+
1182+ expect ( ( client as any ) . pendingWatcherCycleReports . get ( 'watcher' ) ?. has ( 'c1' ) ) . toBe ( true ) ;
1183+ } ) ;
1184+
1185+ test ( 'should clear watcher-cycle reports when the last container in a watcher is removed' , ( ) => {
1186+ ( client as any ) . pendingWatcherCycleReports . set (
1187+ 'watcher' ,
1188+ new Map ( [
1189+ [
1190+ 'c1' ,
1191+ {
1192+ container : {
1193+ id : 'c1' ,
1194+ name : 'test' ,
1195+ watcher : 'watcher' ,
1196+ } ,
1197+ changed : true ,
1198+ } ,
1199+ ] ,
1200+ ] ) ,
1201+ ) ;
1202+
1203+ ( client as any ) . clearPendingWatcherCycleReportByContainerId ( 'c1' ) ;
1204+
1205+ expect ( ( client as any ) . pendingWatcherCycleReports . has ( 'watcher' ) ) . toBe ( false ) ;
1206+ } ) ;
1207+
1208+ test ( 'should ignore watcher-cycle reports that do not have a resolvable container key' , ( ) => {
1209+ const beforeSize = ( client as any ) . pendingWatcherCycleReports . size ;
1210+
1211+ ( client as any ) . rememberPendingWatcherCycleReport ( {
1212+ container : {
1213+ watcher : 'watcher' ,
1214+ } ,
1215+ changed : true ,
1216+ } ) ;
1217+
1218+ expect ( ( client as any ) . pendingWatcherCycleReports . size ) . toBe ( beforeSize ) ;
1219+ } ) ;
1220+
1221+ test ( 'should ignore invalid watcher-cycle lookups before taking a pending report' , ( ) => {
1222+ const report = {
1223+ container : {
1224+ id : 'c1' ,
1225+ name : 'test' ,
1226+ watcher : 'watcher' ,
1227+ } ,
1228+ changed : true ,
1229+ } ;
1230+ ( client as any ) . pendingWatcherCycleReports . set ( 'watcher' , new Map ( [ [ 'c1' , report ] ] ) ) ;
1231+
1232+ expect ( ( client as any ) . takePendingWatcherCycleReport ( '' , report . container ) ) . toBeUndefined ( ) ;
1233+ expect (
1234+ ( client as any ) . takePendingWatcherCycleReport ( 'watcher' , { watcher : 'watcher' } as any ) ,
1235+ ) . toBeUndefined ( ) ;
1236+ expect (
1237+ ( client as any ) . takePendingWatcherCycleReport ( 'watcher' , {
1238+ ...report . container ,
1239+ id : 'missing' ,
1240+ } ) ,
1241+ ) . toBeUndefined ( ) ;
1242+ expect ( ( client as any ) . takePendingWatcherCycleReport ( 'watcher' , report . container ) ) . toBe (
1243+ report ,
1244+ ) ;
1245+ } ) ;
1246+
1247+ test ( 'should return undefined when deriving a watcher-cycle key from a non-container' , ( ) => {
1248+ expect ( ( client as any ) . getPendingWatcherCycleContainerKey ( undefined ) ) . toBeUndefined ( ) ;
1249+ expect ( ( client as any ) . getPendingWatcherCycleContainerKey ( null ) ) . toBeUndefined ( ) ;
1250+ } ) ;
1251+
1252+ test ( 'should fall back to watcher:name when id is missing' , ( ) => {
1253+ expect (
1254+ ( client as any ) . getPendingWatcherCycleContainerKey ( {
1255+ name : 'test' ,
1256+ watcher : 'watcher' ,
1257+ } ) ,
1258+ ) . toBe ( 'watcher:test' ) ;
1259+ } ) ;
1260+
1261+ test ( 'should remove the watcher bucket after taking the last pending watcher-cycle report' , ( ) => {
1262+ const report = {
1263+ container : {
1264+ id : 'c1' ,
1265+ name : 'test' ,
1266+ watcher : 'watcher' ,
1267+ } ,
1268+ changed : true ,
1269+ } ;
1270+ ( client as any ) . pendingWatcherCycleReports . set ( 'watcher' , new Map ( [ [ 'c1' , report ] ] ) ) ;
1271+
1272+ expect ( ( client as any ) . takePendingWatcherCycleReport ( 'watcher' , report . container ) ) . toBe (
1273+ report ,
1274+ ) ;
1275+ expect ( ( client as any ) . pendingWatcherCycleReports . has ( 'watcher' ) ) . toBe ( false ) ;
1276+ } ) ;
1277+
1278+ test ( 'should keep the watcher bucket after taking one report when others remain' , ( ) => {
1279+ const firstReport = {
1280+ container : {
1281+ id : 'c1' ,
1282+ name : 'test' ,
1283+ watcher : 'watcher' ,
1284+ } ,
1285+ changed : true ,
1286+ } ;
1287+ const secondReport = {
1288+ container : {
1289+ id : 'c2' ,
1290+ name : 'test-2' ,
1291+ watcher : 'watcher' ,
1292+ } ,
1293+ changed : true ,
1294+ } ;
1295+ ( client as any ) . pendingWatcherCycleReports . set (
1296+ 'watcher' ,
1297+ new Map ( [
1298+ [ 'c1' , firstReport ] ,
1299+ [ 'c2' , secondReport ] ,
1300+ ] ) ,
1301+ ) ;
1302+
1303+ expect ( ( client as any ) . takePendingWatcherCycleReport ( 'watcher' , firstReport . container ) ) . toBe (
1304+ firstReport ,
1305+ ) ;
1306+ expect ( ( client as any ) . pendingWatcherCycleReports . has ( 'watcher' ) ) . toBe ( true ) ;
1307+ expect ( ( client as any ) . pendingWatcherCycleReports . get ( 'watcher' ) ?. has ( 'c2' ) ) . toBe ( true ) ;
1308+ } ) ;
1309+
1310+ test ( 'should remove the watcher bucket when clearing the last pending watcher-cycle report by id' , ( ) => {
1311+ const report = {
1312+ container : {
1313+ id : 'c1' ,
1314+ name : 'test' ,
1315+ watcher : 'watcher' ,
1316+ } ,
1317+ changed : true ,
1318+ } ;
1319+ ( client as any ) . pendingWatcherCycleReports . set ( 'watcher' , new Map ( [ [ 'c1' , report ] ] ) ) ;
1320+
1321+ ( client as any ) . clearPendingWatcherCycleReportByContainerId ( 'c1' ) ;
1322+
1323+ expect ( ( client as any ) . pendingWatcherCycleReports . has ( 'watcher' ) ) . toBe ( false ) ;
1324+ } ) ;
1325+
1326+ test ( 'should keep the watcher bucket when clearing one watcher-cycle container id and others remain' , ( ) => {
1327+ ( client as any ) . pendingWatcherCycleReports . set (
1328+ 'watcher' ,
1329+ new Map ( [
1330+ [
1331+ 'c1' ,
1332+ {
1333+ container : {
1334+ id : 'c1' ,
1335+ name : 'test' ,
1336+ watcher : 'watcher' ,
1337+ } ,
1338+ changed : true ,
1339+ } ,
1340+ ] ,
1341+ [
1342+ 'c2' ,
1343+ {
1344+ container : {
1345+ id : 'c2' ,
1346+ name : 'test-2' ,
1347+ watcher : 'watcher' ,
1348+ } ,
1349+ changed : true ,
1350+ } ,
1351+ ] ,
1352+ ] ) ,
1353+ ) ;
1354+
1355+ ( client as any ) . clearPendingWatcherCycleReportByContainerId ( 'c1' ) ;
1356+
1357+ expect ( ( client as any ) . pendingWatcherCycleReports . has ( 'watcher' ) ) . toBe ( true ) ;
1358+ expect ( ( client as any ) . pendingWatcherCycleReports . get ( 'watcher' ) ?. has ( 'c2' ) ) . toBe ( true ) ;
1359+ } ) ;
1360+
1361+ test ( 'should remove the watcher bucket after clearing the last watcher-cycle container id' , ( ) => {
1362+ ( client as any ) . pendingWatcherCycleReports . set (
1363+ 'watcher' ,
1364+ new Map ( [
1365+ [
1366+ 'c1' ,
1367+ {
1368+ container : {
1369+ id : 'c1' ,
1370+ name : 'test' ,
1371+ watcher : 'watcher' ,
1372+ } ,
1373+ changed : true ,
1374+ } ,
1375+ ] ,
1376+ ] ) ,
1377+ ) ;
1378+
1379+ ( client as any ) . clearPendingWatcherCycleReportByContainerId ( 'c1' ) ;
1380+
1381+ expect ( ( client as any ) . pendingWatcherCycleReports . has ( 'watcher' ) ) . toBe ( false ) ;
1382+ } ) ;
1383+
11621384 test ( 'should emit update-applied when agent sends dd:update-applied' , async ( ) => {
11631385 await client . handleEvent ( 'dd:update-applied' , 'local_nginx' ) ;
11641386
0 commit comments