Refactoring. No functional changes. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Simplified internal pointer value construction across activity-related test and service code by consolidating helper functions and using Go's built-in operators. No changes to user-facing functionality. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
175 lines
5.9 KiB
Go
175 lines
5.9 KiB
Go
package mysql
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/activity/internal/testutils"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestCleanupExpiredActivities(t *testing.T) {
|
|
tdb := testutils.SetupTestDB(t, "activity_cleanup")
|
|
ds := NewDatastore(tdb.Conns(), tdb.Logger)
|
|
env := &testEnv{TestDB: tdb, ds: ds}
|
|
|
|
cases := []struct {
|
|
name string
|
|
fn func(t *testing.T, env *testEnv)
|
|
}{
|
|
{"NothingToDelete", testCleanupExpiredActivitiesNoop},
|
|
{"DeletesExpiredNonHostActivities", testCleanupExpiredActivitiesBasic},
|
|
{"RespectsMaxCount", testCleanupExpiredActivitiesBatch},
|
|
{"CleanupHostActivities", testCleanupHostActivities},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
defer env.TruncateTables(t)
|
|
c.fn(t, env)
|
|
})
|
|
}
|
|
}
|
|
|
|
func testCleanupExpiredActivitiesNoop(t *testing.T, env *testEnv) {
|
|
ctx := t.Context()
|
|
|
|
// No activities exist -should be a no-op.
|
|
err := env.ds.CleanupExpiredActivities(ctx, 500, 1)
|
|
require.NoError(t, err)
|
|
|
|
// Create a recent activity -should not be deleted.
|
|
userID := env.InsertUser(t, "user", "user@example.com")
|
|
env.InsertActivity(t, &userID, "recent_activity", map[string]any{})
|
|
|
|
err = env.ds.CleanupExpiredActivities(ctx, 500, 1)
|
|
require.NoError(t, err)
|
|
|
|
activities, _, err := env.ds.ListActivities(ctx, listOpts())
|
|
require.NoError(t, err)
|
|
assert.Len(t, activities, 1)
|
|
}
|
|
|
|
func testCleanupExpiredActivitiesBasic(t *testing.T, env *testEnv) {
|
|
ctx := t.Context()
|
|
userID := env.InsertUser(t, "user", "user@example.com")
|
|
hostID := env.InsertHost(t, "h1.local", nil)
|
|
|
|
expiredTime := time.Now().Add(-48 * time.Hour)
|
|
recentTime := time.Now()
|
|
|
|
// Create activities with different states:
|
|
// 1. Expired, no host link → should be deleted
|
|
expiredNoHost := env.InsertActivityWithTime(t, &userID, "expired_no_host", map[string]any{}, expiredTime)
|
|
// 2. Expired, linked to host → should be preserved
|
|
expiredWithHost := env.InsertActivityWithTime(t, &userID, "expired_with_host", map[string]any{}, expiredTime)
|
|
env.InsertHostActivity(t, hostID, expiredWithHost)
|
|
// 3. Recent, no host link → should be preserved
|
|
recentNoHost := env.InsertActivityWithTime(t, &userID, "recent_no_host", map[string]any{}, recentTime)
|
|
|
|
err := env.ds.CleanupExpiredActivities(ctx, 500, 1)
|
|
require.NoError(t, err)
|
|
|
|
activities, _, err := env.ds.ListActivities(ctx, listOpts())
|
|
require.NoError(t, err)
|
|
require.Len(t, activities, 2)
|
|
|
|
activityIDs := make([]uint, len(activities))
|
|
for i, a := range activities {
|
|
activityIDs[i] = a.ID
|
|
}
|
|
assert.NotContains(t, activityIDs, expiredNoHost, "expired non-host activity should be deleted")
|
|
assert.Contains(t, activityIDs, expiredWithHost, "expired host-linked activity should be preserved")
|
|
assert.Contains(t, activityIDs, recentNoHost, "recent activity should be preserved")
|
|
|
|
// Verify activity_host_past link still exists for the preserved activity.
|
|
var hostActivityCount int
|
|
err = env.DB.GetContext(ctx, &hostActivityCount, "SELECT COUNT(*) FROM activity_host_past WHERE activity_id = ?", expiredWithHost)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, hostActivityCount)
|
|
}
|
|
|
|
func testCleanupHostActivities(t *testing.T, env *testEnv) {
|
|
ctx := t.Context()
|
|
userID := env.InsertUser(t, "user", "user@example.com")
|
|
|
|
hostA := env.InsertHost(t, "hostA.local", nil)
|
|
hostB := env.InsertHost(t, "hostB.local", nil)
|
|
|
|
actA := env.InsertActivity(t, &userID, "ran_script", map[string]any{})
|
|
actB := env.InsertActivity(t, &userID, "ran_script", map[string]any{})
|
|
env.InsertHostActivity(t, hostA, actA)
|
|
env.InsertHostActivity(t, hostB, actB)
|
|
|
|
// No-op for empty/nil slices; join table rows remain intact.
|
|
require.NoError(t, env.ds.CleanupHostActivities(ctx, []uint{}))
|
|
require.NoError(t, env.ds.CleanupHostActivities(ctx, nil))
|
|
var count int
|
|
err := env.DB.GetContext(ctx, &count, "SELECT COUNT(*) FROM activity_host_past")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 2, count, "no-op should not remove any join table rows")
|
|
|
|
// Clean up only hostA.
|
|
err = env.ds.CleanupHostActivities(ctx, []uint{hostA})
|
|
require.NoError(t, err)
|
|
|
|
// hostA's join table row is gone.
|
|
err = env.DB.GetContext(ctx, &count, "SELECT COUNT(*) FROM activity_host_past WHERE host_id = ?", hostA)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 0, count)
|
|
|
|
// hostB's join table row is still present.
|
|
err = env.DB.GetContext(ctx, &count, "SELECT COUNT(*) FROM activity_host_past WHERE host_id = ?", hostB)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, count)
|
|
|
|
// The activities themselves still exist (only the join table rows are removed).
|
|
activities, _, err := env.ds.ListActivities(ctx, listOpts())
|
|
require.NoError(t, err)
|
|
assert.Len(t, activities, 2)
|
|
}
|
|
|
|
func testCleanupExpiredActivitiesBatch(t *testing.T, env *testEnv) {
|
|
ctx := t.Context()
|
|
userID := env.InsertUser(t, "user", "user@example.com")
|
|
expiredTime := time.Now().Add(-48 * time.Hour)
|
|
|
|
// Create 10 expired activities (no host links).
|
|
for i := range 10 {
|
|
env.InsertActivityWithTime(t, &userID, fmt.Sprintf("expired_%d", i), map[string]any{}, expiredTime)
|
|
}
|
|
|
|
// Cleanup with maxCount=3 -only 3 should be deleted per call.
|
|
err := env.ds.CleanupExpiredActivities(ctx, 3, 1)
|
|
require.NoError(t, err)
|
|
|
|
activities, _, err := env.ds.ListActivities(ctx, listOpts())
|
|
require.NoError(t, err)
|
|
assert.Len(t, activities, 7, "only 3 of 10 expired activities should be deleted")
|
|
|
|
// Run again -another 3 deleted.
|
|
err = env.ds.CleanupExpiredActivities(ctx, 3, 1)
|
|
require.NoError(t, err)
|
|
|
|
activities, _, err = env.ds.ListActivities(ctx, listOpts())
|
|
require.NoError(t, err)
|
|
assert.Len(t, activities, 4)
|
|
|
|
// Run again -another 3 deleted.
|
|
err = env.ds.CleanupExpiredActivities(ctx, 3, 1)
|
|
require.NoError(t, err)
|
|
|
|
activities, _, err = env.ds.ListActivities(ctx, listOpts())
|
|
require.NoError(t, err)
|
|
assert.Len(t, activities, 1)
|
|
|
|
// Run again -last one deleted.
|
|
err = env.ds.CleanupExpiredActivities(ctx, 3, 1)
|
|
require.NoError(t, err)
|
|
|
|
activities, _, err = env.ds.ListActivities(ctx, listOpts())
|
|
require.NoError(t, err)
|
|
assert.Len(t, activities, 0)
|
|
}
|