HTTP API: Creating new requests
authorMaciej Wereski <m.wereski@partner.samsung.com>
Wed, 6 Sep 2017 15:45:01 +0000 (17:45 +0200)
committerMaciej Wereski <m.wereski@partner.samsung.com>
Tue, 5 Jun 2018 09:26:40 +0000 (11:26 +0200)
Change-Id: I42423080832d0bba13f9b219d05c0e9fa48c7d06
Signed-off-by: Maciej Wereski <m.wereski@partner.samsung.com>
server/api/v1/api.go
server/api/v1/api_test.go
server/api/v1/handlers.go
server/api/v1/handlers_test.go
server/api/v1/testdata/new-req-POST.json [deleted file]
server/api/v1/testdata/new-req-bad-prio-POST.json [new file with mode: 0644]
server/api/v1/testdata/new-req-malformed-json-POST.json [new file with mode: 0644]
server/api/v1/testdata/new-req-valid-POST.json [new file with mode: 0644]

index 4331679..c923096 100644 (file)
@@ -24,6 +24,7 @@ import (
        "fmt"
        "net/http"
 
+       . "git.tizen.org/tools/boruta"
        "github.com/dimfeld/httptreemux"
 )
 
@@ -31,12 +32,18 @@ import (
 // Returned values are directly converted to JSON responses.
 type responseData interface{}
 
+// reqIDPack is used as input for JSON (un)marshaller.
+type reqIDPack struct {
+       ReqID
+}
+
 // reqHandler denotes function that parses HTTP request and returns responseData.
 type reqHandler func(*http.Request, map[string]string) responseData
 
 // API provides HTTP API handlers.
 type API struct {
-       r *httptreemux.TreeMux
+       r    *httptreemux.TreeMux
+       reqs Requests
 }
 
 // jsonMustMarshal tries to marshal responseData to JSON. Panics if error occurs.
@@ -99,9 +106,11 @@ func routerSetHandler(grp *httptreemux.Group, path string, fn reqHandler,
 
 // NewAPI takes router and registers HTTP API in it. httptreemux.PanicHandler
 // function is set. Also other setting of the router may be modified.
-func NewAPI(router *httptreemux.TreeMux) (api *API) {
+func NewAPI(router *httptreemux.TreeMux, requestsAPI Requests) (api *API) {
        api = new(API)
 
+       api.reqs = requestsAPI
+
        api.r = router
        api.r.PanicHandler = panicHandler
 
index 038b678..32ca17d 100644 (file)
@@ -34,7 +34,22 @@ import (
        "github.com/stretchr/testify/assert"
 )
 
-const contentTypeJSON = "application/json"
+const (
+       contentTypeJSON = "application/json"
+       validReqJSON    = `{
+               "ID":1,
+               "State":"WAITING",
+               "Job":null,
+               "Priority":8,
+               "Deadline":"2200-12-31T01:02:03Z",
+               "ValidAfter":"2100-01-01T04:05:06Z",
+               "Caps":{
+                       "architecture":"armv7l",
+                       "monitor":"yes"
+               },
+               "Owner":{}
+       }`
+)
 
 var update bool
 
@@ -53,6 +68,20 @@ type allMocks struct {
        wm   *mocks.MockWorkers
 }
 
+var (
+       // malformedJSONTestTempl may be used by functions that need to check
+       // for malformed JSON to initialize test. Every test must set path, name
+       // and method appropriately.
+       malformedJSONTestTempl = &requestTest{
+               name:        "malformed-json",
+               path:        "",
+               methods:     []string{},
+               json:        `{"Priority{}`,
+               contentType: contentTypeJSON,
+               status:      http.StatusBadRequest,
+       }
+)
+
 func TestMain(m *testing.M) {
        flag.BoolVar(&update, "update", false, "update testdata")
        flag.Parse()
@@ -66,13 +95,24 @@ func initTest(t *testing.T) (*assert.Assertions, *allMocks, *API) {
                rq:   mocks.NewMockRequests(ctrl),
                wm:   mocks.NewMockWorkers(ctrl),
        }
-       return assert.New(t), m, NewAPI(httptreemux.New())
+       return assert.New(t), m, NewAPI(httptreemux.New(), m.rq)
 }
 
 func (m *allMocks) finish() {
        m.ctrl.Finish()
 }
 
+func testFromTempl(templ *requestTest, name string, path string,
+       methods ...string) (ret requestTest) {
+       ret = *templ
+       ret.name = name + templ.name
+       ret.path = path
+       if len(methods) != 0 {
+               ret.methods = methods
+       }
+       return
+}
+
 func runTests(assert *assert.Assertions, api *API, tests []requestTest) {
        srv := httptest.NewServer(api.r)
        defer srv.Close()
index def6731..494bdd8 100644 (file)
 package v1
 
 import (
+       "encoding/json"
        "net/http"
+
+       . "git.tizen.org/tools/boruta"
 )
 
 // newRequestHandler parses HTTP request for creating new Boruta request and
 // calls NewRequest().
 func (api *API) newRequestHandler(r *http.Request, ps map[string]string) responseData {
-       return newServerError(ErrNotImplemented, "new request")
+       var newReq ReqInfo
+       defer r.Body.Close()
+
+       if err := json.NewDecoder(r.Body).Decode(&newReq); err != nil {
+               return newServerError(err)
+       }
+
+       //FIXME: currently UserInfo is ignored. Change when user support is added.
+       rid, err := api.reqs.NewRequest(newReq.Caps, newReq.Priority, UserInfo{},
+               newReq.ValidAfter.UTC(), newReq.Deadline.UTC())
+       if err != nil {
+               return newServerError(err)
+       }
+
+       return reqIDPack{rid}
 }
 
 // closeRequestHandler parses HTTP request for closing existing Boruta request
index 69bd11c..9aa92d1 100644 (file)
 package v1
 
 import (
+       "encoding/json"
        "net/http"
        "testing"
+
+       . "git.tizen.org/tools/boruta"
+       "git.tizen.org/tools/boruta/requests"
 )
 
 func TestNewRequestHandler(t *testing.T) {
        assert, m, api := initTest(t)
        defer m.finish()
 
+       prefix := "new-req-"
+       path := "/api/v1/reqs/"
+       methods := []string{http.MethodPost}
+       malformedJSONTest := testFromTempl(malformedJSONTestTempl, prefix, path, methods...)
+
+       var req ReqInfo
+       err := json.Unmarshal([]byte(validReqJSON), &req)
+       assert.Nil(err)
+
+       m.rq.EXPECT().NewRequest(req.Caps, req.Priority, req.Owner, req.ValidAfter,
+               req.Deadline).Return(ReqID(1), nil)
+       m.rq.EXPECT().NewRequest(req.Caps, Priority(32), req.Owner, req.ValidAfter,
+               req.Deadline).Return(ReqID(0), requests.ErrPriority)
+
        tests := []requestTest{
                {
-                       name:        "new-req",
-                       path:        "/api/v1/reqs/",
-                       methods:     []string{http.MethodPost},
-                       json:        ``,
+                       // valid request
+                       name:        prefix + "valid",
+                       path:        path,
+                       methods:     methods,
+                       json:        validReqJSON,
                        contentType: contentTypeJSON,
-                       status:      http.StatusNotImplemented,
+                       status:      http.StatusCreated,
+               },
+               {
+                       // bad request - priority out of bounds
+                       name:        prefix + "bad-prio",
+                       path:        path,
+                       methods:     methods,
+                       json:        `{"Priority":32,"Deadline":"2200-12-31T01:02:03Z","ValidAfter":"2100-01-01T04:05:06Z","Caps":{"architecture":"armv7l","monitor":"yes"}}`,
+                       contentType: contentTypeJSON,
+                       status:      http.StatusBadRequest,
                },
+               // bad request - malformed request JSON
+               malformedJSONTest,
        }
 
        runTests(assert, api, tests)
diff --git a/server/api/v1/testdata/new-req-POST.json b/server/api/v1/testdata/new-req-POST.json
deleted file mode 100644 (file)
index 620302e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"error":"not implemented yet: new request"}
\ No newline at end of file
diff --git a/server/api/v1/testdata/new-req-bad-prio-POST.json b/server/api/v1/testdata/new-req-bad-prio-POST.json
new file mode 100644 (file)
index 0000000..f97a9e1
--- /dev/null
@@ -0,0 +1 @@
+{"error":"invalid request: requested priority out of bounds"}
\ No newline at end of file
diff --git a/server/api/v1/testdata/new-req-malformed-json-POST.json b/server/api/v1/testdata/new-req-malformed-json-POST.json
new file mode 100644 (file)
index 0000000..c59dde1
--- /dev/null
@@ -0,0 +1 @@
+{"error":"invalid request: unexpected EOF"}
\ No newline at end of file
diff --git a/server/api/v1/testdata/new-req-valid-POST.json b/server/api/v1/testdata/new-req-valid-POST.json
new file mode 100644 (file)
index 0000000..b4770ed
--- /dev/null
@@ -0,0 +1 @@
+{"ReqID":1}
\ No newline at end of file