Skip to content

Commit

Permalink
targets: Generate vegeta.Target JSON schema
Browse files Browse the repository at this point in the history
  • Loading branch information
tsenart committed Jul 7, 2018
1 parent dae3d2d commit eb227c2
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 6 deletions.
8 changes: 7 additions & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ COMMIT=$(shell git rev-parse HEAD)
VERSION=$(shell git describe --tags --exact-match --always)
DATE=$(shell date +'%FT%TZ%z')

vegeta: vendor
vegeta: vendor generate
CGO_ENABLED=0 go build -v -a -tags=netgo \
-ldflags '-s -w -extldflags "-static" -X main.Version=$(VERSION) -X main.Commit=$(COMMIT) -X main.Date=$(DATE)'

clean-vegeta:
rm vegeta

generate: vendor
go install ./internal/cmd/...
go generate ./...

vendor:
dep ensure -v

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ Specifies the targets format to decode.
##### `json` format

The JSON format makes integration with programs that produce targets dynamically easier.
Each target is one JSON object in its own line. If present, the body field must be base64 encoded.
Each target is one JSON object in its own line. The method and url fields are required.
If present, the body field must be base64 encoded. The generated [JSON Schema](lib/target.schema.json)
defines the format in detail.

```bash
jq -ncM '{method: "GET", url: "http://goku", body: "Punch!" | @base64, header: {"Content-Type": ["text/plain"]}}' |
Expand Down
61 changes: 61 additions & 0 deletions internal/cmd/jsonschema/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package main

import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
"strings"

"github.com/alecthomas/jsonschema"

vegeta "github.com/tsenart/vegeta/lib"
)

func main() {
types := map[string]interface{}{
"Target": &vegeta.Target{},
}

valid := strings.Join(keys(types), ", ")

fs := flag.NewFlagSet("jsonschema", flag.ExitOnError)
typ := fs.String("type", "", fmt.Sprintf("Vegeta type to generate a JSON schema for [%s]", valid))
out := fs.String("output", "stdout", "Output file")

fs.Parse(os.Args[1:])

t, ok := types[*typ]
if !ok {
die("invalid type %q not in [%s]", *typ, valid)
}

schema, err := json.MarshalIndent(jsonschema.Reflect(t), "", " ")
if err != nil {
die("%s", err)
}

switch *out {
case "stdout":
_, err = os.Stdout.Write(schema)
default:
err = ioutil.WriteFile(*out, schema, 0644)
}

if err != nil {
die("%s", err)
}
}

func die(s string, args ...interface{}) {
fmt.Fprintf(os.Stderr, s, args...)
os.Exit(1)
}

func keys(types map[string]interface{}) (ks []string) {
for k := range types {
ks = append(ks, k)
}
return ks
}
39 changes: 39 additions & 0 deletions lib/target.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"$ref": "#/definitions/Target",
"definitions": {
"Target": {
"required": [
"method",
"url"
],
"properties": {
"body": {
"type": "string",
"media": {
"binaryEncoding": "base64"
}
},
"header": {
"patternProperties": {
".*": {
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"method": {
"type": "string"
},
"url": {
"type": "string"
}
},
"additionalProperties": false,
"type": "object"
}
}
}
10 changes: 7 additions & 3 deletions lib/targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ import (
)

// Target is an HTTP request blueprint.
//
//go:generate jsonschema -type=Target -output=target.schema.json
type Target struct {
Method string `json:"method"`
URL string `json:"url"`
Body []byte `json:"body"`
Header http.Header `json:"header"`
Body []byte `json:"body,omitempty"`
Header http.Header `json:"header,omitempty"`
}

// Request creates an *http.Request out of Target and returns it along with an
Expand Down Expand Up @@ -64,7 +66,9 @@ type Targeter func(*Target) error

// NewJSONTargeter returns a new targeter that decodes one Target from the
// given io.Reader on every invocation. Each target is one JSON object in its own line.
// The body field of each target must be base64 encoded.
//
// The method and url fields are required. If present, the body field must be base64 encoded.
// The generated [JSON Schema](lib/target.schema.json) defines the format in detail.
//
// {"method":"POST", "url":"https://goku/1", "header":{"Content-Type":["text/plain"], "body": "Rk9P"}
// {"method":"GET", "url":"https://goku/2"}
Expand Down

0 comments on commit eb227c2

Please sign in to comment.