You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
togo/action_httptest.go

175 lines
2.9 KiB
Go

package main
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"log"
"net/textproto"
"os"
"regexp"
"strconv"
"strings"
"github.com/bmatcuk/doublestar"
"github.com/urfave/cli"
"github.com/bradrydzewski/togo/template"
)
type (
httptestParams struct {
Package string
Routes []*httptestRoute
}
httptestRoute struct {
Source string
Method string
Path string
Body string
Status int
Header map[string]string
}
)
var httptestCommand = cli.Command{
Name: "httptest",
Usage: "generate httptest server",
Action: httptestAction,
Flags: []cli.Flag{
cli.StringFlag{
Name: "package",
Value: "testdata",
},
cli.StringFlag{
Name: "input",
Value: "files/**",
},
cli.StringFlag{
Name: "output",
Value: "testdata_gen.go",
},
cli.StringFlag{
Name: "exclude",
},
},
}
func httptestAction(c *cli.Context) error {
pattern := c.Args().First()
if pattern == "" {
pattern = c.String("input")
}
matches, err := doublestar.Glob(pattern)
if err != nil {
return err
}
var exclude *regexp.Regexp
if s := c.String("exclude"); s != "" {
exclude = regexp.MustCompilePOSIX(s)
}
params := httptestParams{
Package: c.String("package"),
}
for _, match := range matches {
stat, oserr := os.Stat(match)
if oserr != nil {
return oserr
}
if stat.IsDir() {
continue
}
if exclude != nil && exclude.MatchString(match) {
continue
}
log.Printf("parsing file %s", match)
raw, ioerr := ioutil.ReadFile(match)
if ioerr != nil {
return ioerr
}
route, parseErr := parseRoute(raw)
if parseErr != nil {
return parseErr
}
route.Source = strings.TrimPrefix(match, "files/")
params.Routes = append(params.Routes, route)
}
wr := os.Stdout
if output := c.String("output"); output != "" {
wr, err = os.Create(output)
if err != nil {
return err
}
defer wr.Close()
}
return template.Execute(wr, "httptest.tmpl", &params)
}
func parseRoute(in []byte) (*httptestRoute, error) {
out := new(httptestRoute)
out.Header = map[string]string{}
buf := bufio.NewReader(bytes.NewBuffer(in))
r := textproto.NewReader(buf)
//
// parses the method and path
//
line, err := r.ReadLine()
if err != nil {
return nil, err
}
parts := strings.Split(line, " ")
if len(parts) != 2 {
return nil, fmt.Errorf("Invalid request line. Want <method> <path>.")
}
out.Method = parts[0]
out.Path = parts[1]
//
// parses the mime headers
//
header, err := r.ReadMIMEHeader()
if err != nil {
fmt.Println(err)
}
for k, v := range header {
out.Header[k] = strings.Join(v, "; ")
}
//
// extracts the response status code
//
out.Status, err = strconv.Atoi(header.Get("Status"))
if err != nil {
return nil, fmt.Errorf("Invalid Status code. %s", err)
}
delete(out.Header, "Status")
//
// parse the remainder of the file as the body
//
body, err := ioutil.ReadAll(buf)
if err != nil {
return nil, err
}
out.Body = string(body)
return out, nil
}