// pushStackHandler adds an element into a Stack and returns 200 and the element. func (c *Conn) pushStackHandler(w http.ResponseWriter, r *http.Request, stack *pila.Stack) { if r.Body == nil { log.Println(r.Method, r.URL, http.StatusBadRequest, "no element provided") w.WriteHeader(http.StatusBadRequest) return } var element pila.Element err := element.Decode(r.Body) if err != nil { log.Println(r.Method, r.URL, http.StatusBadRequest, "error on decoding element:", err) w.WriteHeader(http.StatusBadRequest) return } stack.Push(element.Value) stack.Update(c.opDate) log.Println(r.Method, r.URL, http.StatusOK, element.Value) w.Header().Set("Content-Type", "application/json") // Do not check error as we consider our element // suitable for a JSON encoding. b, _ := element.ToJSON() w.Write(b) }
// configKeyHandler handles a config value. func (c *Conn) configKeyHandler(configKey string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) // we override the mux vars to be able to test // an arbitrary configKey if configKey != "" { vars = map[string]string{ "key": configKey, } } value := c.Config.Get(vars["key"]) if value == nil { c.goneHandler(w, r, fmt.Sprintf("%s is not set", vars["key"])) return } var element pila.Element if r.Method == "GET" { value := c.Config.Get(vars["key"]) element.Value = value } if r.Method == "POST" { if r.Body == nil { log.Println(r.Method, r.URL, http.StatusBadRequest, "no element provided") w.WriteHeader(http.StatusBadRequest) return } err := element.Decode(r.Body) if err != nil { log.Println(r.Method, r.URL, http.StatusBadRequest, "error on decoding element:", err) w.WriteHeader(http.StatusBadRequest) return } c.Config.Set(vars["key"], element.Value) } log.Println(r.Method, r.URL, http.StatusOK, element.Value) w.Header().Set("Content-Type", "application/json") b, err := element.ToJSON() if err != nil { log.Println(r.Method, r.URL, http.StatusBadRequest, "error on decoding element:", err) w.WriteHeader(http.StatusBadRequest) return } w.Write(b) }) }
func TestPeekStackHandler(t *testing.T) { s := pila.NewStack("stack", time.Now().UTC()) db := pila.NewDatabase("db") _ = db.AddStack(s) p := pila.NewPila() _ = p.AddDatabase(db) conn := NewConn() conn.Pila = p element := pila.Element{Value: "test-element"} expectedElementJSON, _ := element.ToJSON() s.Push(element.Value) request, err := http.NewRequest("GET", fmt.Sprintf("/databases/%s/stacks/%s?peek", db.ID.String(), s.ID.String()), nil) if err != nil { t.Fatal(err) } request.Header.Set("Content-Type", "application/json") response := httptest.NewRecorder() conn.peekStackHandler(response, request, s) if peekElement := db.Stacks[s.ID].Peek(); peekElement != element.Value { t.Errorf("peek element is %v, expected %v", peekElement, element.Value) } if contentType := response.Header().Get("Content-Type"); contentType != "application/json" { t.Errorf("Content-Type is %v, expected %v", contentType, "application/json") } if response.Code != http.StatusOK { t.Errorf("response code is %v, expected %v", response.Code, http.StatusOK) } elementJSON, err := ioutil.ReadAll(response.Body) if err != nil { t.Fatal(err) } if string(elementJSON) != string(expectedElementJSON) { t.Errorf("peek element is %v, expected %v", string(elementJSON), string(expectedElementJSON)) } }
// peekStackHandler returns the peek of the Stack without modifying it. func (c *Conn) peekStackHandler(w http.ResponseWriter, r *http.Request, stack *pila.Stack) { var element pila.Element element.Value = stack.Peek() stack.Read(c.opDate) log.Println(r.Method, r.URL, http.StatusOK, element.Value) w.Header().Set("Content-Type", "application/json") // Do not check error as we consider our element // suitable for a JSON encoding. b, _ := element.ToJSON() w.Write(b) }
// popStackHandler extracts the peek element of a Stack, returns 200 and returns it. func (c *Conn) popStackHandler(w http.ResponseWriter, r *http.Request, stack *pila.Stack) { value, ok := stack.Pop() if !ok { log.Println(r.Method, r.URL, http.StatusNoContent) w.WriteHeader(http.StatusNoContent) return } stack.Update(c.opDate) element := pila.Element{Value: value} log.Println(r.Method, r.URL, http.StatusOK, element.Value) w.Header().Set("Content-Type", "application/json") // Do not check error as we consider our element // suitable for a JSON encoding. b, _ := element.ToJSON() w.Write(b) }
func TestStackHandler_DELETE(t *testing.T) { element := pila.Element{Value: "test-element"} expectedElementJSON, _ := element.ToJSON() s := pila.NewStack("stack", time.Now().UTC()) db := pila.NewDatabase("db") _ = db.AddStack(s) p := pila.NewPila() _ = p.AddDatabase(db) conn := NewConn() conn.Pila = p s.Push(element.Value) inputOutput := []struct { input struct { database, stack, op string } output struct { response []byte code int } }{ {struct { database, stack, op string }{db.ID.String(), s.ID.String(), ""}, struct { response []byte code int }{expectedElementJSON, http.StatusOK}, }, {struct { database, stack, op string }{db.Name, s.Name, ""}, struct { response []byte code int }{expectedElementJSON, http.StatusOK}, }, {struct { database, stack, op string }{db.Name, s.Name, "flush"}, struct { response []byte code int }{nil, http.StatusOK}, }, {struct { database, stack, op string }{db.Name, s.Name, "full"}, struct { response []byte code int }{nil, http.StatusNoContent}, }, } for _, io := range inputOutput { request, err := http.NewRequest("DELETE", fmt.Sprintf("/databases/%s/stacks/%s?%s", io.input.database, io.input.stack, io.input.op), nil) if err != nil { t.Fatal(err) } response := httptest.NewRecorder() params := map[string]string{ "database_id": io.input.database, "stack_id": io.input.stack, } stackHandle := conn.stackHandler(¶ms) stackHandle.ServeHTTP(response, request) if response.Code != io.output.code { t.Errorf("on op %s response code is %v, expected %v", io.input.op, response.Code, io.output.code) } responseJSON, err := ioutil.ReadAll(response.Body) if err != nil { t.Fatal(err) } if io.input.op == "flush" { s.Update(conn.opDate) stackStatus := s.Status() expectedStackStatusJSON, err := stackStatus.ToJSON() if err != nil { t.Fatal(err) } if string(responseJSON) != string(expectedStackStatusJSON) { t.Errorf("on op %s response is %s, expected %s", io.input.op, string(responseJSON), string(expectedStackStatusJSON)) } } else if string(responseJSON) != string(io.output.response) { t.Errorf("on op %s response is %s, expected %s", io.input.op, string(responseJSON), string(io.output.response)) } if io.input.op == "full" { if s := db.Stacks[uuid.UUID(io.input.stack)]; s != nil { t.Errorf("db contains %v, expected not to", io.input.stack) } } else { if peek, ok := db.Stacks[s.ID].Pop(); ok { t.Errorf("stack contains %v, expected to be empty", peek) } if contentType := response.Header().Get("Content-Type"); contentType != "application/json" { t.Errorf("Content-Type is %v, expected %v", contentType, "application/json") } // restore element for next table test iteration s.Push(element.Value) } } }
func TestStackHandler_POST(t *testing.T) { s := pila.NewStack("stack", time.Now().UTC()) db := pila.NewDatabase("db") _ = db.AddStack(s) p := pila.NewPila() _ = p.AddDatabase(db) conn := NewConn() conn.Pila = p conn.opDate = time.Now().UTC() element := pila.Element{Value: "test-element"} expectedElementJSON, _ := element.ToJSON() paramss := []map[string]string{ { "database_id": db.ID.String(), "stack_id": s.ID.String(), }, { "database_id": db.Name, "stack_id": s.Name, }, } for _, params := range paramss { request, err := http.NewRequest("POST", fmt.Sprintf("/databases/%s/stacks/%s", params["database_id"], params["stack_id"]), bytes.NewBuffer(expectedElementJSON)) if err != nil { t.Fatal(err) } request.Header.Set("Content-Type", "application/json") response := httptest.NewRecorder() stackHandle := conn.stackHandler(¶ms) stackHandle.ServeHTTP(response, request) if contentType := response.Header().Get("Content-Type"); contentType != "application/json" { t.Errorf("Content-Type is %v, expected %v", contentType, "application/json") } if response.Code != http.StatusOK { t.Errorf("response code is %v, expected %v", response.Code, http.StatusOK) } elementJSON, err := ioutil.ReadAll(response.Body) if err != nil { t.Fatal(err) } if string(elementJSON) != string(expectedElementJSON) { t.Errorf("pushed element is %v, expected %v", string(elementJSON), string(expectedElementJSON)) } } }
func TestStackHandler_GET(t *testing.T) { element := pila.Element{Value: "test-element"} expectedElementJSON, _ := element.ToJSON() createDate := time.Now().UTC() s := pila.NewStack("stack", createDate) s.Update(createDate) db := pila.NewDatabase("db") _ = db.AddStack(s) p := pila.NewPila() _ = p.AddDatabase(db) conn := NewConn() conn.Pila = p conn.opDate = time.Now().UTC() s.Push(element.Value) expectedStackStatusJSON, err := s.Status().ToJSON() if err != nil { t.Fatal(err) } expectedSizeJSON := s.SizeToJSON() inputOutput := []struct { input struct { database, stack, op string } output struct { response []byte code int } }{ {struct { database, stack, op string }{db.ID.String(), s.ID.String(), ""}, struct { response []byte code int }{expectedStackStatusJSON, http.StatusOK}, }, {struct { database, stack, op string }{db.ID.String(), s.ID.String(), "peek"}, struct { response []byte code int }{expectedElementJSON, http.StatusOK}, }, {struct { database, stack, op string }{db.ID.String(), s.ID.String(), "size"}, struct { response []byte code int }{expectedSizeJSON, http.StatusOK}, }, } for _, io := range inputOutput { request, err := http.NewRequest("GET", fmt.Sprintf("/databases/%s/stacks/%s?%s", io.input.database, io.input.stack, io.input.op), nil) if err != nil { t.Fatal(err) } response := httptest.NewRecorder() params := map[string]string{ "database_id": io.input.database, "stack_id": io.input.stack, } stackHandle := conn.stackHandler(¶ms) stackHandle.ServeHTTP(response, request) if peek := db.Stacks[s.ID].Peek(); peek != element.Value { t.Errorf("peek is %v, expected %v", peek, element.Value) } if contentType := response.Header().Get("Content-Type"); contentType != "application/json" { t.Errorf("Content-Type is %v, expected %v", contentType, "application/json") } if response.Code != io.output.code { t.Errorf("on %s response code is %v, expected %v", io.input.op, response.Code, io.output.code) } responseJSON, err := ioutil.ReadAll(response.Body) if err != nil { t.Fatal(err) } if io.input.op == "" { expectedStackStatusJSON, err := s.Status().ToJSON() if err != nil { t.Fatal(err) } else if string(responseJSON) != string(expectedStackStatusJSON) { t.Errorf("on %s response is %s, expected %s", io.input.op, string(responseJSON), string(expectedStackStatusJSON)) } } else if string(responseJSON) != string(io.output.response) { t.Errorf("on %s response is %s, expected %s", io.input.op, string(responseJSON), string(io.output.response)) } } }
func TestPopStackHandler(t *testing.T) { element := pila.Element{Value: "test-element"} expectedElementJSON, _ := element.ToJSON() s := pila.NewStack("stack", time.Now().UTC()) s.Push(element.Value) db := pila.NewDatabase("db") _ = db.AddStack(s) p := pila.NewPila() _ = p.AddDatabase(db) conn := NewConn() conn.Pila = p varss := []map[string]string{ { "database_id": db.ID.String(), "stack_id": s.ID.String(), }, { "database_id": db.Name, "stack_id": s.Name, }, } for _, vars := range varss { request, err := http.NewRequest("DELETE", fmt.Sprintf("/databases/%s/stacks/%s", vars["database_id"], vars["stack_id"]), nil) if err != nil { t.Fatal(err) } response := httptest.NewRecorder() conn.popStackHandler(response, request, s) if peek, ok := db.Stacks[s.ID].Pop(); ok { t.Errorf("stack contains %v, expected to be empty", peek) } if contentType := response.Header().Get("Content-Type"); contentType != "application/json" { t.Errorf("Content-Type is %v, expected %v", contentType, "application/json") } if response.Code != http.StatusOK { t.Errorf("response code is %v, expected %v", response.Code, http.StatusOK) } elementJSON, err := ioutil.ReadAll(response.Body) if err != nil { t.Fatal(err) } if string(elementJSON) != string(expectedElementJSON) { t.Errorf("popped element is %s, expected %s", string(elementJSON), string(expectedElementJSON)) } // restore element for next table test iteration s.Push(element.Value) } }
func TestConfigKeyHandler(t *testing.T) { conn := NewConn() conn.Config = config.NewConfig() conn.Config.Set(vars.MaxStackSize, 2) element := pila.Element{Value: 2} expectedElementJSON, _ := element.ToJSON() newElement := pila.Element{Value: 10} expectedNewElementJSON, _ := newElement.ToJSON() inputOutput := []struct { input struct { method, key string payload io.Reader } output struct { value interface{} response []byte } }{ {struct { method, key string payload io.Reader }{"GET", vars.MaxStackSize, nil}, struct { value interface{} response []byte }{2, expectedElementJSON}, }, {struct { method, key string payload io.Reader }{"POST", vars.MaxStackSize, bytes.NewBuffer(expectedNewElementJSON)}, struct { value interface{} response []byte }{10, expectedNewElementJSON}, }, } for _, io := range inputOutput { request, err := http.NewRequest(io.input.method, fmt.Sprintf("/_config/%s", io.input.key), io.input.payload) if err != nil { t.Fatal(err) } response := httptest.NewRecorder() configKeyHandle := conn.configKeyHandler(io.input.key) configKeyHandle.ServeHTTP(response, request) if value := conn.Config.MaxStackSize(); value != io.output.value { t.Errorf("value is %d, expected %d", value, io.output.value) } if contentType := response.Header().Get("Content-Type"); contentType != "application/json" { t.Errorf("Content-Type is %v, expected %v", contentType, "application/json") } if response.Code != http.StatusOK { t.Errorf("response code is %v, expected %v", response.Code, http.StatusOK) } responseJSON, err := ioutil.ReadAll(response.Body) if err != nil { t.Fatal(err) } if string(responseJSON) != string(io.output.response) { t.Errorf("response is %s, expected %s", string(responseJSON), string(io.output.response)) } } }