github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/job/mem_scheduler_test.go (about)

     1  package job_test
     2  
     3  import (
     4  	"context"
     5  	"sync/atomic"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/cozy/cozy-stack/model/job"
    10  	"github.com/cozy/cozy-stack/pkg/config/config"
    11  	"github.com/cozy/cozy-stack/pkg/couchdb"
    12  	"github.com/cozy/cozy-stack/pkg/realtime"
    13  	"github.com/cozy/cozy-stack/tests/testutils"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestMemScheduler(t *testing.T) {
    19  	if testing.Short() {
    20  		t.Skip("an instance is required for this test: test skipped due to the use of --short flag")
    21  	}
    22  
    23  	config.UseTestFile(t)
    24  	setup := testutils.NewSetup(t, t.Name())
    25  	testInstance := setup.GetTestInstance()
    26  
    27  	t.Run("TriggersBadArguments", func(t *testing.T) {
    28  		var err error
    29  		_, err = job.NewTrigger(testInstance, job.TriggerInfos{
    30  			Type:      "@at",
    31  			Arguments: "garbage",
    32  		}, nil)
    33  		assert.Error(t, err)
    34  
    35  		_, err = job.NewTrigger(testInstance, job.TriggerInfos{
    36  			Type:      "@in",
    37  			Arguments: "garbage",
    38  		}, nil)
    39  		assert.Error(t, err)
    40  
    41  		_, err = job.NewTrigger(testInstance, job.TriggerInfos{
    42  			Type:      "@unknown",
    43  			Arguments: "",
    44  		}, nil)
    45  		if assert.Error(t, err) {
    46  			assert.Equal(t, job.ErrUnknownTrigger, err)
    47  		}
    48  	})
    49  
    50  	t.Run("MemSchedulerWithDebounce", func(t *testing.T) {
    51  		var called int32
    52  		bro := job.NewMemBroker()
    53  		assert.NoError(t, bro.StartWorkers(job.WorkersList{
    54  			{
    55  				WorkerType:   "worker",
    56  				Concurrency:  1,
    57  				MaxExecCount: 1,
    58  				Timeout:      1 * time.Millisecond,
    59  				WorkerFunc: func(_ *job.TaskContext) error {
    60  					atomic.AddInt32(&called, 1)
    61  					return nil
    62  				},
    63  			},
    64  		}))
    65  
    66  		msg, _ := job.NewMessage("@event")
    67  		ti := job.TriggerInfos{
    68  			Type:       "@event",
    69  			Arguments:  "io.cozy.testdebounce io.cozy.moredebounce",
    70  			Debounce:   "2s",
    71  			WorkerType: "worker",
    72  			Message:    msg,
    73  		}
    74  
    75  		var triggers []job.Trigger
    76  		triggersInfos := []job.TriggerInfos{ti}
    77  		sch := job.NewMemScheduler()
    78  		if !assert.NoError(t, sch.StartScheduler(bro)) {
    79  			return
    80  		}
    81  
    82  		// Clear the existing triggers before testing with our triggers
    83  		ts, err := sch.GetAllTriggers(testInstance)
    84  		assert.NoError(t, err)
    85  		for _, trigger := range ts {
    86  			err = sch.DeleteTrigger(testInstance, trigger.ID())
    87  			assert.NoError(t, err)
    88  		}
    89  
    90  		for _, infos := range triggersInfos {
    91  			trigger, err := job.NewTrigger(testInstance, infos, msg)
    92  			require.NoError(t, err)
    93  
    94  			err = sch.AddTrigger(trigger)
    95  			require.NoError(t, err)
    96  
    97  			triggers = append(triggers, trigger)
    98  		}
    99  
   100  		ts, err = sch.GetAllTriggers(testInstance)
   101  		assert.NoError(t, err)
   102  		assert.Len(t, ts, len(triggers))
   103  
   104  		doc := &couchdb.JSONDoc{
   105  			Type: "io.cozy.testdebounce",
   106  			M: map[string]interface{}{
   107  				"_id":  "test-id",
   108  				"_rev": "1-xxabxx",
   109  				"test": "value",
   110  			},
   111  		}
   112  
   113  		for i := 0; i < 24; i++ {
   114  			time.Sleep(200 * time.Millisecond)
   115  			realtime.GetHub().Publish(testInstance, realtime.EventCreate, doc, nil)
   116  		}
   117  
   118  		time.Sleep(3000 * time.Millisecond)
   119  		assert.Equal(t, int32(3), atomic.LoadInt32(&called))
   120  
   121  		doc2 := doc.Clone().(*couchdb.JSONDoc)
   122  		doc2.Type = "io.cozy.moredebounce"
   123  		realtime.GetHub().Publish(testInstance, realtime.EventCreate, doc, nil)
   124  		realtime.GetHub().Publish(testInstance, realtime.EventCreate, doc2, nil)
   125  		time.Sleep(3000 * time.Millisecond)
   126  		assert.Equal(t, int32(4), atomic.LoadInt32(&called))
   127  
   128  		for _, trigger := range triggers {
   129  			err = sch.DeleteTrigger(testInstance, trigger.ID())
   130  			assert.NoError(t, err)
   131  		}
   132  
   133  		err = sch.ShutdownScheduler(context.Background())
   134  		assert.NoError(t, err)
   135  	})
   136  }