github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/jobs/schedulers_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  package jobs
     4  
     5  import (
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  
    12  	"github.com/masterhung0112/hk_server/v5/einterfaces/mocks"
    13  	"github.com/masterhung0112/hk_server/v5/model"
    14  	"github.com/masterhung0112/hk_server/v5/plugin/plugintest/mock"
    15  	"github.com/masterhung0112/hk_server/v5/store/storetest/mockstore"
    16  	"github.com/masterhung0112/hk_server/v5/utils/testutils"
    17  )
    18  
    19  type MockScheduler struct {
    20  	mock.Mock
    21  }
    22  
    23  func (scheduler *MockScheduler) Enabled(cfg *model.Config) bool {
    24  	return true
    25  }
    26  
    27  func (scheduler *MockScheduler) Name() string {
    28  	return "MockScheduler"
    29  }
    30  
    31  func (scheduler *MockScheduler) JobType() string {
    32  	return model.JOB_TYPE_DATA_RETENTION
    33  }
    34  
    35  func (scheduler *MockScheduler) NextScheduleTime(cfg *model.Config, now time.Time, pendingJobs bool, lastSuccessfulJob *model.Job) *time.Time {
    36  	nextTime := time.Now().Add(60 * time.Second)
    37  	return &nextTime
    38  }
    39  
    40  func (scheduler *MockScheduler) ScheduleJob(cfg *model.Config, pendingJobs bool, lastSuccessfulJob *model.Job) (*model.Job, *model.AppError) {
    41  	return nil, nil
    42  }
    43  
    44  func TestScheduler(t *testing.T) {
    45  	mockStore := &mockstore.Store{}
    46  	defer mockStore.AssertExpectations(t)
    47  
    48  	job := &model.Job{
    49  		Id:       model.NewId(),
    50  		CreateAt: model.GetMillis(),
    51  		Status:   model.JOB_STATUS_PENDING,
    52  		Type:     model.JOB_TYPE_MESSAGE_EXPORT,
    53  	}
    54  	// mock job store doesn't return a previously successful job, forcing fallback to config
    55  	mockStore.JobStore.On("GetNewestJobByStatusesAndType", mock.AnythingOfType("[]string"), mock.AnythingOfType("string")).Return(job, nil)
    56  	mockStore.JobStore.On("GetCountByStatusAndType", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(int64(1), nil)
    57  
    58  	jobServer := &JobServer{
    59  		Store: mockStore,
    60  		ConfigService: &testutils.StaticConfigService{
    61  			Cfg: &model.Config{
    62  				// mock config
    63  				DataRetentionSettings: *&model.DataRetentionSettings{
    64  					EnableMessageDeletion: model.NewBool(true),
    65  				},
    66  				MessageExportSettings: *&model.MessageExportSettings{
    67  					EnableExport: model.NewBool(true),
    68  				},
    69  			},
    70  		},
    71  	}
    72  
    73  	jobInterface := new(mocks.DataRetentionJobInterface)
    74  	jobInterface.On("MakeScheduler").Return(new(MockScheduler))
    75  	jobServer.DataRetentionJob = jobInterface
    76  
    77  	exportInterface := new(mocks.MessageExportJobInterface)
    78  	exportInterface.On("MakeScheduler").Return(new(MockScheduler))
    79  	jobServer.MessageExportJob = exportInterface
    80  
    81  	t.Run("Base", func(t *testing.T) {
    82  		jobServer.InitSchedulers()
    83  		jobServer.StartSchedulers()
    84  		time.Sleep(time.Second)
    85  
    86  		jobServer.StopSchedulers()
    87  		// They should be all on here
    88  		for _, element := range jobServer.schedulers.nextRunTimes {
    89  			assert.NotNil(t, element)
    90  		}
    91  	})
    92  
    93  	t.Run("ClusterLeaderChanged", func(t *testing.T) {
    94  		jobServer.InitSchedulers()
    95  		jobServer.StartSchedulers()
    96  		time.Sleep(time.Second)
    97  		jobServer.HandleClusterLeaderChange(false)
    98  		jobServer.StopSchedulers()
    99  		// They should be turned off
   100  		for _, element := range jobServer.schedulers.nextRunTimes {
   101  			assert.Nil(t, element)
   102  		}
   103  	})
   104  
   105  	t.Run("ClusterLeaderChangedBeforeStart", func(t *testing.T) {
   106  		jobServer.InitSchedulers()
   107  		jobServer.HandleClusterLeaderChange(false)
   108  		jobServer.StartSchedulers()
   109  		time.Sleep(time.Second)
   110  		jobServer.StopSchedulers()
   111  		for _, element := range jobServer.schedulers.nextRunTimes {
   112  			assert.Nil(t, element)
   113  		}
   114  	})
   115  
   116  	t.Run("DoubleClusterLeaderChangedBeforeStart", func(t *testing.T) {
   117  		jobServer.InitSchedulers()
   118  		jobServer.HandleClusterLeaderChange(false)
   119  		jobServer.HandleClusterLeaderChange(true)
   120  		jobServer.StartSchedulers()
   121  		time.Sleep(time.Second)
   122  		jobServer.StopSchedulers()
   123  		for _, element := range jobServer.schedulers.nextRunTimes {
   124  			assert.NotNil(t, element)
   125  		}
   126  	})
   127  	t.Run("ConfigChanged", func(t *testing.T) {
   128  		jobServer.InitSchedulers()
   129  		jobServer.StartSchedulers()
   130  		time.Sleep(time.Second)
   131  		jobServer.HandleClusterLeaderChange(false)
   132  		// After running a config change, they should stay off
   133  		jobServer.schedulers.handleConfigChange(nil, nil)
   134  		jobServer.StopSchedulers()
   135  		for _, element := range jobServer.schedulers.nextRunTimes {
   136  			assert.Nil(t, element)
   137  		}
   138  	})
   139  
   140  	t.Run("ConfigChangedDeadlock", func(t *testing.T) {
   141  		jobServer.InitSchedulers()
   142  		jobServer.StartSchedulers()
   143  		time.Sleep(time.Second)
   144  
   145  		var wg sync.WaitGroup
   146  		wg.Add(2)
   147  		go func() {
   148  			defer wg.Done()
   149  			jobServer.StopSchedulers()
   150  		}()
   151  		go func() {
   152  			defer wg.Done()
   153  			jobServer.schedulers.handleConfigChange(nil, nil)
   154  		}()
   155  
   156  		wg.Wait()
   157  	})
   158  }