mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 17:08:53 +00:00
fix: update integration tests to use state machine, fix 402 error (#23181)
> No issue, just some cleanup/bugfix # Checklist for submitter If some of the following don't apply, delete the relevant line. <!-- Note that API documentation changes are now addressed by the product design team. --> See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. - [x] Added/updated tests - [x] Manual QA for all new/changed functionality
This commit is contained in:
parent
d6bd7050c7
commit
25ecc72ab9
4 changed files with 111 additions and 55 deletions
|
|
@ -86,6 +86,7 @@ func NewService(
|
|||
MDMWindowsEnableOSUpdates: eeservice.mdmWindowsEnableOSUpdates,
|
||||
MDMWindowsDisableOSUpdates: eeservice.mdmWindowsDisableOSUpdates,
|
||||
MDMAppleEditedAppleOSUpdates: eeservice.mdmAppleEditedAppleOSUpdates,
|
||||
SetupExperienceNextStep: eeservice.SetupExperienceNextStep,
|
||||
})
|
||||
|
||||
return eeservice, nil
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ type EnterpriseOverrides struct {
|
|||
MDMWindowsEnableOSUpdates func(ctx context.Context, teamID *uint, updates WindowsUpdates) error
|
||||
MDMWindowsDisableOSUpdates func(ctx context.Context, teamID *uint) error
|
||||
MDMAppleEditedAppleOSUpdates func(ctx context.Context, teamID *uint, appleDevice AppleDevice, updates AppleOSUpdateSettings) error
|
||||
SetupExperienceNextStep func(ctx context.Context, hostUUID string) (bool, error)
|
||||
}
|
||||
|
||||
type OsqueryService interface {
|
||||
|
|
|
|||
|
|
@ -1478,6 +1478,7 @@ func (s *integrationMDMTestSuite) TestSetupExperienceFlowWithSoftwareAndScriptAu
|
|||
|
||||
// simulate fleetd being installed and the host being orbit-enrolled now
|
||||
enrolledHost.OsqueryHostID = ptr.String(mdmDevice.UUID)
|
||||
enrolledHost.UUID = mdmDevice.UUID
|
||||
orbitKey := setOrbitEnrollment(t, enrolledHost, s.ds)
|
||||
enrolledHost.OrbitNodeKey = &orbitKey
|
||||
|
||||
|
|
@ -1516,74 +1517,127 @@ func (s *integrationMDMTestSuite) TestSetupExperienceFlowWithSoftwareAndScriptAu
|
|||
require.NoError(t, err)
|
||||
require.Nil(t, cmd)
|
||||
|
||||
// TODO(mna): here we should call the "state machine" to trigger creation of
|
||||
// the software install and script execution requests, but that is not
|
||||
// implemented yet.
|
||||
statusResp = getOrbitSetupExperienceStatusResponse{}
|
||||
s.DoJSON("POST", "/api/fleet/orbit/setup_experience/status", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *enrolledHost.OrbitNodeKey)), http.StatusOK, &statusResp)
|
||||
// Software is now running, script is still pending
|
||||
require.Equal(t, "DummyApp.app", statusResp.Results.Software[0].Name)
|
||||
require.Equal(t, fleet.SetupExperienceStatusRunning, statusResp.Results.Software[0].Status)
|
||||
require.NotNil(t, statusResp.Results.Software[0].SoftwareTitleID)
|
||||
require.NotZero(t, *statusResp.Results.Software[0].SoftwareTitleID)
|
||||
|
||||
// TODO(mna): when callback of software/script results are implemented, this will
|
||||
// automatically update the /status responses, and once everything has run it will
|
||||
// automatically release the device.
|
||||
require.NotNil(t, statusResp.Results.Script)
|
||||
require.Equal(t, "script.sh", statusResp.Results.Script.Name)
|
||||
require.Equal(t, fleet.SetupExperienceStatusPending, statusResp.Results.Script.Status)
|
||||
|
||||
// The /setup_experience/status endpoint doesn't return the various IDs for executions, so pull
|
||||
// it out manually
|
||||
results, err := s.ds.ListSetupExperienceResultsByHostUUID(ctx, enrolledHost.UUID)
|
||||
require.Len(t, results, 2)
|
||||
require.NoError(t, err)
|
||||
var installUUID string
|
||||
for _, r := range results {
|
||||
if r.HostSoftwareInstallsExecutionID != nil {
|
||||
installUUID = *r.HostSoftwareInstallsExecutionID
|
||||
}
|
||||
}
|
||||
|
||||
require.NotEmpty(t, installUUID)
|
||||
|
||||
// record a result for software installation
|
||||
/*
|
||||
var installResp orbitPostSoftwareInstallResultResponse
|
||||
s.DoJSON("POST", "/api/fleet/orbit/software_install/result",
|
||||
json.RawMessage(fmt.Sprintf(`{
|
||||
s.Do("POST", "/api/fleet/orbit/software_install/result",
|
||||
json.RawMessage(fmt.Sprintf(`{
|
||||
"orbit_node_key": %q,
|
||||
"install_uuid": %q,
|
||||
"install_script_exit_code": 0,
|
||||
"install_script_output": "ok"
|
||||
}`, *enrolledHost.OrbitNodeKey, installUUID)), http.StatusOK, &installResp)
|
||||
}`, *enrolledHost.OrbitNodeKey, installUUID)), http.StatusNoContent)
|
||||
|
||||
// status still shows script as pending
|
||||
statusResp = getOrbitSetupExperienceStatusResponse{}
|
||||
s.DoJSON("POST", "/api/fleet/orbit/setup_experience/status", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *enrolledHost.OrbitNodeKey)), http.StatusOK, &statusResp)
|
||||
require.Nil(t, statusResp.Results.BootstrapPackage) // no bootstrap package involved
|
||||
require.Nil(t, statusResp.Results.AccountConfiguration) // no SSO involved
|
||||
require.Len(t, statusResp.Results.ConfigurationProfiles, 3) // fleetd config, root CA, custom profile
|
||||
require.NotNil(t, statusResp.Results.Script)
|
||||
require.Equal(t, "script.sh", statusResp.Results.Script.Name)
|
||||
require.Equal(t, fleet.SetupExperienceStatusPending, statusResp.Results.Script.Status)
|
||||
require.Len(t, statusResp.Results.Software, 1)
|
||||
require.Equal(t, "DummyApp.app", statusResp.Results.Software[0].Name)
|
||||
require.Equal(t, fleet.SetupExperienceStatusSuccess, statusResp.Results.Software[0].Status)
|
||||
// status still shows script as pending
|
||||
statusResp = getOrbitSetupExperienceStatusResponse{}
|
||||
s.DoJSON("POST", "/api/fleet/orbit/setup_experience/status", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *enrolledHost.OrbitNodeKey)), http.StatusOK, &statusResp)
|
||||
require.Nil(t, statusResp.Results.BootstrapPackage) // no bootstrap package involved
|
||||
require.Nil(t, statusResp.Results.AccountConfiguration) // no SSO involved
|
||||
require.Len(t, statusResp.Results.ConfigurationProfiles, 3) // fleetd config, root CA, custom profile
|
||||
require.NotNil(t, statusResp.Results.Script)
|
||||
require.Equal(t, "script.sh", statusResp.Results.Script.Name)
|
||||
require.Equal(t, fleet.SetupExperienceStatusPending, statusResp.Results.Script.Status)
|
||||
require.Len(t, statusResp.Results.Software, 1)
|
||||
require.Equal(t, "DummyApp.app", statusResp.Results.Software[0].Name)
|
||||
require.Equal(t, fleet.SetupExperienceStatusSuccess, statusResp.Results.Software[0].Status)
|
||||
|
||||
// no MDM command got enqueued due to the /status call (device not released yet)
|
||||
cmd, err = mdmDevice.Idle()
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, cmd)
|
||||
// no MDM command got enqueued due to the /status call (device not released yet)
|
||||
cmd, err = mdmDevice.Idle()
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, cmd)
|
||||
|
||||
// record a result for script execution
|
||||
var scriptResp orbitPostScriptResultResponse
|
||||
s.DoJSON("POST", "/api/fleet/orbit/scripts/result",
|
||||
json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q, "execution_id": %q, "exit_code": 0, "output": "ok"}`, *enrolledHost.OrbitNodeKey, execID)),
|
||||
http.StatusOK, &scriptResp)
|
||||
// Software is installed, now we should run the script
|
||||
statusResp = getOrbitSetupExperienceStatusResponse{}
|
||||
s.DoJSON("POST", "/api/fleet/orbit/setup_experience/status", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *enrolledHost.OrbitNodeKey)), http.StatusOK, &statusResp)
|
||||
// Software is now running, script is still pending
|
||||
require.Equal(t, "DummyApp.app", statusResp.Results.Software[0].Name)
|
||||
require.Equal(t, fleet.SetupExperienceStatusSuccess, statusResp.Results.Software[0].Status)
|
||||
require.NotNil(t, statusResp.Results.Software[0].SoftwareTitleID)
|
||||
require.NotZero(t, *statusResp.Results.Software[0].SoftwareTitleID)
|
||||
|
||||
// check that the host received the device configured command automatically
|
||||
cmd, err = mdmDevice.Idle()
|
||||
require.NoError(t, err)
|
||||
cmds = cmds[:0]
|
||||
for cmd != nil {
|
||||
var fullCmd micromdm.CommandPayload
|
||||
require.NoError(t, plist.Unmarshal(cmd.Raw, &fullCmd))
|
||||
cmds = append(cmds, &fullCmd)
|
||||
cmd, err = mdmDevice.Acknowledge(cmd.CommandUUID)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, statusResp.Results.Script)
|
||||
require.Equal(t, "script.sh", statusResp.Results.Script.Name)
|
||||
require.Equal(t, fleet.SetupExperienceStatusRunning, statusResp.Results.Script.Status)
|
||||
|
||||
// Get script exec ID
|
||||
results, err = s.ds.ListSetupExperienceResultsByHostUUID(ctx, enrolledHost.UUID)
|
||||
require.Len(t, results, 2)
|
||||
require.NoError(t, err)
|
||||
var execID string
|
||||
for _, r := range results {
|
||||
if r.ScriptExecutionID != nil {
|
||||
execID = *r.ScriptExecutionID
|
||||
}
|
||||
}
|
||||
|
||||
require.Len(t, cmds, 1)
|
||||
var deviceConfiguredCount int
|
||||
for _, cmd := range cmds {
|
||||
switch cmd.Command.RequestType {
|
||||
case "DeviceConfigured":
|
||||
deviceConfiguredCount++
|
||||
default:
|
||||
otherCount++
|
||||
}
|
||||
// record a result for script execution
|
||||
var scriptResp orbitPostScriptResultResponse
|
||||
s.DoJSON("POST", "/api/fleet/orbit/scripts/result",
|
||||
json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q, "execution_id": %q, "exit_code": 0, "output": "ok"}`, *enrolledHost.OrbitNodeKey, execID)),
|
||||
http.StatusOK, &scriptResp)
|
||||
|
||||
// Get status again, now the script should be complete. This should also trigger the automatic
|
||||
// release of the device, as all setup experience steps are now complete.
|
||||
statusResp = getOrbitSetupExperienceStatusResponse{}
|
||||
s.DoJSON("POST", "/api/fleet/orbit/setup_experience/status", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *enrolledHost.OrbitNodeKey)), http.StatusOK, &statusResp)
|
||||
// Software is now running, script is still pending
|
||||
require.Equal(t, "DummyApp.app", statusResp.Results.Software[0].Name)
|
||||
require.Equal(t, fleet.SetupExperienceStatusSuccess, statusResp.Results.Software[0].Status)
|
||||
require.NotNil(t, statusResp.Results.Software[0].SoftwareTitleID)
|
||||
require.NotZero(t, *statusResp.Results.Software[0].SoftwareTitleID)
|
||||
|
||||
require.NotNil(t, statusResp.Results.Script)
|
||||
require.Equal(t, "script.sh", statusResp.Results.Script.Name)
|
||||
require.Equal(t, fleet.SetupExperienceStatusSuccess, statusResp.Results.Script.Status)
|
||||
|
||||
// check that the host received the device configured command automatically
|
||||
cmd, err = mdmDevice.Idle()
|
||||
require.NoError(t, err)
|
||||
cmds = cmds[:0]
|
||||
for cmd != nil {
|
||||
var fullCmd micromdm.CommandPayload
|
||||
require.NoError(t, plist.Unmarshal(cmd.Raw, &fullCmd))
|
||||
cmds = append(cmds, &fullCmd)
|
||||
cmd, err = mdmDevice.Acknowledge(cmd.CommandUUID)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
require.Len(t, cmds, 1)
|
||||
var deviceConfiguredCount int
|
||||
for _, cmd := range cmds {
|
||||
switch cmd.Command.RequestType {
|
||||
case "DeviceConfigured":
|
||||
deviceConfiguredCount++
|
||||
default:
|
||||
otherCount++
|
||||
}
|
||||
require.Equal(t, 1, deviceConfiguredCount)
|
||||
require.Equal(t, 0, otherCount)
|
||||
*/
|
||||
}
|
||||
require.Equal(t, 1, deviceConfiguredCount)
|
||||
require.Equal(t, 0, otherCount)
|
||||
}
|
||||
|
||||
func (s *integrationMDMTestSuite) TestSetupExperienceFlowWithSoftwareAndScriptForceRelease() {
|
||||
|
|
|
|||
|
|
@ -712,7 +712,7 @@ func (svc *Service) SaveHostScriptResult(ctx context.Context, result *fleet.Host
|
|||
return ctxerr.Wrap(ctx, err, "update setup experience status")
|
||||
} else if updated {
|
||||
level.Debug(svc.logger).Log("msg", "setup experience script result updated", "host_uuid", host.UUID, "execution_id", result.ExecutionID)
|
||||
_, err := svc.SetupExperienceNextStep(ctx, host.UUID)
|
||||
_, err := svc.EnterpriseOverrides.SetupExperienceNextStep(ctx, host.UUID)
|
||||
if err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "getting next step for host setup experience")
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue