gointegration

package module
v0.0.0-...-04cc07e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 11, 2019 License: MIT Imports: 18 Imported by: 0

README

GoIntegration

GoIntegration is the Swagger Expectation Aassertion Runtime for go. GoIntegration is used to create integration test suites for ensuring your service API. GoIntegration reads your swagger.json file and exposes an interface for querying the API and setting expectations / assertions.

Installation

go get github.com/btm6084/gointegration

How To Use

The GoIntegration Client's Exec and ExecJSON functions perform the requested operation and return a ClientResponse or a JSONResponse, respectively. The Exec* functions take an operation ID which is in the form tag.operationId. In the sample swagger.json below, the /health endpoint has an operation ID of health.HealthCheck. When there are no tags defined, the tag "default" is used.

ClientResponse returns all the pertinent information about the API request enacted by calling Exec(). If any errors occured during the execution of the requested API endpoint, ClientResponse.Errors will be non-nil, containing instead the error that last occured.

JSONResponse provides everything that ClientResponse does, except that it also includes a JSONReader (github.com/btm6084/gojson) object which is pre-loaded with the body of the response. If the response was not JSON, JSONResponse.Errors will be non-nil. While you can access this directly to create whatever type of assertions you would like, the real power comes from the Expect* functions, which provide a very nice chained API for creating assertions about the response.

Host, Port, and Scheme

When being constructed, Client will examine the local environment for HOST, PORT, and SCHEME. If any exist, they will override defaults. Defaults are localhost, 4080, and http respectively.

Parameters to the API

The parameter lists are parsed for each endpoint in the swagger.json file. Each parameter is passed by name in the map that is the second parameter to the Exec* functions. Missing required parameters will cause test failures. Extra parameters that a given endpoint doesn't specify will also cause a test failure.

Example Use

Given a swagger.json file that looks like this:

{
   "host" : "localhost:4080",
   "paths" : {
      "/health" : {
         "get" : {
            "summary" : "Health monitoring endpoint",
            "operationId" : "HealthCheck",
            "tags" : [
               "health"
            ],
            "schemes" : [
               "http"
            ],
            "description" : "Returns a status of the health of the service",
            "produces" : [
               "application/hal+json"
            ],
            "responses" : {
               "200" : {
                  "$ref" : "#/responses/halResponseSwagger"
               }
            }
         }
      }
   },
   "basePath" : "/",
   "produces" : [
      "application/hal+json"
   ],
   "info" : {
      "title" : "GoIntegration Example Swagger File",
      "description" : ""
   },
   "swagger" : "2.0",
   "schemes" : [
      "http"
   ],
   "responses" : {
      "halResponseSwagger" : {
         "schema" : {
            "properties" : {
               "_embedded" : {
                  "type" : "object",
                  "x-go-name" : "Embeddded"
               },
               "_links" : {
                  "type" : "object",
                  "x-go-name" : "Links"
               },
               "_meta" : {
                  "x-go-name" : "Meta",
                  "type" : "object"
               }
            },
            "type" : "object"
         },
         "description" : "HAL only response containing api endpoints"
      }
   }
}

Which returns this JSON object:

{
	"name": "My Service Health Check",
	"version": "1.0.0",
	"checks": {
		"service": {
			"status": "OK",
			"message": "Service Ok"
		},
		"storage": {
			"status": "OK",
			"message": "Storage Ok"
		}
	}
}

We can construct an integration test that looks like this:

package integration

import (
	"regexp"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/btm6084/gointegration"
)

func TestHealthEndpoint(t *testing.T) {
	client, err := gointegration.BuildClient("./swagger.json")
	if err != nil {
		assert.Fail(t, err.Error())
		return
	}

	// Expect version 1
	versionRE := regexp.MustCompile(`1\.\d\.\d`)

	// Match a date in the format `Tue, 23 Jan 2018 01:06:08 GMT``
	dateRE   = regexp.MustCompile(`^[A-z]+, [0-9]{2} [A-z]+ \d{4} \d{2}:\d{2}:\d{2} [A-Z]+$`)

	client.ExecJSON("health.HealthCheck", map[string]interface{}{}).
		ExpectStatus(t, 200).
		ExpectValue(t, "name", "My Service Health Check").
		ExpectValueMatch(t, "version", versionRE).
		ExpectValue(t, "checks.service.status", "OK").
		ExpectValue(t, "checks.service.message", "Service Ok").
		ExpectValue(t, "checks.storage.status", "OK").
		ExpectValue(t, "checks.storage.message", "Storage Ok").
		ExpectHeaderValue(t, "Vary", "Accept-Encoding").
		ExpectHeaderValue(t, "Content-Type", "application/json").
		ExpectHeaderMatch(t, "Date", dateRE)

	// If you need something a little more complex, you can always take over control by capturing the response, instead of chaining it:
	resp := client.ExecJSON("health.HealthCheck", map[string]interface{}{})
	assert.Nil(t, resp.Error)

	version := resp.Reader.GetString("version")

	client.ExecJSON("example.TakesVersion", map[string]interface{}{
		"version": version,
	}).ExpectStatus(t, 201)
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	FollowRedirects bool
	Hostname        string
	IdentityHeader  string
	Port            int
	Scheme          string
	Endpoints       map[string]Endpoints

	// Time is in MS
	Timeout int

	Client *http.Client
}

