diff --git a/go.mod b/go.mod
index cb47b270..f36c7f12 100644
--- a/go.mod
+++ b/go.mod
@@ -9,6 +9,7 @@ require (
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7
github.com/getkin/kin-openapi v0.88.0
github.com/gofrs/uuid v4.0.0+incompatible // indirect
+ github.com/golang/mock v1.6.0 // indirect
github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.4.2 // indirect
github.com/graarh/golang-socketio v0.0.0-20170510162725-2c44953b9b5f
diff --git a/go.sum b/go.sum
index cbe3d6ca..37fb582d 100644
--- a/go.sum
+++ b/go.sum
@@ -52,6 +52,8 @@ github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPh
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
@@ -227,6 +229,7 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziflex/lecho/v3 v3.1.0 h1:65bSzSc0yw7EEhi44lMnkOI877ZzbE7tGDWfYCQXZwI=
@@ -258,6 +261,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -266,6 +270,7 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211013171255-e13a2654a71e h1:Xj+JO91noE97IN6F/7WZxzC5QE6yENAQPrwIYhW3bsA=
@@ -289,7 +294,9 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -320,6 +327,8 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/internal/manager/api_impl/api_impl.go b/internal/manager/api_impl/api_impl.go
index dd25efd4..b427839c 100644
--- a/internal/manager/api_impl/api_impl.go
+++ b/internal/manager/api_impl/api_impl.go
@@ -36,10 +36,14 @@ type Flamenco struct {
persist PersistenceService
}
+// Generate mock implementations of these interfaces.
+//go:generate go run github.com/golang/mock/mockgen -destination mocks/api_impl_mock.gen.go -package mocks gitlab.com/blender/flamenco-ng-poc/internal/manager/api_impl PersistenceService,JobCompiler
+
type PersistenceService interface {
StoreAuthoredJob(ctx context.Context, authoredJob job_compilers.AuthoredJob) error
FetchJob(ctx context.Context, jobID string) (*persistence.Job, error)
FetchTask(ctx context.Context, taskID string) (*persistence.Task, error)
+ SaveTask(ctx context.Context, task *persistence.Task) error
CreateWorker(ctx context.Context, w *persistence.Worker) error
FetchWorker(ctx context.Context, uuid string) (*persistence.Worker, error)
diff --git a/internal/manager/api_impl/jobs.go b/internal/manager/api_impl/jobs.go
index e96e97a5..5bfdeb05 100644
--- a/internal/manager/api_impl/jobs.go
+++ b/internal/manager/api_impl/jobs.go
@@ -21,12 +21,15 @@ package api_impl
* ***** END GPL LICENSE BLOCK ***** */
import (
+ "context"
"fmt"
"net/http"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
+ "github.com/rs/zerolog"
"github.com/rs/zerolog/log"
+ "gitlab.com/blender/flamenco-ng-poc/internal/manager/persistence"
"gitlab.com/blender/flamenco-ng-poc/pkg/api"
)
@@ -126,6 +129,7 @@ func (f *Flamenco) FetchJob(e echo.Context, jobId string) error {
func (f *Flamenco) TaskUpdate(e echo.Context, taskID string) error {
logger := requestLogger(e)
+ worker := requestWorkerOrPanic(e)
if _, err := uuid.Parse(taskID); err != nil {
logger.Debug().Msg("invalid task ID received")
@@ -140,22 +144,63 @@ func (f *Flamenco) TaskUpdate(e echo.Context, taskID string) error {
logger.Warn().Err(err).Msg("cannot fetch task")
return sendAPIError(e, http.StatusNotFound, fmt.Sprintf("task %+v not found", taskID))
}
+ if dbTask == nil {
+ panic("task could not be fetched, but database gave no error either")
+ }
- worker := requestWorker(e)
+ // Decode the request body.
+ var taskUpdate api.TaskUpdateJSONRequestBody
+ if err := e.Bind(&taskUpdate); err != nil {
+ logger.Warn().Err(err).Msg("bad request received")
+ return sendAPIError(e, http.StatusBadRequest, "invalid format")
+ }
if dbTask.Worker == nil {
logger.Warn().
- Str("requestingWorkerID", worker.UUID).
Msg("worker trying to update task that's not assigned to any worker")
return sendAPIError(e, http.StatusConflict, fmt.Sprintf("task %+v is not assigned to any worker, so also not to you", taskID))
}
if dbTask.Worker.UUID != worker.UUID {
logger.Warn().
- Str("requestingWorkerID", worker.UUID).
Str("assignedWorkerID", dbTask.Worker.UUID).
Msg("worker trying to update task that's assigned to another worker")
return sendAPIError(e, http.StatusConflict, fmt.Sprintf("task %+v is not assigned to you, but to worker %v", taskID, dbTask.Worker.UUID))
}
- // TODO: actually handle the task update.
+ // TODO: check whether this task may undergo the requested status change.
+
+ if err := f.doTaskUpdate(ctx, logger, worker, dbTask, taskUpdate); err != nil {
+ return sendAPIError(e, http.StatusInternalServerError, "unable to handle status update: %v", err)
+ }
+
return e.String(http.StatusNoContent, "")
}
+
+func (f *Flamenco) doTaskUpdate(
+ ctx context.Context,
+ logger zerolog.Logger,
+ w *persistence.Worker,
+ dbTask *persistence.Task,
+ update api.TaskUpdateJSONRequestBody,
+) error {
+ if update.TaskStatus != nil {
+ // TODO: check that this status transition is valid.
+ // TODO: process this status transition.
+ newStatus := string(*update.TaskStatus)
+ logger.Info().
+ Str("oldStatus", dbTask.Status).
+ Str("newStatus", newStatus).
+ Msg("task changing status")
+ dbTask.Status = newStatus
+ }
+
+ if update.Activity != nil {
+ dbTask.Worker.LastActivity = *update.Activity
+ }
+
+ if update.Log != nil {
+ // TODO: write log to disk.
+ logger.Warn().Msg("task logs are not yet handled")
+ }
+
+ return f.persist.SaveTask(ctx, dbTask)
+}
diff --git a/internal/manager/api_impl/jobs_test.go b/internal/manager/api_impl/jobs_test.go
new file mode 100644
index 00000000..377e09f2
--- /dev/null
+++ b/internal/manager/api_impl/jobs_test.go
@@ -0,0 +1,75 @@
+package api_impl
+
+import (
+ "context"
+ "testing"
+
+ "github.com/golang/mock/gomock"
+ "github.com/stretchr/testify/assert"
+ "gitlab.com/blender/flamenco-ng-poc/internal/manager/persistence"
+ "gitlab.com/blender/flamenco-ng-poc/pkg/api"
+)
+
+/* ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Original Code Copyright (C) 2022 Blender Foundation.
+ *
+ * This file is part of Flamenco.
+ *
+ * Flamenco is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * Flamenco is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Flamenco. If not, see .
+ *
+ * ***** END GPL LICENSE BLOCK ***** */
+
+func TestTaskUpdate(t *testing.T) {
+ mockCtrl := gomock.NewController(t)
+ defer mockCtrl.Finish()
+
+ mf := newMockedFlamenco(mockCtrl)
+ worker := testWorker()
+
+ // Construct the JSON request object.
+ s := func(value string) *string { return &value }
+ ts := func(value api.TaskStatus) *api.TaskStatus { return &value }
+ taskUpdate := api.TaskUpdateJSONRequestBody{
+ Activity: s("testing"),
+ Log: s("line1\nline2\n"),
+ TaskStatus: ts(api.TaskStatusFailed),
+ }
+
+ // Construct the task that's supposed to be updated.
+ taskID := "181eab68-1123-4790-93b1-94309a899411"
+ mockTask := persistence.Task{
+ UUID: taskID,
+ Worker: &worker,
+ WorkerID: &worker.ID,
+ }
+
+ // Expect the task to be fetched.
+ mf.persistence.EXPECT().FetchTask(gomock.Any(), taskID).Return(&mockTask, nil)
+
+ // Expect the task to be saved.
+ var savedTask persistence.Task
+ mf.persistence.EXPECT().SaveTask(gomock.Any(), gomock.Any()).DoAndReturn(
+ func(ctx context.Context, task *persistence.Task) error {
+ savedTask = *task
+ return nil
+ })
+
+ // Do the call.
+ echoCtx := mf.prepareMockedJSONRequest(&worker, taskUpdate)
+ err := mf.flamenco.TaskUpdate(echoCtx, taskID)
+
+ // Check the saved task.
+ assert.NoError(t, err)
+ assert.Equal(t, mockTask.UUID, savedTask.UUID)
+}
diff --git a/internal/manager/api_impl/mocks/api_impl_mock.gen.go b/internal/manager/api_impl/mocks/api_impl_mock.gen.go
new file mode 100644
index 00000000..d0cd5baf
--- /dev/null
+++ b/internal/manager/api_impl/mocks/api_impl_mock.gen.go
@@ -0,0 +1,220 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: gitlab.com/blender/flamenco-ng-poc/internal/manager/api_impl (interfaces: PersistenceService,JobCompiler)
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+ context "context"
+ reflect "reflect"
+
+ gomock "github.com/golang/mock/gomock"
+ job_compilers "gitlab.com/blender/flamenco-ng-poc/internal/manager/job_compilers"
+ persistence "gitlab.com/blender/flamenco-ng-poc/internal/manager/persistence"
+ api "gitlab.com/blender/flamenco-ng-poc/pkg/api"
+)
+
+// MockPersistenceService is a mock of PersistenceService interface.
+type MockPersistenceService struct {
+ ctrl *gomock.Controller
+ recorder *MockPersistenceServiceMockRecorder
+}
+
+// MockPersistenceServiceMockRecorder is the mock recorder for MockPersistenceService.
+type MockPersistenceServiceMockRecorder struct {
+ mock *MockPersistenceService
+}
+
+// NewMockPersistenceService creates a new mock instance.
+func NewMockPersistenceService(ctrl *gomock.Controller) *MockPersistenceService {
+ mock := &MockPersistenceService{ctrl: ctrl}
+ mock.recorder = &MockPersistenceServiceMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockPersistenceService) EXPECT() *MockPersistenceServiceMockRecorder {
+ return m.recorder
+}
+
+// CreateWorker mocks base method.
+func (m *MockPersistenceService) CreateWorker(arg0 context.Context, arg1 *persistence.Worker) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "CreateWorker", arg0, arg1)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// CreateWorker indicates an expected call of CreateWorker.
+func (mr *MockPersistenceServiceMockRecorder) CreateWorker(arg0, arg1 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateWorker", reflect.TypeOf((*MockPersistenceService)(nil).CreateWorker), arg0, arg1)
+}
+
+// FetchJob mocks base method.
+func (m *MockPersistenceService) FetchJob(arg0 context.Context, arg1 string) (*persistence.Job, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "FetchJob", arg0, arg1)
+ ret0, _ := ret[0].(*persistence.Job)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// FetchJob indicates an expected call of FetchJob.
+func (mr *MockPersistenceServiceMockRecorder) FetchJob(arg0, arg1 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchJob", reflect.TypeOf((*MockPersistenceService)(nil).FetchJob), arg0, arg1)
+}
+
+// FetchTask mocks base method.
+func (m *MockPersistenceService) FetchTask(arg0 context.Context, arg1 string) (*persistence.Task, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "FetchTask", arg0, arg1)
+ ret0, _ := ret[0].(*persistence.Task)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// FetchTask indicates an expected call of FetchTask.
+func (mr *MockPersistenceServiceMockRecorder) FetchTask(arg0, arg1 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchTask", reflect.TypeOf((*MockPersistenceService)(nil).FetchTask), arg0, arg1)
+}
+
+// FetchWorker mocks base method.
+func (m *MockPersistenceService) FetchWorker(arg0 context.Context, arg1 string) (*persistence.Worker, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "FetchWorker", arg0, arg1)
+ ret0, _ := ret[0].(*persistence.Worker)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// FetchWorker indicates an expected call of FetchWorker.
+func (mr *MockPersistenceServiceMockRecorder) FetchWorker(arg0, arg1 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchWorker", reflect.TypeOf((*MockPersistenceService)(nil).FetchWorker), arg0, arg1)
+}
+
+// SaveTask mocks base method.
+func (m *MockPersistenceService) SaveTask(arg0 context.Context, arg1 *persistence.Task) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "SaveTask", arg0, arg1)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// SaveTask indicates an expected call of SaveTask.
+func (mr *MockPersistenceServiceMockRecorder) SaveTask(arg0, arg1 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveTask", reflect.TypeOf((*MockPersistenceService)(nil).SaveTask), arg0, arg1)
+}
+
+// SaveWorker mocks base method.
+func (m *MockPersistenceService) SaveWorker(arg0 context.Context, arg1 *persistence.Worker) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "SaveWorker", arg0, arg1)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// SaveWorker indicates an expected call of SaveWorker.
+func (mr *MockPersistenceServiceMockRecorder) SaveWorker(arg0, arg1 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveWorker", reflect.TypeOf((*MockPersistenceService)(nil).SaveWorker), arg0, arg1)
+}
+
+// SaveWorkerStatus mocks base method.
+func (m *MockPersistenceService) SaveWorkerStatus(arg0 context.Context, arg1 *persistence.Worker) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "SaveWorkerStatus", arg0, arg1)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// SaveWorkerStatus indicates an expected call of SaveWorkerStatus.
+func (mr *MockPersistenceServiceMockRecorder) SaveWorkerStatus(arg0, arg1 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveWorkerStatus", reflect.TypeOf((*MockPersistenceService)(nil).SaveWorkerStatus), arg0, arg1)
+}
+
+// ScheduleTask mocks base method.
+func (m *MockPersistenceService) ScheduleTask(arg0 *persistence.Worker) (*persistence.Task, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "ScheduleTask", arg0)
+ ret0, _ := ret[0].(*persistence.Task)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// ScheduleTask indicates an expected call of ScheduleTask.
+func (mr *MockPersistenceServiceMockRecorder) ScheduleTask(arg0 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScheduleTask", reflect.TypeOf((*MockPersistenceService)(nil).ScheduleTask), arg0)
+}
+
+// StoreAuthoredJob mocks base method.
+func (m *MockPersistenceService) StoreAuthoredJob(arg0 context.Context, arg1 job_compilers.AuthoredJob) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "StoreAuthoredJob", arg0, arg1)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// StoreAuthoredJob indicates an expected call of StoreAuthoredJob.
+func (mr *MockPersistenceServiceMockRecorder) StoreAuthoredJob(arg0, arg1 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreAuthoredJob", reflect.TypeOf((*MockPersistenceService)(nil).StoreAuthoredJob), arg0, arg1)
+}
+
+// MockJobCompiler is a mock of JobCompiler interface.
+type MockJobCompiler struct {
+ ctrl *gomock.Controller
+ recorder *MockJobCompilerMockRecorder
+}
+
+// MockJobCompilerMockRecorder is the mock recorder for MockJobCompiler.
+type MockJobCompilerMockRecorder struct {
+ mock *MockJobCompiler
+}
+
+// NewMockJobCompiler creates a new mock instance.
+func NewMockJobCompiler(ctrl *gomock.Controller) *MockJobCompiler {
+ mock := &MockJobCompiler{ctrl: ctrl}
+ mock.recorder = &MockJobCompilerMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockJobCompiler) EXPECT() *MockJobCompilerMockRecorder {
+ return m.recorder
+}
+
+// Compile mocks base method.
+func (m *MockJobCompiler) Compile(arg0 context.Context, arg1 api.SubmittedJob) (*job_compilers.AuthoredJob, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Compile", arg0, arg1)
+ ret0, _ := ret[0].(*job_compilers.AuthoredJob)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// Compile indicates an expected call of Compile.
+func (mr *MockJobCompilerMockRecorder) Compile(arg0, arg1 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Compile", reflect.TypeOf((*MockJobCompiler)(nil).Compile), arg0, arg1)
+}
+
+// ListJobTypes mocks base method.
+func (m *MockJobCompiler) ListJobTypes() api.AvailableJobTypes {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "ListJobTypes")
+ ret0, _ := ret[0].(api.AvailableJobTypes)
+ return ret0
+}
+
+// ListJobTypes indicates an expected call of ListJobTypes.
+func (mr *MockJobCompilerMockRecorder) ListJobTypes() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListJobTypes", reflect.TypeOf((*MockJobCompiler)(nil).ListJobTypes))
+}
diff --git a/internal/manager/api_impl/test_support.go b/internal/manager/api_impl/test_support.go
new file mode 100644
index 00000000..8e69364f
--- /dev/null
+++ b/internal/manager/api_impl/test_support.go
@@ -0,0 +1,85 @@
+package api_impl
+
+import (
+ "bytes"
+ "encoding/json"
+ "net/http"
+ "net/http/httptest"
+
+ "github.com/golang/mock/gomock"
+ "github.com/labstack/echo/v4"
+ "gitlab.com/blender/flamenco-ng-poc/internal/manager/api_impl/mocks"
+ "gitlab.com/blender/flamenco-ng-poc/internal/manager/persistence"
+ "gitlab.com/blender/flamenco-ng-poc/pkg/api"
+ "gorm.io/gorm"
+)
+
+/* ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Original Code Copyright (C) 2022 Blender Foundation.
+ *
+ * This file is part of Flamenco.
+ *
+ * Flamenco is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * Flamenco is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Flamenco. If not, see .
+ *
+ * ***** END GPL LICENSE BLOCK ***** */
+
+type mockedFlamenco struct {
+ flamenco *Flamenco
+ jobCompiler *mocks.MockJobCompiler
+ persistence *mocks.MockPersistenceService
+}
+
+func newMockedFlamenco(mockCtrl *gomock.Controller) mockedFlamenco {
+ jc := mocks.NewMockJobCompiler(mockCtrl)
+ ps := mocks.NewMockPersistenceService(mockCtrl)
+ f := NewFlamenco(jc, ps)
+
+ return mockedFlamenco{
+ flamenco: f,
+ jobCompiler: jc,
+ persistence: ps,
+ }
+}
+
+func (mf *mockedFlamenco) prepareMockedJSONRequest(worker *persistence.Worker, requestBody interface{}) echo.Context {
+
+ e := echo.New()
+
+ bodyBytes, err := json.MarshalIndent(requestBody, "", " ")
+ if err != nil {
+ panic(err)
+ }
+
+ req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(bodyBytes))
+ req.Header.Add(echo.HeaderContentType, "application/json")
+ rec := httptest.NewRecorder()
+ c := e.NewContext(req, rec)
+ requestWorkerStore(c, worker)
+
+ return c
+}
+
+func testWorker() persistence.Worker {
+ return persistence.Worker{
+ Model: gorm.Model{ID: 1},
+ UUID: "e7632d62-c3b8-4af0-9e78-01752928952c",
+ Name: "дрон",
+ Address: "fe80::5054:ff:fede:2ad7",
+ LastActivity: "",
+ Platform: "linux",
+ Software: "3.0",
+ Status: api.WorkerStatusAwake,
+ SupportedTaskTypes: "blender,ffmpeg,file-management,misc",
+ }
+}
diff --git a/internal/manager/api_impl/worker_auth.go b/internal/manager/api_impl/worker_auth.go
index 4f3c9c2f..4b2f703f 100644
--- a/internal/manager/api_impl/worker_auth.go
+++ b/internal/manager/api_impl/worker_auth.go
@@ -72,13 +72,17 @@ func WorkerAuth(ctx context.Context, authInfo *openapi3filter.AuthenticationInpu
return authInfo.NewError(errAuthBad)
}
- // Store the Worker in the request context, so that it doesn't need to be fetched again later.
- reqCtx := context.WithValue(req.Context(), workerKey, w)
- echo.SetRequest(req.WithContext(reqCtx))
-
+ requestWorkerStore(echo, w)
return nil
}
+// Store the Worker in the request context, so that it doesn't need to be fetched again later.
+func requestWorkerStore(e echo.Context, w *persistence.Worker) {
+ req := e.Request()
+ reqCtx := context.WithValue(req.Context(), workerKey, w)
+ e.SetRequest(req.WithContext(reqCtx))
+}
+
// requestWorker returns the Worker associated with this HTTP request, or nil if there is none.
func requestWorker(e echo.Context) *persistence.Worker {
ctx := e.Request().Context()
diff --git a/internal/manager/persistence/jobs.go b/internal/manager/persistence/jobs.go
index 6dd98c84..c6294826 100644
--- a/internal/manager/persistence/jobs.go
+++ b/internal/manager/persistence/jobs.go
@@ -211,3 +211,10 @@ func (db *DB) FetchTask(ctx context.Context, taskUUID string) (*Task, error) {
return &dbTask, nil
}
+
+func (db *DB) SaveTask(ctx context.Context, t *Task) error {
+ if err := db.gormDB.Save(t).Error; err != nil {
+ return fmt.Errorf("error saving task: %w", err)
+ }
+ return nil
+}