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  }