package requests
import (
+ "reflect"
+ "sort"
"sync"
"time"
}
// ListRequests is part of implementation of Requests interface. It returns slice
-// of ReqInfo that matches ListFilter.
+// of ReqInfo that matches ListFilter. Returned slice is sorted by request ids.
func (reqs *ReqsCollection) ListRequests(filter ListFilter) ([]ReqInfo, error) {
reqs.mutex.RLock()
- defer reqs.mutex.RUnlock()
res := make([]ReqInfo, 0, len(reqs.requests))
for _, req := range reqs.requests {
- if filter == nil || filter.Match(req) {
+ if filter == nil || reflect.ValueOf(filter).IsNil() ||
+ filter.Match(req) {
res = append(res, *req)
}
}
+ reqs.mutex.RUnlock()
+ // TODO(mwereski): HTTP backend needs this to be sorted. This isn't best
+ // place to do it, rethink that when DB backend is implemented.
+ sort.Slice(res, func(i, j int) bool { return res[i].ID < res[j].ID })
return res, nil
}
}
// Nil filter should return all requests.
+
+ // Nil interface.
resp, err := rqueue.ListRequests(nil)
assert.Nil(err)
checkReqs(reqs, resp)
+ var flt *reqFilter
+ // Concrete type is nil but interface isn't nil.
+ resp, err = rqueue.ListRequests(flt)
+ assert.Nil(err)
+ checkReqs(reqs, resp)
}
func TestAcquireWorker(t *testing.T) {
const (
contentTypeJSON = "application/json"
invalidID = "test"
+ dateLayout = "2006-01-02"
+ past = "1683-09-12"
+ future = "2222-12-31"
validReqJSON = `{
"ID":1,
"State":"WAITING",
import (
"encoding/json"
+ "io"
"net/http"
. "git.tizen.org/tools/boruta"
// listRequestsHandler parses HTTP request for listing Boruta requests and calls
// ListRequests().
func (api *API) listRequestsHandler(r *http.Request, ps map[string]string) responseData {
- return newServerError(ErrNotImplemented, "list requests")
+ var filter *RequestFilter
+ defer r.Body.Close()
+
+ if r.Method == http.MethodPost {
+ filter = new(RequestFilter)
+ if err := json.NewDecoder(r.Body).Decode(filter); err != nil {
+ if err != io.EOF {
+ return newServerError(err)
+ }
+ filter = nil
+ }
+ }
+
+ reqs, err := api.reqs.ListRequests(filter)
+ if err != nil {
+ return newServerError(err)
+ }
+
+ return reqs
}
// acquireWorkerHandler parses HTTP request for acquiring worker for Boruta
import (
"encoding/json"
+ "errors"
"fmt"
"net/http"
"testing"
+ "time"
. "git.tizen.org/tools/boruta"
"git.tizen.org/tools/boruta/requests"
assert, m, api := initTest(t)
defer m.finish()
+ deadline, err := time.Parse(dateLayout, future)
+ assert.Nil(err)
+ validAfter, err := time.Parse(dateLayout, past)
+ assert.Nil(err)
+ reqs := []ReqInfo{
+ {ID: 1, Priority: (HiPrio + LoPrio) / 2, State: WAIT,
+ Deadline: deadline, ValidAfter: validAfter},
+ {ID: 2, Priority: (HiPrio+LoPrio)/2 + 1, State: WAIT,
+ Deadline: deadline, ValidAfter: validAfter},
+ {ID: 3, Priority: (HiPrio + LoPrio) / 2, State: CANCEL,
+ Deadline: deadline, ValidAfter: validAfter},
+ {ID: 4, Priority: (HiPrio+LoPrio)/2 + 1, State: CANCEL,
+ Deadline: deadline, ValidAfter: validAfter},
+ }
+
+ methods := []string{http.MethodPost}
+ prefix := "filter-reqs-"
+ filterPath := "/api/v1/reqs/list"
+ malformedJSONTest := testFromTempl(malformedJSONTestTempl, prefix, filterPath, methods...)
+
+ validFilter := NewRequestFilter("WAIT", "")
+ m.rq.EXPECT().ListRequests(validFilter).Return(reqs[:2], nil)
+
+ emptyFilter := NewRequestFilter("", "")
+ m.rq.EXPECT().ListRequests(emptyFilter).Return(reqs, nil).Times(2)
+ m.rq.EXPECT().ListRequests(nil).Return(reqs, nil).Times(3)
+
+ missingFilter := NewRequestFilter("INVALID", "")
+ m.rq.EXPECT().ListRequests(missingFilter).Return([]ReqInfo{}, nil)
+
+ // Currently ListRequests doesn't return any error hence the meaningless values.
+ badFilter := NewRequestFilter("FAIL", "-1")
+ m.rq.EXPECT().ListRequests(badFilter).Return([]ReqInfo{}, errors.New("foo bar: pizza failed"))
+
tests := []requestTest{
+ // Valid filter - list some requests.
+ {
+ name: prefix + "valid-filter",
+ path: filterPath,
+ methods: methods,
+ json: string(jsonMustMarshal(validFilter)),
+ contentType: contentTypeJSON,
+ status: http.StatusOK,
+ },
+ // List all requests.
{
name: "list-reqs-all",
path: "/api/v1/reqs/",
methods: []string{http.MethodGet, http.MethodHead},
json: ``,
contentType: contentTypeJSON,
- status: http.StatusNotImplemented,
+ status: http.StatusOK,
},
+ // Empty body - list all requests.
{
- name: "list-reqs-filter",
- path: "/api/v1/reqs/list",
- methods: []string{http.MethodPost},
- json: ``,
+ name: prefix + "empty-json",
+ path: filterPath,
+ methods: methods,
+ json: "",
contentType: contentTypeJSON,
- status: http.StatusNotImplemented,
+ status: http.StatusOK,
},
+ // Nil filter - list all requests (same as emptyFilter).
+ {
+ name: prefix + "nil",
+ path: filterPath,
+ methods: methods,
+ json: string(jsonMustMarshal(nil)),
+ contentType: contentTypeJSON,
+ status: http.StatusOK,
+ },
+ // Empty filter - list all requests.
+ {
+ name: prefix + "empty",
+ path: filterPath,
+ methods: methods,
+ json: string(jsonMustMarshal(emptyFilter)),
+ contentType: contentTypeJSON,
+ status: http.StatusOK,
+ },
+ // No matches
+ {
+ name: prefix + "nomatch-all",
+ path: filterPath,
+ methods: methods,
+ json: string(jsonMustMarshal(missingFilter)),
+ contentType: contentTypeJSON,
+ status: http.StatusOK,
+ },
+ // Error
+ {
+ name: prefix + "bad-filter",
+ path: filterPath,
+ methods: methods,
+ json: string(jsonMustMarshal(badFilter)),
+ contentType: contentTypeJSON,
+ status: http.StatusBadRequest,
+ },
+ malformedJSONTest,
}
runTests(assert, api, tests)
--- /dev/null
+{"error":"invalid request: foo bar: pizza failed"}
\ No newline at end of file
--- /dev/null
+[{"ID":1,"Priority":8,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"WAITING","Job":null,"Caps":null},{"ID":2,"Priority":9,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"WAITING","Job":null,"Caps":null},{"ID":3,"Priority":8,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"CANCELLED","Job":null,"Caps":null},{"ID":4,"Priority":9,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"CANCELLED","Job":null,"Caps":null}]
\ No newline at end of file
--- /dev/null
+[{"ID":1,"Priority":8,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"WAITING","Job":null,"Caps":null},{"ID":2,"Priority":9,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"WAITING","Job":null,"Caps":null},{"ID":3,"Priority":8,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"CANCELLED","Job":null,"Caps":null},{"ID":4,"Priority":9,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"CANCELLED","Job":null,"Caps":null}]
\ No newline at end of file
--- /dev/null
+{"error":"invalid request: unexpected EOF"}
\ No newline at end of file
--- /dev/null
+[{"ID":1,"Priority":8,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"WAITING","Job":null,"Caps":null},{"ID":2,"Priority":9,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"WAITING","Job":null,"Caps":null},{"ID":3,"Priority":8,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"CANCELLED","Job":null,"Caps":null},{"ID":4,"Priority":9,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"CANCELLED","Job":null,"Caps":null}]
\ No newline at end of file
--- /dev/null
+[]
\ No newline at end of file
--- /dev/null
+[{"ID":1,"Priority":8,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"WAITING","Job":null,"Caps":null},{"ID":2,"Priority":9,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"WAITING","Job":null,"Caps":null}]
\ No newline at end of file
-{"error":"not implemented yet: list requests"}
\ No newline at end of file
+[{"ID":1,"Priority":8,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"WAITING","Job":null,"Caps":null},{"ID":2,"Priority":9,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"WAITING","Job":null,"Caps":null},{"ID":3,"Priority":8,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"CANCELLED","Job":null,"Caps":null},{"ID":4,"Priority":9,"Owner":{"Groups":null},"Deadline":"2222-12-31T00:00:00Z","ValidAfter":"1683-09-12T00:00:00Z","State":"CANCELLED","Job":null,"Caps":null}]
\ No newline at end of file
+++ /dev/null
-{"error":"not implemented yet: list requests"}
\ No newline at end of file