2021-06-06 22:07:29 +00:00
package fleet
2016-12-01 17:00:00 +00:00
import (
2023-01-03 21:45:12 +00:00
"fmt"
2016-12-01 17:00:00 +00:00
"testing"
2017-01-04 21:16:17 +00:00
"time"
2016-12-01 17:00:00 +00:00
2017-01-04 21:16:17 +00:00
"github.com/WatchBeam/clock"
2023-10-06 22:04:33 +00:00
"github.com/fleetdm/fleet/v4/server/ptr"
2016-12-01 17:00:00 +00:00
"github.com/stretchr/testify/assert"
2021-12-07 18:37:00 +00:00
"github.com/stretchr/testify/require"
2016-12-01 17:00:00 +00:00
)
2017-01-04 21:16:17 +00:00
func TestHostStatus ( t * testing . T ) {
mockClock := clock . NewMockClock ( )
2021-12-01 12:05:23 +00:00
testCases := [ ] struct {
2017-04-18 17:39:50 +00:00
seenTime time . Time
distributedInterval uint
configTLSRefresh uint
2020-03-30 02:19:54 +00:00
status HostStatus
2017-04-18 17:39:50 +00:00
} {
{ mockClock . Now ( ) . Add ( - 30 * time . Second ) , 10 , 3600 , StatusOnline } ,
2021-11-30 21:37:27 +00:00
{ mockClock . Now ( ) . Add ( - 75 * time . Second ) , 10 , 3600 , StatusOffline } ,
2017-04-18 17:39:50 +00:00
{ mockClock . Now ( ) . Add ( - 30 * time . Second ) , 3600 , 10 , StatusOnline } ,
2021-11-30 21:37:27 +00:00
{ mockClock . Now ( ) . Add ( - 75 * time . Second ) , 3600 , 10 , StatusOffline } ,
2017-04-18 17:39:50 +00:00
2021-11-30 21:37:27 +00:00
{ mockClock . Now ( ) . Add ( - 60 * time . Second ) , 60 , 60 , StatusOnline } ,
{ mockClock . Now ( ) . Add ( - 121 * time . Second ) , 60 , 60 , StatusOffline } ,
2017-04-18 17:39:50 +00:00
{ mockClock . Now ( ) . Add ( - 1 * time . Second ) , 10 , 10 , StatusOnline } ,
2021-11-30 21:37:27 +00:00
{ mockClock . Now ( ) . Add ( - 2 * time . Minute ) , 10 , 10 , StatusOffline } ,
2022-05-23 19:11:02 +00:00
{ mockClock . Now ( ) . Add ( - 31 * 24 * time . Hour ) , 10 , 10 , StatusOffline } , // As of Fleet 4.15, StatusMIA is deprecated in favor of StatusOffline
2017-04-18 17:39:50 +00:00
// Ensure behavior is reasonable if we don't have the values
{ mockClock . Now ( ) . Add ( - 1 * time . Second ) , 0 , 0 , StatusOnline } ,
2021-11-30 21:37:27 +00:00
{ mockClock . Now ( ) . Add ( - 2 * time . Minute ) , 0 , 0 , StatusOffline } ,
2022-05-23 19:11:02 +00:00
{ mockClock . Now ( ) . Add ( - 31 * 24 * time . Hour ) , 0 , 0 , StatusOffline } , // As of Fleet 4.15, StatusMIA is deprecated in favor of StatusOffline
2017-04-18 17:39:50 +00:00
}
2017-01-04 21:16:17 +00:00
2017-04-18 17:39:50 +00:00
for _ , tt := range testCases {
t . Run ( "" , func ( t * testing . T ) {
// Save interval values
h := Host {
DistributedInterval : tt . distributedInterval ,
ConfigTLSRefresh : tt . configTLSRefresh ,
SeenTime : tt . seenTime ,
}
assert . Equal ( t , tt . status , h . Status ( mockClock . Now ( ) ) )
} )
}
2017-01-04 21:16:17 +00:00
}
2017-01-20 13:57:47 +00:00
2024-03-11 16:02:51 +00:00
func TestHostStatusIsValid ( t * testing . T ) {
for _ , tt := range [ ] struct {
name string
status HostStatus
expected bool
} {
{ "online" , StatusOnline , true } ,
{ "offline" , StatusOffline , true } ,
{ "new" , StatusNew , true } ,
{ "missing" , StatusMissing , true } ,
{ "mia" , StatusMIA , true } , // As of Fleet 4.15, StatusMIA is deprecated in favor of StatusOffline
{ "empty" , HostStatus ( "" ) , false } ,
{ "invalid" , HostStatus ( "invalid" ) , false } ,
} {
t . Run ( tt . name , func ( t * testing . T ) {
assert . Equal ( t , tt . expected , tt . status . IsValid ( ) )
} )
}
}
2017-01-20 13:57:47 +00:00
func TestHostIsNew ( t * testing . T ) {
mockClock := clock . NewMockClock ( )
host := Host { }
host . CreatedAt = mockClock . Now ( ) . AddDate ( 0 , 0 , - 1 )
assert . True ( t , host . IsNew ( mockClock . Now ( ) ) )
host . CreatedAt = mockClock . Now ( ) . AddDate ( 0 , 0 , - 2 )
assert . False ( t , host . IsNew ( mockClock . Now ( ) ) )
}
2021-12-07 18:37:00 +00:00
func TestPlatformFromHost ( t * testing . T ) {
for _ , tc := range [ ] struct {
host string
expPlatform string
} {
{
host : "unknown" ,
expPlatform : "" ,
} ,
{
host : "" ,
expPlatform : "" ,
} ,
{
host : "linux" ,
expPlatform : "linux" ,
} ,
{
host : "ubuntu" ,
expPlatform : "linux" ,
} ,
{
host : "debian" ,
expPlatform : "linux" ,
} ,
{
host : "rhel" ,
expPlatform : "linux" ,
} ,
{
host : "centos" ,
expPlatform : "linux" ,
} ,
{
host : "sles" ,
expPlatform : "linux" ,
} ,
{
host : "kali" ,
expPlatform : "linux" ,
} ,
{
host : "gentoo" ,
expPlatform : "linux" ,
} ,
2024-05-29 16:54:07 +00:00
{
host : "tuxedo" ,
expPlatform : "linux" ,
} ,
2021-12-07 18:37:00 +00:00
{
host : "darwin" ,
expPlatform : "darwin" ,
} ,
{
host : "windows" ,
expPlatform : "windows" ,
} ,
} {
fleetPlatform := PlatformFromHost ( tc . host )
require . Equal ( t , tc . expPlatform , fleetPlatform )
}
}
2023-01-03 21:45:12 +00:00
func TestHostDisplayName ( t * testing . T ) {
const (
computerName = "K0mpu73rN4M3"
hostname = "h0s7N4ME"
hardwareModel = "M0D3l"
hardwareSerial = "53r14l"
)
for _ , tc := range [ ] struct {
host Host
expected string
} {
{
host : Host { ComputerName : computerName , Hostname : hostname , HardwareModel : hardwareModel , HardwareSerial : hardwareSerial } ,
expected : computerName , // If ComputerName is present, DisplayName is ComputerName
} ,
{
host : Host { ComputerName : "" , Hostname : "h0s7N4ME" , HardwareModel : "M0D3l" , HardwareSerial : "53r14l" } ,
expected : hostname , // If ComputerName is empty, DisplayName is Hostname (if present)
} ,
{
host : Host { ComputerName : "" , Hostname : "" , HardwareModel : "M0D3l" , HardwareSerial : "53r14l" } ,
expected : fmt . Sprintf ( "%s (%s)" , hardwareModel , hardwareSerial ) , // If ComputerName and Hostname are empty, DisplayName is composite of HardwareModel and HardwareSerial (if both are present)
} ,
{
host : Host { ComputerName : "" , Hostname : "" , HardwareModel : "" , HardwareSerial : hardwareSerial } ,
expected : "" , // If HarwareModel and/or HardwareSerial are empty, DisplayName is also empty
} ,
{
host : Host { ComputerName : "" , Hostname : "" , HardwareModel : hardwareModel , HardwareSerial : "" } ,
expected : "" , // If HarwareModel and/or HardwareSerial are empty, DisplayName is also empty
} ,
{
host : Host { ComputerName : "" , Hostname : "" , HardwareModel : "" , HardwareSerial : "" } ,
expected : "" , // If HarwareModel and/or HardwareSerial are empty, DisplayName is also empty
} ,
} {
require . Equal ( t , tc . expected , tc . host . DisplayName ( ) )
}
}
2023-01-05 21:52:46 +00:00
func TestMDMEnrollmentStatus ( t * testing . T ) {
for _ , tc := range [ ] struct {
hostMDM HostMDM
expected string
} {
{
hostMDM : HostMDM { Enrolled : true , InstalledFromDep : true } ,
expected : "On (automatic)" ,
} ,
{
hostMDM : HostMDM { Enrolled : true , InstalledFromDep : false } ,
expected : "On (manual)" ,
} ,
{
hostMDM : HostMDM { Enrolled : false , InstalledFromDep : true } ,
expected : "Pending" ,
} ,
{
hostMDM : HostMDM { Enrolled : false , InstalledFromDep : false } ,
expected : "Off" ,
} ,
} {
require . Equal ( t , tc . expected , tc . hostMDM . EnrollmentStatus ( ) )
}
}
2023-05-15 20:00:52 +00:00
2024-04-08 14:10:29 +00:00
func TestIsEligibleForDEPMigration ( t * testing . T ) {
testCases := [ ] struct {
name string
osqueryHostID * string
depAssignedToFleet * bool
depProfileResponse DEPAssignProfileResponseStatus
enrolledInThirdPartyMDM bool
expected bool
2024-08-08 19:46:42 +00:00
expectedManual bool
2024-08-13 20:14:35 +00:00
hostOS string
2024-04-08 14:10:29 +00:00
} {
{
name : "Eligible for DEP migration" ,
osqueryHostID : ptr . String ( "some-id" ) ,
depAssignedToFleet : ptr . Bool ( true ) ,
depProfileResponse : DEPAssignProfileResponseSuccess ,
enrolledInThirdPartyMDM : true ,
expected : true ,
2024-08-08 19:46:42 +00:00
expectedManual : false ,
2024-04-08 14:10:29 +00:00
} ,
{
name : "Not eligible - osqueryHostID nil" ,
osqueryHostID : nil ,
depAssignedToFleet : ptr . Bool ( true ) ,
depProfileResponse : DEPAssignProfileResponseSuccess ,
enrolledInThirdPartyMDM : true ,
expected : false ,
2024-08-08 19:46:42 +00:00
expectedManual : false ,
2024-04-08 14:10:29 +00:00
} ,
{
name : "Not eligible - not DEP assigned to Fleet" ,
osqueryHostID : ptr . String ( "some-id" ) ,
depAssignedToFleet : ptr . Bool ( false ) ,
depProfileResponse : DEPAssignProfileResponseSuccess ,
enrolledInThirdPartyMDM : true ,
expected : false ,
2024-08-08 19:46:42 +00:00
expectedManual : false ,
2024-04-08 14:10:29 +00:00
} ,
{
name : "Not eligible - not enrolled in third-party MDM" ,
osqueryHostID : ptr . String ( "some-id" ) ,
depAssignedToFleet : ptr . Bool ( true ) ,
depProfileResponse : DEPAssignProfileResponseSuccess ,
enrolledInThirdPartyMDM : false ,
expected : false ,
2024-08-08 19:46:42 +00:00
expectedManual : false ,
2024-04-08 14:10:29 +00:00
} ,
{
name : "Not eligible - not DEP assigned and DEP profile failed" ,
osqueryHostID : ptr . String ( "some-id" ) ,
depAssignedToFleet : ptr . Bool ( false ) ,
depProfileResponse : DEPAssignProfileResponseNotAccessible ,
enrolledInThirdPartyMDM : true ,
expected : false ,
2024-08-08 19:46:42 +00:00
expectedManual : true ,
2024-08-13 20:14:35 +00:00
hostOS : "macOS 14.5" ,
2024-04-08 14:10:29 +00:00
} ,
{
name : "Not eligible - DEP assigned and DEP profile failed" ,
osqueryHostID : ptr . String ( "some-id" ) ,
depAssignedToFleet : ptr . Bool ( true ) ,
depProfileResponse : DEPAssignProfileResponseFailed ,
enrolledInThirdPartyMDM : true ,
expected : false ,
2024-08-08 19:46:42 +00:00
expectedManual : false ,
2024-04-08 14:10:29 +00:00
} ,
{
name : "Not eligible - DEP assigned but not response yet" ,
osqueryHostID : ptr . String ( "some-id" ) ,
depAssignedToFleet : ptr . Bool ( true ) ,
depProfileResponse : "" ,
enrolledInThirdPartyMDM : true ,
expected : false ,
2024-08-08 19:46:42 +00:00
expectedManual : false ,
2024-04-08 14:10:29 +00:00
} ,
{
name : "Not eligible - DEP assigned but not accessible" ,
osqueryHostID : ptr . String ( "some-id" ) ,
depAssignedToFleet : ptr . Bool ( true ) ,
depProfileResponse : DEPAssignProfileResponseNotAccessible ,
enrolledInThirdPartyMDM : true ,
expected : false ,
2024-08-08 19:46:42 +00:00
expectedManual : false ,
} ,
{
name : "Manual migration eligible - enrolled in 3rd party, but not DEP" ,
osqueryHostID : ptr . String ( "some-id" ) ,
depAssignedToFleet : ptr . Bool ( false ) ,
depProfileResponse : "" ,
enrolledInThirdPartyMDM : true ,
expected : false ,
expectedManual : true ,
2024-08-13 20:14:35 +00:00
hostOS : "macOS 14.5" ,
} ,
{
name : "Manual migration ineligible - enrolled in 3rd party, not DEP, but OS version too low" ,
osqueryHostID : ptr . String ( "some-id" ) ,
depAssignedToFleet : ptr . Bool ( false ) ,
depProfileResponse : "" ,
enrolledInThirdPartyMDM : true ,
expected : false ,
expectedManual : false ,
hostOS : "macOS 13.9" ,
2024-04-08 14:10:29 +00:00
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
host := & Host {
OsqueryHostID : tc . osqueryHostID ,
DEPAssignedToFleet : tc . depAssignedToFleet ,
2024-08-13 20:14:35 +00:00
OSVersion : tc . hostOS ,
2024-04-08 14:10:29 +00:00
}
2024-06-28 15:09:22 +00:00
mdmInfo := & HostMDM {
Enrolled : tc . enrolledInThirdPartyMDM ,
Name : "Some MDM" ,
DEPProfileAssignStatus : ptr . String ( string ( tc . depProfileResponse ) ) ,
}
require . Equal ( t , tc . expected , IsEligibleForDEPMigration ( host , mdmInfo , false ) )
2024-08-13 20:14:35 +00:00
manual , err := IsEligibleForManualMigration ( host , mdmInfo , false )
require . NoError ( t , err )
require . Equal ( t , tc . expectedManual , manual )
2024-04-08 14:10:29 +00:00
} )
}
}
func TestHasJSONProfileAssigned ( t * testing . T ) {
testCases := [ ] struct {
name string
hostMDM * HostMDM
expected bool
} {
{
name : "nil HostMDM" ,
hostMDM : nil ,
expected : false ,
} ,
{
name : "nil DEPProfileAssignStatus" ,
hostMDM : & HostMDM {
DEPProfileAssignStatus : nil ,
} ,
expected : false ,
} ,
{
name : "DEPProfileAssignStatus not successful" ,
hostMDM : & HostMDM {
DEPProfileAssignStatus : new ( string ) ,
} ,
expected : false ,
} ,
{
name : "DEPProfileAssignStatus successful" ,
hostMDM : & HostMDM {
DEPProfileAssignStatus : ptr . String ( string ( DEPAssignProfileResponseSuccess ) ) ,
} ,
expected : true ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
result := tc . hostMDM . HasJSONProfileAssigned ( )
require . Equal ( t , tc . expected , result )
} )
}
}