fleet/server/activity/internal/tests/integration_test.go
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

235 lines
8.6 KiB
Go

package tests
import (
"net/http"
"strconv"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestIntegration(t *testing.T) {
s := setupIntegrationTest(t)
cases := []struct {
name string
fn func(t *testing.T, s *integrationTestSuite)
}{
{"ListActivities", testListActivities},
{"ListActivitiesPagination", testListActivitiesPagination},
{"ListActivitiesCursorPagination", testListActivitiesCursorPagination},
{"ListActivitiesFilters", testListActivitiesFilters},
{"ListActivitiesUserEnrichment", testListActivitiesUserEnrichment},
{"ListHostPastActivities", testListHostPastActivities},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
defer s.truncateTables(t)
c.fn(t, s)
})
}
}
func testListActivities(t *testing.T, s *integrationTestSuite) {
userID := s.insertUser(t, "admin", "admin@example.com")
// Insert activities
s.InsertActivity(t, &userID, "applied_spec_pack", map[string]any{})
s.InsertActivity(t, &userID, "deleted_pack", map[string]any{})
s.InsertActivity(t, &userID, "edited_pack", map[string]any{})
result, statusCode := s.getActivities(t, "per_page=100")
assert.Equal(t, http.StatusOK, statusCode)
assert.Len(t, result.Activities, 3)
assert.NotNil(t, result.Meta)
// Verify order (newest first by default)
assert.Equal(t, "edited_pack", result.Activities[0].Type)
assert.Equal(t, "deleted_pack", result.Activities[1].Type)
assert.Equal(t, "applied_spec_pack", result.Activities[2].Type)
}
func testListActivitiesPagination(t *testing.T, s *integrationTestSuite) {
userID := s.insertUser(t, "admin", "admin@example.com")
// Insert 5 activities
for i := range 5 {
s.InsertActivity(t, &userID, "test_activity", map[string]any{"index": i})
}
// First page
result, _ := s.getActivities(t, "per_page=2&order_key=id&order_direction=asc")
assert.Len(t, result.Activities, 2)
assert.True(t, result.Meta.HasNextResults)
assert.False(t, result.Meta.HasPreviousResults)
// Second page
result, _ = s.getActivities(t, "per_page=2&page=1&order_key=id&order_direction=asc")
assert.Len(t, result.Activities, 2)
assert.True(t, result.Meta.HasNextResults)
assert.True(t, result.Meta.HasPreviousResults)
// Last page
result, _ = s.getActivities(t, "per_page=2&page=2&order_key=id&order_direction=asc")
assert.Len(t, result.Activities, 1)
assert.False(t, result.Meta.HasNextResults)
assert.True(t, result.Meta.HasPreviousResults)
}
func testListActivitiesCursorPagination(t *testing.T, s *integrationTestSuite) {
userID := s.insertUser(t, "admin", "admin@example.com")
// Insert 3 activities
s.InsertActivity(t, &userID, "applied_spec_pack", map[string]any{})
s.InsertActivity(t, &userID, "deleted_pack", map[string]any{})
s.InsertActivity(t, &userID, "edited_pack", map[string]any{})
// Test cursor-based pagination with after=0
// Meta should be nil for cursor-based pagination (doesn't return metadata)
result, statusCode := s.getActivities(t, "per_page=1&order_key=id&after=0")
assert.Equal(t, http.StatusOK, statusCode)
assert.Len(t, result.Activities, 1)
assert.Nil(t, result.Meta)
assert.Equal(t, "applied_spec_pack", result.Activities[0].Type)
// Test cursor pagination to get the next activity
firstID := result.Activities[0].ID
result, _ = s.getActivities(t, "per_page=1&order_key=id&after="+strconv.FormatUint(uint64(firstID), 10))
assert.Len(t, result.Activities, 1)
assert.Nil(t, result.Meta)
assert.Equal(t, "deleted_pack", result.Activities[0].Type)
// Test descending order with cursor
result, _ = s.getActivities(t, "per_page=1&order_key=id&order_direction=desc&after=999999")
assert.Len(t, result.Activities, 1)
assert.Nil(t, result.Meta)
// Descending order, so the newest (edited_pack) should be first
assert.Equal(t, "edited_pack", result.Activities[0].Type)
}
func testListActivitiesFilters(t *testing.T, s *integrationTestSuite) {
johnUserID := s.insertUser(t, "john_doe", "john@example.com")
janeUserID := s.insertUser(t, "jane_smith", "jane@example.com")
now := time.Now().UTC().Truncate(time.Second)
// Insert activities with different types, times, and users
s.InsertActivityWithTime(t, &johnUserID, "type_a", map[string]any{}, now.Add(-48*time.Hour))
s.InsertActivityWithTime(t, &johnUserID, "type_a", map[string]any{}, now.Add(-24*time.Hour))
s.InsertActivityWithTime(t, &johnUserID, "type_b", map[string]any{}, now)
s.InsertActivityWithTime(t, &janeUserID, "type_a", map[string]any{}, now) // Jane's activity
// Filter by type
result, _ := s.getActivities(t, "per_page=100&activity_type=type_a")
assert.Len(t, result.Activities, 3) // 2 from john + 1 from jane
for _, a := range result.Activities {
assert.Equal(t, "type_a", a.Type)
}
// Filter by date range
startDate := now.Add(-36 * time.Hour).Format(time.RFC3339)
result, _ = s.getActivities(t, "per_page=100&start_created_at="+startDate)
assert.Len(t, result.Activities, 3) // -24h, now (john), now (jane)
// Filter by user search query - should only return john's activities
result, _ = s.getActivities(t, "per_page=100&query=john")
assert.Len(t, result.Activities, 3) // Only john's 3 activities, not jane's
for _, a := range result.Activities {
require.NotNil(t, a.ActorID)
assert.Equal(t, johnUserID, *a.ActorID)
}
// Filter by user search query - should only return jane's activities
result, _ = s.getActivities(t, "per_page=100&query=jane")
assert.Len(t, result.Activities, 1) // Only jane's 1 activity
require.NotNil(t, result.Activities[0].ActorID)
assert.Equal(t, janeUserID, *result.Activities[0].ActorID)
}
func testListActivitiesUserEnrichment(t *testing.T, s *integrationTestSuite) {
userID := s.insertUser(t, "John Doe", "john@example.com")
s.InsertActivity(t, &userID, "test_activity", map[string]any{})
result, _ := s.getActivities(t, "per_page=100")
require.Len(t, result.Activities, 1)
// Verify user enrichment from mock user provider
a := result.Activities[0]
assert.NotNil(t, a.ActorID)
assert.Equal(t, userID, *a.ActorID)
assert.NotNil(t, a.ActorFullName)
assert.Equal(t, "John Doe", *a.ActorFullName)
assert.NotNil(t, a.ActorEmail)
assert.Equal(t, "john@example.com", *a.ActorEmail)
}
func testListHostPastActivities(t *testing.T, s *integrationTestSuite) {
userID := s.insertUser(t, "admin", "admin@example.com")
// Create two hosts
hostA := s.insertHost(t, "host-a.example.com", nil)
hostB := s.insertHost(t, "host-b.example.com", nil)
// Create activities linked to different hosts
actA := s.InsertActivity(t, &userID, "ran_script", map[string]any{"host": "host-a"})
actB := s.InsertActivity(t, &userID, "installed_software", map[string]any{"host": "host-a"})
actC := s.InsertActivity(t, &userID, "ran_script", map[string]any{"host": "host-b"})
// Link activities to hosts
s.InsertHostActivity(t, hostA, actA)
s.InsertHostActivity(t, hostA, actB)
s.InsertHostActivity(t, hostB, actC)
t.Run("returns activities for specific host", func(t *testing.T) {
result, statusCode := s.getHostPastActivities(t, hostA, "per_page=100")
assert.Equal(t, http.StatusOK, statusCode)
assert.Len(t, result.Activities, 2)
assert.NotNil(t, result.Meta)
// Verify order (newest first by default)
assert.Equal(t, "installed_software", result.Activities[0].Type)
assert.Equal(t, "ran_script", result.Activities[1].Type)
// Host B should only have its own activity
result, statusCode = s.getHostPastActivities(t, hostB, "per_page=100")
assert.Equal(t, http.StatusOK, statusCode)
assert.Len(t, result.Activities, 1)
assert.Equal(t, "ran_script", result.Activities[0].Type)
})
t.Run("returns 404 for non-existent host", func(t *testing.T) {
_, statusCode := s.getHostPastActivities(t, 99999, "per_page=100")
assert.Equal(t, http.StatusNotFound, statusCode)
})
t.Run("pagination", func(t *testing.T) {
host := s.insertHost(t, "pagination-host.example.com", nil)
// Insert 5 activities for the host
for i := range 5 {
actID := s.InsertActivity(t, &userID, "test_activity", map[string]any{"index": i})
s.InsertHostActivity(t, host, actID)
}
// First page
result, _ := s.getHostPastActivities(t, host, "per_page=2")
assert.Len(t, result.Activities, 2)
assert.True(t, result.Meta.HasNextResults)
assert.False(t, result.Meta.HasPreviousResults)
// Second page
result, _ = s.getHostPastActivities(t, host, "per_page=2&page=1")
assert.Len(t, result.Activities, 2)
assert.True(t, result.Meta.HasNextResults)
assert.True(t, result.Meta.HasPreviousResults)
// Last page
result, _ = s.getHostPastActivities(t, host, "per_page=2&page=2")
assert.Len(t, result.Activities, 1)
assert.False(t, result.Meta.HasNextResults)
assert.True(t, result.Meta.HasPreviousResults)
})
}