return
}
+// getHeaders is a helper function that makes HEAD HTTP request for given address,
+// checks Status and returns HTTP headers and error.
+func getHeaders(url string) (http.Header, error) {
+ resp, err := http.Head(url)
+ if err != nil {
+ return nil, err
+ }
+ if err = checkStatus(http.StatusNoContent, resp); err != nil {
+ return nil, err
+ }
+ return resp.Header, nil
+}
+
// NewRequest creates new Boruta request.
func (client *BorutaClient) NewRequest(caps boruta.Capabilities,
priority boruta.Priority, owner boruta.UserInfo, validAfter time.Time,
// request state.
func (client *BorutaClient) GetRequestState(reqID boruta.ReqID) (boruta.ReqState, error) {
path := client.url + "reqs/" + strconv.Itoa(int(reqID))
- resp, err := http.Head(path)
+ headers, err := getHeaders(path)
if err != nil {
return boruta.FAILED, err
}
- if err = checkStatus(http.StatusNoContent, resp); err != nil {
- return boruta.FAILED, err
- }
- return boruta.ReqState(resp.Header.Get("Boruta-Request-State")), nil
+ return boruta.ReqState(headers.Get("Boruta-Request-State")), nil
}
// GetWorkerState is convenient way to check state of a worker with given UUID.
func (client *BorutaClient) GetWorkerState(uuid boruta.WorkerUUID) (boruta.WorkerState, error) {
path := client.url + "workers/" + string(uuid)
- resp, err := http.Head(path)
+ headers, err := getHeaders(path)
if err != nil {
return boruta.FAIL, err
}
- if err = checkStatus(http.StatusNoContent, resp); err != nil {
- return boruta.FAIL, err
+ return boruta.WorkerState(headers.Get("Boruta-Worker-State")), nil
+}
+
+// GetJobTimeout is convenient way to check when Job of a request with given
+// reqID will timeout. The request must be in INPROGRESS state.
+func (client *BorutaClient) GetJobTimeout(reqID boruta.ReqID) (time.Time, error) {
+ var t time.Time
+ path := client.url + "reqs/" + strconv.Itoa(int(reqID))
+ headers, err := getHeaders(path)
+ if err != nil {
+ return t, err
+ }
+ if boruta.ReqState(headers.Get("Boruta-Request-State")) != boruta.INPROGRESS {
+ return t, errors.New(`request must be in "IN PROGRESS" state`)
}
- return boruta.WorkerState(resp.Header.Get("Boruta-Worker-State")), nil
+ return time.Parse(util.DateFormat, headers.Get("Boruta-Job-Timeout"))
}
assert.Equal(err, checkStatus(http.StatusBadRequest, &resp))
}
+func TestGetHeaders(t *testing.T) {
+ prefix := "boruta-headers-"
+ pathW := "/api/v1/workers/"
+ pathR := "/api/v1/reqs/"
+ date := time.Now().Format(util.DateFormat)
+
+ worker := make(http.Header)
+ worker.Set("Boruta-Worker-State", string(RUN))
+
+ request := make(http.Header)
+ request.Set("Boruta-Request-State", string(INPROGRESS))
+ request.Set("Boruta-Job-Timeout", date)
+
+ tests := []*testCase{
+ &testCase{
+ // valid worker
+ name: prefix + "worker",
+ path: pathW + validUUID,
+ status: http.StatusNoContent,
+ header: worker,
+ },
+ &testCase{
+ // valid request
+ name: prefix + "request",
+ path: pathR + "1",
+ status: http.StatusNoContent,
+ header: request,
+ },
+
+ &testCase{
+ // invalid UUID
+ name: prefix + "bad-uuid",
+ path: pathW + invalidID,
+ contentType: contentJSON,
+ status: http.StatusBadRequest,
+ },
+ }
+
+ assert := assert.New(t)
+ srv := prepareServer(http.MethodHead, tests)
+ url := srv.URL
+ defer srv.Close()
+
+ // valid worker
+ headers, err := getHeaders(url + pathW + validUUID)
+ assert.Nil(err)
+ assert.Equal(worker.Get("Boruta-Worker-State"), headers.Get("Boruta-Worker-State"))
+
+ // valid request
+ headers, err = getHeaders(url + pathR + "1")
+ assert.Nil(err)
+ assert.Equal(request.Get("Boruta-Request-State"), headers.Get("Boruta-Request-State"))
+ assert.Equal(request.Get("Boruta-Job-Timeout"), headers.Get("Boruta-Job-Timeout"))
+
+ // invalid UUID
+ headers, err = getHeaders(url + pathW + invalidID)
+ assert.Nil(headers)
+ assert.Equal(errors.New("bad HTTP status: 400 Bad Request"), err)
+
+ // http.Head failure
+ url = "http://nosuchaddress.fail"
+ headers, err = getHeaders(url)
+ assert.Nil(headers)
+ assert.NotNil(err)
+
+}
+
func TestNewRequest(t *testing.T) {
prefix := "new-req-"
path := "/api/v1/reqs/"
// missing request
state, err = client.GetRequestState(ReqID(2))
assert.Equal(errors.New("bad HTTP status: 404 Not Found"), err)
-
- // http.Head failure
- client.url = "http://nosuchaddress.fail"
- assert.NotNil(client.GetRequestState(ReqID(1)))
}
func TestGetWorkerState(t *testing.T) {
// invalid UUID
state, err = client.GetWorkerState(invalidID)
assert.Equal(errors.New("bad HTTP status: 400 Bad Request"), err)
+}
- // http.Head failure
- client.url = "http://nosuchaddress.fail"
- assert.NotNil(client.GetWorkerState(validUUID))
+func TestGetJobTimeout(t *testing.T) {
+ prefix := "get-job-timeout-"
+ path := "/api/v1/reqs/"
+ date := time.Now().Round(time.Second)
+
+ header := make(http.Header)
+ header.Set("Boruta-Request-State", string(INPROGRESS))
+ header.Set("Boruta-Job-Timeout", date.Format(util.DateFormat))
+
+ wait := make(http.Header)
+ wait.Set("Boruta-Request-State", string(WAIT))
+
+ bad := make(http.Header)
+ bad.Set("Boruta-Request-State", string(INPROGRESS))
+ bad.Set("Boruta-Job-Timeout", "fail")
+
+ tests := []*testCase{
+ &testCase{
+ // valid request
+ name: prefix + "valid",
+ path: path + "1",
+ status: http.StatusNoContent,
+ header: header,
+ },
+ &testCase{
+ // request in wrong state
+ name: prefix + "wrong-state",
+ path: path + "2",
+ status: http.StatusNoContent,
+ header: wait,
+ },
+ &testCase{
+ // missing request
+ name: prefix + "missing",
+ path: path + "3",
+ contentType: contentJSON,
+ status: http.StatusNotFound,
+ },
+ &testCase{
+ // invalid date format
+ name: prefix + "bad-date",
+ path: path + "4",
+ contentType: contentJSON,
+ status: http.StatusNoContent,
+ header: bad,
+ },
+ }
+
+ srv := prepareServer(http.MethodHead, tests)
+ defer srv.Close()
+ assert, client := initTest(t, srv.URL)
+
+ // valid
+ timeout, err := client.GetJobTimeout(ReqID(1))
+ assert.Nil(err)
+ assert.True(date.Equal(timeout))
+
+ // wrong state
+ _, err = client.GetJobTimeout(ReqID(2))
+ assert.Equal(errors.New(`request must be in "IN PROGRESS" state`), err)
+
+ // missing
+ _, err = client.GetJobTimeout(ReqID(3))
+ assert.Equal(errors.New("bad HTTP status: 404 Not Found"), err)
+
+ // wrong date format
+ _, err = client.GetJobTimeout(ReqID(4))
+ assert.NotNil(err)
+ var parseErr *time.ParseError
+ assert.IsType(parseErr, err)
}
header := make(http.Header)
header.Set("Boruta-Request-State", "WAITING")
- notFoundTest := testFromTempl(notFoundTestTempl, prefix, path+"2", methods...)
+ timeout, err := time.Parse(dateLayout, future)
+ assert.Nil(err)
+ var running ReqInfo
+ err = json.Unmarshal([]byte(validReqJSON), &running)
+ assert.Nil(err)
+ running.ID = ReqID(2)
+ running.State = INPROGRESS
+ running.Job = &JobInfo{
+ WorkerUUID: validUUID,
+ Timeout: timeout,
+ }
+ rheader := make(http.Header)
+ rheader.Set("Boruta-Request-State", string(INPROGRESS))
+ rheader.Set("Boruta-Job-Timeout", timeout.Format(util.DateFormat))
+
+ notFoundTest := testFromTempl(notFoundTestTempl, prefix, path+"3", methods...)
invalidIDTest := testFromTempl(invalidIDTestTempl, prefix, path+invalidID, methods...)
m.rq.EXPECT().GetRequestInfo(ReqID(1)).Return(req, nil).Times(2)
- m.rq.EXPECT().GetRequestInfo(ReqID(2)).Return(ReqInfo{}, NotFoundError("Request")).Times(2)
+ m.rq.EXPECT().GetRequestInfo(ReqID(2)).Return(running, nil).Times(2)
+ m.rq.EXPECT().GetRequestInfo(ReqID(3)).Return(ReqInfo{}, NotFoundError("Request")).Times(2)
tests := []requestTest{
// Get information of existing request.
status: http.StatusOK,
header: header,
},
+ // Get information of running request.
+ {
+ name: "req-info-running",
+ path: path + "2",
+ methods: methods,
+ json: ``,
+ contentType: contentTypeJSON,
+ status: http.StatusOK,
+ header: rheader,
+ },
// Try to get request information of request that doesn't exist.
notFoundTest,
// Try to get request with invalid ID.