Merge pull request #157 from keel-hq/feature/http-approvals

Feature/http approvals
feature/updated_gcr_pubsub_chan
Karolis Rusenas 2018-03-11 13:28:43 +00:00 committed by GitHub
commit 638ef933c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 247 additions and 1 deletions

View File

@ -5,9 +5,15 @@ import (
"fmt"
"net/http"
"github.com/keel-hq/keel/cache"
"github.com/keel-hq/keel/types"
)
type approveRequest struct {
Identifier string `json:"identifier"`
Voter string `json:"voter"`
}
func (s *TriggerServer) approvalsHandler(resp http.ResponseWriter, req *http.Request) {
// unknown lists all
approvals, err := s.approvalsManager.List()
@ -31,6 +37,46 @@ func (s *TriggerServer) approvalsHandler(resp http.ResponseWriter, req *http.Req
resp.Write(bts)
}
func (s *TriggerServer) approvalApproveHandler(resp http.ResponseWriter, req *http.Request) {
var ar approveRequest
dec := json.NewDecoder(req.Body)
defer req.Body.Close()
err := dec.Decode(&ar)
if err != nil {
fmt.Fprintf(resp, "%s", err)
resp.WriteHeader(http.StatusBadRequest)
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)
return
}
fmt.Fprintf(resp, "%s", err)
resp.WriteHeader(http.StatusInternalServerError)
return
}
bts, err := json.Marshal(&approval)
if err != nil {
fmt.Fprintf(resp, "%s", err)
resp.WriteHeader(http.StatusInternalServerError)
return
}
resp.Write(bts)
}
func (s *TriggerServer) approvalDeleteHandler(resp http.ResponseWriter, req *http.Request) {
identifier := getID(req)

View File

@ -1,6 +1,7 @@
package http
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
@ -109,5 +110,202 @@ func TestDeleteApproval(t *testing.T) {
if err == nil {
t.Errorf("expected approval to be deleted")
}
}
func TestApprove(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("POST", "/v1/approvals", bytes.NewBufferString(`{"identifier":"12345", "voter": "foo"}`))
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.VotesReceived != 1 {
t.Errorf("expected to find one voter")
}
if approved.Voters[0] != "foo" {
t.Errorf("unexpected voter: %s", approved.Voters[0])
}
}
func TestApproveNotFound(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)
// listing
req, err := http.NewRequest("POST", "/v1/approvals", bytes.NewBufferString(`{"identifier":"12345", "voter": "foo"}`))
if err != nil {
t.Fatalf("failed to create req: %s", err)
}
rec := httptest.NewRecorder()
srv.router.ServeHTTP(rec, req)
if rec.Code != 404 {
t.Errorf("unexpected status code: %d", rec.Code)
t.Log(rec.Body.String())
}
}
func TestApproveGarbageRequest(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)
// listing
req, err := http.NewRequest("POST", "/v1/approvals", bytes.NewBufferString(`{"foo":"bar"}`))
if err != nil {
t.Fatalf("failed to create req: %s", err)
}
rec := httptest.NewRecorder()
srv.router.ServeHTTP(rec, req)
if rec.Code != 400 {
t.Errorf("unexpected status code: %d", rec.Code)
t.Log(rec.Body.String())
}
}
func TestSameVoter(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",
VotesReceived: 1,
Voters: []string{"foo"},
})
if err != nil {
t.Fatalf("failed to create approval: %s", err)
}
// listing
req, err := http.NewRequest("POST", "/v1/approvals", bytes.NewBufferString(`{"identifier":"12345", "voter": "foo"}`))
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.VotesReceived != 1 {
t.Errorf("expected to find one voter")
}
if approved.Voters[0] != "foo" {
t.Errorf("unexpected voter: %s", approved.Voters[0])
}
}
func TestDifferentVoter(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",
VotesReceived: 1,
Voters: []string{"bar"},
})
if err != nil {
t.Fatalf("failed to create approval: %s", err)
}
// listing
req, err := http.NewRequest("POST", "/v1/approvals", bytes.NewBufferString(`{"identifier":"12345", "voter": "foo"}`))
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.VotesReceived != 2 {
t.Errorf("expected to find 2 voters")
}
if approved.Voters[0] != "bar" {
t.Errorf("unexpected voter: %s", approved.Voters[0])
}
if approved.Voters[1] != "foo" {
t.Errorf("unexpected voter: %s", approved.Voters[0])
}
}

View File

@ -85,6 +85,8 @@ 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.approvalDeleteHandler).Methods("DELETE", "OPTIONS")
// native webhooks handler