github.com/matrixorigin/matrixone@v1.2.0/pkg/taskservice/task_service_test.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package taskservice
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"os"
    21  	"os/exec"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    26  	"github.com/matrixorigin/matrixone/pkg/common/runtime"
    27  	"github.com/matrixorigin/matrixone/pkg/pb/task"
    28  	"github.com/stretchr/testify/assert"
    29  )
    30  
    31  func TestCreateAsyncTask(t *testing.T) {
    32  	store := NewMemTaskStorage()
    33  	s := NewTaskService(runtime.DefaultRuntime(), store)
    34  	defer func() {
    35  		assert.NoError(t, s.Close())
    36  	}()
    37  
    38  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
    39  	defer cancel()
    40  	assert.NoError(t, s.CreateAsyncTask(ctx, newTestTaskMetadata("t1")))
    41  	assert.NoError(t, s.CreateAsyncTask(ctx, newTestTaskMetadata("t1")))
    42  
    43  	v := mustGetTestAsyncTask(t, store, 1)[0]
    44  	assert.True(t, v.ID > 0)
    45  	assert.True(t, v.CreateAt > 0)
    46  	assert.Equal(t, int64(0), v.CompletedAt)
    47  	assert.Equal(t, task.TaskStatus_Created, v.Status)
    48  	assert.Equal(t, "", v.ParentTaskID)
    49  	assert.Equal(t, "", v.TaskRunner)
    50  	assert.Equal(t, uint32(0), v.Epoch)
    51  	assert.Equal(t, int64(0), v.LastHeartbeat)
    52  	assert.Nil(t, v.ExecuteResult)
    53  	assert.Equal(t, newTestTaskMetadata("t1"), v.Metadata)
    54  }
    55  
    56  func TestCreateBatch(t *testing.T) {
    57  	store := NewMemTaskStorage()
    58  	s := NewTaskService(runtime.DefaultRuntime(), store)
    59  	defer func() {
    60  		assert.NoError(t, s.Close())
    61  	}()
    62  
    63  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
    64  	defer cancel()
    65  
    66  	n := 10
    67  	var tasks []task.TaskMetadata
    68  	for i := 0; i < n; i++ {
    69  		tasks = append(tasks, newTestTaskMetadata(fmt.Sprintf("task-%d", i)))
    70  	}
    71  
    72  	assert.NoError(t, s.CreateBatch(ctx, tasks))
    73  
    74  	values := mustGetTestAsyncTask(t, store, n)
    75  	for i := 0; i < n; i++ {
    76  		v := values[i]
    77  		assert.True(t, v.ID > 0)
    78  		assert.True(t, v.CreateAt > 0)
    79  		assert.Equal(t, int64(0), v.CompletedAt)
    80  		assert.Equal(t, task.TaskStatus_Created, v.Status)
    81  		assert.Equal(t, "", v.ParentTaskID)
    82  		assert.Equal(t, "", v.TaskRunner)
    83  		assert.Equal(t, uint32(0), v.Epoch)
    84  		assert.Equal(t, int64(0), v.LastHeartbeat)
    85  		assert.Nil(t, v.ExecuteResult)
    86  		assert.Equal(t, newTestTaskMetadata(fmt.Sprintf("task-%d", i)), v.Metadata)
    87  	}
    88  }
    89  
    90  func TestAllocate(t *testing.T) {
    91  	store := NewMemTaskStorage()
    92  	s := NewTaskService(runtime.DefaultRuntime(), store)
    93  	defer func() {
    94  		assert.NoError(t, s.Close())
    95  	}()
    96  
    97  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
    98  	defer cancel()
    99  
   100  	assert.NoError(t, s.CreateAsyncTask(ctx, newTestTaskMetadata("t1")))
   101  	v := mustGetTestAsyncTask(t, store, 1)[0]
   102  	assert.NoError(t, s.Allocate(ctx, v, "r1"))
   103  
   104  	v = mustGetTestAsyncTask(t, store, 1)[0]
   105  	assert.Equal(t, task.TaskStatus_Running, v.Status)
   106  	assert.True(t, v.LastHeartbeat > 0)
   107  	assert.Equal(t, "r1", v.TaskRunner)
   108  	assert.Equal(t, uint32(1), v.Epoch)
   109  }
   110  
   111  func TestReAllocate(t *testing.T) {
   112  	store := NewMemTaskStorage()
   113  	s := NewTaskService(runtime.DefaultRuntime(), store)
   114  	defer func() {
   115  		assert.NoError(t, s.Close())
   116  	}()
   117  
   118  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   119  	defer cancel()
   120  
   121  	assert.NoError(t, s.CreateAsyncTask(ctx, newTestTaskMetadata("t1")))
   122  	v := mustGetTestAsyncTask(t, store, 1)[0]
   123  	assert.NoError(t, s.Allocate(ctx, v, "r1"))
   124  
   125  	v = mustGetTestAsyncTask(t, store, 1)[0]
   126  	assert.Equal(t, task.TaskStatus_Running, v.Status)
   127  	assert.True(t, v.LastHeartbeat > 0)
   128  	assert.Equal(t, "r1", v.TaskRunner)
   129  	assert.Equal(t, uint32(1), v.Epoch)
   130  
   131  	last := v.LastHeartbeat
   132  	time.Sleep(time.Millisecond)
   133  	assert.NoError(t, s.Allocate(ctx, v, "r2"))
   134  	v = mustGetTestAsyncTask(t, store, 1)[0]
   135  	assert.Equal(t, task.TaskStatus_Running, v.Status)
   136  	assert.True(t, v.LastHeartbeat > last)
   137  	assert.Equal(t, "r2", v.TaskRunner)
   138  	assert.Equal(t, uint32(2), v.Epoch)
   139  }
   140  
   141  func allocateWithNotExistTask(t *testing.T) {
   142  	store := NewMemTaskStorage()
   143  	s := NewTaskService(runtime.DefaultRuntime(), store)
   144  	defer func() {
   145  		assert.NoError(t, s.Close())
   146  	}()
   147  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   148  	defer cancel()
   149  	_ = s.Allocate(ctx, task.AsyncTask{ID: 1}, "r1")
   150  }
   151  
   152  func TestAllocateWithNotExistTask(t *testing.T) {
   153  	if os.Getenv("RUN_TEST") == "1" {
   154  		allocateWithNotExistTask(t)
   155  		return
   156  	}
   157  	cmd := exec.Command(os.Args[0], "-test.run=TestAllocateWithNotExistTask")
   158  	cmd.Env = append(os.Environ(), "RUN_TEST=1")
   159  	err := cmd.Run()
   160  	// check Fatal is called
   161  	if e, ok := err.(*exec.ExitError); ok && !e.Success() {
   162  		return
   163  	}
   164  	t.Fatalf("process ran with err %v, want exit status 1", err)
   165  }
   166  
   167  func TestAllocateWithInvalidEpoch(t *testing.T) {
   168  	store := NewMemTaskStorage().(*memTaskStorage)
   169  	s := NewTaskService(runtime.DefaultRuntime(), store)
   170  	defer func() {
   171  		assert.NoError(t, s.Close())
   172  	}()
   173  
   174  	store.preUpdate = func() {
   175  		store.Lock()
   176  		defer store.Unlock()
   177  
   178  		for k, v := range store.asyncTasks {
   179  			v.Epoch++
   180  			store.asyncTasks[k] = v
   181  		}
   182  	}
   183  
   184  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   185  	defer cancel()
   186  
   187  	assert.NoError(t, s.CreateAsyncTask(ctx, newTestTaskMetadata("t1")))
   188  	v := mustGetTestAsyncTask(t, store, 1)[0]
   189  	err := s.Allocate(ctx, v, "r2")
   190  	assert.True(t, moerr.IsMoErrCode(err, moerr.ErrInvalidTask))
   191  }
   192  
   193  func TestCompleted(t *testing.T) {
   194  	store := NewMemTaskStorage()
   195  	s := NewTaskService(runtime.DefaultRuntime(), store)
   196  	defer func() {
   197  		assert.NoError(t, s.Close())
   198  	}()
   199  
   200  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   201  	defer cancel()
   202  
   203  	assert.NoError(t, s.CreateAsyncTask(ctx, newTestTaskMetadata("t1")))
   204  	v := mustGetTestAsyncTask(t, store, 1)[0]
   205  	assert.NoError(t, s.Allocate(ctx, v, "r1"))
   206  
   207  	v = mustGetTestAsyncTask(t, store, 1)[0]
   208  	assert.NoError(t, s.Complete(ctx, "r1", v,
   209  		task.ExecuteResult{Code: task.ResultCode_Failed, Error: "error"}))
   210  
   211  	v = mustGetTestAsyncTask(t, store, 1)[0]
   212  	assert.Equal(t, task.TaskStatus_Completed, v.Status)
   213  	assert.Equal(t, task.ExecuteResult{Code: task.ResultCode_Failed, Error: "error"}, *v.ExecuteResult)
   214  }
   215  
   216  func TestCompletedWithInvalidStatus(t *testing.T) {
   217  	store := NewMemTaskStorage()
   218  	s := NewTaskService(runtime.DefaultRuntime(), store)
   219  	defer func() {
   220  		assert.NoError(t, s.Close())
   221  	}()
   222  
   223  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   224  	defer cancel()
   225  
   226  	assert.NoError(t, s.CreateAsyncTask(ctx, newTestTaskMetadata("t1")))
   227  	v := mustGetTestAsyncTask(t, store, 1)[0]
   228  	assert.NoError(t, s.Allocate(ctx, v, "r1"))
   229  
   230  	v = mustGetTestAsyncTask(t, store, 1)[0]
   231  	v.Status = task.TaskStatus_Created
   232  	mustUpdateTestAsyncTask(t, store, 1, []task.AsyncTask{v})
   233  
   234  	err := s.Complete(ctx, "r1", v,
   235  		task.ExecuteResult{Code: task.ResultCode_Failed, Error: "error"})
   236  	assert.True(t, moerr.IsMoErrCode(err, moerr.ErrInvalidTask))
   237  }
   238  
   239  func TestCompletedWithInvalidEpoch(t *testing.T) {
   240  	store := NewMemTaskStorage()
   241  	s := NewTaskService(runtime.DefaultRuntime(), store)
   242  	defer func() {
   243  		assert.NoError(t, s.Close())
   244  	}()
   245  
   246  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   247  	defer cancel()
   248  
   249  	assert.NoError(t, s.CreateAsyncTask(ctx, newTestTaskMetadata("t1")))
   250  	v := mustGetTestAsyncTask(t, store, 1)[0]
   251  	assert.NoError(t, s.Allocate(ctx, v, "r1"))
   252  
   253  	v = mustGetTestAsyncTask(t, store, 1)[0]
   254  	v.Epoch = 2
   255  	mustUpdateTestAsyncTask(t, store, 1, []task.AsyncTask{v})
   256  
   257  	v.Epoch = 1
   258  	err := s.Complete(ctx, "r1", v,
   259  		task.ExecuteResult{Code: task.ResultCode_Failed, Error: "error"})
   260  	assert.True(t, moerr.IsMoErrCode(err, moerr.ErrInvalidTask))
   261  }
   262  
   263  func TestCompletedWithInvalidTaskRunner(t *testing.T) {
   264  	store := NewMemTaskStorage()
   265  	s := NewTaskService(runtime.DefaultRuntime(), store)
   266  	defer func() {
   267  		assert.NoError(t, s.Close())
   268  	}()
   269  
   270  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   271  	defer cancel()
   272  
   273  	assert.NoError(t, s.CreateAsyncTask(ctx, newTestTaskMetadata("t1")))
   274  	v := mustGetTestAsyncTask(t, store, 1)[0]
   275  	assert.NoError(t, s.Allocate(ctx, v, "r1"))
   276  
   277  	v = mustGetTestAsyncTask(t, store, 1)[0]
   278  	err := s.Complete(ctx, "r2", v,
   279  		task.ExecuteResult{Code: task.ResultCode_Failed, Error: "error"})
   280  	assert.True(t, moerr.IsMoErrCode(err, moerr.ErrInvalidTask))
   281  }
   282  
   283  func TestHeartbeat(t *testing.T) {
   284  	store := NewMemTaskStorage()
   285  	s := NewTaskService(runtime.DefaultRuntime(), store)
   286  	defer func() {
   287  		assert.NoError(t, s.Close())
   288  	}()
   289  
   290  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   291  	defer cancel()
   292  
   293  	assert.NoError(t, s.CreateAsyncTask(ctx, newTestTaskMetadata("t1")))
   294  	v := mustGetTestAsyncTask(t, store, 1)[0]
   295  	assert.NoError(t, s.Allocate(ctx, v, "r1"))
   296  
   297  	v = mustGetTestAsyncTask(t, store, 1)[0]
   298  	lastHeartbeat := v.LastHeartbeat
   299  	time.Sleep(time.Millisecond * 5)
   300  	assert.NoError(t, s.Heartbeat(ctx, v))
   301  
   302  	v = mustGetTestAsyncTask(t, store, 1)[0]
   303  	assert.True(t, v.LastHeartbeat > lastHeartbeat)
   304  }
   305  
   306  func TestHeartbeatWithSmallEpoch(t *testing.T) {
   307  	store := NewMemTaskStorage()
   308  	s := NewTaskService(runtime.DefaultRuntime(), store)
   309  	defer func() {
   310  		assert.NoError(t, s.Close())
   311  	}()
   312  
   313  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   314  	defer cancel()
   315  
   316  	assert.NoError(t, s.CreateAsyncTask(ctx, newTestTaskMetadata("t1")))
   317  	v := mustGetTestAsyncTask(t, store, 1)[0]
   318  	assert.NoError(t, s.Allocate(ctx, v, "r1"))
   319  
   320  	v = mustGetTestAsyncTask(t, store, 1)[0]
   321  	v.Epoch = 2
   322  	mustUpdateTestAsyncTask(t, store, 1, []task.AsyncTask{v})
   323  
   324  	v.Epoch = 1
   325  	err := s.Heartbeat(ctx, v)
   326  	assert.True(t, moerr.IsMoErrCode(err, moerr.ErrInvalidTask))
   327  }
   328  
   329  func TestHeartbeatWithBiggerEpochShouldSuccess(t *testing.T) {
   330  	store := NewMemTaskStorage()
   331  	s := NewTaskService(runtime.DefaultRuntime(), store)
   332  	defer func() {
   333  		assert.NoError(t, s.Close())
   334  	}()
   335  
   336  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   337  	defer cancel()
   338  
   339  	assert.NoError(t, s.CreateAsyncTask(ctx, newTestTaskMetadata("t1")))
   340  	v := mustGetTestAsyncTask(t, store, 1)[0]
   341  	assert.NoError(t, s.Allocate(ctx, v, "r1"))
   342  
   343  	v = mustGetTestAsyncTask(t, store, 1)[0]
   344  	v.Epoch = 2
   345  	mustUpdateTestAsyncTask(t, store, 1, []task.AsyncTask{v})
   346  
   347  	v.Epoch = 3
   348  	assert.NoError(t, s.Heartbeat(ctx, v))
   349  }
   350  
   351  func TestCreateCronTask(t *testing.T) {
   352  	store := NewMemTaskStorage()
   353  	s := NewTaskService(runtime.DefaultRuntime(), store)
   354  	defer func() {
   355  		assert.NoError(t, s.Close())
   356  	}()
   357  
   358  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   359  	defer cancel()
   360  	assert.NoError(t, s.CreateCronTask(ctx, newTestTaskMetadata("t1"), "* */5 * * * *"))
   361  	assert.NoError(t, s.CreateCronTask(ctx, newTestTaskMetadata("t1"), "* */5 * * * *"))
   362  }
   363  
   364  func TestQueryCronTask(t *testing.T) {
   365  	store := NewMemTaskStorage()
   366  	s := NewTaskService(runtime.DefaultRuntime(), store)
   367  	defer func() {
   368  		assert.NoError(t, s.Close())
   369  	}()
   370  
   371  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   372  	defer cancel()
   373  
   374  	v1 := newTestCronTask("t1", "cron1")
   375  	v2 := newTestCronTask("t2", "cron2")
   376  	mustAddTestCronTask(t, store, 2, v1, v2)
   377  
   378  	v, err := s.QueryCronTask(ctx)
   379  	assert.NoError(t, err)
   380  	assert.Equal(t, 2, len(v))
   381  }
   382  
   383  func TestQueryAsyncTask(t *testing.T) {
   384  	store := NewMemTaskStorage()
   385  	s := NewTaskService(runtime.DefaultRuntime(), store)
   386  	defer func() {
   387  		assert.NoError(t, s.Close())
   388  	}()
   389  
   390  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   391  	defer cancel()
   392  
   393  	v1 := newTestAsyncTask("t1")
   394  	v2 := newTestAsyncTask("t2")
   395  	mustAddTestAsyncTask(t, store, 2, v1, v2)
   396  
   397  	v, err := s.QueryAsyncTask(ctx)
   398  	assert.NoError(t, err)
   399  	assert.Equal(t, 2, len(v))
   400  }
   401  
   402  func newTestTaskMetadata(id string) task.TaskMetadata {
   403  	return task.TaskMetadata{
   404  		ID: id,
   405  	}
   406  }
   407  
   408  func TestCreateDaemonTask(t *testing.T) {
   409  	store := NewMemTaskStorage()
   410  	s := NewTaskService(runtime.DefaultRuntime(), store)
   411  	defer func() {
   412  		assert.NoError(t, s.Close())
   413  	}()
   414  
   415  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   416  	defer cancel()
   417  	assert.NoError(t, s.CreateDaemonTask(ctx, newTestTaskMetadata("t1"),
   418  		&task.Details{
   419  			AccountID: 10,
   420  			Account:   "a1",
   421  			Username:  "u1",
   422  			Details: &task.Details_Connector{
   423  				Connector: &task.ConnectorDetails{
   424  					TableName: "d1.t1",
   425  					Options: map[string]string{
   426  						"k1": "v1",
   427  					},
   428  				},
   429  			},
   430  		}))
   431  
   432  	v := mustGetTestDaemonTask(t, store, 1)[0]
   433  	assert.Equal(t, uint64(0), v.ID)
   434  	assert.False(t, v.CreateAt.IsZero())
   435  	assert.Equal(t, task.TaskStatus_Created, v.TaskStatus)
   436  	assert.Equal(t, "", v.TaskRunner)
   437  	assert.True(t, v.LastHeartbeat.IsZero())
   438  	assert.Equal(t, newTestTaskMetadata("t1"), v.Metadata)
   439  	assert.Equal(t, task.TaskType_TypeKafkaSinkConnector, v.TaskType)
   440  	assert.Equal(t, uint32(10), v.Details.AccountID)
   441  	assert.Equal(t, "a1", v.Details.Account)
   442  	assert.Equal(t, "u1", v.Details.Username)
   443  	details, ok := v.Details.Details.(*task.Details_Connector)
   444  	assert.True(t, ok)
   445  	assert.Equal(t, "d1.t1", details.Connector.TableName)
   446  	assert.Equal(t, "v1", details.Connector.Options["k1"])
   447  }
   448  
   449  func TestQueryDaemonTask(t *testing.T) {
   450  	store := NewMemTaskStorage()
   451  	s := NewTaskService(runtime.DefaultRuntime(), store)
   452  	defer func() {
   453  		assert.NoError(t, s.Close())
   454  	}()
   455  
   456  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   457  	defer cancel()
   458  
   459  	v1 := newTestDaemonTask(1, "t1")
   460  	v2 := newTestDaemonTask(2, "t2")
   461  	mustAddTestDaemonTask(t, store, 2, v1, v2)
   462  
   463  	v, err := s.QueryDaemonTask(ctx)
   464  	assert.NoError(t, err)
   465  	assert.Equal(t, 2, len(v))
   466  }
   467  
   468  func TestUpdateDaemonTaskTS(t *testing.T) {
   469  	store := NewMemTaskStorage()
   470  	s := NewTaskService(runtime.DefaultRuntime(), store)
   471  	defer func() {
   472  		assert.NoError(t, s.Close())
   473  	}()
   474  
   475  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   476  	defer cancel()
   477  
   478  	v1 := newTestDaemonTask(1, "t1")
   479  	mustAddTestDaemonTask(t, store, 1, v1)
   480  
   481  	v1.TaskStatus = task.TaskStatus_Running
   482  
   483  	c, err := s.UpdateDaemonTask(ctx, []task.DaemonTask{v1})
   484  	assert.NoError(t, err)
   485  	assert.Equal(t, 1, c)
   486  
   487  	ts, err := s.QueryDaemonTask(ctx)
   488  	assert.NoError(t, err)
   489  	assert.Equal(t, 1, len(ts))
   490  	assert.Equal(t, task.TaskStatus_Running, ts[0].TaskStatus)
   491  }
   492  
   493  func TestHeartbeatDaemonTask(t *testing.T) {
   494  	store := NewMemTaskStorage()
   495  	s := NewTaskService(runtime.DefaultRuntime(), store)
   496  	defer func() {
   497  		assert.NoError(t, s.Close())
   498  	}()
   499  
   500  	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   501  	defer cancel()
   502  
   503  	v1 := newTestDaemonTask(1, "t1")
   504  	v1.TaskStatus = task.TaskStatus_Running
   505  	mustAddTestDaemonTask(t, store, 1, v1)
   506  
   507  	v1.LastHeartbeat = time.Now()
   508  
   509  	err := s.HeartbeatDaemonTask(ctx, v1)
   510  	assert.NoError(t, err)
   511  
   512  	ts, err := s.QueryDaemonTask(ctx)
   513  	assert.NoError(t, err)
   514  	assert.Equal(t, 1, len(ts))
   515  	assert.False(t, ts[0].LastHeartbeat.IsZero())
   516  }