From 6c6f2a1138447777bbf46cc2c40e1b3c47204466 Mon Sep 17 00:00:00 2001 From: George Goldberg Date: Thu, 20 Jul 2017 16:25:35 +0100 Subject: PLT-6595-Server: Job Management APIs. (#6931) * PLT-6595-Server: Job Management APIs. * MANAGE_JOBS Permission * Fix test. --- api4/apitestlib.go | 9 +++ api4/job.go | 81 +++++++++++++++++++++--- api4/job_test.go | 182 ++++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 234 insertions(+), 38 deletions(-) (limited to 'api4') diff --git a/api4/apitestlib.go b/api4/apitestlib.go index 537d8610c..d70b9e5f6 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -24,6 +24,7 @@ import ( "github.com/mattermost/platform/wsapi" s3 "github.com/minio/minio-go" + "github.com/mattermost/platform/jobs" ) type TestHelper struct { @@ -68,6 +69,10 @@ func SetupEnterprise() *TestHelper { *utils.Cfg.TeamSettings.EnableOpenServer = true } + if jobs.Srv.Store == nil { + jobs.Srv.Store = app.Srv.Store + } + th := &TestHelper{} th.Client = th.CreateClient() th.SystemAdminClient = th.CreateClient() @@ -99,6 +104,10 @@ func Setup() *TestHelper { *utils.Cfg.TeamSettings.EnableOpenServer = true } + if jobs.Srv.Store == nil { + jobs.Srv.Store = app.Srv.Store + } + th := &TestHelper{} th.Client = th.CreateClient() th.SystemAdminClient = th.CreateClient() diff --git a/api4/job.go b/api4/job.go index e6c17c42d..941e5d543 100644 --- a/api4/job.go +++ b/api4/job.go @@ -14,8 +14,11 @@ import ( func InitJob() { l4g.Info("Initializing job API routes") - BaseRoutes.Jobs.Handle("/type/{job_type:[A-Za-z0-9_-]+}/statuses", ApiSessionRequired(getJobsByType)).Methods("GET") - BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}/status", ApiSessionRequired(getJob)).Methods("GET") + BaseRoutes.Jobs.Handle("", ApiSessionRequired(getJobs)).Methods("GET") + BaseRoutes.Jobs.Handle("", ApiSessionRequired(createJob)).Methods("POST") + BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}", ApiSessionRequired(getJob)).Methods("GET") + BaseRoutes.Jobs.Handle("/{job_id:[A-Za-z0-9]+}/cancel", ApiSessionRequired(cancelJob)).Methods("POST") + BaseRoutes.Jobs.Handle("/type/{job_type:[A-Za-z0-9_-]+}", ApiSessionRequired(getJobsByType)).Methods("GET") } func getJob(c *Context, w http.ResponseWriter, r *http.Request) { @@ -24,16 +27,55 @@ func getJob(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_JOBS) { + c.SetPermissionError(model.PERMISSION_MANAGE_JOBS) return } - if status, err := app.GetJob(c.Params.JobId); err != nil { + if job, err := app.GetJob(c.Params.JobId); err != nil { c.Err = err return } else { - w.Write([]byte(status.ToJson())) + w.Write([]byte(job.ToJson())) + } +} + +func createJob(c *Context, w http.ResponseWriter, r *http.Request) { + job := model.JobFromJson(r.Body) + if job == nil { + c.SetInvalidParam("job") + return + } + + if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_JOBS) { + c.SetPermissionError(model.PERMISSION_MANAGE_JOBS) + return + } + + if job, err := app.CreateJob(job); err != nil { + c.Err = err + return + } else { + w.WriteHeader(http.StatusCreated) + w.Write([]byte(job.ToJson())) + } +} + +func getJobs(c *Context, w http.ResponseWriter, r *http.Request) { + if c.Err != nil { + return + } + + if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_JOBS) { + c.SetPermissionError(model.PERMISSION_MANAGE_JOBS) + return + } + + if jobs, err := app.GetJobsPage(c.Params.Page, c.Params.PerPage); err != nil { + c.Err = err + return + } else { + w.Write([]byte(model.JobsToJson(jobs))) } } @@ -43,15 +85,34 @@ func getJobsByType(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_JOBS) { + c.SetPermissionError(model.PERMISSION_MANAGE_JOBS) return } - if statuses, err := app.GetJobsByTypePage(c.Params.JobType, c.Params.Page, c.Params.PerPage); err != nil { + if jobs, err := app.GetJobsByTypePage(c.Params.JobType, c.Params.Page, c.Params.PerPage); err != nil { c.Err = err return } else { - w.Write([]byte(model.JobsToJson(statuses))) + w.Write([]byte(model.JobsToJson(jobs))) } } + +func cancelJob(c *Context, w http.ResponseWriter, r *http.Request) { + c.RequireJobId() + if c.Err != nil { + return + } + + if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_JOBS) { + c.SetPermissionError(model.PERMISSION_MANAGE_JOBS) + return + } + + if err := app.CancelJob(c.Params.JobId); err != nil { + c.Err = err + return + } + + ReturnStatusOK(w) +} diff --git a/api4/job_test.go b/api4/job_test.go index 8bbea83e1..3dcdbe58b 100644 --- a/api4/job_test.go +++ b/api4/job_test.go @@ -12,74 +12,157 @@ import ( "github.com/mattermost/platform/store" ) -func TestGetJobStatus(t *testing.T) { +func TestCreateJob(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer TearDown() - status := &model.Job{ + job := &model.Job{ + Type: model.JOB_TYPE_DATA_RETENTION, + Data: map[string]interface{}{ + "thing": "stuff", + }, + } + + received, resp := th.SystemAdminClient.CreateJob(job) + CheckNoError(t, resp) + + defer app.Srv.Store.Job().Delete(received.Id) + + job = &model.Job{ + Type: model.NewId(), + } + + _, resp = th.SystemAdminClient.CreateJob(job) + CheckBadRequestStatus(t, resp) + + _, resp = th.Client.CreateJob(job) + CheckForbiddenStatus(t, resp) +} + +func TestGetJob(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + + job := &model.Job{ Id: model.NewId(), - Status: model.NewId(), + Status: model.JOB_STATUS_PENDING, } - if result := <-app.Srv.Store.Job().Save(status); result.Err != nil { + if result := <-app.Srv.Store.Job().Save(job); result.Err != nil { t.Fatal(result.Err) } - defer app.Srv.Store.Job().Delete(status.Id) + defer app.Srv.Store.Job().Delete(job.Id) - received, resp := th.SystemAdminClient.GetJob(status.Id) + received, resp := th.SystemAdminClient.GetJob(job.Id) CheckNoError(t, resp) - if received.Id != status.Id || received.Status != status.Status { - t.Fatal("incorrect job status received") + if received.Id != job.Id || received.Status != job.Status { + t.Fatal("incorrect job received") } _, resp = th.SystemAdminClient.GetJob("1234") CheckBadRequestStatus(t, resp) - _, resp = th.Client.GetJob(status.Id) + _, resp = th.Client.GetJob(job.Id) CheckForbiddenStatus(t, resp) _, resp = th.SystemAdminClient.GetJob(model.NewId()) CheckNotFoundStatus(t, resp) } -func TestGetJobStatusesByType(t *testing.T) { +func TestGetJobs(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + + jobType := model.NewId() + + jobs := []*model.Job{ + { + Id: model.NewId(), + Type: jobType, + CreateAt: model.GetMillis() + 1, + }, + { + Id: model.NewId(), + Type: jobType, + CreateAt: model.GetMillis(), + }, + { + Id: model.NewId(), + Type: jobType, + CreateAt: model.GetMillis() + 2, + }, + } + + for _, job := range jobs { + store.Must(app.Srv.Store.Job().Save(job)) + defer app.Srv.Store.Job().Delete(job.Id) + } + + received, resp := th.SystemAdminClient.GetJobs(0, 2) + CheckNoError(t, resp) + + if len(received) != 2 { + t.Fatal("received wrong number of jobs") + } else if received[0].Id != jobs[2].Id { + t.Fatal("should've received newest job first") + } else if received[1].Id != jobs[0].Id { + t.Fatal("should've received second newest job second") + } + + received, resp = th.SystemAdminClient.GetJobs(1, 2) + CheckNoError(t, resp) + + if received[0].Id != jobs[1].Id { + t.Fatal("should've received oldest job last") + } + + _, resp = th.Client.GetJobs(0, 60) + CheckForbiddenStatus(t, resp) +} + +func TestGetJobsByType(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer TearDown() jobType := model.NewId() - statuses := []*model.Job{ + jobs := []*model.Job{ { - Id: model.NewId(), - Type: jobType, - StartAt: 1000, + Id: model.NewId(), + Type: jobType, + CreateAt: 1000, }, { - Id: model.NewId(), - Type: jobType, - StartAt: 999, + Id: model.NewId(), + Type: jobType, + CreateAt: 999, }, { - Id: model.NewId(), - Type: jobType, - StartAt: 1001, + Id: model.NewId(), + Type: jobType, + CreateAt: 1001, + }, + { + Id: model.NewId(), + Type: model.NewId(), + CreateAt: 1002, }, } - for _, status := range statuses { - store.Must(app.Srv.Store.Job().Save(status)) - defer app.Srv.Store.Job().Delete(status.Id) + for _, job := range jobs { + store.Must(app.Srv.Store.Job().Save(job)) + defer app.Srv.Store.Job().Delete(job.Id) } received, resp := th.SystemAdminClient.GetJobsByType(jobType, 0, 2) CheckNoError(t, resp) if len(received) != 2 { - t.Fatal("received wrong number of statuses") - } else if received[0].Id != statuses[1].Id { + t.Fatal("received wrong number of jobs") + } else if received[0].Id != jobs[2].Id { t.Fatal("should've received newest job first") - } else if received[1].Id != statuses[0].Id { + } else if received[1].Id != jobs[0].Id { t.Fatal("should've received second newest job second") } @@ -87,8 +170,8 @@ func TestGetJobStatusesByType(t *testing.T) { CheckNoError(t, resp) if len(received) != 1 { - t.Fatal("received wrong number of statuses") - } else if received[0].Id != statuses[2].Id { + t.Fatal("received wrong number of jobs") + } else if received[0].Id != jobs[1].Id { t.Fatal("should've received oldest job last") } @@ -101,3 +184,46 @@ func TestGetJobStatusesByType(t *testing.T) { _, resp = th.Client.GetJobsByType(jobType, 0, 60) CheckForbiddenStatus(t, resp) } + +func TestCancelJob(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + + jobs := []*model.Job{ + { + Id: model.NewId(), + Type: model.NewId(), + Status: model.JOB_STATUS_PENDING, + }, + { + Id: model.NewId(), + Type: model.NewId(), + Status: model.JOB_STATUS_IN_PROGRESS, + }, + { + Id: model.NewId(), + Type: model.NewId(), + Status: model.JOB_STATUS_SUCCESS, + }, + } + + for _, job := range jobs { + store.Must(app.Srv.Store.Job().Save(job)) + defer app.Srv.Store.Job().Delete(job.Id) + } + + _, resp := th.Client.CancelJob(jobs[0].Id) + CheckForbiddenStatus(t, resp) + + _, resp = th.SystemAdminClient.CancelJob(jobs[0].Id) + CheckNoError(t, resp) + + _, resp = th.SystemAdminClient.CancelJob(jobs[1].Id) + CheckNoError(t, resp) + + _, resp = th.SystemAdminClient.CancelJob(jobs[2].Id) + CheckInternalErrorStatus(t, resp) + + _, resp = th.SystemAdminClient.CancelJob(model.NewId()) + CheckInternalErrorStatus(t, resp) +} -- cgit v1.2.3-1-g7c22