fleet/server/test/activities.go
Victor Lyuboslavsky a0e9d88e0d
Updated SQL modes in tests to match production. (#31445)
Fixes #31444 

The changes are primarily in tests. The only changes in production code
are a couple validations/checks for invalid values in:
- mysql/apple_mdm.go
- mysql/hosts.go
- mysql/queries.go

# 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`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## 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

* **Bug Fixes**
* Improved handling of timestamp and default values across various
features to prevent database errors and warnings.
* Enhanced validation and data consistency for Apple Business Manager
tokens and MDM profiles.
* Updated test data and logic to comply with stricter database
constraints and realistic scenarios, including date handling and field
lengths.

* **Chores**
* Updated test setups to reflect schema changes, improve data integrity,
and avoid future compatibility issues.
  * Standardized SQL mode and timestamp usage in test environments.
* Refined test data for VPP apps, software installers, and device
enrollments for better reliability.

* **Tests**
* Expanded and updated tests to cover new fields, stricter validation,
and more accurate simulation of real-world conditions.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-03 08:18:13 +02:00

158 lines
6.2 KiB
Go

package test
import (
"context"
"strings"
"testing"
"time"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/mdm/nanomdm/mdm"
"github.com/fleetdm/fleet/v4/server/mdm/nanomdm/storage"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
)
// CreateHostScriptUpcomingActivity creates a host script execution request
// for the provided host. It returns the upcoming activity's execution ID.
func CreateHostScriptUpcomingActivity(t *testing.T, ds fleet.Datastore, host *fleet.Host) string {
ctx := context.Background()
hsr, err := ds.NewHostScriptExecutionRequest(ctx, &fleet.HostScriptRequestPayload{
HostID: host.ID,
ScriptContents: "echo 'a'",
})
require.NoError(t, err)
return hsr.ExecutionID
}
// SetHostScriptResult sets the result of a host script queued via
// CreateHostScriptUpcomingActivity.
func SetHostScriptResult(t *testing.T, ds fleet.Datastore, host *fleet.Host, execID string, exitCode int) {
ctx := context.Background()
_, _, err := ds.SetHostScriptExecutionResult(ctx, &fleet.HostScriptResultPayload{
HostID: host.ID, ExecutionID: execID, Output: "a", ExitCode: exitCode,
})
require.NoError(t, err)
}
// CreateHostSoftwareInstallUpcomingActivity creates a host software install
// execution request for the provided host. It returns the upcoming activity's
// execution ID.
func CreateHostSoftwareInstallUpcomingActivity(t *testing.T, ds fleet.Datastore, host *fleet.Host, user *fleet.User) string {
ctx := context.Background()
installer, err := fleet.NewTempFileReader(strings.NewReader("echo"), t.TempDir)
require.NoError(t, err)
installerID, _, err := ds.MatchOrCreateSoftwareInstaller(ctx, &fleet.UploadSoftwareInstallerPayload{
InstallScript: "install foo",
InstallerFile: installer,
StorageID: uuid.NewString(),
Filename: "foo.pkg",
Title: uuid.NewString(),
Source: "apps",
Version: "0.0.1",
UserID: user.ID,
UninstallScript: "uninstall foo",
ValidatedLabels: &fleet.LabelIdentsWithScope{},
})
require.NoError(t, err)
execID, err := ds.InsertSoftwareInstallRequest(ctx, host.ID, installerID, fleet.HostSoftwareInstallOptions{})
require.NoError(t, err)
return execID
}
// SetHostSoftwareInstallResult sets the result of a host software install
// queued via CreateHostSoftwareInstallUpcomingActivity.
func SetHostSoftwareInstallResult(t *testing.T, ds fleet.Datastore, host *fleet.Host, execID string, exitCode int) {
ctx := context.Background()
_, err := ds.SetHostSoftwareInstallResult(ctx, &fleet.HostSoftwareInstallResultPayload{
HostID: host.ID,
InstallUUID: execID,
InstallScriptExitCode: &exitCode,
})
require.NoError(t, err)
}
// CreateHostSoftwareUninstallUpcomingActivity creates a host software uninstall
// execution request for the provided host. It returns the upcoming activity's
// execution ID.
func CreateHostSoftwareUninstallUpcomingActivity(t *testing.T, ds fleet.Datastore, host *fleet.Host, user *fleet.User) string {
ctx := context.Background()
installer, err := fleet.NewTempFileReader(strings.NewReader("echo"), t.TempDir)
require.NoError(t, err)
installerID, _, err := ds.MatchOrCreateSoftwareInstaller(ctx, &fleet.UploadSoftwareInstallerPayload{
InstallScript: "install foo",
InstallerFile: installer,
StorageID: uuid.NewString(),
Filename: "foo.pkg",
Title: uuid.NewString(),
Source: "apps",
Version: "0.0.1",
UserID: user.ID,
UninstallScript: "uninstall foo",
ValidatedLabels: &fleet.LabelIdentsWithScope{},
})
require.NoError(t, err)
execID := uuid.NewString()
err = ds.InsertSoftwareUninstallRequest(ctx, execID, host.ID, installerID, false)
require.NoError(t, err)
return execID
}
// SetHostSoftwareUninstallResult sets the result of a host software uninstall
// queued via CreateHostSoftwareUninstallUpcomingActivity.
func SetHostSoftwareUninstallResult(t *testing.T, ds fleet.Datastore, host *fleet.Host, execID string, exitCode int) {
ctx := context.Background()
_, _, err := ds.SetHostScriptExecutionResult(ctx, &fleet.HostScriptResultPayload{
HostID: host.ID,
ExecutionID: execID,
ExitCode: exitCode,
})
require.NoError(t, err)
}
// CreateHostVPPAppInstallUpcomingActivity creates a VPP app install request
// for the provided host. It returns the upcoming activity's execution ID.
// Note that test.CreateInsertGlobalVPPToken(t, ds) should be used to enable
// VPP apps (create a VPP token).
func CreateHostVPPAppInstallUpcomingActivity(t *testing.T, ds fleet.Datastore, host *fleet.Host) (execID, adamID string) {
ctx := context.Background()
// Generate a short adamID that fits within the 16 character limit
adamID = uuid.NewString()[:16]
vppApp := &fleet.VPPApp{
Name: "vpp_1", VPPAppTeam: fleet.VPPAppTeam{VPPAppID: fleet.VPPAppID{AdamID: adamID, Platform: fleet.MacOSPlatform}},
BundleIdentifier: adamID,
}
_, err := ds.InsertVPPAppWithTeam(ctx, vppApp, nil)
require.NoError(t, err)
execID = uuid.NewString()
err = ds.InsertHostVPPSoftwareInstall(ctx, host.ID, vppApp.VPPAppID, execID, "event-id-1", fleet.HostSoftwareInstallOptions{})
require.NoError(t, err)
return execID, adamID
}
// SetHostVPPAppInstallResult sets the result of a VPP app install queued via
// CreateHostVPPAppInstallUpcomingActivity.
// The adamID is the one for the VPP app created by that call, and status is
// one of the Apple MDM status string (Acknowledged, Error, CommandFormatError,
// etc).
func SetHostVPPAppInstallResult(t *testing.T, ds fleet.Datastore, nanods storage.CommandAndReportResultsStore, host *fleet.Host, execID, adamID, status string) {
ctx := context.Background()
ctx = context.WithValue(ctx, fleet.ActivityWebhookContextKey, true)
nanoCtx := &mdm.Request{EnrollID: &mdm.EnrollID{ID: host.UUID}, Context: ctx}
cmdRes := &mdm.CommandResults{
CommandUUID: execID,
Status: status,
Raw: []byte(`<?xml version="1.0" encoding="UTF-8"?>`),
}
err := nanods.StoreCommandReport(nanoCtx, cmdRes)
require.NoError(t, err)
err = ds.NewActivity(ctx, nil, fleet.ActivityInstalledAppStoreApp{
HostID: host.ID,
AppStoreID: adamID,
CommandUUID: execID,
}, []byte(`{}`), time.Now())
require.NoError(t, err)
}