Skip to content

Commit

Permalink
Merge pull request #158 from keel-hq/feature/http-approvals
Browse files Browse the repository at this point in the history
Feature/http approvals
  • Loading branch information
rusenask authored Mar 11, 2018
2 parents 638ef93 + 1b463aa commit bc62041
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 22 deletions.
51 changes: 35 additions & 16 deletions trigger/http/approvals_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ import (
)

type approveRequest struct {
Identifier string `json:"identifier"`
Voter string `json:"voter"`
Voter string `json:"voter"`
Action string `json:"action"` // defaults to approve
}

// available API actions
const (
actionApprove = "approve"
actionReject = "reject"
)

func (s *TriggerServer) approvalsHandler(resp http.ResponseWriter, req *http.Request) {
// unknown lists all
approvals, err := s.approvalsManager.List()
Expand Down Expand Up @@ -45,32 +51,45 @@ func (s *TriggerServer) approvalApproveHandler(resp http.ResponseWriter, req *ht

err := dec.Decode(&ar)
if err != nil {
fmt.Fprintf(resp, "%s", err)
resp.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(resp, "%s", err)
return
}

if ar.Identifier == "" {
http.Error(resp, "identifier not supplied", http.StatusBadRequest)
return
}

approval, err := s.approvalsManager.Approve(ar.Identifier, ar.Voter)
if err != nil {
if err == cache.ErrNotFound {
http.Error(resp, fmt.Sprintf("approval '%s' not found", ar.Identifier), http.StatusNotFound)
var approval *types.Approval

// checking action
switch ar.Action {
case actionReject:
approval, err = s.approvalsManager.Reject(getID(req))
if err != nil {
if err == cache.ErrNotFound {
http.Error(resp, fmt.Sprintf("approval '%s' not found", getID(req)), http.StatusNotFound)
return
}
resp.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(resp, "%s", err)
return
}

fmt.Fprintf(resp, "%s", err)
resp.WriteHeader(http.StatusInternalServerError)
return
default:
// "" or "approve"
approval, err = s.approvalsManager.Approve(getID(req), ar.Voter)
if err != nil {
if err == cache.ErrNotFound {
http.Error(resp, fmt.Sprintf("approval '%s' not found", getID(req)), http.StatusNotFound)
return
}
resp.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(resp, "%s", err)
return
}
}

bts, err := json.Marshal(&approval)
if err != nil {
fmt.Fprintf(resp, "%s", err)
resp.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(resp, "%s", err)
return
}

Expand Down
55 changes: 50 additions & 5 deletions trigger/http/approvals_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func TestApprove(t *testing.T) {
}

// listing
req, err := http.NewRequest("POST", "/v1/approvals", bytes.NewBufferString(`{"identifier":"12345", "voter": "foo"}`))
req, err := http.NewRequest("PUT", "/v1/approvals/12345", bytes.NewBufferString(`{"voter": "foo"}`))
if err != nil {
t.Fatalf("failed to create req: %s", err)
}
Expand Down Expand Up @@ -169,7 +169,7 @@ func TestApproveNotFound(t *testing.T) {
srv.registerRoutes(srv.router)

// listing
req, err := http.NewRequest("POST", "/v1/approvals", bytes.NewBufferString(`{"identifier":"12345", "voter": "foo"}`))
req, err := http.NewRequest("PUT", "/v1/approvals/random", bytes.NewBufferString(`{"voter": "foo"}`))
if err != nil {
t.Fatalf("failed to create req: %s", err)
}
Expand All @@ -193,7 +193,7 @@ func TestApproveGarbageRequest(t *testing.T) {
srv.registerRoutes(srv.router)

// listing
req, err := http.NewRequest("POST", "/v1/approvals", bytes.NewBufferString(`{"foo":"bar"}`))
req, err := http.NewRequest("PUT", "/v1/approvals/111", bytes.NewBufferString(`<>`))
if err != nil {
t.Fatalf("failed to create req: %s", err)
}
Expand Down Expand Up @@ -230,7 +230,7 @@ func TestSameVoter(t *testing.T) {
}

// listing
req, err := http.NewRequest("POST", "/v1/approvals", bytes.NewBufferString(`{"identifier":"12345", "voter": "foo"}`))
req, err := http.NewRequest("PUT", "/v1/approvals/12345", bytes.NewBufferString(`{"voter": "foo"}`))
if err != nil {
t.Fatalf("failed to create req: %s", err)
}
Expand Down Expand Up @@ -279,7 +279,7 @@ func TestDifferentVoter(t *testing.T) {
}

// listing
req, err := http.NewRequest("POST", "/v1/approvals", bytes.NewBufferString(`{"identifier":"12345", "voter": "foo"}`))
req, err := http.NewRequest("PUT", "/v1/approvals/12345", bytes.NewBufferString(`{"voter": "foo"}`))
if err != nil {
t.Fatalf("failed to create req: %s", err)
}
Expand Down Expand Up @@ -309,3 +309,48 @@ func TestDifferentVoter(t *testing.T) {
t.Errorf("unexpected voter: %s", approved.Voters[0])
}
}

func TestReject(t *testing.T) {
fp := &fakeProvider{}
mem := memory.NewMemoryCache(100*time.Second, 100*time.Second, 10*time.Second)
am := approvals.New(mem, codecs.DefaultSerializer())
providers := provider.New([]provider.Provider{fp}, am)
srv := NewTriggerServer(&Opts{Providers: providers, ApprovalManager: am})
srv.registerRoutes(srv.router)

err := am.Create(&types.Approval{
Identifier: "12345",
VotesRequired: 5,
NewVersion: "2.0.0",
CurrentVersion: "1.0.0",
})

if err != nil {
t.Fatalf("failed to create approval: %s", err)
}

// listing
req, err := http.NewRequest("PUT", "/v1/approvals/12345", bytes.NewBufferString(`{"voter": "foo", "action": "reject"}`))
if err != nil {
t.Fatalf("failed to create req: %s", err)
}

rec := httptest.NewRecorder()

srv.router.ServeHTTP(rec, req)
if rec.Code != 200 {
t.Errorf("unexpected status code: %d", rec.Code)

t.Log(rec.Body.String())
}

approved, err := am.Get("12345")
if err != nil {
t.Fatalf("failed to get approval: %s", err)
}

if approved.Rejected != true {
t.Errorf("expected to find approval rejected")
}

}
2 changes: 1 addition & 1 deletion trigger/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (s *TriggerServer) registerRoutes(mux *mux.Router) {
// approvals
mux.HandleFunc("/v1/approvals", s.approvalsHandler).Methods("GET", "OPTIONS")
// approving
mux.HandleFunc("/v1/approvals", s.approvalApproveHandler).Methods("POST", "OPTIONS")
mux.HandleFunc("/v1/approvals/{id}", s.approvalApproveHandler).Methods("PUT", "OPTIONS")
mux.HandleFunc("/v1/approvals/{id}", s.approvalDeleteHandler).Methods("DELETE", "OPTIONS")

// native webhooks handler
Expand Down

0 comments on commit bc62041

Please sign in to comment.