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  }