Client parses a swagger.json document and exposes an interface for creating API calls to the endpoint specified.

func BuildClient

func BuildClient(path string) (*Client, error)

BuildClient creates a new swagger dument from a file on the filesystem.

func (*Client) Exec

func (sc *Client) Exec(specifier string, params map[string]interface{}) ClientResponse

Exec takes a path specifier and executes the corresponding functionality if found in the loaded swagger doc, returning a generic ClientResponse.

func (*Client) ExecJSON

func (sc *Client) ExecJSON(specifier string, params map[string]interface{}) JSONResponse

ExecJSON takes a path specifier and executes the corresponding functionality if found in the loaded swagger doc, returning a JSONResponse.

func (*Client) MakeRequest

func (sc *Client) MakeRequest(req *http.Request) ClientResponse

MakeRequest makes a request to a third party HTTP resource based on the given http.Request object.

type ClientResponse

type ClientResponse struct {
	Body        string            `json:"body"`
	Cookies     []*http.Cookie    `json:"cookies"`
	Error       error             `json:"error"`
	Headers     map[string]string `json:"headers"`
	RequestTime string            `json:"request_time"`
	RequestURL  string            `json:"request_url"`
	Status      string            `json:"status"`
	StatusCode  int               `json:"status_code"`
}

ClientResponse holds the pertinent information returned from a third party request.

func (ClientResponse) Expect

func (c ClientResponse) Expect(t *testing.T, eval func(c ClientResponse) error) ClientResponse

Expect allows custom assertions to be run. A error returned from the eval function will cause the test to be failed.

func (ClientResponse) ExpectError

func (c ClientResponse) ExpectError(t *testing.T, err error) ClientResponse

ExpectError is used to assert that a certain error condition has occured.

func (ClientResponse) ExpectHeaderEmpty

func (c ClientResponse) ExpectHeaderEmpty(t *testing.T, key string) ClientResponse

ExpectHeaderEmpty asserts that there was no header value set at a given key.

func (ClientResponse) ExpectHeaderMatch

func (c ClientResponse) ExpectHeaderMatch(t *testing.T, key string, re *regexp.Regexp) ClientResponse

ExpectHeaderMatch asserts that the header value at the given key will match the given regular expression.

func (ClientResponse) ExpectHeaderValue

func (c ClientResponse) ExpectHeaderValue(t *testing.T, key string, value string) ClientResponse

ExpectHeaderValue asserts that the header value at the given key will match the given value.

func (ClientResponse) ExpectStatus

func (c ClientResponse) ExpectStatus(t *testing.T, status int) ClientResponse

ExpectStatus asserts that a specific status code was received.

func (ClientResponse) OptionalHeaderMatch

func (c ClientResponse) OptionalHeaderMatch(t *testing.T, key string, re *regexp.Regexp) ClientResponse

OptionalHeaderMatch differs from ExpectHeaderMatch in that it can only fail if the given key exists. If the key is missing entirely, the test will pass.

func (ClientResponse) OptionalHeaderValue

func (c ClientResponse) OptionalHeaderValue(t *testing.T, key string, value string) ClientResponse

OptionalHeaderValue differs from ExpectHeaderValue in that it can only fail if the given key exists. If the key is missing entirely, the test will pass.

type Endpoints

type Endpoints map[string]Route

Endpoints is a collection of swagger endpoints

type JSONResponse

type JSONResponse struct {
	ClientResponse
	Reader *gojson.JSONReader `json:"-"`
}

JSONResponse is a ClientResponse with added functionality specifically for dealing with json API responses.

func (JSONResponse) Expect

func (c JSONResponse) Expect(t *testing.T, eval func(c JSONResponse) error) JSONResponse

Expect allows custom assertions to be run. A error returned from the eval function will cause the test to be failed.

func (JSONResponse) ExpectError

func (c JSONResponse) ExpectError(t *testing.T, err error) JSONResponse

ExpectError is used to assert that a certain error condition has occured.

