// createStackHandler handles the creation of a stack, given a database // by its id and the time of creation. Returns the status of the new stack. func (c *Conn) createStackHandler(w http.ResponseWriter, r *http.Request, databaseID string) { name := r.FormValue("name") if name == "" { log.Println(r.Method, r.URL, http.StatusBadRequest, "missing name") w.WriteHeader(http.StatusBadRequest) return } db, ok := c.Pila.Database(uuid.UUID(databaseID)) if !ok { c.goneHandler(w, r, fmt.Sprintf("database %s is Gone", databaseID)) return } stack := pila.NewStack(name, c.opDate) err := db.AddStack(stack) if err != nil { log.Println(r.Method, r.URL, http.StatusConflict, err) w.WriteHeader(http.StatusConflict) return } stack.Update(c.opDate) // Do not check error as the Status of a new stack does // not contain types that could cause such case. // See http://golang.org/src/encoding/json/encode.go?s=5438:5481#L125 res, _ := stack.Status().ToJSON() w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) w.Write(res) log.Println(r.Method, r.URL, http.StatusCreated) }
// ResourceStack will return the right Stack resource // given a Database and a Stack ID or Name. func ResourceStack(db *pila.Database, stackInput string) (*pila.Stack, bool) { stack, ok := db.Stacks[uuid.UUID(stackInput)] if !ok { // Fallback to find by stack name stack, ok = db.Stacks[uuid.New(db.Name+stackInput)] } return stack, ok }
// ResourceDatabase will return the right Database resource // given a Conn and a database ID or Name. func ResourceDatabase(conn *Conn, databaseInput string) (*pila.Database, bool) { db, ok := conn.Pila.Database(uuid.UUID(databaseInput)) if !ok { // Fallback to find by database name db, ok = conn.Pila.Database(uuid.New(databaseInput)) } return db, ok }
func TestDeleteStackHandler(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 s.Push("one") 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?full", vars["database_id"], vars["stack_id"]), nil) if err != nil { t.Fatal(err) } response := httptest.NewRecorder() conn.deleteStackHandler(response, request, db, s) if expectedStack := db.Stacks[uuid.UUID(vars["stack_id"])]; expectedStack != nil { t.Errorf("db contains %v, expected not to", vars["stack_id"]) } if response.Code != http.StatusNoContent { t.Errorf("response code is %v, expected %v", response.Code, http.StatusNoContent) } // restore elements for next table test iteration s = pila.NewStack("stack", time.Now().UTC()) _ = db.AddStack(s) s.Push("one") } }
func TestDatabaseHandler_Gone(t *testing.T) { conn := NewConn() request, err := http.NewRequest("GET", fmt.Sprintf("/databases/%s", "nodb"), nil) if err != nil { t.Fatal(err) } response := httptest.NewRecorder() databaseHandle := conn.databaseHandler(uuid.UUID("nodb").String()) databaseHandle.ServeHTTP(response, request) if response.Code != http.StatusGone { t.Errorf("response code is %v, expected %v", response.Code, http.StatusGone) } }
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) } } }