mirror of
https://github.com/fleetdm/fleet
synced 2026-05-22 16:39:01 +00:00
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #37806 This PR creates an activity bounded context and moves the following HTTP endpoint (including the full vertical slice) there: `/api/latest/fleet/activities` NONE of the other activity functionality is moved! This is an incremental approach starting with just 1 API/service endpoint. A significant part of this PR is tests. This feature is now receiving significantly more unit/integration test coverage than before. Also, this PR does not remove the `ListActivities` datastore method in the legacy code. That will be done in the follow up PR (part 2 of 2). This refactoring effort also uncovered an activity/user authorization issue: https://fleetdm.slack.com/archives/C02A8BRABB5/p1768582236611479 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Activity listing API now available with query filtering, date-range filtering, and type-based filtering * Pagination support for activity results with cursor-based and offset-based options * Configurable sorting by creation date or activity ID in ascending or descending order * Automatic enrichment of activity records with actor user details (name, email, avatar) * Role-based access controls applied to activity visibility based on user permissions <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
99 lines
2.8 KiB
Go
99 lines
2.8 KiB
Go
package tests
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/activity"
|
|
api_http "github.com/fleetdm/fleet/v4/server/activity/api/http"
|
|
"github.com/fleetdm/fleet/v4/server/activity/internal/mysql"
|
|
"github.com/fleetdm/fleet/v4/server/activity/internal/service"
|
|
"github.com/fleetdm/fleet/v4/server/activity/internal/testutils"
|
|
"github.com/go-kit/kit/endpoint"
|
|
"github.com/gorilla/mux"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// integrationTestSuite holds all dependencies for integration tests.
|
|
type integrationTestSuite struct {
|
|
*testutils.TestDB
|
|
ds *mysql.Datastore
|
|
server *httptest.Server
|
|
userProvider *mockUserProvider
|
|
}
|
|
|
|
// setupIntegrationTest creates a new test suite with a real database and HTTP server.
|
|
func setupIntegrationTest(t *testing.T) *integrationTestSuite {
|
|
t.Helper()
|
|
|
|
tdb := testutils.SetupTestDB(t, "activity_integration")
|
|
ds := mysql.NewDatastore(tdb.Conns(), tdb.Logger)
|
|
|
|
// Create mocks
|
|
authorizer := &mockAuthorizer{}
|
|
userProvider := newMockUserProvider()
|
|
|
|
// Create service
|
|
svc := service.NewService(authorizer, ds, userProvider, tdb.Logger)
|
|
|
|
// Create router with routes
|
|
router := mux.NewRouter()
|
|
// Pass-through auth middleware (authzcheck middleware handles creating the authz context)
|
|
authMiddleware := func(e endpoint.Endpoint) endpoint.Endpoint { return e }
|
|
routesFn := service.GetRoutes(svc, authMiddleware)
|
|
routesFn(router, nil)
|
|
|
|
// Create test server
|
|
server := httptest.NewServer(router)
|
|
t.Cleanup(func() {
|
|
server.Close()
|
|
})
|
|
|
|
return &integrationTestSuite{
|
|
TestDB: tdb,
|
|
ds: ds,
|
|
server: server,
|
|
userProvider: userProvider,
|
|
}
|
|
}
|
|
|
|
// truncateTables clears all test data between tests.
|
|
func (s *integrationTestSuite) truncateTables(t *testing.T) {
|
|
t.Helper()
|
|
s.TruncateTables(t)
|
|
}
|
|
|
|
// insertUser creates a user in the database and mock user provider.
|
|
func (s *integrationTestSuite) insertUser(t *testing.T, name, email string) uint {
|
|
t.Helper()
|
|
userID := s.TestDB.InsertUser(t, name, email)
|
|
|
|
// Also add to mock user provider for enrichment
|
|
s.userProvider.AddUser(&activity.User{
|
|
ID: userID,
|
|
Name: name,
|
|
Email: email,
|
|
})
|
|
|
|
return userID
|
|
}
|
|
|
|
// getActivities makes an HTTP request to list activities and returns the parsed response.
|
|
func (s *integrationTestSuite) getActivities(t *testing.T, queryParams string) (*api_http.ListActivitiesResponse, int) {
|
|
t.Helper()
|
|
url := s.server.URL + "/api/v1/fleet/activities"
|
|
if queryParams != "" {
|
|
url += "?" + queryParams
|
|
}
|
|
resp, err := http.Get(url) //nolint:gosec // test server URL is safe
|
|
require.NoError(t, err)
|
|
|
|
var result api_http.ListActivitiesResponse
|
|
err = json.NewDecoder(resp.Body).Decode(&result)
|
|
resp.Body.Close()
|
|
require.NoError(t, err)
|
|
|
|
return &result, resp.StatusCode
|
|
}
|