go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/_motor/providers/os/events/jobmanager_test.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package events 5 6 import ( 7 "io/ioutil" 8 "path/filepath" 9 "sync" 10 "testing" 11 "time" 12 13 "go.mondoo.com/cnquery/motor/providers/os" 14 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 "go.mondoo.com/cnquery/motor/providers" 18 "go.mondoo.com/cnquery/motor/providers/mock" 19 ) 20 21 func SetupTest() *JobManager { 22 filepath, _ := filepath.Abs("testdata/watcher_test.toml") 23 trans, _ := mock.NewFromTomlFile(filepath) 24 return NewJobManager(trans) 25 } 26 27 func TeardownTest(jm *JobManager) { 28 jm.TearDown() 29 } 30 31 func TestJobCreation(t *testing.T) { 32 jm := SetupTest() 33 jobid, err := jm.Schedule(&Job{ 34 ID: "command", 35 ScheduledFor: time.Now(), 36 Interval: time.Duration(10 * time.Second), 37 Repeat: 5, 38 Runnable: func(m os.OperatingSystemProvider) (providers.Observable, error) { 39 cmd, _ := m.RunCommand("hostname") 40 return &CommandObservable{Result: cmd}, nil 41 }, 42 Callback: []func(o providers.Observable){ 43 func(o providers.Observable) { 44 // noop 45 }, 46 }, 47 }) 48 49 assert.NotNil(t, jobid, "job is scheduled") 50 assert.Nil(t, err, "job could be scheduled without any error") 51 52 job, err := jm.GetJob(jobid) 53 assert.NotNil(t, job, "able to retrieve the job") 54 assert.Nil(t, err, "job could be retrieved without any error") 55 56 TeardownTest(jm) 57 } 58 59 func TestJobDeletion(t *testing.T) { 60 jm := SetupTest() 61 62 assert.Equal(t, 0, jm.Metrics().Jobs, "no job is scheduled") 63 64 // schedule a new job 65 jobid, err := jm.Schedule(&Job{ 66 ID: "command", 67 ScheduledFor: time.Now(), 68 Interval: time.Duration(10 * time.Second), 69 Repeat: 5, 70 Runnable: func(m os.OperatingSystemProvider) (providers.Observable, error) { 71 cmd, _ := m.RunCommand("hostname") 72 return &CommandObservable{Result: cmd}, nil 73 }, 74 Callback: []func(o providers.Observable){ 75 func(o providers.Observable) { 76 // noop 77 }, 78 }, 79 }) 80 assert.Nil(t, err, "job was scheduled without any error") 81 82 // verify that the job is stored with the ID 83 job, err := jm.GetJob(jobid) 84 assert.Nil(t, err, "job was retrieved without any error") 85 assert.NotNil(t, job, "job could be retrieved") 86 87 // cancel the job 88 jm.Delete(jobid) 89 assert.Nil(t, err, "job could be deleted without any error") 90 91 // verify that the job is not there anymore 92 job, err = jm.GetJob(jobid) 93 assert.NotNil(t, err, "job could not be retrieved") 94 assert.Nil(t, job) 95 96 assert.Equal(t, 0, jm.Metrics().Jobs, "no job is scheduled") 97 TeardownTest(jm) 98 } 99 100 func TestRejectEmptyJob(t *testing.T) { 101 jm := SetupTest() 102 103 assert.Equal(t, 0, jm.Metrics().Jobs, "no job is scheduled") 104 105 // schedule a new job 106 id, err := jm.Schedule(&Job{}) 107 assert.Equal(t, 0, len(id), "job is not scheduled") 108 assert.NotNil(t, err, "job schedule returns an error") 109 110 assert.Equal(t, 0, jm.Metrics().Jobs, "no job is scheduled") 111 TeardownTest(jm) 112 } 113 114 func TestCommandJob(t *testing.T) { 115 var wg sync.WaitGroup 116 jm := SetupTest() 117 118 var res *CommandObservable 119 wg.Add(1) 120 _, err := jm.Schedule(&Job{ 121 ID: "command-abc", 122 ScheduledFor: time.Now(), 123 Interval: time.Duration(10 * time.Second), 124 Repeat: 5, 125 Runnable: func(m os.OperatingSystemProvider) (providers.Observable, error) { 126 cmd, _ := m.RunCommand("hostname") 127 return &CommandObservable{Result: cmd}, nil 128 }, 129 Callback: []func(o providers.Observable){ 130 func(o providers.Observable) { 131 defer wg.Done() 132 switch x := o.(type) { 133 case *CommandObservable: 134 res = x 135 } 136 }, 137 }, 138 }) 139 require.NoError(t, err) 140 141 wg.Wait() 142 143 stdout, err := ioutil.ReadAll(res.Result.Stdout) 144 assert.Nil(t, err, "could extract stdout") 145 assert.Equal(t, "mockland.local", string(stdout), "get the expected command output") 146 TeardownTest(jm) 147 } 148 149 func TestFileJob(t *testing.T) { 150 var wg sync.WaitGroup 151 jm := SetupTest() 152 path := "/tmp/test" 153 var res *FileObservable 154 wg.Add(1) 155 _, err := jm.Schedule(&Job{ 156 ID: "file-abc", 157 ScheduledFor: time.Now(), 158 Interval: time.Duration(10 * time.Second), 159 Runnable: func(m os.OperatingSystemProvider) (providers.Observable, error) { 160 file, _ := m.FS().Open(path) 161 return &FileObservable{File: file, FileOp: Modify}, nil 162 }, 163 Callback: []func(o providers.Observable){ 164 func(o providers.Observable) { 165 defer wg.Done() 166 switch x := o.(type) { 167 case *FileObservable: 168 res = x 169 } 170 }, 171 }, 172 }) 173 require.NoError(t, err) 174 wg.Wait() 175 assert.Equal(t, path, res.File.Name(), "get the expected file") 176 assert.Equal(t, Modify, res.FileOp, "get the expected file event") 177 TeardownTest(jm) 178 } 179 180 func TestScheduleRepeating(t *testing.T) { 181 var wg sync.WaitGroup 182 jm := SetupTest() 183 184 var res *CommandObservable 185 186 wg.Add(2) 187 // one call is executed at the scheduled time 188 _, err := jm.Schedule(&Job{ 189 ID: "command-abc", 190 ScheduledFor: time.Now(), 191 Repeat: 1, 192 Interval: time.Duration(1), 193 Runnable: func(m os.OperatingSystemProvider) (providers.Observable, error) { 194 cmd, _ := m.RunCommand("hostname") 195 return &CommandObservable{Result: cmd}, nil 196 }, 197 Callback: []func(o providers.Observable){ 198 func(o providers.Observable) { 199 defer wg.Done() 200 201 switch x := o.(type) { 202 case *CommandObservable: 203 res = x 204 } 205 }, 206 }, 207 }) 208 assert.Nil(t, err, "job was scheduled without any error") 209 wg.Wait() 210 211 // check that the result expects the outcome 212 stdout, err := ioutil.ReadAll(res.Result.Stdout) 213 assert.Nil(t, err, "could extract stdout") 214 assert.Equal(t, "mockland.local", string(stdout), "get the expected command output") 215 TeardownTest(jm) 216 }