@@ -1148,192 +1148,135 @@ func TestDeleteOldAIBridgeRecords(t *testing.T) {
11481148func TestDeleteOldAuditLogs (t * testing.T ) {
11491149 t .Parallel ()
11501150
1151- t .Run ("RetentionEnabled" , func (t * testing.T ) {
1152- t .Parallel ()
1153-
1154- ctx := testutil .Context (t , testutil .WaitShort )
1155-
1156- clk := quartz .NewMock (t )
1157- now := time .Date (2025 , 1 , 15 , 7 , 30 , 0 , 0 , time .UTC )
1158- retentionPeriod := 30 * 24 * time .Hour // 30 days
1159- afterThreshold := now .Add (- retentionPeriod ).Add (- 24 * time .Hour ) // 31 days ago (older than threshold)
1160- beforeThreshold := now .Add (- 15 * 24 * time .Hour ) // 15 days ago (newer than threshold)
1161- clk .Set (now ).MustWait (ctx )
1162-
1163- db , _ := dbtestutil .NewDB (t , dbtestutil .WithDumpOnFailure ())
1164- logger := slogtest .Make (t , & slogtest.Options {IgnoreErrors : true })
1165- user := dbgen .User (t , db , database.User {})
1166- org := dbgen .Organization (t , db , database.Organization {})
1167-
1168- // Create old audit log (should be deleted)
1169- oldLog := dbgen .AuditLog (t , db , database.AuditLog {
1170- UserID : user .ID ,
1171- OrganizationID : org .ID ,
1172- Time : afterThreshold ,
1173- Action : database .AuditActionCreate ,
1174- ResourceType : database .ResourceTypeWorkspace ,
1175- })
1176-
1177- // Create recent audit log (should be kept)
1178- recentLog := dbgen .AuditLog (t , db , database.AuditLog {
1179- UserID : user .ID ,
1180- OrganizationID : org .ID ,
1181- Time : beforeThreshold ,
1182- Action : database .AuditActionCreate ,
1183- ResourceType : database .ResourceTypeWorkspace ,
1184- })
1185-
1186- // Run the purge with configured retention period
1187- done := awaitDoTick (ctx , t , clk )
1188- closer := dbpurge .New (ctx , logger , db , & codersdk.DeploymentValues {
1189- Retention : codersdk.RetentionConfig {
1151+ now := time .Date (2025 , 1 , 15 , 7 , 30 , 0 , 0 , time .UTC )
1152+ retentionPeriod := 30 * 24 * time .Hour
1153+ afterThreshold := now .Add (- retentionPeriod ).Add (- 24 * time .Hour ) // 31 days ago (older than threshold)
1154+ beforeThreshold := now .Add (- 15 * 24 * time .Hour ) // 15 days ago (newer than threshold)
1155+
1156+ testCases := []struct {
1157+ name string
1158+ retentionConfig codersdk.RetentionConfig
1159+ oldLogTime time.Time
1160+ recentLogTime * time.Time // nil means no recent log created
1161+ expectOldDeleted bool
1162+ expectedLogsRemaining int
1163+ }{
1164+ {
1165+ name : "RetentionEnabled" ,
1166+ retentionConfig : codersdk.RetentionConfig {
11901167 AuditLogs : serpent .Duration (retentionPeriod ),
11911168 },
1192- }, clk )
1193- defer closer .Close ()
1194- testutil .TryReceive (ctx , t , done )
1195-
1196- // Verify results by querying all audit logs
1197- logs , err := db .GetAuditLogsOffset (ctx , database.GetAuditLogsOffsetParams {
1198- LimitOpt : 100 ,
1199- })
1200- require .NoError (t , err )
1201-
1202- logIDs := make ([]uuid.UUID , len (logs ))
1203- for i , log := range logs {
1204- logIDs [i ] = log .AuditLog .ID
1205- }
1206-
1207- require .NotContains (t , logIDs , oldLog .ID , "old audit log should be deleted" )
1208- require .Contains (t , logIDs , recentLog .ID , "recent audit log should be kept" )
1209- })
1210-
1211- t .Run ("RetentionDisabled" , func (t * testing.T ) {
1212- t .Parallel ()
1213-
1214- ctx := testutil .Context (t , testutil .WaitShort )
1215-
1216- clk := quartz .NewMock (t )
1217- now := time .Date (2025 , 1 , 15 , 7 , 30 , 0 , 0 , time .UTC )
1218- oldTime := now .Add (- 365 * 24 * time .Hour ) // 1 year ago
1219- clk .Set (now ).MustWait (ctx )
1220-
1221- db , _ := dbtestutil .NewDB (t , dbtestutil .WithDumpOnFailure ())
1222- logger := slogtest .Make (t , & slogtest.Options {IgnoreErrors : true })
1223- user := dbgen .User (t , db , database.User {})
1224- org := dbgen .Organization (t , db , database.Organization {})
1225-
1226- // Create old audit log (should NOT be deleted when retention is 0)
1227- oldLog := dbgen .AuditLog (t , db , database.AuditLog {
1228- UserID : user .ID ,
1229- OrganizationID : org .ID ,
1230- Time : oldTime ,
1231- Action : database .AuditActionCreate ,
1232- ResourceType : database .ResourceTypeWorkspace ,
1233- })
1234-
1235- // Run the purge with retention disabled (0)
1236- done := awaitDoTick (ctx , t , clk )
1237- closer := dbpurge .New (ctx , logger , db , & codersdk.DeploymentValues {
1238- Retention : codersdk.RetentionConfig {
1239- AuditLogs : serpent .Duration (0 ), // disabled
1169+ oldLogTime : afterThreshold ,
1170+ recentLogTime : & beforeThreshold ,
1171+ expectOldDeleted : true ,
1172+ expectedLogsRemaining : 1 , // only recent log remains
1173+ },
1174+ {
1175+ name : "RetentionDisabled" ,
1176+ retentionConfig : codersdk.RetentionConfig {
1177+ AuditLogs : serpent .Duration (0 ),
12401178 },
1241- }, clk )
1242- defer closer .Close ()
1243- testutil .TryReceive (ctx , t , done )
1244-
1245- // Verify old log is still present
1246- logs , err := db .GetAuditLogsOffset (ctx , database.GetAuditLogsOffsetParams {
1247- LimitOpt : 100 ,
1248- })
1249- require .NoError (t , err )
1250-
1251- logIDs := make ([]uuid.UUID , len (logs ))
1252- for i , log := range logs {
1253- logIDs [i ] = log .AuditLog .ID
1254- }
1255-
1256- require .Contains (t , logIDs , oldLog .ID , "old audit log should NOT be deleted when retention is disabled" )
1257- })
1258-
1259- t .Run ("GlobalRetentionFallback" , func (t * testing.T ) {
1260- t .Parallel ()
1179+ oldLogTime : now .Add (- 365 * 24 * time .Hour ), // 1 year ago
1180+ recentLogTime : nil ,
1181+ expectOldDeleted : false ,
1182+ expectedLogsRemaining : 1 , // old log is kept
1183+ },
1184+ {
1185+ name : "GlobalRetentionFallback" ,
1186+ retentionConfig : codersdk.RetentionConfig {
1187+ Global : serpent .Duration (retentionPeriod ),
1188+ AuditLogs : serpent .Duration (0 ), // Not set, should fall back to global
1189+ },
1190+ oldLogTime : afterThreshold ,
1191+ recentLogTime : & beforeThreshold ,
1192+ expectOldDeleted : true ,
1193+ expectedLogsRemaining : 1 , // only recent log remains
1194+ },
1195+ }
12611196
1262- ctx := testutil .Context (t , testutil .WaitShort )
1197+ for _ , tc := range testCases {
1198+ t .Run (tc .name , func (t * testing.T ) {
1199+ t .Parallel ()
12631200
1264- clk := quartz .NewMock (t )
1265- now := time .Date (2025 , 1 , 15 , 7 , 30 , 0 , 0 , time .UTC )
1266- retentionPeriod := 30 * 24 * time .Hour // 30 days
1267- afterThreshold := now .Add (- retentionPeriod ).Add (- 24 * time .Hour ) // 31 days ago (older than threshold)
1268- beforeThreshold := now .Add (- 15 * 24 * time .Hour ) // 15 days ago (newer than threshold)
1269- clk .Set (now ).MustWait (ctx )
1201+ ctx := testutil .Context (t , testutil .WaitShort )
1202+ clk := quartz .NewMock (t )
1203+ clk .Set (now ).MustWait (ctx )
1204+
1205+ db , _ := dbtestutil .NewDB (t , dbtestutil .WithDumpOnFailure ())
1206+ logger := slogtest .Make (t , & slogtest.Options {IgnoreErrors : true })
1207+
1208+ // Setup test fixtures.
1209+ user := dbgen .User (t , db , database.User {})
1210+ org := dbgen .Organization (t , db , database.Organization {})
1211+
1212+ // Create old audit log.
1213+ oldLog := dbgen .AuditLog (t , db , database.AuditLog {
1214+ UserID : user .ID ,
1215+ OrganizationID : org .ID ,
1216+ Time : tc .oldLogTime ,
1217+ Action : database .AuditActionCreate ,
1218+ ResourceType : database .ResourceTypeWorkspace ,
1219+ })
12701220
1271- db , _ := dbtestutil .NewDB (t , dbtestutil .WithDumpOnFailure ())
1272- logger := slogtest .Make (t , & slogtest.Options {IgnoreErrors : true })
1273- user := dbgen .User (t , db , database.User {})
1274- org := dbgen .Organization (t , db , database.Organization {})
1221+ // Create recent audit log if specified.
1222+ var recentLog database.AuditLog
1223+ if tc .recentLogTime != nil {
1224+ recentLog = dbgen .AuditLog (t , db , database.AuditLog {
1225+ UserID : user .ID ,
1226+ OrganizationID : org .ID ,
1227+ Time : * tc .recentLogTime ,
1228+ Action : database .AuditActionCreate ,
1229+ ResourceType : database .ResourceTypeWorkspace ,
1230+ })
1231+ }
12751232
1276- // Create old audit log (should be deleted)
1277- oldLog := dbgen .AuditLog (t , db , database.AuditLog {
1278- UserID : user .ID ,
1279- OrganizationID : org .ID ,
1280- Time : afterThreshold ,
1281- Action : database .AuditActionCreate ,
1282- ResourceType : database .ResourceTypeWorkspace ,
1283- })
1233+ // Run the purge.
1234+ done := awaitDoTick (ctx , t , clk )
1235+ closer := dbpurge .New (ctx , logger , db , & codersdk.DeploymentValues {
1236+ Retention : tc .retentionConfig ,
1237+ }, clk )
1238+ defer closer .Close ()
1239+ testutil .TryReceive (ctx , t , done )
1240+
1241+ // Verify results.
1242+ logs , err := db .GetAuditLogsOffset (ctx , database.GetAuditLogsOffsetParams {
1243+ LimitOpt : 100 ,
1244+ })
1245+ require .NoError (t , err )
1246+ require .Len (t , logs , tc .expectedLogsRemaining , "unexpected number of logs remaining" )
12841247
1285- // Create recent audit log (should be kept)
1286- recentLog := dbgen .AuditLog (t , db , database.AuditLog {
1287- UserID : user .ID ,
1288- OrganizationID : org .ID ,
1289- Time : beforeThreshold ,
1290- Action : database .AuditActionCreate ,
1291- ResourceType : database .ResourceTypeWorkspace ,
1292- })
1248+ logIDs := make ([]uuid.UUID , len (logs ))
1249+ for i , log := range logs {
1250+ logIDs [i ] = log .AuditLog .ID
1251+ }
12931252
1294- // Run the purge with global retention (audit logs retention is 0, so it falls back)
1295- done := awaitDoTick (ctx , t , clk )
1296- closer := dbpurge .New (ctx , logger , db , & codersdk.DeploymentValues {
1297- Retention : codersdk.RetentionConfig {
1298- Global : serpent .Duration (retentionPeriod ), // Use global
1299- AuditLogs : serpent .Duration (0 ), // Not set, should fall back to global
1300- },
1301- }, clk )
1302- defer closer .Close ()
1303- testutil .TryReceive (ctx , t , done )
1253+ if tc .expectOldDeleted {
1254+ require .NotContains (t , logIDs , oldLog .ID , "old audit log should be deleted" )
1255+ } else {
1256+ require .Contains (t , logIDs , oldLog .ID , "old audit log should NOT be deleted" )
1257+ }
13041258
1305- // Verify results
1306- logs , err := db . GetAuditLogsOffset ( ctx , database. GetAuditLogsOffsetParams {
1307- LimitOpt : 100 ,
1259+ if tc . recentLogTime != nil {
1260+ require . Contains ( t , logIDs , recentLog . ID , "recent audit log should be kept" )
1261+ }
13081262 })
1309- require .NoError (t , err )
1310-
1311- logIDs := make ([]uuid.UUID , len (logs ))
1312- for i , log := range logs {
1313- logIDs [i ] = log .AuditLog .ID
1314- }
1315-
1316- require .NotContains (t , logIDs , oldLog .ID , "old audit log should be deleted via global retention" )
1317- require .Contains (t , logIDs , recentLog .ID , "recent audit log should be kept" )
1318- })
1263+ }
13191264
1265+ // ConnectionEventsNotDeleted is a special case that tests multiple audit
1266+ // action types, so it's kept as a separate subtest.
13201267 t .Run ("ConnectionEventsNotDeleted" , func (t * testing.T ) {
13211268 t .Parallel ()
13221269
13231270 ctx := testutil .Context (t , testutil .WaitShort )
1324-
13251271 clk := quartz .NewMock (t )
1326- now := time .Date (2025 , 1 , 15 , 7 , 30 , 0 , 0 , time .UTC )
1327- retentionPeriod := 30 * 24 * time .Hour // 30 days
1328- afterThreshold := now .Add (- retentionPeriod ).Add (- 24 * time .Hour ) // 31 days ago (older than threshold)
13291272 clk .Set (now ).MustWait (ctx )
13301273
13311274 db , _ := dbtestutil .NewDB (t , dbtestutil .WithDumpOnFailure ())
13321275 logger := slogtest .Make (t , & slogtest.Options {IgnoreErrors : true })
13331276 user := dbgen .User (t , db , database.User {})
13341277 org := dbgen .Organization (t , db , database.Organization {})
13351278
1336- // Create old connection events (should NOT be deleted by audit logs retention)
1279+ // Create old connection events (should NOT be deleted by audit logs retention).
13371280 oldConnectLog := dbgen .AuditLog (t , db , database.AuditLog {
13381281 UserID : user .ID ,
13391282 OrganizationID : org .ID ,
@@ -1366,7 +1309,7 @@ func TestDeleteOldAuditLogs(t *testing.T) {
13661309 ResourceType : database .ResourceTypeWorkspace ,
13671310 })
13681311
1369- // Create old non-connection audit log (should be deleted)
1312+ // Create old non-connection audit log (should be deleted).
13701313 oldCreateLog := dbgen .AuditLog (t , db , database.AuditLog {
13711314 UserID : user .ID ,
13721315 OrganizationID : org .ID ,
@@ -1375,7 +1318,7 @@ func TestDeleteOldAuditLogs(t *testing.T) {
13751318 ResourceType : database .ResourceTypeWorkspace ,
13761319 })
13771320
1378- // Run the purge with audit logs retention enabled
1321+ // Run the purge with audit logs retention enabled.
13791322 done := awaitDoTick (ctx , t , clk )
13801323 closer := dbpurge .New (ctx , logger , db , & codersdk.DeploymentValues {
13811324 Retention : codersdk.RetentionConfig {
@@ -1385,24 +1328,25 @@ func TestDeleteOldAuditLogs(t *testing.T) {
13851328 defer closer .Close ()
13861329 testutil .TryReceive (ctx , t , done )
13871330
1388- // Verify results
1331+ // Verify results.
13891332 logs , err := db .GetAuditLogsOffset (ctx , database.GetAuditLogsOffsetParams {
13901333 LimitOpt : 100 ,
13911334 })
13921335 require .NoError (t , err )
1336+ require .Len (t , logs , 4 , "should have 4 connection event logs remaining" )
13931337
13941338 logIDs := make ([]uuid.UUID , len (logs ))
13951339 for i , log := range logs {
13961340 logIDs [i ] = log .AuditLog .ID
13971341 }
13981342
1399- // Connection events should NOT be deleted by audit logs retention
1343+ // Connection events should NOT be deleted by audit logs retention.
14001344 require .Contains (t , logIDs , oldConnectLog .ID , "old connect log should NOT be deleted by audit logs retention" )
14011345 require .Contains (t , logIDs , oldDisconnectLog .ID , "old disconnect log should NOT be deleted by audit logs retention" )
14021346 require .Contains (t , logIDs , oldOpenLog .ID , "old open log should NOT be deleted by audit logs retention" )
14031347 require .Contains (t , logIDs , oldCloseLog .ID , "old close log should NOT be deleted by audit logs retention" )
14041348
1405- // Non-connection event should be deleted
1349+ // Non-connection event should be deleted.
14061350 require .NotContains (t , logIDs , oldCreateLog .ID , "old create log should be deleted by audit logs retention" )
14071351 })
14081352}
0 commit comments