diff --git a/api/v2.0/swagger.yaml b/api/v2.0/swagger.yaml index aedfaec7d..3677c87af 100644 --- a/api/v2.0/swagger.yaml +++ b/api/v2.0/swagger.yaml @@ -1013,6 +1013,151 @@ paths: $ref: '#/responses/403' '500': $ref: '#/responses/500' + /projects/{project_name}/preheat/policies/{preheat_policy_name}/executions: + get: + summary: List executions for the given policy + description: List executions for the given policy + tags: + - preheat + operationId: ListExecutions + parameters: + - $ref: '#/parameters/requestId' + - $ref: '#/parameters/projectName' + - $ref: '#/parameters/preheatPolicyName' + - $ref: '#/parameters/page' + - $ref: '#/parameters/pageSize' + - $ref: '#/parameters/query' + responses: + '200': + description: List executions success + schema: + type: array + items: + $ref: '#/definitions/Execution' + '400': + $ref: '#/responses/400' + '401': + $ref: '#/responses/401' + '404': + $ref: '#/responses/404' + '403': + $ref: '#/responses/403' + '500': + $ref: '#/responses/500' + /projects/{project_name}/preheat/policies/{preheat_policy_name}/executions/{execution_id}: + get: + summary: Get a execution detail by id + description: Get a execution detail by id + tags: + - preheat + operationId: GetExecution + parameters: + - $ref: '#/parameters/requestId' + - $ref: '#/parameters/projectName' + - $ref: '#/parameters/preheatPolicyName' + - $ref: '#/parameters/executionId' + responses: + '200': + description: Get execution success + schema: + $ref: '#/definitions/Execution' + '400': + $ref: '#/responses/400' + '401': + $ref: '#/responses/401' + '404': + $ref: '#/responses/404' + '403': + $ref: '#/responses/403' + '500': + $ref: '#/responses/500' + patch: + summary: Stop a execution + description: Stop a execution + tags: + - preheat + operationId: StopExecution + parameters: + - $ref: '#/parameters/requestId' + - $ref: '#/parameters/projectName' + - $ref: '#/parameters/preheatPolicyName' + - $ref: '#/parameters/executionId' + - name: execution + description: The data of execution + in: body + required: true + schema: + $ref: '#/definitions/Execution' + responses: + '200': + $ref: '#/responses/200' + '400': + $ref: '#/responses/400' + '401': + $ref: '#/responses/401' + '404': + $ref: '#/responses/404' + '403': + $ref: '#/responses/403' + '500': + $ref: '#/responses/500' + /projects/{project_name}/preheat/policies/{preheat_policy_name}/executions/{execution_id}/tasks: + get: + summary: List all the related tasks for the given execution + description: List all the related tasks for the given execution + tags: + - preheat + operationId: ListTasks + parameters: + - $ref: '#/parameters/requestId' + - $ref: '#/parameters/projectName' + - $ref: '#/parameters/preheatPolicyName' + - $ref: '#/parameters/executionId' + responses: + '200': + description: List tasks success + schema: + type: array + items: + $ref: '#/definitions/Task' + '400': + $ref: '#/responses/400' + '401': + $ref: '#/responses/401' + '404': + $ref: '#/responses/404' + '403': + $ref: '#/responses/403' + '500': + $ref: '#/responses/500' + /projects/{project_name}/preheat/policies/{preheat_policy_name}/executions/{execution_id}/tasks/{task_id}/logs: + get: + summary: Get the log text stream of the specified task for the given execution + description: Get the log text stream of the specified task for the given execution + tags: + - preheat + operationId: GetLog + parameters: + - $ref: '#/parameters/requestId' + - $ref: '#/parameters/projectName' + - $ref: '#/parameters/preheatPolicyName' + - $ref: '#/parameters/executionId' + - $ref: '#/parameters/taskId' + responses: + '200': + description: Get log success + schema: + type: string + '400': + $ref: '#/responses/400' + '401': + $ref: '#/responses/401' + '404': + $ref: '#/responses/404' + '403': + $ref: '#/responses/403' + '500': + $ref: '#/responses/500' parameters: query: name: q @@ -1085,7 +1230,18 @@ parameters: description: Preheat Policy Name required: true type: string - + executionId: + name: execution_id + in: path + description: Execution ID + required: true + type: integer + taskId: + name: task_id + in: path + description: Task ID + required: true + type: integer responses: '200': description: Success @@ -1601,3 +1757,90 @@ definitions: type: string format: date-time description: The Update Time of preheat policy + Metrics: + type: object + properties: + task_count: + type: integer + description: The count of task + success_task_count: + type: integer + description: The count of success task + error_task_count: + type: integer + description: The count of error task + pending_task_count: + type: integer + description: The count of pending task + running_task_count: + type: integer + description: The count of running task + scheduled_task_count: + type: integer + description: The count of scheduled task + stopped_task_count: + type: integer + description: The count of stopped task + Execution: + type: object + properties: + id: + type: integer + description: The ID of execution + vendor_type: + type: string + description: The vendor type of execution + vendor_id: + type: integer + description: The vendor id of execution + status: + type: string + description: The status of execution + status_message: + type: string + description: The status message of execution + metrics: + $ref: '#/definitions/Metrics' + trigger: + type: string + description: The trigger of execution + extra_attrs: + $ref: '#/definitions/ExtraAttrs' + start_time: + type: string + description: The start time of execution + end_time: + type: string + description: The end time of execution + Task: + type: object + properties: + id: + type: integer + description: The ID of task + execution_id: + type: integer + description: The ID of task execution + status: + type: string + description: The status of task + status_message: + type: string + description: The status message of task + run_count: + type: integer + description: The count of task run + extra_attrs: + $ref: '#/definitions/ExtraAttrs' + creation_time: + type: string + description: The creation time of task + update_time: + type: string + description: The update time of task + start_time: + type: string + description: The start time of task + end_time: + type: string + description: The end time of task diff --git a/src/controller/task/controller.go b/src/controller/task/controller.go new file mode 100644 index 000000000..bd8f80871 --- /dev/null +++ b/src/controller/task/controller.go @@ -0,0 +1,71 @@ +// 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 ( + "context" + + "github.com/goharbor/harbor/src/lib/q" + "github.com/goharbor/harbor/src/pkg/task" +) + +var ( + // Ctl is a global task controller instance + Ctl = NewController() +) + +// Controller manages the task +type Controller interface { + // Stop the specified task. + Stop(ctx context.Context, id int64) (err error) + // Get the specified task. + Get(ctx context.Context, id int64) (task *task.Task, err error) + // List the tasks according to the query. + List(ctx context.Context, query *q.Query) (tasks []*task.Task, err error) + // Get the log of the specified task. + GetLog(ctx context.Context, id int64) (log []byte, err error) +} + +// NewController creates an instance of the default task controller. +func NewController() Controller { + return &controller{ + mgr: task.Mgr, + } +} + +// controller defines the default task controller. +type controller struct { + mgr task.Manager +} + +// Stop the specified task. +func (c *controller) Stop(ctx context.Context, id int64) (err error) { + return c.mgr.Stop(ctx, id) +} + +// Get the specified task. +func (c *controller) Get(ctx context.Context, id int64) (task *task.Task, err error) { + return c.mgr.Get(ctx, id) +} + +// List the tasks according to the query. +func (c *controller) List(ctx context.Context, query *q.Query) (tasks []*task.Task, err error) { + return c.mgr.List(ctx, query) +} + +// Get the log of the specified task. +func (c *controller) GetLog(ctx context.Context, id int64) (log []byte, err error) { + return c.mgr.GetLog(ctx, id) +} diff --git a/src/controller/task/controller_test.go b/src/controller/task/controller_test.go new file mode 100644 index 000000000..b0ac6ca0a --- /dev/null +++ b/src/controller/task/controller_test.go @@ -0,0 +1,74 @@ +// 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" + + model "github.com/goharbor/harbor/src/pkg/task" + "github.com/goharbor/harbor/src/testing/mock" + "github.com/goharbor/harbor/src/testing/pkg/task" + "github.com/stretchr/testify/suite" +) + +type controllerTestSuite struct { + suite.Suite + ctl *controller + mgr *task.FakeManager +} + +// TestControllerTestSuite tests controller. +func TestControllerTestSuite(t *testing.T) { + suite.Run(t, &controllerTestSuite{}) +} + +// SetupTest setups the testing env. +func (c *controllerTestSuite) SetupTest() { + c.mgr = &task.FakeManager{} + c.ctl = &controller{mgr: c.mgr} +} + +// TestStop tests stop. +func (c *controllerTestSuite) TestStop() { + c.mgr.On("Stop", mock.Anything, mock.Anything).Return(nil) + err := c.ctl.Stop(nil, 1) + c.NoError(err) +} + +// TestGet tests get. +func (c *controllerTestSuite) TestGet() { + c.mgr.On("Get", mock.Anything, int64(1)).Return(&model.Task{ID: 1}, nil) + t, err := c.ctl.Get(nil, 1) + c.NoError(err) + c.Equal(int64(1), t.ID) +} + +// TestList tests list. +func (c *controllerTestSuite) TestList() { + c.mgr.On("List", mock.Anything, mock.Anything).Return([]*model.Task{ + {ID: 1}, {ID: 2}, + }, nil) + ts, err := c.ctl.List(nil, nil) + c.NoError(err) + c.Len(ts, 2) +} + +// TestGetLog tests get log. +func (c *controllerTestSuite) TestGetLog() { + c.mgr.On("GetLog", mock.Anything, mock.Anything).Return([]byte("logs"), nil) + l, err := c.ctl.GetLog(nil, 1) + c.NoError(err) + c.Equal([]byte("logs"), l) +} diff --git a/src/controller/task/execution_controller.go b/src/controller/task/execution_controller.go new file mode 100644 index 000000000..49b7821f1 --- /dev/null +++ b/src/controller/task/execution_controller.go @@ -0,0 +1,71 @@ +// 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 ( + "context" + + "github.com/goharbor/harbor/src/lib/q" + "github.com/goharbor/harbor/src/pkg/task" +) + +var ( + // ExecutionCtl is a global execution controller. + ExecutionCtl = NewExecutionController() +) + +// ExecutionController manages the execution. +type ExecutionController interface { + // Stop all linked tasks of the specified execution. + Stop(ctx context.Context, id int64) (err error) + // Delete the specified execution and its tasks. + Delete(ctx context.Context, id int64) (err error) + // Get the specified execution. + Get(ctx context.Context, id int64) (execution *task.Execution, err error) + // List executions according to the query. + List(ctx context.Context, query *q.Query) (executions []*task.Execution, err error) +} + +// executionController defines the execution controller. +type executionController struct { + mgr task.ExecutionManager +} + +// NewExecutionController creates an instance of the default execution controller. +func NewExecutionController() ExecutionController { + return &executionController{ + mgr: task.ExecMgr, + } +} + +// Stop all linked tasks of the specified execution. +func (ec *executionController) Stop(ctx context.Context, id int64) (err error) { + return ec.mgr.Stop(ctx, id) +} + +// Delete the specified execution and its tasks. +func (ec *executionController) Delete(ctx context.Context, id int64) (err error) { + return ec.mgr.Delete(ctx, id) +} + +// Get the specified execution. +func (ec *executionController) Get(ctx context.Context, id int64) (execution *task.Execution, err error) { + return ec.mgr.Get(ctx, id) +} + +// List executions according to the query. +func (ec *executionController) List(ctx context.Context, query *q.Query) (executions []*task.Execution, err error) { + return ec.mgr.List(ctx, query) +} diff --git a/src/controller/task/execution_controller_test.go b/src/controller/task/execution_controller_test.go new file mode 100644 index 000000000..2a956cf00 --- /dev/null +++ b/src/controller/task/execution_controller_test.go @@ -0,0 +1,76 @@ +// 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" + + model "github.com/goharbor/harbor/src/pkg/task" + "github.com/goharbor/harbor/src/testing/mock" + "github.com/goharbor/harbor/src/testing/pkg/task" + "github.com/stretchr/testify/suite" +) + +type executionControllerTestSuite struct { + suite.Suite + ctl *executionController + mgr *task.FakeExecutionManager +} + +// TestExecutionControllerTestSuite tests controller. +func TestExecutionControllerTestSuite(t *testing.T) { + suite.Run(t, &executionControllerTestSuite{}) +} + +// SetupTest setups the testing env. +func (ec *executionControllerTestSuite) SetupTest() { + ec.mgr = &task.FakeExecutionManager{} + ec.ctl = &executionController{ + mgr: ec.mgr, + } +} + +// TestStop tests stop. +func (ec *executionControllerTestSuite) TestStop() { + ec.mgr.On("Stop", mock.Anything, mock.Anything).Return(nil) + err := ec.ctl.Stop(nil, 1) + ec.NoError(err) +} + +// TestDelete tests delete. +func (ec *executionControllerTestSuite) TestDelete() { + ec.mgr.On("Delete", mock.Anything, mock.Anything).Return(nil) + err := ec.ctl.Delete(nil, 1) + ec.NoError(err) +} + +// TestGet tests get. +func (ec *executionControllerTestSuite) TestGet() { + ec.mgr.On("Get", mock.Anything, mock.Anything).Return(&model.Execution{ID: 1}, nil) + e, err := ec.ctl.Get(nil, 1) + ec.NoError(err) + ec.Equal(int64(1), e.ID) +} + +// TestList tests list. +func (ec *executionControllerTestSuite) TestList() { + ec.mgr.On("List", mock.Anything, mock.Anything).Return([]*model.Execution{ + {ID: 1}, + {ID: 2}, + }, nil) + es, err := ec.ctl.List(nil, nil) + ec.NoError(err) + ec.Len(es, 2) +} diff --git a/src/server/v2.0/handler/preheat.go b/src/server/v2.0/handler/preheat.go index e78ae878b..87281f3c9 100644 --- a/src/server/v2.0/handler/preheat.go +++ b/src/server/v2.0/handler/preheat.go @@ -8,11 +8,18 @@ import ( "regexp" "time" + "github.com/goharbor/harbor/src/lib/q" + + "github.com/goharbor/harbor/src/jobservice/job" + + "github.com/goharbor/harbor/src/pkg/task" + "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/strfmt" "github.com/goharbor/harbor/src/common/rbac" preheatCtl "github.com/goharbor/harbor/src/controller/p2p/preheat" projectCtl "github.com/goharbor/harbor/src/controller/project" + taskCtl "github.com/goharbor/harbor/src/controller/task" liberrors "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/pkg/p2p/preheat/models/policy" instanceModel "github.com/goharbor/harbor/src/pkg/p2p/preheat/models/provider" @@ -24,9 +31,11 @@ import ( func newPreheatAPI() *preheatAPI { return &preheatAPI{ - preheatCtl: preheatCtl.Ctl, - projectCtl: projectCtl.Ctl, - enforcer: preheatCtl.Enf, + preheatCtl: preheatCtl.Ctl, + projectCtl: projectCtl.Ctl, + enforcer: preheatCtl.Enf, + executionCtl: taskCtl.ExecutionCtl, + taskCtl: taskCtl.Ctl, } } @@ -37,9 +46,11 @@ const nameRegex = "^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$" type preheatAPI struct { BaseAPI - preheatCtl preheatCtl.Controller - projectCtl projectCtl.Controller - enforcer preheatCtl.Enforcer + preheatCtl preheatCtl.Controller + projectCtl projectCtl.Controller + enforcer preheatCtl.Enforcer + executionCtl taskCtl.ExecutionController + taskCtl taskCtl.Controller } func (api *preheatAPI) Prepare(ctx context.Context, operation string, params interface{}) middleware.Responder { @@ -473,3 +484,178 @@ func convertParamInstanceToModelInstance(model *models.Instance) (*instanceModel Vendor: model.Vendor, }, nil } + +// convertExecutionToPayload converts model execution to swagger model. +func convertExecutionToPayload(model *task.Execution) (*models.Execution, error) { + if model == nil { + return nil, errors.New("execution can not be nil") + } + + execution := &models.Execution{ + EndTime: model.EndTime.String(), + ExtraAttrs: model.ExtraAttrs, + ID: model.ID, + StartTime: model.StartTime.String(), + Status: model.Status, + StatusMessage: model.StatusMessage, + Trigger: model.Trigger, + VendorID: model.VendorID, + VendorType: model.VendorType, + } + if model.Metrics != nil { + execution.Metrics = &models.Metrics{ + ErrorTaskCount: model.Metrics.ErrorTaskCount, + PendingTaskCount: model.Metrics.PendingTaskCount, + RunningTaskCount: model.Metrics.RunningTaskCount, + ScheduledTaskCount: model.Metrics.ScheduledTaskCount, + StoppedTaskCount: model.Metrics.StoppedTaskCount, + SuccessTaskCount: model.Metrics.SuccessTaskCount, + TaskCount: model.Metrics.TaskCount, + } + } + + return execution, nil +} + +// GetExecution gets an execution. +func (api *preheatAPI) GetExecution(ctx context.Context, params operation.GetExecutionParams) middleware.Responder { + if err := api.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionRead, rbac.ResourcePreatPolicy); err != nil { + return api.SendError(ctx, err) + } + + execution, err := api.executionCtl.Get(ctx, params.ExecutionID) + if err != nil { + return api.SendError(ctx, err) + } + + payload, err := convertExecutionToPayload(execution) + if err != nil { + return api.SendError(ctx, err) + } + + return operation.NewGetExecutionOK().WithPayload(payload) +} + +// ListExecutions lists executions. +func (api *preheatAPI) ListExecutions(ctx context.Context, params operation.ListExecutionsParams) middleware.Responder { + if err := api.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionList, rbac.ResourcePreatPolicy); err != nil { + return api.SendError(ctx, err) + } + + project, err := api.projectCtl.GetByName(ctx, params.ProjectName) + if err != nil { + return api.SendError(ctx, err) + } + + policy, err := api.preheatCtl.GetPolicyByName(ctx, project.ProjectID, params.PreheatPolicyName) + if err != nil { + return api.SendError(ctx, err) + } + + query, err := api.BuildQuery(ctx, params.Q, params.Page, params.PageSize) + if err != nil { + return api.SendError(ctx, err) + } + + if query != nil { + query.Keywords["vendor_type"] = job.P2PPreheat + query.Keywords["vendor_id"] = policy.ID + } + + executions, err := api.executionCtl.List(ctx, query) + if err != nil { + return api.SendError(ctx, err) + } + + var payloads []*models.Execution + for _, exec := range executions { + p, err := convertExecutionToPayload(exec) + if err != nil { + return api.SendError(ctx, err) + } + payloads = append(payloads, p) + } + + return operation.NewListExecutionsOK().WithPayload(payloads) +} + +// StopExecution stops execution. +func (api *preheatAPI) StopExecution(ctx context.Context, params operation.StopExecutionParams) middleware.Responder { + if err := api.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionUpdate, rbac.ResourcePreatPolicy); err != nil { + return api.SendError(ctx, err) + } + + if params.Execution.Status == "Stopped" { + err := api.executionCtl.Stop(ctx, params.ExecutionID) + if err != nil { + return api.SendError(ctx, err) + } + + return operation.NewStopExecutionOK() + } + + return api.SendError(ctx, fmt.Errorf("param status invalid: %#v", params.Execution)) +} + +// convertTaskToPayload converts task to swagger model. +func convertTaskToPayload(model *task.Task) (*models.Task, error) { + if model == nil { + return nil, errors.New("task model can not be nil") + } + + return &models.Task{ + CreationTime: model.CreationTime.String(), + EndTime: model.EndTime.String(), + ExecutionID: model.ExecutionID, + ExtraAttrs: model.ExtraAttrs, + ID: model.ID, + RunCount: int64(model.RunCount), + StartTime: model.StartTime.String(), + Status: model.Status, + StatusMessage: model.StatusMessage, + UpdateTime: model.UpdateTime.String(), + }, nil +} + +// ListTasks lists tasks. +func (api *preheatAPI) ListTasks(ctx context.Context, params operation.ListTasksParams) middleware.Responder { + if err := api.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionList, rbac.ResourcePreatPolicy); err != nil { + return api.SendError(ctx, err) + } + + query := &q.Query{ + Keywords: map[string]interface{}{ + "execution_id": params.ExecutionID, + }, + } + + tasks, err := api.taskCtl.List(ctx, query) + if err != nil { + return api.SendError(ctx, err) + } + + var payloads []*models.Task + for _, task := range tasks { + p, err := convertTaskToPayload(task) + if err != nil { + return api.SendError(ctx, err) + } + payloads = append(payloads, p) + } + + return operation.NewListTasksOK().WithPayload(payloads) +} + +// GetLog gets log. +func (api *preheatAPI) GetLog(ctx context.Context, params operation.GetLogParams) middleware.Responder { + if err := api.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionRead, rbac.ResourcePreatPolicy); err != nil { + return api.SendError(ctx, err) + } + + l, err := api.taskCtl.GetLog(ctx, params.TaskID) + if err != nil { + return api.SendError(ctx, err) + } + + return operation.NewGetLogOK().WithPayload(string(l)) +} diff --git a/src/server/v2.0/handler/preheat_test.go b/src/server/v2.0/handler/preheat_test.go index 4936ecb19..d4f0c6f4d 100644 --- a/src/server/v2.0/handler/preheat_test.go +++ b/src/server/v2.0/handler/preheat_test.go @@ -5,6 +5,8 @@ import ( "testing" "time" + "github.com/goharbor/harbor/src/pkg/task" + "github.com/go-openapi/strfmt" "github.com/goharbor/harbor/src/pkg/p2p/preheat/models/policy" instanceModel "github.com/goharbor/harbor/src/pkg/p2p/preheat/models/provider" @@ -289,3 +291,113 @@ func Test_convertParamInstanceToModelInstance(t *testing.T) { }) } } + +func Test_convertExecutionToPayload(t *testing.T) { + tests := []struct { + name string + input *task.Execution + expect *models.Execution + shouldErr bool + }{ + { + name: "nil model", + input: nil, + expect: nil, + shouldErr: true, + }, + { + name: "should ok", + input: &task.Execution{ + ID: 1, + VendorType: "p2p", + VendorID: 1, + Status: "", + StatusMessage: "", + Metrics: nil, + Trigger: "", + ExtraAttrs: nil, + StartTime: time.Time{}, + EndTime: time.Time{}, + }, + expect: &models.Execution{ + EndTime: "0001-01-01 00:00:00 +0000 UTC", + ExtraAttrs: nil, + ID: 1, + Metrics: nil, + StartTime: "0001-01-01 00:00:00 +0000 UTC", + Status: "", + StatusMessage: "", + Trigger: "", + VendorID: 1, + VendorType: "p2p", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := convertExecutionToPayload(tt.input) + if (err != nil) != tt.shouldErr { + t.Errorf("convertExecutionToPayload() error = %v, wantErr %v", err, tt.shouldErr) + return + } + if !reflect.DeepEqual(got, tt.expect) { + t.Errorf("convertExecutionToPayload() = %v, want %v", got, tt.expect) + } + }) + } +} + +func Test_convertTaskToPayload(t *testing.T) { + tests := []struct { + name string + input *task.Task + expect *models.Task + shouldErr bool + }{ + { + name: "nil model", + input: nil, + expect: nil, + shouldErr: true, + }, + { + name: "should ok", + input: &task.Task{ + ID: 0, + ExecutionID: 0, + Status: "", + StatusMessage: "", + RunCount: 0, + ExtraAttrs: nil, + CreationTime: time.Time{}, + StartTime: time.Time{}, + UpdateTime: time.Time{}, + EndTime: time.Time{}, + }, + expect: &models.Task{ + CreationTime: "0001-01-01 00:00:00 +0000 UTC", + EndTime: "0001-01-01 00:00:00 +0000 UTC", + ExecutionID: 0, + ExtraAttrs: nil, + ID: 0, + RunCount: 0, + StartTime: "0001-01-01 00:00:00 +0000 UTC", + Status: "", + StatusMessage: "", + UpdateTime: "0001-01-01 00:00:00 +0000 UTC", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := convertTaskToPayload(tt.input) + if (err != nil) != tt.shouldErr { + t.Errorf("convertTaskToPayload() error = %v, wantErr %v", err, tt.shouldErr) + return + } + if !reflect.DeepEqual(got, tt.expect) { + t.Errorf("convertTaskToPayload() = %v, want %v", got, tt.expect) + } + }) + } +}