func (JSONResponse) ExpectHeaderEmpty

func (c JSONResponse) ExpectHeaderEmpty(t *testing.T, key string) JSONResponse

ExpectHeaderEmpty asserts that there was no header value set at a given key.

func (JSONResponse) ExpectHeaderMatch

func (c JSONResponse) ExpectHeaderMatch(t *testing.T, key string, re *regexp.Regexp) JSONResponse

ExpectHeaderMatch asserts that the header value at the given key will match the given regular expression.

func (JSONResponse) ExpectHeaderValue

func (c JSONResponse) ExpectHeaderValue(t *testing.T, key string, value string) JSONResponse

ExpectHeaderValue asserts that the header value at the given key will match the given value.

func (JSONResponse) ExpectStatus

func (c JSONResponse) ExpectStatus(t *testing.T, status int) JSONResponse

ExpectStatus asserts that a specific status code was received.

func (JSONResponse) ExpectType

func (c JSONResponse) ExpectType(t *testing.T, key, typ string) JSONResponse

ExpectType asserts the data type at the given key will match the given JSON data type.

func (JSONResponse) ExpectTypes

func (c JSONResponse) ExpectTypes(t *testing.T, key string, typ ...string) JSONResponse

ExpectTypes asserts the data type at the given key will match the given JSON data types.

func (JSONResponse) ExpectValue

func (c JSONResponse) ExpectValue(t *testing.T, key string, b interface{}) JSONResponse

ExpectValue asserts the value at the given key will match the given value.

func (JSONResponse) ExpectValueCount

func (c JSONResponse) ExpectValueCount(t *testing.T, key string, count int) JSONResponse

ExpectValueCount asserts the aggregate data type at the given key will have the given number of child nodes.

func (JSONResponse) ExpectValueCountCompare

func (c JSONResponse) ExpectValueCountCompare(t *testing.T, key string, comp string, count int) JSONResponse

ExpectValueCountCompare asserts the aggregate data type at the given key will have the given number of child nodes.

func (JSONResponse) ExpectValueMatch

func (c JSONResponse) ExpectValueMatch(t *testing.T, key string, re *regexp.Regexp) JSONResponse

ExpectValueMatch asserts that the value at the given key will match the given regular expression.

func (JSONResponse) ExpectValueString

func (c JSONResponse) ExpectValueString(t *testing.T, key, b string) JSONResponse

ExpectValueString asserts the value at the given key will match the given value. All comparisons are done as string comparisons.

func (JSONResponse) OptionalHeaderMatch

func (c JSONResponse) OptionalHeaderMatch(t *testing.T, key string, re *regexp.Regexp) JSONResponse

OptionalHeaderMatch differs from ExpectHeaderMatch in that it can only fail if the given key exists. If the key is missing entirely, the test will pass.

func (JSONResponse) OptionalHeaderValue

func (c JSONResponse) OptionalHeaderValue(t *testing.T, key string, value string) JSONResponse

OptionalHeaderValue differs from ExpectHeaderValue in that it can only fail if the given key exists. If the key is missing entirely, the test will pass.

func (JSONResponse) OptionalType

func (c JSONResponse) OptionalType(t *testing.T, key, typ string) JSONResponse

OptionalType differs from ExpectType in that it can only fail if the given key exists. If the key is missing entirely, the test will pass.

func (JSONResponse) OptionalTypes

func (c JSONResponse) OptionalTypes(t *testing.T, key string, typ ...string) JSONResponse

OptionalTypes differs from ExpectTypes in that it can only fail if the given key exists. If the key is missing entirely, the test will pass.

func (JSONResponse) OptionalValue

func (c JSONResponse) OptionalValue(t *testing.T, key string, b interface{}) JSONResponse

OptionalValue differs from ExpectValue in that it can only fail if the given key exists. If the key is missing entirely, the test will pass.

func (JSONResponse) OptionalValueMatch

func (c JSONResponse) OptionalValueMatch(t *testing.T, key string, re *regexp.Regexp) JSONResponse

OptionalValueMatch differs from ExpectValueMatch in that it can only fail if the given key exists. If the key is missing entirely, the test will pass.

type ParamSpec

type ParamSpec struct {
	FoundIn     string `json:"found_in"`
	Name        string `json:"name"`
	Required    bool   `json:"required"`
	Type        string `json:"type"`
	ContentType string `json:"content_type"`
}

ParamSpec represent API param specifications.

type Route

type Route struct {
	ID         string               `json:"id"`
	Method     string               `json:"method"`
	Parameters map[string]ParamSpec `json:"parameters"`
	Path       string               `json:"path"`
	Produces   []string             `json:"produces"`
}

Route represents an API path.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL