Files
Victor Lyuboslavsky eb71cd43b9 Removed the ptr helper package from Activity bounded context (#42161)
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 -->
2026-03-23 14:10:07 -05:00

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)
}