Skip to content

Commit

Permalink
[Aishwarya|Jenson] Add describe,remove scheduled jobs functionality t…
Browse files Browse the repository at this point in the history
…o server
  • Loading branch information
jensoncs committed Jan 21, 2019
1 parent 5943c47 commit d435d5e
Show file tree
Hide file tree
Showing 10 changed files with 425 additions and 22 deletions.
84 changes: 84 additions & 0 deletions proctord/jobs/schedule/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package schedule

import (
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"net/http"
"strings"

Expand All @@ -22,6 +24,8 @@ type scheduler struct {
type Scheduler interface {
Schedule() http.HandlerFunc
GetScheduledJobs() http.HandlerFunc
GetScheduledJob() http.HandlerFunc
RemoveScheduledJob() http.HandlerFunc
}

func NewScheduler(store storage.Store, metadataStore metadata.Store) Scheduler {
Expand Down Expand Up @@ -137,6 +141,13 @@ func (scheduler *scheduler) GetScheduledJobs() http.HandlerFunc {
return
}

if len(scheduledJobsStoreFormat) == 0 {
logger.Error("No scheduled jobs found on proctord", nil)
w.WriteHeader(http.StatusOK)
w.Write([]byte("No scheduled jobs found on proctord"))
return
}

scheduledJobs := FromStoreToHandler(scheduledJobsStoreFormat)

scheduledJobsJson, err := json.Marshal(scheduledJobs)
Expand All @@ -151,3 +162,76 @@ func (scheduler *scheduler) GetScheduledJobs() http.HandlerFunc {
w.Write(scheduledJobsJson)
}
}

func (scheduler *scheduler) GetScheduledJob() http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
jobID := mux.Vars(req)["id"]
scheduledJob, err := scheduler.store.GetScheduledJob(jobID)
if err != nil {
if err.Error() == fmt.Sprintf("pq: invalid input syntax for type uuid: \"%s\"", jobID) {
logger.Error(err.Error())
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Invalid Job ID"))
return
}
logger.Error("Error fetching scheduled job", err.Error())

w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(utility.ServerError))
return
}

if len(scheduledJob) == 0 {
logger.Error(utility.JobNotFoundError, nil)

w.WriteHeader(http.StatusNotFound)
w.Write([]byte(utility.JobNotFoundError))
return
}

job := FromStoreToHandler(scheduledJob)

scheduledJobJson, err := json.Marshal(job)
if err != nil {
logger.Error("Error marshalling scheduled job", err.Error())

w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(utility.ServerError))
return
}

w.Write(scheduledJobJson)
}
}

func (scheduler *scheduler) RemoveScheduledJob() http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
jobID := mux.Vars(req)["id"]
removedJobsCount, err := scheduler.store.RemoveScheduledJob(jobID)
if err != nil {
if err.Error() == fmt.Sprintf("pq: invalid input syntax for type uuid: \"%s\"", jobID) {
logger.Error(err.Error())
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Invalid Job ID"))
return
}
logger.Error("Error fetching scheduled job", err.Error())

w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(utility.ServerError))
return
}

if removedJobsCount == 0 {
logger.Error(utility.JobNotFoundError, nil)

w.WriteHeader(http.StatusNotFound)
w.Write([]byte(utility.JobNotFoundError))
return
}

w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf("Successfully unscheduled Job ID: %s", jobID)))
}
}

224 changes: 223 additions & 1 deletion proctord/jobs/schedule/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/gorilla/mux"
"github.com/urfave/negroni"
"io/ioutil"
"net/http"
"net/http/httptest"
Expand All @@ -23,13 +26,23 @@ type SchedulerTestSuite struct {
mockMetadataStore *metadata.MockStore

testScheduler Scheduler

Client *http.Client
TestServer *httptest.Server
}

func (suite *SchedulerTestSuite) SetupTest() {
suite.mockMetadataStore = &metadata.MockStore{}
suite.mockStore = &storage.MockStore{}

suite.testScheduler = NewScheduler(suite.mockStore, suite.mockMetadataStore)

suite.Client = &http.Client{}
router := mux.NewRouter()
router.HandleFunc("/jobs/schedule/{id}", suite.testScheduler.GetScheduledJob()).Methods("GET")
router.HandleFunc("/jobs/schedule/{id}", suite.testScheduler.RemoveScheduledJob()).Methods("DELETE")
n := negroni.Classic()
n.UseHandler(router)
suite.TestServer = httptest.NewServer(n)
}

