// Copyright Project Harbor Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package task import ( "testing" "time" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" "github.com/goharbor/harbor/src/jobservice/job" "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/lib/q" "github.com/goharbor/harbor/src/pkg/task/dao" "github.com/goharbor/harbor/src/testing/lib/orm" ) type executionManagerTestSuite struct { suite.Suite execMgr *executionManager taskMgr *mockTaskManager execDAO *mockExecutionDAO taskDAO *mockTaskDAO ormCreator *orm.Creator } func (e *executionManagerTestSuite) SetupTest() { e.taskMgr = &mockTaskManager{} e.execDAO = &mockExecutionDAO{} e.taskDAO = &mockTaskDAO{} e.ormCreator = &orm.Creator{} e.execMgr = &executionManager{ executionDAO: e.execDAO, taskMgr: e.taskMgr, taskDAO: e.taskDAO, } } func (e *executionManagerTestSuite) TestCount() { e.execDAO.On("Count", mock.Anything, mock.Anything).Return(int64(10), nil) total, err := e.execMgr.Count(nil, &q.Query{}) e.Require().Nil(err) e.Equal(int64(10), total) e.execDAO.AssertExpectations(e.T()) } func (e *executionManagerTestSuite) TestCreate() { e.execDAO.On("Create", mock.Anything, mock.Anything).Return(int64(1), nil) id, err := e.execMgr.Create(nil, "vendor", 0, ExecutionTriggerManual, map[string]interface{}{"k": "v"}) e.Require().Nil(err) e.Equal(int64(1), id) // sleep to make sure the function in the goroutine run time.Sleep(1 * time.Second) e.execDAO.AssertExpectations(e.T()) } func (e *executionManagerTestSuite) TestUpdateExtraAttrs() { e.execDAO.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) err := e.execMgr.UpdateExtraAttrs(nil, 1, map[string]interface{}{"key": "value"}) e.Require().Nil(err) e.execDAO.AssertExpectations(e.T()) } func (e *executionManagerTestSuite) TestMarkDone() { e.execDAO.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) err := e.execMgr.MarkDone(nil, 1, "success") e.Require().Nil(err) e.execDAO.AssertExpectations(e.T()) } func (e *executionManagerTestSuite) TestMarkError() { e.execDAO.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) err := e.execMgr.MarkError(nil, 1, "error") e.Require().Nil(err) e.execDAO.AssertExpectations(e.T()) } func (e *executionManagerTestSuite) TestStop() { // the execution contains no tasks and the status is final e.execDAO.On("Get", mock.Anything, mock.Anything).Return(&dao.Execution{ ID: 1, Status: job.SuccessStatus.String(), }, nil) e.taskDAO.On("List", mock.Anything, mock.Anything).Return(nil, nil) err := e.execMgr.Stop(nil, 1) e.Require().Nil(err) e.taskDAO.AssertExpectations(e.T()) e.execDAO.AssertExpectations(e.T()) // reset the mocks e.SetupTest() // the execution contains no tasks and the status isn't final e.execDAO.On("Get", mock.Anything, mock.Anything).Return(&dao.Execution{ ID: 1, Status: job.RunningStatus.String(), }, nil) e.taskDAO.On("List", mock.Anything, mock.Anything).Return(nil, nil) e.execDAO.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) err = e.execMgr.Stop(nil, 1) e.Require().Nil(err) e.taskDAO.AssertExpectations(e.T()) e.execDAO.AssertExpectations(e.T()) // reset the mocks e.SetupTest() // the execution contains tasks e.execDAO.On("Get", mock.Anything, mock.Anything).Return(&dao.Execution{ ID: 1, Status: job.RunningStatus.String(), }, nil) e.taskDAO.On("List", mock.Anything, mock.Anything).Return([]*dao.Task{ { ID: 1, ExecutionID: 1, }, }, nil) e.taskMgr.On("Stop", mock.Anything, mock.Anything).Return(nil) err = e.execMgr.Stop(nil, 1) e.Require().Nil(err) e.taskDAO.AssertExpectations(e.T()) e.execDAO.AssertExpectations(e.T()) e.taskMgr.AssertExpectations(e.T()) } func (e *executionManagerTestSuite) TestStopAndWait() { // timeout e.execDAO.On("Get", mock.Anything, mock.Anything).Return(&dao.Execution{ ID: 1, Status: job.RunningStatus.String(), }, nil) e.taskDAO.On("List", mock.Anything, mock.Anything).Return([]*dao.Task{ { ID: 1, ExecutionID: 1, }, }, nil) e.taskMgr.On("Stop", mock.Anything, mock.Anything).Return(nil) err := e.execMgr.StopAndWait(nil, 1, 1*time.Second) e.Require().NotNil(err) e.taskDAO.AssertExpectations(e.T()) e.execDAO.AssertExpectations(e.T()) e.taskMgr.AssertExpectations(e.T()) // reset mocks e.SetupTest() // pass e.execDAO.On("Get", mock.Anything, mock.Anything).Return(&dao.Execution{ ID: 1, Status: job.StoppedStatus.String(), }, nil) e.taskDAO.On("List", mock.Anything, mock.Anything).Return([]*dao.Task{ { ID: 1, ExecutionID: 1, }, }, nil) e.taskMgr.On("Stop", mock.Anything, mock.Anything).Return(nil) err = e.execMgr.StopAndWait(nil, 1, 1*time.Second) e.Require().Nil(err) e.taskDAO.AssertExpectations(e.T()) e.execDAO.AssertExpectations(e.T()) e.taskMgr.AssertExpectations(e.T()) } func (e *executionManagerTestSuite) TestDelete() { // try to delete the execution which contains running tasks e.taskDAO.On("List", mock.Anything, mock.Anything).Return([]*dao.Task{ { ID: 1, ExecutionID: 1, Status: job.RunningStatus.String(), }, }, nil) err := e.execMgr.Delete(nil, 1) e.Require().NotNil(err) e.True(errors.IsErr(err, errors.PreconditionCode)) e.taskDAO.AssertExpectations(e.T()) // reset the mock e.SetupTest() e.taskDAO.On("List", mock.Anything, mock.Anything).Return([]*dao.Task{ { ID: 1, ExecutionID: 1, Status: job.SuccessStatus.String(), }, }, nil) e.taskDAO.On("Delete", mock.Anything, mock.Anything).Return(nil) e.execDAO.On("Delete", mock.Anything, mock.Anything).Return(nil) err = e.execMgr.Delete(nil, 1) e.Require().Nil(err) e.taskDAO.AssertExpectations(e.T()) e.execDAO.AssertExpectations(e.T()) } func (e *executionManagerTestSuite) TestGet() { e.execDAO.On("Get", mock.Anything, mock.Anything).Return(&dao.Execution{ ID: 1, Status: job.SuccessStatus.String(), }, nil) e.execDAO.On("GetMetrics", mock.Anything, mock.Anything).Return(&dao.Metrics{ TaskCount: 1, SuccessTaskCount: 1, }, nil) exec, err := e.execMgr.Get(nil, 1) e.Require().Nil(err) e.Equal(int64(1), exec.ID) e.Equal(job.SuccessStatus.String(), exec.Status) e.Equal(int64(1), exec.Metrics.TaskCount) e.Equal(int64(1), exec.Metrics.SuccessTaskCount) e.execDAO.AssertExpectations(e.T()) } func (e *executionManagerTestSuite) TestList() { e.execDAO.On("List", mock.Anything, mock.Anything).Return([]*dao.Execution{ { ID: 1, Status: job.SuccessStatus.String(), }, }, nil) e.execDAO.On("GetMetrics", mock.Anything, mock.Anything).Return(&dao.Metrics{ TaskCount: 1, SuccessTaskCount: 1, }, nil) execs, err := e.execMgr.List(nil, nil) e.Require().Nil(err) e.Require().Len(execs, 1) e.Equal(int64(1), execs[0].ID) e.Equal(job.SuccessStatus.String(), execs[0].Status) e.Equal(int64(1), execs[0].Metrics.TaskCount) e.Equal(int64(1), execs[0].Metrics.SuccessTaskCount) e.execDAO.AssertExpectations(e.T()) } func TestExecutionManagerSuite(t *testing.T) { suite.Run(t, &executionManagerTestSuite{}) }