github.com/lonnblad/godog@v0.7.14-0.20200306004719-1b0cb3259847/_examples/db/api_test.go (about) 1 package main 2 3 import ( 4 "database/sql" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "net/http/httptest" 9 "reflect" 10 "strings" 11 12 txdb "github.com/DATA-DOG/go-txdb" 13 "github.com/cucumber/messages-go/v9" 14 "github.com/lonnblad/godog" 15 ) 16 17 func init() { 18 // we register an sql driver txdb 19 txdb.Register("txdb", "mysql", "root@/godog_test") 20 } 21 22 type apiFeature struct { 23 server 24 resp *httptest.ResponseRecorder 25 } 26 27 func (a *apiFeature) resetResponse(*messages.Pickle) { 28 a.resp = httptest.NewRecorder() 29 if a.db != nil { 30 a.db.Close() 31 } 32 db, err := sql.Open("txdb", "api") 33 if err != nil { 34 panic(err) 35 } 36 a.db = db 37 } 38 39 func (a *apiFeature) iSendrequestTo(method, endpoint string) (err error) { 40 req, err := http.NewRequest(method, endpoint, nil) 41 if err != nil { 42 return 43 } 44 45 // handle panic 46 defer func() { 47 switch t := recover().(type) { 48 case string: 49 err = fmt.Errorf(t) 50 case error: 51 err = t 52 } 53 }() 54 55 switch endpoint { 56 case "/users": 57 a.users(a.resp, req) 58 default: 59 err = fmt.Errorf("unknown endpoint: %s", endpoint) 60 } 61 return 62 } 63 64 func (a *apiFeature) theResponseCodeShouldBe(code int) error { 65 if code != a.resp.Code { 66 if a.resp.Code >= 400 { 67 return fmt.Errorf("expected response code to be: %d, but actual is: %d, response message: %s", code, a.resp.Code, string(a.resp.Body.Bytes())) 68 } 69 return fmt.Errorf("expected response code to be: %d, but actual is: %d", code, a.resp.Code) 70 } 71 return nil 72 } 73 74 func (a *apiFeature) theResponseShouldMatchJSON(body *messages.PickleStepArgument_PickleDocString) (err error) { 75 var expected, actual interface{} 76 77 // re-encode expected response 78 if err = json.Unmarshal([]byte(body.Content), &expected); err != nil { 79 return 80 } 81 82 // re-encode actual response too 83 if err = json.Unmarshal(a.resp.Body.Bytes(), &actual); err != nil { 84 return 85 } 86 87 // the matching may be adapted per different requirements. 88 if !reflect.DeepEqual(expected, actual) { 89 return fmt.Errorf("expected JSON does not match actual, %v vs. %v", expected, actual) 90 } 91 return nil 92 } 93 94 func (a *apiFeature) thereAreUsers(users *messages.PickleStepArgument_PickleTable) error { 95 var fields []string 96 var marks []string 97 head := users.Rows[0].Cells 98 for _, cell := range head { 99 fields = append(fields, cell.Value) 100 marks = append(marks, "?") 101 } 102 103 stmt, err := a.db.Prepare("INSERT INTO users (" + strings.Join(fields, ", ") + ") VALUES(" + strings.Join(marks, ", ") + ")") 104 if err != nil { 105 return err 106 } 107 for i := 1; i < len(users.Rows); i++ { 108 var vals []interface{} 109 for n, cell := range users.Rows[i].Cells { 110 switch head[n].Value { 111 case "username": 112 vals = append(vals, cell.Value) 113 case "email": 114 vals = append(vals, cell.Value) 115 default: 116 return fmt.Errorf("unexpected column name: %s", head[n].Value) 117 } 118 } 119 if _, err = stmt.Exec(vals...); err != nil { 120 return err 121 } 122 } 123 return nil 124 } 125 126 func FeatureContext(s *godog.Suite) { 127 api := &apiFeature{} 128 129 s.BeforeScenario(api.resetResponse) 130 131 s.Step(`^I send "(GET|POST|PUT|DELETE)" request to "([^"]*)"$`, api.iSendrequestTo) 132 s.Step(`^the response code should be (\d+)$`, api.theResponseCodeShouldBe) 133 s.Step(`^the response should match json:$`, api.theResponseShouldMatchJSON) 134 s.Step(`^there are users:$`, api.thereAreUsers) 135 }