func (suite *SchedulerTestSuite) TestSuccessfulJobScheduling() {
Expand Down Expand Up @@ -266,6 +279,28 @@ func (s *SchedulerTestSuite) TestGetScheduledJobs() {
assert.Equal(t, scheduledJobsStoreFormat[0].ID, scheduledJobs[0].ID)
}

func (s *SchedulerTestSuite) TestGetScheduledJobsWhenNoJobsFound() {
t := s.T()

req := httptest.NewRequest("GET", "/jobs/schedule", bytes.NewReader([]byte{}))
responseRecorder := httptest.NewRecorder()

scheduledJobsStoreFormat := []postgres.JobsSchedule{}
s.mockStore.On("GetEnabledScheduledJobs").Return(scheduledJobsStoreFormat, nil).Once()

s.testScheduler.GetScheduledJobs()(responseRecorder, req)

s.mockStore.AssertExpectations(t)

assert.Equal(t, http.StatusOK, responseRecorder.Code)

buf := new(bytes.Buffer)
buf.ReadFrom(responseRecorder.Body)
responseBody := buf.String()
assert.Equal(t, "No scheduled jobs found on proctord", responseBody)

}

func (s *SchedulerTestSuite) TestGetScheduledJobsFailure() {
t := s.T()

Expand All @@ -283,6 +318,193 @@ func (s *SchedulerTestSuite) TestGetScheduledJobsFailure() {
assert.Equal(t, utility.ServerError, responseRecorder.Body.String())
}

func (s *SchedulerTestSuite) TestGetScheduledJobByID() {
t := s.T()
jobID := "some-id"

scheduledJobsStoreFormat := []postgres.JobsSchedule{
postgres.JobsSchedule{
ID: jobID,
},
}
s.mockStore.On("GetScheduledJob", jobID).Return(scheduledJobsStoreFormat, nil).Once()

url := fmt.Sprintf("%s/jobs/schedule/%s", s.TestServer.URL, jobID)
req, _ := http.NewRequest("GET", url, nil)

response, err := s.Client.Do(req)

assert.NoError(t, err)
assert.Equal(t, http.StatusOK, response.StatusCode)

var scheduledJobs []ScheduledJob
err = json.NewDecoder(response.Body).Decode(&scheduledJobs)
assert.NoError(t, err)
assert.Equal(t, jobID, scheduledJobs[0].ID)

s.mockStore.AssertExpectations(t)
}

func (s *SchedulerTestSuite) TestGetScheduledJobByIDOnInvalidJobID() {
t := s.T()
jobID := "invalid-job-id"

scheduledJobsStoreFormat := []postgres.JobsSchedule{}

s.mockStore.On("GetScheduledJob", jobID).Return(scheduledJobsStoreFormat, errors.New(fmt.Sprintf("pq: invalid input syntax for type uuid: \"%s\"", jobID))).Once()

url := fmt.Sprintf("%s/jobs/schedule/%s", s.TestServer.URL, jobID)
req, _ := http.NewRequest("GET", url, nil)

response, err := s.Client.Do(req)

assert.NoError(t, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)

buf := new(bytes.Buffer)
buf.ReadFrom(response.Body)
responseBody := buf.String()
assert.Equal(t, "Invalid Job ID", responseBody)

s.mockStore.AssertExpectations(t)
}

func (s *SchedulerTestSuite) TestGetScheduledJobByIDOnInternalServerError() {
t := s.T()
jobID := "job-id"

scheduledJobsStoreFormat := []postgres.JobsSchedule{}

s.mockStore.On("GetScheduledJob", jobID).Return(scheduledJobsStoreFormat, errors.New("some-error")).Once()

url := fmt.Sprintf("%s/jobs/schedule/%s", s.TestServer.URL, jobID)
req, _ := http.NewRequest("GET", url, nil)

response, err := s.Client.Do(req)
assert.NoError(t, err)

assert.Equal(t, http.StatusInternalServerError, response.StatusCode)

buf := new(bytes.Buffer)
buf.ReadFrom(response.Body)
responseBody := buf.String()
assert.Equal(t, "Something went wrong", responseBody)

s.mockStore.AssertExpectations(t)
}

func (s *SchedulerTestSuite) TestGetScheduledJobByIDOnJobIDNotFound() {
t := s.T()
jobID := "absent-job-id"

scheduledJobsStoreFormat := []postgres.JobsSchedule{}

s.mockStore.On("GetScheduledJob", jobID).Return(scheduledJobsStoreFormat, nil).Once()

url := fmt.Sprintf("%s/jobs/schedule/%s", s.TestServer.URL, jobID)
req, _ := http.NewRequest("GET", url, nil)

response, err := s.Client.Do(req)
assert.NoError(t, err)

assert.Equal(t, http.StatusNotFound, response.StatusCode)

buf := new(bytes.Buffer)
buf.ReadFrom(response.Body)
responseBody := buf.String()
assert.Equal(t, "Job not found", responseBody)

s.mockStore.AssertExpectations(t)
}

func (s *SchedulerTestSuite) TestRemoveScheduledJobByID() {
t := s.T()
jobID := "some-id"

s.mockStore.On("RemoveScheduledJob", jobID).Return(int64(1), nil).Once()

url := fmt.Sprintf("%s/jobs/schedule/%s", s.TestServer.URL, jobID)
req, _ := http.NewRequest("DELETE", url, nil)

response, err := s.Client.Do(req)

assert.NoError(t, err)
assert.Equal(t, http.StatusOK, response.StatusCode)

buf := new(bytes.Buffer)
buf.ReadFrom(response.Body)
responseBody := buf.String()
assert.Equal(t, "Successfully unscheduled Job ID: some-id", responseBody)

s.mockStore.AssertExpectations(t)
}

func (s *SchedulerTestSuite) TestRemoveScheduledJobByIDOnInvalidJobID() {
t := s.T()
jobID := "invalid-job-id"

s.mockStore.On("RemoveScheduledJob", jobID).Return(int64(0), errors.New(fmt.Sprintf("pq: invalid input syntax for type uuid: \"%s\"", jobID))).Once()

url := fmt.Sprintf("%s/jobs/schedule/%s", s.TestServer.URL, jobID)
req, _ := http.NewRequest("DELETE", url, nil)

response, err := s.Client.Do(req)

assert.NoError(t, err)
assert.Equal(t, http.StatusBadRequest, response.StatusCode)

buf := new(bytes.Buffer)
buf.ReadFrom(response.Body)
responseBody := buf.String()
assert.Equal(t, "Invalid Job ID", responseBody)

s.mockStore.AssertExpectations(t)
}

func (s *SchedulerTestSuite) TestRemoveScheduledJobByIDOnInternalServerError() {
t := s.T()
jobID := "job-id"

s.mockStore.On("RemoveScheduledJob", jobID).Return(int64(0), errors.New("some-error")).Once()

url := fmt.Sprintf("%s/jobs/schedule/%s", s.TestServer.URL, jobID)
req, _ := http.NewRequest("DELETE", url, nil)

response, err := s.Client.Do(req)
assert.NoError(t, err)

assert.Equal(t, http.StatusInternalServerError, response.StatusCode)

buf := new(bytes.Buffer)
buf.ReadFrom(response.Body)
responseBody := buf.String()
assert.Equal(t, "Something went wrong", responseBody)

s.mockStore.AssertExpectations(t)
}

func (s *SchedulerTestSuite) TestRemoveScheduledJobByIDOnJobIDNotFound() {
t := s.T()
jobID := "absent-job-id"

s.mockStore.On("RemoveScheduledJob", jobID).Return(int64(0), nil).Once()

url := fmt.Sprintf("%s/jobs/schedule/%s", s.TestServer.URL, jobID)
req, _ := http.NewRequest("DELETE", url, nil)

response, err := s.Client.Do(req)
assert.NoError(t, err)

assert.Equal(t, http.StatusNotFound, response.StatusCode)

buf := new(bytes.Buffer)
buf.ReadFrom(response.Body)
responseBody := buf.String()
assert.Equal(t, "Job not found", responseBody)

s.mockStore.AssertExpectations(t)
}

func TestScheduleTestSuite(t *testing.T) {
suite.Run(t, new(SchedulerTestSuite))
}
2 changes: 2 additions & 0 deletions proctord/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,7 @@ func NewRouter() (*mux.Router, error) {
router.HandleFunc(instrumentation.Wrap("/jobs/secrets", middleware.ValidateClientVersion(jobSecretsHandler.HandleSubmission()))).Methods("POST")
router.HandleFunc(instrumentation.Wrap("/jobs/schedule", middleware.ValidateClientVersion(scheduledJobsHandler.Schedule()))).Methods("POST")
router.HandleFunc(instrumentation.Wrap("/jobs/schedule", middleware.ValidateClientVersion(scheduledJobsHandler.GetScheduledJobs()))).Methods("GET")
router.HandleFunc(instrumentation.Wrap("/jobs/schedule/{id}", middleware.ValidateClientVersion(scheduledJobsHandler.GetScheduledJob()))).Methods("GET")
router.HandleFunc(instrumentation.Wrap("/jobs/schedule/{id}", middleware.ValidateClientVersion(scheduledJobsHandler.RemoveScheduledJob()))).Methods("DELETE")
return router, nil
}
Loading

0 comments on commit d435d5e

Please sign in to comment.