github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/store/storetest/job_store.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package storetest
     5  
     6  import (
     7  	"errors"
     8  	"testing"
     9  
    10  	"time"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/mattermost/mattermost-server/v5/model"
    16  	"github.com/mattermost/mattermost-server/v5/store"
    17  )
    18  
    19  func TestJobStore(t *testing.T, ss store.Store) {
    20  	t.Run("JobSaveGet", func(t *testing.T) { testJobSaveGet(t, ss) })
    21  	t.Run("JobGetAllByType", func(t *testing.T) { testJobGetAllByType(t, ss) })
    22  	t.Run("JobGetAllByTypePage", func(t *testing.T) { testJobGetAllByTypePage(t, ss) })
    23  	t.Run("JobGetAllPage", func(t *testing.T) { testJobGetAllPage(t, ss) })
    24  	t.Run("JobGetAllByStatus", func(t *testing.T) { testJobGetAllByStatus(t, ss) })
    25  	t.Run("GetNewestJobByStatusAndType", func(t *testing.T) { testJobStoreGetNewestJobByStatusAndType(t, ss) })
    26  	t.Run("GetNewestJobByStatusesAndType", func(t *testing.T) { testJobStoreGetNewestJobByStatusesAndType(t, ss) })
    27  	t.Run("GetCountByStatusAndType", func(t *testing.T) { testJobStoreGetCountByStatusAndType(t, ss) })
    28  	t.Run("JobUpdateOptimistically", func(t *testing.T) { testJobUpdateOptimistically(t, ss) })
    29  	t.Run("JobUpdateStatusUpdateStatusOptimistically", func(t *testing.T) { testJobUpdateStatusUpdateStatusOptimistically(t, ss) })
    30  	t.Run("JobDelete", func(t *testing.T) { testJobDelete(t, ss) })
    31  }
    32  
    33  func testJobSaveGet(t *testing.T, ss store.Store) {
    34  	job := &model.Job{
    35  		Id:     model.NewId(),
    36  		Type:   model.NewId(),
    37  		Status: model.NewId(),
    38  		Data: map[string]string{
    39  			"Processed":     "0",
    40  			"Total":         "12345",
    41  			"LastProcessed": "abcd",
    42  		},
    43  	}
    44  
    45  	_, err := ss.Job().Save(job)
    46  	require.NoError(t, err)
    47  
    48  	defer ss.Job().Delete(job.Id)
    49  
    50  	received, err := ss.Job().Get(job.Id)
    51  	require.NoError(t, err)
    52  	require.Equal(t, job.Id, received.Id, "received incorrect job after save")
    53  	require.Equal(t, "12345", received.Data["Total"])
    54  }
    55  
    56  func testJobGetAllByType(t *testing.T, ss store.Store) {
    57  	jobType := model.NewId()
    58  
    59  	jobs := []*model.Job{
    60  		{
    61  			Id:   model.NewId(),
    62  			Type: jobType,
    63  		},
    64  		{
    65  			Id:   model.NewId(),
    66  			Type: jobType,
    67  		},
    68  		{
    69  			Id:   model.NewId(),
    70  			Type: model.NewId(),
    71  		},
    72  	}
    73  
    74  	for _, job := range jobs {
    75  		_, err := ss.Job().Save(job)
    76  		require.NoError(t, err)
    77  		defer ss.Job().Delete(job.Id)
    78  	}
    79  
    80  	received, err := ss.Job().GetAllByType(jobType)
    81  	require.NoError(t, err)
    82  	require.Len(t, received, 2)
    83  	require.ElementsMatch(t, []string{jobs[0].Id, jobs[1].Id}, []string{received[0].Id, received[1].Id})
    84  }
    85  
    86  func testJobGetAllByTypePage(t *testing.T, ss store.Store) {
    87  	jobType := model.NewId()
    88  
    89  	jobs := []*model.Job{
    90  		{
    91  			Id:       model.NewId(),
    92  			Type:     jobType,
    93  			CreateAt: 1000,
    94  		},
    95  		{
    96  			Id:       model.NewId(),
    97  			Type:     jobType,
    98  			CreateAt: 999,
    99  		},
   100  		{
   101  			Id:       model.NewId(),
   102  			Type:     jobType,
   103  			CreateAt: 1001,
   104  		},
   105  		{
   106  			Id:       model.NewId(),
   107  			Type:     model.NewId(),
   108  			CreateAt: 1002,
   109  		},
   110  	}
   111  
   112  	for _, job := range jobs {
   113  		_, err := ss.Job().Save(job)
   114  		require.NoError(t, err)
   115  		defer ss.Job().Delete(job.Id)
   116  	}
   117  
   118  	received, err := ss.Job().GetAllByTypePage(jobType, 0, 2)
   119  	require.NoError(t, err)
   120  	require.Len(t, received, 2)
   121  	require.Equal(t, received[0].Id, jobs[2].Id, "should've received newest job first")
   122  	require.Equal(t, received[1].Id, jobs[0].Id, "should've received second newest job second")
   123  
   124  	received, err = ss.Job().GetAllByTypePage(jobType, 2, 2)
   125  	require.NoError(t, err)
   126  	require.Len(t, received, 1)
   127  	require.Equal(t, received[0].Id, jobs[1].Id, "should've received oldest job last")
   128  }
   129  
   130  func testJobGetAllPage(t *testing.T, ss store.Store) {
   131  	jobType := model.NewId()
   132  	createAtTime := model.GetMillis()
   133  
   134  	jobs := []*model.Job{
   135  		{
   136  			Id:       model.NewId(),
   137  			Type:     jobType,
   138  			CreateAt: createAtTime + 1,
   139  		},
   140  		{
   141  			Id:       model.NewId(),
   142  			Type:     jobType,
   143  			CreateAt: createAtTime,
   144  		},
   145  		{
   146  			Id:       model.NewId(),
   147  			Type:     jobType,
   148  			CreateAt: createAtTime + 2,
   149  		},
   150  	}
   151  
   152  	for _, job := range jobs {
   153  		_, err := ss.Job().Save(job)
   154  		require.NoError(t, err)
   155  		defer ss.Job().Delete(job.Id)
   156  	}
   157  
   158  	received, err := ss.Job().GetAllPage(0, 2)
   159  	require.NoError(t, err)
   160  	require.Len(t, received, 2)
   161  	require.Equal(t, received[0].Id, jobs[2].Id, "should've received newest job first")
   162  	require.Equal(t, received[1].Id, jobs[0].Id, "should've received second newest job second")
   163  
   164  	received, err = ss.Job().GetAllPage(2, 2)
   165  	require.NoError(t, err)
   166  	require.NotEmpty(t, received)
   167  	require.Equal(t, received[0].Id, jobs[1].Id, "should've received oldest job last")
   168  }
   169  
   170  func testJobGetAllByStatus(t *testing.T, ss store.Store) {
   171  	jobType := model.NewId()
   172  	status := model.NewId()
   173  
   174  	jobs := []*model.Job{
   175  		{
   176  			Id:       model.NewId(),
   177  			Type:     jobType,
   178  			CreateAt: 1000,
   179  			Status:   status,
   180  			Data: map[string]string{
   181  				"test": "data",
   182  			},
   183  		},
   184  		{
   185  			Id:       model.NewId(),
   186  			Type:     jobType,
   187  			CreateAt: 999,
   188  			Status:   status,
   189  		},
   190  		{
   191  			Id:       model.NewId(),
   192  			Type:     jobType,
   193  			CreateAt: 1001,
   194  			Status:   status,
   195  		},
   196  		{
   197  			Id:       model.NewId(),
   198  			Type:     jobType,
   199  			CreateAt: 1002,
   200  			Status:   model.NewId(),
   201  		},
   202  	}
   203  
   204  	for _, job := range jobs {
   205  		_, err := ss.Job().Save(job)
   206  		require.NoError(t, err)
   207  		defer ss.Job().Delete(job.Id)
   208  	}
   209  
   210  	received, err := ss.Job().GetAllByStatus(status)
   211  	require.NoError(t, err)
   212  	require.Len(t, received, 3)
   213  	require.Equal(t, received[0].Id, jobs[1].Id)
   214  	require.Equal(t, received[1].Id, jobs[0].Id)
   215  	require.Equal(t, received[2].Id, jobs[2].Id)
   216  	require.Equal(t, "data", received[1].Data["test"], "should've received job data field back as saved")
   217  }
   218  
   219  func testJobStoreGetNewestJobByStatusAndType(t *testing.T, ss store.Store) {
   220  	jobType1 := model.NewId()
   221  	jobType2 := model.NewId()
   222  	status1 := model.NewId()
   223  	status2 := model.NewId()
   224  
   225  	jobs := []*model.Job{
   226  		{
   227  			Id:       model.NewId(),
   228  			Type:     jobType1,
   229  			CreateAt: 1001,
   230  			Status:   status1,
   231  		},
   232  		{
   233  			Id:       model.NewId(),
   234  			Type:     jobType1,
   235  			CreateAt: 1000,
   236  			Status:   status1,
   237  		},
   238  		{
   239  			Id:       model.NewId(),
   240  			Type:     jobType2,
   241  			CreateAt: 1003,
   242  			Status:   status1,
   243  		},
   244  		{
   245  			Id:       model.NewId(),
   246  			Type:     jobType1,
   247  			CreateAt: 1004,
   248  			Status:   status2,
   249  		},
   250  	}
   251  
   252  	for _, job := range jobs {
   253  		_, err := ss.Job().Save(job)
   254  		require.NoError(t, err)
   255  		defer ss.Job().Delete(job.Id)
   256  	}
   257  
   258  	received, err := ss.Job().GetNewestJobByStatusAndType(status1, jobType1)
   259  	assert.NoError(t, err)
   260  	assert.EqualValues(t, jobs[0].Id, received.Id)
   261  
   262  	received, err = ss.Job().GetNewestJobByStatusAndType(model.NewId(), model.NewId())
   263  	assert.Error(t, err)
   264  	var nfErr *store.ErrNotFound
   265  	assert.True(t, errors.As(err, &nfErr))
   266  	assert.Nil(t, received)
   267  }
   268  
   269  func testJobStoreGetNewestJobByStatusesAndType(t *testing.T, ss store.Store) {
   270  	jobType1 := model.NewId()
   271  	jobType2 := model.NewId()
   272  	status1 := model.NewId()
   273  	status2 := model.NewId()
   274  
   275  	jobs := []*model.Job{
   276  		{
   277  			Id:       model.NewId(),
   278  			Type:     jobType1,
   279  			CreateAt: 1001,
   280  			Status:   status1,
   281  		},
   282  		{
   283  			Id:       model.NewId(),
   284  			Type:     jobType1,
   285  			CreateAt: 1000,
   286  			Status:   status1,
   287  		},
   288  		{
   289  			Id:       model.NewId(),
   290  			Type:     jobType2,
   291  			CreateAt: 1003,
   292  			Status:   status1,
   293  		},
   294  		{
   295  			Id:       model.NewId(),
   296  			Type:     jobType1,
   297  			CreateAt: 1004,
   298  			Status:   status2,
   299  		},
   300  	}
   301  
   302  	for _, job := range jobs {
   303  		_, err := ss.Job().Save(job)
   304  		require.NoError(t, err)
   305  		defer ss.Job().Delete(job.Id)
   306  	}
   307  
   308  	received, err := ss.Job().GetNewestJobByStatusesAndType([]string{status1, status2}, jobType1)
   309  	assert.NoError(t, err)
   310  	assert.EqualValues(t, jobs[3].Id, received.Id)
   311  
   312  	received, err = ss.Job().GetNewestJobByStatusesAndType([]string{model.NewId(), model.NewId()}, model.NewId())
   313  	assert.Error(t, err)
   314  	var nfErr *store.ErrNotFound
   315  	assert.True(t, errors.As(err, &nfErr))
   316  	assert.Nil(t, received)
   317  
   318  	received, err = ss.Job().GetNewestJobByStatusesAndType([]string{status2}, jobType2)
   319  	assert.Error(t, err)
   320  	assert.True(t, errors.As(err, &nfErr))
   321  	assert.Nil(t, received)
   322  
   323  	received, err = ss.Job().GetNewestJobByStatusesAndType([]string{status1}, jobType2)
   324  	assert.NoError(t, err)
   325  	assert.EqualValues(t, jobs[2].Id, received.Id)
   326  
   327  	received, err = ss.Job().GetNewestJobByStatusesAndType([]string{}, jobType1)
   328  	assert.Error(t, err)
   329  	assert.True(t, errors.As(err, &nfErr))
   330  	assert.Nil(t, received)
   331  }
   332  
   333  func testJobStoreGetCountByStatusAndType(t *testing.T, ss store.Store) {
   334  	jobType1 := model.NewId()
   335  	jobType2 := model.NewId()
   336  	status1 := model.NewId()
   337  	status2 := model.NewId()
   338  
   339  	jobs := []*model.Job{
   340  		{
   341  			Id:       model.NewId(),
   342  			Type:     jobType1,
   343  			CreateAt: 1000,
   344  			Status:   status1,
   345  		},
   346  		{
   347  			Id:       model.NewId(),
   348  			Type:     jobType1,
   349  			CreateAt: 999,
   350  			Status:   status1,
   351  		},
   352  		{
   353  			Id:       model.NewId(),
   354  			Type:     jobType2,
   355  			CreateAt: 1001,
   356  			Status:   status1,
   357  		},
   358  		{
   359  			Id:       model.NewId(),
   360  			Type:     jobType1,
   361  			CreateAt: 1002,
   362  			Status:   status2,
   363  		},
   364  	}
   365  
   366  	for _, job := range jobs {
   367  		_, err := ss.Job().Save(job)
   368  		require.NoError(t, err)
   369  		defer ss.Job().Delete(job.Id)
   370  	}
   371  
   372  	count, err := ss.Job().GetCountByStatusAndType(status1, jobType1)
   373  	assert.NoError(t, err)
   374  	assert.EqualValues(t, 2, count)
   375  
   376  	count, err = ss.Job().GetCountByStatusAndType(status2, jobType2)
   377  	assert.NoError(t, err)
   378  	assert.EqualValues(t, 0, count)
   379  
   380  	count, err = ss.Job().GetCountByStatusAndType(status1, jobType2)
   381  	assert.NoError(t, err)
   382  	assert.EqualValues(t, 1, count)
   383  
   384  	count, err = ss.Job().GetCountByStatusAndType(status2, jobType1)
   385  	assert.NoError(t, err)
   386  	assert.EqualValues(t, 1, count)
   387  }
   388  
   389  func testJobUpdateOptimistically(t *testing.T, ss store.Store) {
   390  	job := &model.Job{
   391  		Id:       model.NewId(),
   392  		Type:     model.JOB_TYPE_DATA_RETENTION,
   393  		CreateAt: model.GetMillis(),
   394  		Status:   model.JOB_STATUS_PENDING,
   395  	}
   396  
   397  	_, err := ss.Job().Save(job)
   398  	require.NoError(t, err)
   399  	defer ss.Job().Delete(job.Id)
   400  
   401  	job.LastActivityAt = model.GetMillis()
   402  	job.Status = model.JOB_STATUS_IN_PROGRESS
   403  	job.Progress = 50
   404  	job.Data = map[string]string{
   405  		"Foo": "Bar",
   406  	}
   407  
   408  	updated, err := ss.Job().UpdateOptimistically(job, model.JOB_STATUS_SUCCESS)
   409  	require.False(t, err != nil && updated)
   410  
   411  	time.Sleep(2 * time.Millisecond)
   412  
   413  	updated, err = ss.Job().UpdateOptimistically(job, model.JOB_STATUS_PENDING)
   414  	require.NoError(t, err)
   415  	require.True(t, updated)
   416  
   417  	updatedJob, err := ss.Job().Get(job.Id)
   418  	require.NoError(t, err)
   419  
   420  	require.Equal(t, updatedJob.Type, job.Type)
   421  	require.Equal(t, updatedJob.CreateAt, job.CreateAt)
   422  	require.Equal(t, updatedJob.Status, job.Status)
   423  	require.Greater(t, updatedJob.LastActivityAt, job.LastActivityAt)
   424  	require.Equal(t, updatedJob.Progress, job.Progress)
   425  	require.Equal(t, updatedJob.Data["Foo"], job.Data["Foo"])
   426  }
   427  
   428  func testJobUpdateStatusUpdateStatusOptimistically(t *testing.T, ss store.Store) {
   429  	job := &model.Job{
   430  		Id:       model.NewId(),
   431  		Type:     model.JOB_TYPE_DATA_RETENTION,
   432  		CreateAt: model.GetMillis(),
   433  		Status:   model.JOB_STATUS_SUCCESS,
   434  	}
   435  
   436  	var lastUpdateAt int64
   437  	received, err := ss.Job().Save(job)
   438  	require.NoError(t, err)
   439  	lastUpdateAt = received.LastActivityAt
   440  
   441  	defer ss.Job().Delete(job.Id)
   442  
   443  	time.Sleep(2 * time.Millisecond)
   444  
   445  	received, err = ss.Job().UpdateStatus(job.Id, model.JOB_STATUS_PENDING)
   446  	require.NoError(t, err)
   447  
   448  	require.Equal(t, model.JOB_STATUS_PENDING, received.Status)
   449  	require.Greater(t, received.LastActivityAt, lastUpdateAt)
   450  	lastUpdateAt = received.LastActivityAt
   451  
   452  	time.Sleep(2 * time.Millisecond)
   453  
   454  	updated, err := ss.Job().UpdateStatusOptimistically(job.Id, model.JOB_STATUS_IN_PROGRESS, model.JOB_STATUS_SUCCESS)
   455  	require.NoError(t, err)
   456  	require.False(t, updated)
   457  
   458  	received, err = ss.Job().Get(job.Id)
   459  	require.NoError(t, err)
   460  
   461  	require.Equal(t, model.JOB_STATUS_PENDING, received.Status)
   462  	require.Equal(t, received.LastActivityAt, lastUpdateAt)
   463  
   464  	time.Sleep(2 * time.Millisecond)
   465  
   466  	updated, err = ss.Job().UpdateStatusOptimistically(job.Id, model.JOB_STATUS_PENDING, model.JOB_STATUS_IN_PROGRESS)
   467  	require.NoError(t, err)
   468  	require.True(t, updated, "should have succeeded")
   469  
   470  	var startAtSet int64
   471  	received, err = ss.Job().Get(job.Id)
   472  	require.NoError(t, err)
   473  	require.Equal(t, model.JOB_STATUS_IN_PROGRESS, received.Status)
   474  	require.NotEqual(t, 0, received.StartAt)
   475  	require.Greater(t, received.LastActivityAt, lastUpdateAt)
   476  	lastUpdateAt = received.LastActivityAt
   477  	startAtSet = received.StartAt
   478  
   479  	time.Sleep(2 * time.Millisecond)
   480  
   481  	updated, err = ss.Job().UpdateStatusOptimistically(job.Id, model.JOB_STATUS_IN_PROGRESS, model.JOB_STATUS_SUCCESS)
   482  	require.NoError(t, err)
   483  	require.True(t, updated, "should have succeeded")
   484  
   485  	received, err = ss.Job().Get(job.Id)
   486  	require.NoError(t, err)
   487  	require.Equal(t, model.JOB_STATUS_SUCCESS, received.Status)
   488  	require.Equal(t, startAtSet, received.StartAt)
   489  	require.Greater(t, received.LastActivityAt, lastUpdateAt)
   490  }
   491  
   492  func testJobDelete(t *testing.T, ss store.Store) {
   493  	job, err := ss.Job().Save(&model.Job{Id: model.NewId()})
   494  	require.NoError(t, err)
   495  
   496  	_, err = ss.Job().Delete(job.Id)
   497  	assert.NoError(t, err)
   498  }