Repository: osbuild/osbuild-composer
Pull request #332 (2020-03-16 23:39:18)

rcm: merge the two PushCompose functions
See individual commits. Lots of cleanup-type commits leading up to be able to merge these two functions.

@msehnout I wonder about the benefit of the common types. There's lots of code to convert between them and strings, all of which can return an error.

larskarlitski: I've manually verified that the rcm integration tests still pass on Fedora (after applying the patch in https://github.com/osbuild/osbuild-composer/pull/333):

```
$ make rpm
$ sudo dnf install rpmbuild/x86_64/RPMS/*.rpm
$ sudo systemctl start osbuild-rcm.socket
$ sudo /usr/libexec/tests/osbuild-composer/osbuild-rcm-tests 
2020/03/17 06:52:21 Success: the v1/compose returned compose UUID: ace94271-418d-4661-818b-74c073759930
2020/03/17 06:52:21 Success: the v1/compose/ace94271-418d-4661-818b-74c073759930 returned status: RUNNING
[vm-user@vm osbuild-composer]$ echo $?
0
```

msehnout: > @msehnout I wonder about the benefit of the common types. There's lots of code to convert between them and strings, all of which can return an error.

We discussed this when I was working on the prevous refactoring. Most of them will go away once we use ONLY the common types and never strings, because we shouldn't hardcode the same string all around the place.

The other thing is that golang does not provide an enumeration type which leaves us only with type aliases and named constants. This inherently leaves space for errors but it is a language design choice, so there is nothing I can do about it.
larskarlitski: > We discussed this when I was working on the prevous refactoring. Most of them will go away once we use ONLY the common types and never strings, because we shouldn't hardcode the same string all around the place.
> 
> The other thing is that golang does not provide an enumeration type which leaves us only with type aliases and named constants. This inherently leaves space for errors but it is a language design choice, so there is nothing I can do about it.

I think this is a bigger discussion which we should have separately. I shouldn't have started it on this PR. I'll file an issue.
msehnout: > I think this is a bigger discussion which we should have separately. I shouldn't have started it on this PR. I'll file an issue.

We had a discussion on this here: https://github.com/osbuild/osbuild-composer/issues/193 and follow up discussions over BlueJeans.

Patch:
diff --git a/.golangci.yml b/.golangci.yml
index 1958a0ac2..34f2dc815 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -4,6 +4,10 @@ linters-settings:
       - shadow # default value recommended by golangci
       - composites
 
+run:
+  build-tags:
+    - integration
+
 issues:
   # Maximum issues count per one linter. Set to 0 to disable. Default is 50.
   max-issues-per-linter: 0
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..bd186a48d
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,68 @@
+# Contributing to osbuild-composer
+
+First of all, thank you for taking the time to contribute to osbuild-composer. In this document you will find information that can help you with your contribution.
+
+### Running from sources
+
+We recommend using the latest stable Fedora for development but latest minor release of RHEL/CentOS 8 should work just fine as well. To run osbuild-composer from sources, follow these steps:
+
+1. Clone the repository and create a local checkout:
+
+```
+$ git clone https://github.com/osbuild/osbuild-composer.git
+$ cd osbuild-composer
+```
+
+2. To install the build-requirements for Fedora and friends, use:
+
+```
+$ dnf group install 'RPM Development Tools'        # Install rpmbuild
+$ dnf builddep golang-github-osbuild-composer.spec # Install build-time dependencies
+$ sudo dnf -y install cockpit-composer             # Optional: Install cockpit integration
+$ sudo systemctl start cockpit.socket              # Optional: Start cockpit
+```
+
+3. Finally, use the following to compile the project from the working directory, install it, and then run it:
+
+```
+$ make rpm
+$ sudo dnf -y install rpmbuild/RPMS/x86_64/*
+$ sudo systemctl start osbuild-composer.socket
+```
+
+You can now open https://localhost:9090 in your browser to open cockpit console and check the "Image Builder" section.
+
+Alternatively you can use `composer-cli` to interact with the Weldr API. We don't have any client for the RCM API, so the only option there is a plain `curl`.
+
+When developing the code, use `go` executable to build, run, and test you code [1]:
+
+```
+$ go test ./...
+$ go build ./...
+$ go run ./cmd/osbuild-pipeline/
+```
+
+### Testing
+
+See [test/README.md](test/README.md) for more information about testing.
+
+### Planning the work
+
+In general we encourage you to first fill in an issue and discuss the feature you would like to work on before you start. This can prevent the scenario where you work on something we don't want to include in our code.
+
+That being said, you are of course welcome to implement an example of what you would like to achieve.
+
+### Creating a PR
+
+The commits in the PR should have these properties:
+
+* Preferably minimal and well documented
+  * Where minimal means: don't do unrelated changes even if the code is obviously wrong
+  * Well documented: both code and commit message
+  * The commit message should start with the module you work on, like: `weldr: `, or `rcm:`
+* The code should compile and the composer should start, so that we can run `git bisect` on it
+* All code should be covered by unit-tests
+
+### Notes:
+
+[1] If you are running macOS, you can still compile osbuild-composer. If it doesn't work out of the box, use `-tags macos` together with any `go` command, for example: `go test -tags macos ./...`
diff --git a/Makefile b/Makefile
index a1053f3cc..325098d60 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ build:
 	go build -o osbuild-upload-azure ./cmd/osbuild-upload-azure/
 	go build -o osbuild-upload-aws ./cmd/osbuild-upload-aws/
 	go build -o osbuild-tests ./cmd/osbuild-tests/
-	go build -o osbuild-weldr-tests ./cmd/osbuild-weldr-tests/
+	go test -c -tags=integration -o osbuild-weldr-tests ./internal/weldrcheck/
 	go test -c -tags=integration -o osbuild-dnf-json-tests ./cmd/osbuild-dnf-json-tests/main_test.go
 	go build -o osbuild-rcm-tests ./cmd/osbuild-rcm-tests/
 
diff --git a/cmd/osbuild-composer/main.go b/cmd/osbuild-composer/main.go
index e57aa97a0..24ca655ef 100644
--- a/cmd/osbuild-composer/main.go
+++ b/cmd/osbuild-composer/main.go
@@ -99,7 +99,7 @@ func main() {
 		logger = log.New(os.Stdout, "", 0)
 	}
 
-	store := store.New(&stateDir, distribution, *distros)
+	store := store.New(&stateDir, *distros)
 
 	jobAPI := jobqueue.New(logger, store)
 	weldrAPI := weldr.New(rpm, common.CurrentArch(), distribution, logger, store)
@@ -116,7 +116,7 @@ func main() {
 			log.Fatal("The RCM API socket unit is misconfigured. It should contain only one socket.")
 		}
 		rcmListener := rcmApiListeners[0]
-		rcmAPI := rcm.New(logger, store, rpm)
+		rcmAPI := rcm.New(logger, store, rpm, distros)
 		go func() {
 			err := rcmAPI.Serve(rcmListener)
 			// If the RCM API fails, take down the whole process, not just a single gorutine
diff --git a/golang-github-osbuild-composer.spec b/golang-github-osbuild-composer.spec
index 77d7bee07..799b0984b 100644
--- a/golang-github-osbuild-composer.spec
+++ b/golang-github-osbuild-composer.spec
@@ -67,7 +67,6 @@ export GOFLAGS=-mod=vendor
 %gobuild -o _bin/osbuild-composer %{goipath}/cmd/osbuild-composer
 %gobuild -o _bin/osbuild-worker %{goipath}/cmd/osbuild-worker
 %gobuild -o _bin/osbuild-tests %{goipath}/cmd/osbuild-tests
-%gobuild -o _bin/osbuild-weldr-tests %{goipath}/cmd/osbuild-weldr-tests
 %gobuild -o _bin/osbuild-image-tests %{goipath}/cmd/osbuild-image-tests
 %gobuild -o _bin/osbuild-rcm-tests %{goipath}/cmd/osbuild-rcm-tests
 
@@ -78,6 +77,7 @@ export GOFLAGS=-mod=vendor
 TEST_LDFLAGS="${LDFLAGS:-} -B 0x$(od -N 20 -An -tx1 -w100 /dev/urandom | tr -d ' ')"
 
 go test -c -tags=integration -ldflags="${TEST_LDFLAGS}" -o _bin/osbuild-dnf-json-tests %{goipath}/cmd/osbuild-dnf-json-tests
+go test -c -tags=integration -ldflags="${TEST_LDFLAGS}" -o _bin/osbuild-weldr-tests %{goipath}/internal/weldrcheck/
 
 %install
 install -m 0755 -vd                                         %{buildroot}%{_libexecdir}/osbuild-composer
diff --git a/internal/mocks/rpmmd/fixtures.go b/internal/mocks/rpmmd/fixtures.go
index 34c17f77f..a54603d25 100644
--- a/internal/mocks/rpmmd/fixtures.go
+++ b/internal/mocks/rpmmd/fixtures.go
@@ -10,7 +10,6 @@ import (
 
 	"github.com/google/uuid"
 	"github.com/osbuild/osbuild-composer/internal/blueprint"
-	test_distro "github.com/osbuild/osbuild-composer/internal/distro/fedoratest"
 	"github.com/osbuild/osbuild-composer/internal/rpmmd"
 	"github.com/osbuild/osbuild-composer/internal/store"
 	"github.com/osbuild/osbuild-composer/internal/target"
@@ -93,9 +92,8 @@ func createBaseStoreFixture() *store.Store {
 		},
 	}
 
-	d := test_distro.New()
 	r, _ := distro_mock.NewDefaultRegistry()
-	s := store.New(nil, d, *r)
+	s := store.New(nil, *r)
 
 	s.Blueprints[bName] = b
 	s.Composes = map[uuid.UUID]compose.Compose{
@@ -190,9 +188,8 @@ func createStoreWithoutComposesFixture() *store.Store {
 		Customizations: nil,
 	}
 
-	d := test_distro.New()
 	r, _ := distro_mock.NewDefaultRegistry()
-	s := store.New(nil, d, *r)
+	s := store.New(nil, *r)
 
 	s.Blueprints[bName] = b
 
diff --git a/internal/rcm/api.go b/internal/rcm/api.go
index 88e230528..d7ea01228 100644
--- a/internal/rcm/api.go
+++ b/internal/rcm/api.go
@@ -16,6 +16,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/julienschmidt/httprouter"
 	"github.com/osbuild/osbuild-composer/internal/blueprint"
+	"github.com/osbuild/osbuild-composer/internal/distro"
 	"github.com/osbuild/osbuild-composer/internal/store"
 )
 
@@ -27,15 +28,17 @@ type API struct {
 	// rpmMetadata is an interface to dnf-json and we include it here so that we can
 	// mock it in the unit tests
 	rpmMetadata rpmmd.RPMMD
+	distros     *distro.Registry
 }
 
 // New creates new RCM API
-func New(logger *log.Logger, store *store.Store, rpmMetadata rpmmd.RPMMD) *API {
+func New(logger *log.Logger, store *store.Store, rpmMetadata rpmmd.RPMMD, distros *distro.Registry) *API {
 	api := &API{
 		logger:      logger,
 		store:       store,
 		router:      httprouter.New(),
 		rpmMetadata: rpmMetadata,
+		distros:     distros,
 	}
 
 	api.router.RedirectTrailingSlash = false
@@ -79,6 +82,32 @@ func notFoundHandler(writer http.ResponseWriter, request *http.Request) {
 	writer.WriteHeader(http.StatusNotFound)
 }
 
+// Depsolves packages and build packages for building an image for a given
+// distro, in the given architecture
+func depsolve(rpmmd rpmmd.RPMMD, distro distro.Distro, repos []rpmmd.RepoConfig, imageType, arch string) ([]rpmmd.PackageSpec, []rpmmd.PackageSpec, error) {
+	specs, excludeSpecs, err := distro.BasePackages(imageType, arch)
+	if err != nil {
+		return nil, nil, fmt.Errorf("Distro.BasePackages: %v", err)
+	}
+
+	packages, _, err := rpmmd.Depsolve(specs, excludeSpecs, repos, distro.ModulePlatformID())
+	if err != nil {
+		return nil, nil, fmt.Errorf("RPMMD.Depsolve: %v", err)
+	}
+
+	specs, err = distro.BuildPackages(arch)
+	if err != nil {
+		return nil, nil, fmt.Errorf("Distro.BuildPackages: %v", err)
+	}
+
+	buildPackages, _, err := rpmmd.Depsolve(specs, nil, repos, distro.ModulePlatformID())
+	if err != nil {
+		return nil, nil, fmt.Errorf("RPMMD.Depsolve: %v", err)
+	}
+
+	return packages, buildPackages, err
+}
+
 func (api *API) submit(writer http.ResponseWriter, request *http.Request, _ httprouter.Params) {
 	// Check some basic HTTP parameters
 	contentType := request.Header["Content-Type"]
@@ -93,7 +122,7 @@ func (api *API) submit(writer http.ResponseWriter, request *http.Request, _ http
 
 	// JSON structure expected from the client
 	var composeRequest struct {
-		Distribution  common.Distribution   `json:"distribution"`
+		Distribution  string                `json:"distribution"`
 		ImageTypes    []common.ImageType    `json:"image_types"`
 		Architectures []common.Architecture `json:"architectures"`
 		Repositories  []Repository          `json:"repositories"`
@@ -145,28 +174,26 @@ func (api *API) submit(writer http.ResponseWriter, request *http.Request, _ http
 		})
 	}
 
-	// Image requests are derived from requested image types. All of them are uploaded to Koji, because
-	// this API is only for RCM.
-	requestedImages := []common.ImageRequest{}
-	for _, imgType := range composeRequest.ImageTypes {
-		requestedImages = append(requestedImages, common.ImageRequest{
-			ImgType: imgType,
-			// TODO: use koji upload type as soon as it is available
-			UpTarget: []common.UploadTarget{},
-		})
-	}
-
-	modulePlatformID, err := composeRequest.Distribution.ModulePlatformID()
-	if err != nil {
+	distro := api.distros.GetDistro(composeRequest.Distribution)
+	if distro == nil {
 		writer.WriteHeader(http.StatusBadRequest)
-		_, err := writer.Write([]byte(err.Error()))
+		_, err := writer.Write([]byte("unknown distro"))
 		if err != nil {
 			panic("Failed to write response")
 		}
 	}
 
-	// map( repo-id => checksum )
-	_, checksums, err := api.rpmMetadata.FetchMetadata(repoConfigs, modulePlatformID)
+	arch, ok := composeRequest.Architectures[0].ToString()
+	if !ok {
+		panic("architecture was validated before")
+	}
+
+	imageType, ok := composeRequest.ImageTypes[0].ToString()
+	if !ok {
+		panic("image type was validated before")
+	}
+
+	packages, buildPackages, err := depsolve(api.rpmMetadata, distro, repoConfigs, imageType, arch)
 	if err != nil {
 		writer.WriteHeader(http.StatusBadRequest)
 		_, err := writer.Write([]byte(err.Error()))
@@ -178,15 +205,7 @@ func (api *API) submit(writer http.ResponseWriter, request *http.Request, _ http
 	// Push the requested compose to the store
 	composeUUID := uuid.New()
 	// nil is used as an upload target, because LocalTarget is already used in the PushCompose function
-	err = api.store.PushComposeRequest(store.ComposeRequest{
-		Blueprint:       blueprint.Blueprint{},
-		ComposeID:       composeUUID,
-		Distro:          composeRequest.Distribution,
-		Arch:            composeRequest.Architectures[0],
-		Repositories:    repoConfigs,
-		Checksums:       checksums,
-		RequestedImages: requestedImages,
-	})
+	err = api.store.PushCompose(distro, composeUUID, &blueprint.Blueprint{}, packages, buildPackages, arch, imageType, 0, nil)
 	if err != nil {
 		if api.logger != nil {
 			api.logger.Println("RCM API failed to push compose:", err)
diff --git a/internal/store/store.go b/internal/store/store.go
index 0807866ef..2d3b440ca 100644
--- a/internal/store/store.go
+++ b/internal/store/store.go
@@ -15,7 +15,6 @@ import (
 	"log"
 	"os"
 	"path/filepath"
-	"reflect"
 	"sort"
 	"sync"
 	"time"
@@ -46,7 +45,6 @@ type Store struct {
 	mu             sync.RWMutex // protects all fields
 	pendingJobs    chan Job
 	stateChannel   chan []byte
-	distro         distro.Distro
 	distroRegistry distro.Registry
 	stateDir       *string
 }
@@ -70,17 +68,6 @@ type SourceConfig struct {
 	System   bool   `json:"system"`
 }
 
-// ComposeRequest is used to submit a new compose to the store
-type ComposeRequest struct {
-	Blueprint       blueprint.Blueprint
-	ComposeID       uuid.UUID
-	Distro          common.Distribution
-	Arch            common.Architecture
-	Repositories    []rpmmd.RepoConfig
-	Checksums       map[string]string
-	RequestedImages []common.ImageRequest
-}
-
 type NotFoundError struct {
 	message string
 }
@@ -121,7 +108,7 @@ func (e *NoLocalTargetError) Error() string {
 	return e.message
 }
 
-func New(stateDir *string, distroArg distro.Distro, distroRegistryArg distro.Registry) *Store {
+func New(stateDir *string, distroRegistryArg distro.Registry) *Store {
 	var s Store
 
 	if stateDir != nil {
@@ -155,7 +142,6 @@ func New(stateDir *string, distroArg distro.Distro, distroRegistryArg distro.Reg
 	}
 
 	s.pendingJobs = make(chan Job, 200)
-	s.distro = distroArg
 	s.distroRegistry = distroRegistryArg
 	s.stateDir = stateDir
 
@@ -556,8 +542,18 @@ func (s *Store) GetImageBuildImage(composeId uuid.UUID, imageBuildId int) (io.Re
 		return nil, 0, &NoLocalTargetError{"compose does not have local target"}
 	}
 
+	name, ok := imageBuild.Distro.ToString()
+	if !ok {
+		panic("distro name was validated earlier")
+	}
+
+	distro := s.distroRegistry.GetDistro(name)
+	if distro == nil {
+		panic("distro was validated earlier")
+	}
+
 	compatString, _ := imageBuild.ImageType.ToCompatString()
-	filename, _, err := s.distro.FilenameFromType(compatString)
+	filename, _, err := distro.FilenameFromType(compatString)
 	if err != nil {
 		panic(err)
 	}
@@ -588,7 +584,7 @@ func (s *Store) getImageBuildDirectory(composeID uuid.UUID, imageBuildID int) st
 	return fmt.Sprintf("%s/%d", s.getComposeDirectory(composeID), imageBuildID)
 }
 
-func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, packages, buildPackages []rpmmd.PackageSpec, arch, composeType string, size uint64, uploadTarget *target.Target) error {
+func (s *Store) PushCompose(distro distro.Distro, composeID uuid.UUID, bp *blueprint.Blueprint, packages, buildPackages []rpmmd.PackageSpec, arch, composeType string, size uint64, uploadTarget *target.Target) error {
 	targets := []*target.Target{}
 
 	// Compatibility layer for image types in Weldr API v0
@@ -610,7 +606,7 @@ func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, packag
 		))
 	}
 
-	size = s.distro.GetSizeForOutputType(composeType, size)
+	size = distro.GetSizeForOutputType(composeType, size)
 
 	if uploadTarget != nil {
 		targets = append(targets, uploadTarget)
@@ -621,7 +617,7 @@ func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, packag
 		repos = append(repos, source.RepoConfig())
 	}
 
-	manifestStruct, err := s.distro.Manifest(bp.Customizations, repos, packages, buildPackages, arch, composeType, size)
+	manifestStruct, err := distro.Manifest(bp.Customizations, repos, packages, buildPackages, arch, composeType, size)
 	if err != nil {
 		return err
 	}
@@ -645,7 +641,7 @@ func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, packag
 	s.pendingJobs <- Job{
 		ComposeID:    composeID,
 		ImageBuildID: 0,
-		Distro:       s.distro.Name(),
+		Distro:       distro.Name(),
 		Manifest:     manifestStruct,
 		Targets:      targets,
 		ImageType:    composeType,
@@ -654,90 +650,6 @@ func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, packag
 	return nil
 }
 
-// PushComposeRequest is an alternative to PushCompose which does not assume a pre-defined distro, as such it is better
-// suited for RCM API and possible future API that would respect the fact that we can build any distro and any arch
-func (s *Store) PushComposeRequest(request ComposeRequest) error {
-	// This should never happen and once distro.Manifest is refactored this check will go away
-	arch, exists := request.Arch.ToString()
-	if !exists {
-		panic("fatal error, arch should exist but it does not")
-	}
-	distroString, exists := request.Distro.ToString()
-	if !exists {
-		panic("fatal error, distro should exist but it does not")
-	}
-
-	distroStruct := s.distroRegistry.GetDistro(distroString)
-	if distroStruct == nil || (reflect.ValueOf(distroStruct).Kind() == reflect.Ptr && reflect.ValueOf(distroStruct).IsNil()) {
-		panic("fatal error, distro should exist but it is not in the registry")
-	}
-
-	// This will be a list of imageBuilds that will be submitted to the state channel
-	imageBuilds := []compose.ImageBuild{}
-	newJobs := []Job{}
-
-	// TODO: remove this
-	if len(request.RequestedImages) > 1 {
-		panic("Multiple image requests are not yet properly implemented")
-	}
-
-	for imageBuildID, imageRequest := range request.RequestedImages {
-		// TODO: handle custom upload targets
-		// TODO: this requires changes in the Compose Request struct
-		// This should never happen and once distro.Manifest is refactored this check will go away
-		imgTypeCompatStr, exists := imageRequest.ImgType.ToCompatString()
-		if !exists {
-			panic("fatal error, image type should exist but it does not")
-		}
-		manifestStruct, err := distroStruct.Manifest(request.Blueprint.Customizations, request.Repositories, nil, nil, arch, imgTypeCompatStr, 0)
-		if err != nil {
-			return err
-		}
-
-		if s.stateDir != nil {
-			err = os.MkdirAll(s.getImageBuildDirectory(request.ComposeID, imageBuildID), 0755)
-			if err != nil {
-				return err
-			}
-		}
-
-		// This will make the job submission atomic: either all of them or none of them
-		newJobs = append(newJobs, Job{
-			ComposeID:    request.ComposeID,
-			ImageBuildID: imageBuildID,
-			Distro:       distroString,
-			Manifest:     manifestStruct,
-			Targets:      []*target.Target{},
-			ImageType:    imgTypeCompatStr,
-		})
-
-		imageBuilds = append(imageBuilds, compose.ImageBuild{
-			Distro:      request.Distro,
-			QueueStatus: common.IBWaiting,
-			ImageType:   imageRequest.ImgType,
-			Manifest:    manifestStruct,
-			Targets:     []*target.Target{},
-			JobCreated:  time.Now(),
-		})
-	}
-
-	// submit all the jobs now
-	for _, job := range newJobs {
-		s.pendingJobs <- job
-	}
-
-	// ignore error because the previous implementation does the same
-	_ = s.change(func() error {
-		s.Composes[request.ComposeID] = compose.Compose{
-			Blueprint:   &request.Blueprint,
-			ImageBuilds: imageBuilds,
-		}
-		return nil
-	})
-
-	return nil
-}
-
 // DeleteCompose deletes the compose from the state file and also removes all files on disk that are
 // associated with this compose
 func (s *Store) DeleteCompose(id uuid.UUID) error {
@@ -869,8 +781,18 @@ func (s *Store) AddImageToImageUpload(composeID uuid.UUID, imageBuildID int, rea
 		return &NoLocalTargetError{fmt.Sprintf("image upload requested for compse %s and image build %d but it has no local target", composeID.String(), imageBuildID)}
 	}
 
+	name, ok := imageBuild.Distro.ToString()
+	if !ok {
+		panic("distro name was validated earlier")
+	}
+
+	distro := s.distroRegistry.GetDistro(name)
+	if distro == nil {
+		panic("distro was validated earlier")
+	}
+
 	imageType, _ := imageBuild.ImageType.ToCompatString()
-	filename, _, err := s.distro.FilenameFromType(imageType)
+	filename, _, err := distro.FilenameFromType(imageType)
 
 	if err != nil {
 		return &InvalidRequestError{err.Error()}
diff --git a/internal/weldr/api.go b/internal/weldr/api.go
index a082f291a..19d1c8ba0 100644
--- a/internal/weldr/api.go
+++ b/internal/weldr/api.go
@@ -843,7 +843,7 @@ func (api *API) blueprintsDepsolveHandler(writer http.ResponseWriter, request *h
 			continue
 		}
 
-		dependencies, _, err := api.depsolveBlueprint(blueprint, "", api.arch, false)
+		dependencies, _, err := api.depsolveBlueprint(blueprint, "", api.arch)
 
 		if err != nil {
 			errors := responseError{
@@ -939,7 +939,7 @@ func (api *API) blueprintsFreezeHandler(writer http.ResponseWriter, request *htt
 			break
 		}
 
-		dependencies, _, err := api.depsolveBlueprint(&blueprint, "", api.arch, false)
+		dependencies, _, err := api.depsolveBlueprint(&blueprint, "", api.arch)
 		if err != nil {
 			rerr := responseError{
 				ID:  "BlueprintsError",
@@ -1364,7 +1364,6 @@ func (api *API) composeHandler(writer http.ResponseWriter, request *http.Request
 		BuildID uuid.UUID `json:"build_id"`
 		Status  bool      `json:"status"`
 	}
-	const MegaByte = 1024 * 1024
 
 	contentType := request.Header["Content-Type"]
 	if len(contentType) != 1 || contentType[0] != "application/json" {
@@ -1409,16 +1408,8 @@ func (api *API) composeHandler(writer http.ResponseWriter, request *http.Request
 	}
 
 	bp := api.store.GetBlueprintCommitted(cr.BlueprintName)
-
-	size := cr.Size
-
-	// Microsoft Azure requires vhd images to be rounded up to the nearest MB
-	if cr.ComposeType == "vhd" && size%MegaByte != 0 {
-		size = (size/MegaByte + 1) * MegaByte
-	}
-
 	if bp != nil {
-		packages, buildPackages, err := api.depsolveBlueprint(bp, cr.ComposeType, api.arch, true)
+		packages, buildPackages, err := api.depsolveBlueprint(bp, cr.ComposeType, api.arch)
 		if err != nil {
 			errors := responseError{
 				ID:  "DepsolveError",
@@ -1428,7 +1419,7 @@ func (api *API) composeHandler(writer http.ResponseWriter, request *http.Request
 			return
 		}
 
-		err = api.store.PushCompose(reply.BuildID, bp, packages, buildPackages, api.arch, cr.ComposeType, size, uploadTarget)
+		err = api.store.PushCompose(api.distro, reply.BuildID, bp, packages, buildPackages, api.arch, cr.ComposeType, cr.Size, uploadTarget)
 
 		// TODO: we should probably do some kind of blueprint validation in future
 		// for now, let's just 500 and bail out
@@ -1977,7 +1968,7 @@ func getPkgNameGlob(pkg blueprint.Package) string {
 	return pkg.Name
 }
 
-func (api *API) depsolveBlueprint(bp *blueprint.Blueprint, outputType, arch string, clean bool) ([]rpmmd.PackageSpec, []rpmmd.PackageSpec, error) {
+func (api *API) depsolveBlueprint(bp *blueprint.Blueprint, outputType, arch string) ([]rpmmd.PackageSpec, []rpmmd.PackageSpec, error) {
 	repos := api.distro.Repositories(api.arch)
 	for _, source := range api.store.GetAllSources() {
 		repos = append(repos, source.RepoConfig())
diff --git a/internal/weldrcheck/blueprints.go b/internal/weldrcheck/blueprints.go
deleted file mode 100644
index 4ff252fe4..000000000
--- a/internal/weldrcheck/blueprints.go
+++ /dev/null
@@ -1,1479 +0,0 @@
-// Package weldrcheck - blueprints contains functions to check the blueprints API
-// Copyright (C) 2020 by Red Hat, Inc.
-package weldrcheck
-
-import (
-	"log"
-	"net/http"
-	"reflect"
-	"sort"
-	"strings"
-
-	"github.com/BurntSushi/toml"
-
-	"github.com/osbuild/osbuild-composer/internal/client"
-)
-
-type checkBlueprintsV0 struct {
-	socket *http.Client
-}
-
-// Run will execute the API V0 Blueprint check functions
-// This will call all of the methods that start with 'Check', passing them a pointer to a
-// checkBlueprintsV0 struct and expecting a bool to be returned to indicate whether or not the test
-// passed.
-// If any of the tests fail it will return false.
-func (c *checkBlueprintsV0) Run() bool {
-	pass := true
-
-	// Construct a reflect.Type to use for checking method type signatures
-	boolType := reflect.TypeOf(true)
-	structType := reflect.TypeOf(c)
-	funcType := reflect.FuncOf([]reflect.Type{structType}, []reflect.Type{boolType}, false)
-
-	structValue := reflect.ValueOf(c)
-	// Get all the exported methods on this struct named 'Check*' and run them
-	for i := 0; i < structType.NumMethod(); i++ {
-		method := structType.Method(i)
-		// Make sure it starts with Check and matches the type signature
-		if strings.HasPrefix(method.Name, "Check") {
-			if method.Type != funcType {
-				log.Printf("ERROR: Check function '%s' has wrong type: %s", method.Name, method.Type)
-				pass = false
-				continue
-			}
-
-			r := structValue.Method(i).Call(nil)
-			if !r[0].Bool() {
-				pass = false
-			}
-		}
-	}
-
-	return pass
-}
-
-// POST a new TOML blueprint
-func (c *checkBlueprintsV0) CheckPostTOML() bool {
-	name := "POST of a TOML blueprint"
-
-	bp := `
-		name="test-toml-blueprint-v0"
-		description="postTOMLBlueprintV0"
-		version="0.0.1"
-		[[packages]]
-		name="bash"
-		version="*"
-
-		[[modules]]
-		name="util-linux"
-		version="*"
-
-		[[customizations.user]]
-		name="root"
-		password="qweqweqwe"
-		`
-	resp, err := client.PostTOMLBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// POST an invalid TOML blueprint
-func (c *checkBlueprintsV0) CheckPostInvalidTOML() bool {
-	name := "POST of an invalid TOML blueprint"
-
-	bp := `
-		name="test-invalid-toml-blueprint-v0"
-		version="0.0.1"
-		[package
-		name="bash"
-		version="*"
-		`
-	resp, err := client.PostTOMLBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if resp.Status {
-		log.Printf("FAIL: %s did not return an error", name)
-		return false
-	}
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// POST an empty TOML blueprint
-func (c *checkBlueprintsV0) CheckPostEmptyTOML() bool {
-	name := "POST of an empty TOML blueprint"
-
-	resp, err := client.PostTOMLBlueprintV0(c.socket, "")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if resp.Status {
-		log.Printf("FAIL: %s did not return an error", name)
-		return false
-	}
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// POST a new JSON blueprint
-func (c *checkBlueprintsV0) CheckPostJSON() bool {
-	name := "POST of a JSON blueprint"
-
-	bp := `{
-		"name": "test-json-blueprint-v0",
-		"description": "postJSONBlueprintV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`
-
-	resp, err := client.PostJSONBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// POST an invalid JSON blueprint
-func (c *checkBlueprintsV0) CheckPostInvalidJSON() bool {
-	name := "POST of an invalid JSON blueprint"
-
-	bp := `{
-		"name": "test-invalid-json-blueprint-v0",
-		"version": "0.0.1",
-		"modules": [{"name: "util-linux", "version": "*"}],
-	}`
-
-	resp, err := client.PostJSONBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if resp.Status {
-		log.Printf("FAIL: %s did not return an error", name)
-		return false
-	}
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// POST an empty JSON blueprint
-func (c *checkBlueprintsV0) CheckPostEmptyJSON() bool {
-	name := "POST of an empty JSON blueprint"
-
-	resp, err := client.PostJSONBlueprintV0(c.socket, "")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if resp.Status {
-		log.Printf("FAIL: %s did not return an error", name)
-		return false
-	}
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// POST a blueprint to the workspace as TOML
-func (c *checkBlueprintsV0) CheckPostTOMLWS() bool {
-	name := "POST TOML blueprint to workspace"
-
-	bp := `
-		name="test-toml-blueprint-ws-v0"
-		description="postTOMLBlueprintWSV0"
-		version="0.0.1"
-		[[packages]]
-		name="bash"
-		version="*"
-
-		[[modules]]
-		name="util-linux"
-		version="*"
-
-		[[customizations.user]]
-		name="root"
-		password="qweqweqwe"
-		`
-	resp, err := client.PostTOMLWorkspaceV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// POST an invalid TOML blueprint to the workspace
-func (c *checkBlueprintsV0) CheckPostInvalidTOMLWS() bool {
-	name := "POST of an invalid TOML blueprint to workspace"
-
-	bp := `
-		name="test-invalid-toml-blueprint-ws-v0"
-		version="0.0.1"
-		[package
-		name="bash"
-		version="*"
-		`
-	resp, err := client.PostTOMLWorkspaceV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if resp.Status {
-		log.Printf("FAIL: %s did not return an error", name)
-		return false
-	}
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// POST an empty TOML blueprint to the workspace
-func (c *checkBlueprintsV0) CheckPostEmptyTOMLWS() bool {
-	name := "POST of an empty TOML blueprint to workspace"
-
-	resp, err := client.PostTOMLWorkspaceV0(c.socket, "")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if resp.Status {
-		log.Printf("FAIL: %s did not return an error", name)
-		return false
-	}
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// POST a blueprint to the workspace as JSON
-func (c *checkBlueprintsV0) CheckPostJSONWS() bool {
-	name := "POST JSON blueprint to workspace"
-
-	bp := `{
-		"name": "test-json-blueprint-ws-v0",
-		"description": "postJSONBlueprintWSV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`
-
-	resp, err := client.PostJSONWorkspaceV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// POST an invalid JSON blueprint to the workspace
-func (c *checkBlueprintsV0) CheckPostInvalidJSONWS() bool {
-	name := "POST of an invalid JSON blueprint to workspace"
-
-	bp := `{
-		"name": "test-invalid-json-blueprint-ws-v0",
-		"version": "0.0.1",
-		"modules": [{"name: "util-linux", "version": "*"}],
-	}`
-
-	resp, err := client.PostJSONBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if resp.Status {
-		log.Printf("FAIL: %s did not return an error", name)
-		return false
-	}
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// POST an empty JSON blueprint to the workspace
-func (c *checkBlueprintsV0) CheckPostEmptyJSONWS() bool {
-	name := "POST of an empty JSON blueprint to workspace"
-
-	resp, err := client.PostJSONBlueprintV0(c.socket, "")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if resp.Status {
-		log.Printf("FAIL: %s did not return an error", name)
-		return false
-	}
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// delete a blueprint
-func (c *checkBlueprintsV0) CheckDelete() bool {
-	name := "DELETE blueprint"
-
-	// POST a blueprint to delete
-	bp := `{
-		"name": "test-delete-blueprint-v0",
-		"description": "deleteBlueprintV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`
-
-	resp, err := client.PostJSONBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	// Delete the blueprint
-	resp, err = client.DeleteBlueprintV0(c.socket, "test-delete-blueprint-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// delete a non-existent blueprint
-func (c *checkBlueprintsV0) CheckDeleteNonBlueprint() bool {
-	name := "DELETE a non-existent blueprint"
-
-	resp, err := client.DeleteBlueprintV0(c.socket, "test-delete-non-blueprint-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if resp.Status {
-		log.Printf("FAIL: %s did not return an error", name)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// delete a new blueprint from the workspace
-func (c *checkBlueprintsV0) CheckDeleteNewWS() bool {
-	name := "DELETE new blueprint from workspace"
-
-	// POST a blueprint to delete
-	bp := `{
-		"name": "test-delete-new-blueprint-ws-v0",
-		"description": "deleteNewBlueprintWSV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`
-
-	resp, err := client.PostJSONWorkspaceV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	// Delete the blueprint
-	resp, err = client.DeleteWorkspaceV0(c.socket, "test-delete-new-blueprint-ws-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// delete blueprint changes from the workspace
-func (c *checkBlueprintsV0) CheckDeleteChangesWS() bool {
-	name := "DELETE blueprint changes from workspace"
-
-	// POST a blueprint first
-	bp := `{
-		"name": "test-delete-blueprint-changes-ws-v0",
-		"description": "deleteBlueprintChangesWSV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`
-
-	resp, err := client.PostJSONBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	// Post blueprint changes to the workspace
-	bp = `{
-		"name": "test-delete-blueprint-changes-ws-v0",
-		"description": "workspace copy",
-		"version": "0.2.0",
-		"packages": [{"name": "frobozz", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`
-
-	resp, err = client.PostJSONWorkspaceV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	// Get the blueprint, make sure it is the modified one and that changes = true
-	info, api, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-delete-blueprint-changes-ws-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s BlueprintsInfo request failed: %s", name, api)
-		return false
-	}
-
-	if len(info.Blueprints) < 1 {
-		log.Printf("FAIL: %s failed: No blueprints returned", name)
-		return false
-	}
-
-	if len(info.Changes) < 1 {
-		log.Printf("FAIL: %s failed: No change states returned", name)
-		return false
-	}
-
-	if info.Blueprints[0].Name != "test-delete-blueprint-changes-ws-v0" {
-		log.Printf("FAIL: %s failed: wrong blueprint returned", name)
-		return false
-	}
-
-	if info.Changes[0].Name != "test-delete-blueprint-changes-ws-v0" {
-		log.Printf("FAIL: %s failed: wrong change state returned", name)
-		return false
-	}
-
-	if !info.Changes[0].Changed {
-		log.Printf("FAIL: %s failed: wrong change state returned (false)", name)
-		return false
-	}
-
-	if info.Blueprints[0].Description != "workspace copy" {
-		log.Printf("FAIL: %s failed: workspace copy not returned", name)
-		return false
-	}
-
-	// Delete the blueprint from the workspace
-	resp, err = client.DeleteWorkspaceV0(c.socket, "test-delete-blueprint-changes-ws-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	// Get the blueprint, make sure it is the un-modified one
-	info, api, err = client.GetBlueprintsInfoJSONV0(c.socket, "test-delete-blueprint-changes-ws-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s BlueprintsInfo request failed: %s", name, api)
-		return false
-	}
-
-	if len(info.Blueprints) < 1 {
-		log.Printf("FAIL: %s failed: No blueprints returned", name)
-		return false
-	}
-
-	if len(info.Changes) < 1 {
-		log.Printf("FAIL: %s failed: No change states returned", name)
-		return false
-	}
-
-	if info.Blueprints[0].Name != "test-delete-blueprint-changes-ws-v0" {
-		log.Printf("FAIL: %s failed: wrong blueprint returned", name)
-		return false
-	}
-
-	if info.Changes[0].Name != "test-delete-blueprint-changes-ws-v0" {
-		log.Printf("FAIL: %s failed: wrong change state returned", name)
-		return false
-	}
-
-	if info.Changes[0].Changed {
-		log.Printf("FAIL: %s failed: wrong change state returned (true)", name)
-		return false
-	}
-
-	if info.Blueprints[0].Description != "deleteBlueprintChangesWSV0" {
-		log.Printf("FAIL: %s failed: original blueprint not returned", name)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// list blueprints
-func (c *checkBlueprintsV0) CheckList() bool {
-	name := "List blueprints"
-	// Post a couple of blueprints
-	bps := []string{`{
-		"name": "test-list-blueprint-1-v0",
-		"description": "listBlueprintsV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`,
-		`{
-		"name": "test-list-blueprint-2-v0",
-		"description": "listBlueprintsV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`}
-
-	for i := range bps {
-		resp, err := client.PostJSONBlueprintV0(c.socket, bps[i])
-		if err != nil {
-			log.Printf("FAIL: %s failed with a client error: %s", name, err)
-			return false
-		}
-		if !resp.Status {
-			log.Printf("FAIL: %s failed: %s", name, resp)
-			return false
-		}
-	}
-
-	// Get the list of blueprints
-	list, api, err := client.ListBlueprintsV0(c.socket)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err.Error())
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s ListBlueprints failed: %s", name, api)
-		return false
-	}
-
-	// Make sure the blueprints are in the list
-	sorted := sort.StringSlice(list)
-	if !isStringInSlice(sorted, "test-list-blueprint-1-v0") ||
-		!isStringInSlice(sorted, "test-list-blueprint-2-v0") {
-		log.Printf("FAIL: %s failed", name)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// get blueprint contents as TOML
-func (c *checkBlueprintsV0) CheckGetTOML() bool {
-	name := "Get TOML Blueprint"
-	bp := `{
-		"name": "test-get-blueprint-1-v0",
-		"description": "getTOMLBlueprintV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`
-
-	// Post a blueprint
-	resp, err := client.PostJSONBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	// Get it as TOML
-	body, api, err := client.GetBlueprintInfoTOMLV0(c.socket, "test-get-blueprint-1-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s GetBlueprintInfo failed: %s", name, api)
-		return false
-	}
-
-	if len(body) == 0 {
-		log.Printf("FAIL: %s failed: body of response is empty", name)
-		return false
-	}
-
-	// Can it be decoded as TOML?
-	var decoded interface{}
-	if _, err := toml.Decode(body, &decoded); err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// get non-existent blueprint contents as TOML
-func (c *checkBlueprintsV0) CheckGetNonTOML() bool {
-	name := "Get non-existent TOML Blueprint"
-
-	_, api, err := client.GetBlueprintInfoTOMLV0(c.socket, "test-get-non-blueprint-1-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-	if api == nil || api.Status {
-		log.Printf("FAIL: %s did not return an error", name)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// get blueprint contents as JSON
-func (c *checkBlueprintsV0) CheckGetJSON() bool {
-	name := "Get JSON Blueprint"
-	bp := `{
-		"name": "test-get-blueprint-2-v0",
-		"description": "getJSONBlueprintV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`
-
-	// Post a blueprint
-	resp, err := client.PostJSONBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	// Get the blueprint and its changed state
-	info, api, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-get-blueprint-2-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s GetBlueprintsInfo failed: %s", name, api)
-		return false
-	}
-
-	if len(info.Blueprints) < 1 {
-		log.Printf("FAIL: %s failed: No blueprints returned", name)
-		return false
-	}
-
-	if len(info.Changes) < 1 {
-		log.Printf("FAIL: %s failed: No change states returned", name)
-		return false
-	}
-
-	if info.Blueprints[0].Name != "test-get-blueprint-2-v0" {
-		log.Printf("FAIL: %s failed: wrong blueprint returned", name)
-		return false
-	}
-
-	if info.Changes[0].Name != "test-get-blueprint-2-v0" {
-		log.Printf("FAIL: %s failed: wrong change state returned", name)
-		return false
-	}
-
-	if info.Changes[0].Changed {
-		log.Printf("FAIL: %s failed: unexpected changes", name)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// get non-existent blueprint contents as JSON
-func (c *checkBlueprintsV0) CheckGetNonJSON() bool {
-	name := "Get non-existent JSON Blueprint"
-
-	resp, api, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-get-non-blueprint-1-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s failed: %s", name, api)
-		return false
-	}
-	if len(resp.Errors) == 0 {
-		log.Printf("FAIL: %s failed with no error: %v", name, resp)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// pushing the same blueprint bumps the version number returned by show
-func (c *checkBlueprintsV0) CheckBumpVersion() bool {
-	name := "Bump Blueprint Version number"
-	bp := `{
-		"name": "test-bump-blueprint-1-v0",
-		"description": "bumpBlueprintVersionV0",
-		"version": "2.1.2",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`
-
-	// List blueprints
-	list, api, err := client.ListBlueprintsV0(c.socket)
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err.Error())
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s ListBlueprints failed: %s", name, api)
-		return false
-	}
-
-	// If the blueprint already exists it needs to be deleted to start from a known state
-	sorted := sort.StringSlice(list)
-	if isStringInSlice(sorted, "test-bump-blueprint-1-v0") {
-		// Delete this blueprint if it already exists
-		resp, err := client.DeleteBlueprintV0(c.socket, "test-bump-blueprint-1-v0")
-		if err != nil {
-			log.Printf("FAIL: %s failed with a client error: %s", name, err)
-			return false
-		}
-		if !resp.Status {
-			log.Printf("FAIL: %s failed: %s", name, resp)
-			return false
-		}
-	}
-
-	// Post a blueprint
-	resp, err := client.PostJSONBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	// Post a blueprint again to bump verion to 2.1.3
-	resp, err = client.PostJSONBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	// Get the blueprint and its changed state
-	info, api, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-bump-blueprint-1-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s GetBlueprintsInfo failed: %s", name, api)
-		return false
-	}
-
-	if len(info.Blueprints) < 1 {
-		log.Printf("FAIL: %s failed: No blueprints returned", name)
-		return false
-	}
-
-	if info.Blueprints[0].Name != "test-bump-blueprint-1-v0" {
-		log.Printf("FAIL: %s failed: wrong blueprint returned", name)
-		return false
-	}
-
-	if info.Blueprints[0].Version != "2.1.3" {
-		log.Printf("FAIL: %s failed: wrong blueprint version", name)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// Make several changes to a blueprint and list the changes
-func (c *checkBlueprintsV0) CheckBlueprintChangesV0() bool {
-	name := "List blueprint changes"
-
-	bps := []string{`{
-		"name": "test-blueprint-changes-v0",
-		"description": "CheckBlueprintChangesV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}]
-	}`,
-		`{
-		"name": "test-blueprint-changes-v0",
-		"description": "CheckBlueprintChangesV0",
-		"version": "0.1.0",
-		"packages": [{"name": "bash", "version": "*"}, {"name": "tmux", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`,
-		`{
-		"name": "test-blueprint-changes-v0",
-		"description": "CheckBlueprintChangesV0",
-		"version": "0.1.1",
-		"packages": [{"name": "bash", "version": "*"}, {"name": "tmux", "version": "*"}],
-		"modules": [],
-		"customizations": {"user": [{"name": "root", "password": "asdasdasd"}]}
-	}`}
-
-	// Push 3 changes to the blueprint
-	for i := range bps {
-		resp, err := client.PostJSONBlueprintV0(c.socket, bps[i])
-		if err != nil {
-			log.Printf("FAIL: %s failed with a client error: %s", name, err)
-			return false
-		}
-		if !resp.Status {
-			log.Printf("FAIL: %s failed: %s", name, resp)
-			return false
-		}
-	}
-
-	// List the changes
-	changes, api, err := client.GetBlueprintsChangesV0(c.socket, []string{"test-blueprint-changes-v0"})
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s GetBlueprintsChanges failed: %s", name, api)
-		return false
-	}
-
-	if len(changes.BlueprintsChanges) != 1 {
-		log.Printf("FAIL: %s failed: No changes returned", name)
-		return false
-	}
-
-	if changes.BlueprintsChanges[0].Name != "test-blueprint-changes-v0" {
-		log.Printf("FAIL: %s failed: Wrong blueprint changes returned", name)
-		return false
-	}
-
-	if len(changes.BlueprintsChanges[0].Changes) < 3 {
-		log.Printf("FAIL: %s failed: Wrong number of changes returned", name)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// Get changes for a non-existent blueprint
-func (c *checkBlueprintsV0) CheckBlueprintNonChangesV0() bool {
-	name := "List non-existent blueprint changes"
-
-	resp, api, err := client.GetBlueprintsChangesV0(c.socket, []string{"test-non-blueprint-changes-v0"})
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s failed: %s", name, api)
-		return false
-	}
-	if len(resp.Errors) == 0 {
-		log.Printf("FAIL: %s failed with no error: %v", name, resp)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// Undo blueprint changes
-func (c *checkBlueprintsV0) CheckUndoBlueprintV0() bool {
-	name := "Undo blueprint changes"
-
-	bps := []string{`{
-		"name": "test-undo-blueprint-v0",
-		"description": "CheckUndoBlueprintV0",
-		"version": "0.0.5",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`,
-		`{
-		"name": "test-undo-blueprint-v0",
-		"description": "CheckUndoBlueprintv0",
-		"version": "0.0.6",
-		"packages": [{"name": "bash", "version": "0.5.*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`}
-
-	// Push original version of the blueprint
-	resp, err := client.PostJSONBlueprintV0(c.socket, bps[0])
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	// Get the commit hash
-	changes, api, err := client.GetBlueprintsChangesV0(c.socket, []string{"test-undo-blueprint-v0"})
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s GetBlueprintsChanges failed: %s", name, api)
-		return false
-	}
-
-	if len(changes.BlueprintsChanges) != 1 {
-		log.Printf("FAIL: %s failed: No changes returned", name)
-		return false
-	}
-
-	if len(changes.BlueprintsChanges[0].Changes) < 1 {
-		log.Printf("FAIL: %s failed: Wrong number of changes returned", name)
-		return false
-	}
-	commit := changes.BlueprintsChanges[0].Changes[0].Commit
-
-	if len(commit) == 0 {
-		log.Printf("FAIL: %s failed: First commit is empty", name)
-		return false
-	}
-
-	// Push the new version with wrong bash version
-	resp, err = client.PostJSONBlueprintV0(c.socket, bps[1])
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	// Get the blueprint, confirm bash version is '0.5.*'
-	info, api, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-undo-blueprint-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s GetBlueprintsInfo failed: %s", name, api)
-		return false
-	}
-
-	if len(info.Blueprints) < 1 {
-		log.Printf("FAIL: %s failed: No blueprints returned", name)
-		return false
-	}
-
-	if len(info.Blueprints[0].Packages) < 1 {
-		log.Printf("FAIL: %s failed: No packages in the blueprint", name)
-		return false
-	}
-
-	if info.Blueprints[0].Packages[0].Name != "bash" ||
-		info.Blueprints[0].Packages[0].Version != "0.5.*" {
-		log.Printf("FAIL: %s failed to push change: Wrong package in the blueprint: %s", name, info.Blueprints[0].Packages[0])
-		log.Printf("%#v", info)
-		return false
-	}
-
-	// Revert the blueprint to the original version
-	resp, err = client.UndoBlueprintChangeV0(c.socket, "test-undo-blueprint-v0", commit)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s failed: %s", name, resp)
-		return false
-	}
-
-	// Get the blueprint, confirm bash version is '*'
-	info, api, err = client.GetBlueprintsInfoJSONV0(c.socket, "test-undo-blueprint-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s GetBlueprintsInfo failed: %s", name, api)
-		return false
-	}
-
-	if len(info.Blueprints) < 1 {
-		log.Printf("FAIL: %s failed: No blueprints returned", name)
-		return false
-	}
-
-	if len(info.Blueprints[0].Packages) < 1 {
-		log.Printf("FAIL: %s failed: No packages in the blueprint", name)
-		return false
-	}
-
-	if info.Blueprints[0].Packages[0].Name != "bash" ||
-		info.Blueprints[0].Packages[0].Version != "*" {
-		log.Printf("FAIL: %s failed to undo change: Wrong package in the blueprint: %s", name, info.Blueprints[0].Packages[0])
-		log.Printf("%#v", info)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// Undo non-existent commit blueprint changes
-func (c *checkBlueprintsV0) CheckUndoBlueprintNonCommitV0() bool {
-	name := "Undo blueprint non-existent commit"
-
-	bps := []string{`{
-		"name": "test-undo-blueprint-non-commit-v0",
-		"description": "CheckUndoBlueprintNonCommitV0",
-		"version": "0.0.5",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`,
-		`{
-		"name": "test-undo-blueprint-non-commit-v0",
-		"description": "CheckUndoBlueprintNonCommitv0",
-		"version": "0.0.6",
-		"packages": [{"name": "bash", "version": "0.5.*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`}
-
-	for i := range bps {
-		resp, err := client.PostJSONBlueprintV0(c.socket, bps[i])
-		if err != nil {
-			log.Printf("FAIL: %s failed with a client error: %s", name, err)
-			return false
-		}
-		if !resp.Status {
-			log.Printf("FAIL: %s failed: %s", name, resp)
-			return false
-		}
-	}
-
-	resp, err := client.UndoBlueprintChangeV0(c.socket, "test-undo-blueprint-non-commit-v0", "FFFF")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if resp.Status {
-		log.Printf("FAIL: %s did not return an error", name)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// Undo non-existent blueprint changes
-func (c *checkBlueprintsV0) CheckUndoNonBlueprintV0() bool {
-	name := "Undo non-existent blueprint changes"
-
-	resp, err := client.UndoBlueprintChangeV0(c.socket, "test-undo-non-blueprint-v0", "FFFF")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if resp.Status {
-		log.Printf("FAIL: %s did not return an error", name)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// Tag a blueprint with a new revision
-// The blueprint revision tag cannot be reset, it always increments by one, and cannot be deleted.
-// So to test tagging we tag two blueprint changes and make sure the second is first +1
-func (c *checkBlueprintsV0) CheckBlueprintTagV0() bool {
-	name := "Tag a blueprint"
-
-	bps := []string{`{
-		"name": "test-tag-blueprint-v0",
-		"description": "CheckBlueprintTagV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "0.1.*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`,
-		`{
-		"name": "test-tag-blueprint-v0",
-		"description": "CheckBlueprintTagV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "0.5.*"}],
-		"modules": [{"name": "util-linux", "version": "*"}],
-		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
-	}`}
-
-	// Push a blueprint
-	resp, err := client.PostJSONBlueprintV0(c.socket, bps[0])
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s POST failed: %s", name, resp)
-		return false
-	}
-
-	// Tag the blueprint
-	tagResp, err := client.TagBlueprintV0(c.socket, "test-tag-blueprint-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !tagResp.Status {
-		log.Printf("FAIL: %s Tag failed: %s", name, tagResp)
-		return false
-	}
-
-	// Get changes, get the blueprint's revision
-	changes, api, err := client.GetBlueprintsChangesV0(c.socket, []string{"test-tag-blueprint-v0"})
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s GetBlueprintsChange failed: %s", name, api)
-		return false
-	}
-
-	if len(changes.BlueprintsChanges) != 1 {
-		log.Printf("FAIL: %s failed: No changes returned", name)
-		return false
-	}
-
-	if len(changes.BlueprintsChanges[0].Changes) < 1 {
-		log.Printf("FAIL: %s failed: Wrong number of changes returned", name)
-		return false
-	}
-
-	revision := changes.BlueprintsChanges[0].Changes[0].Revision
-	if revision == nil || *revision == 0 {
-		log.Printf("FAIL: %s failed: Revision is zero", name)
-		return false
-	}
-
-	// Push a new version of the blueprint
-	resp, err = client.PostJSONBlueprintV0(c.socket, bps[1])
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s POST failed: %s", name, resp)
-		return false
-	}
-
-	// Tag the blueprint
-	tagResp, err = client.TagBlueprintV0(c.socket, "test-tag-blueprint-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !tagResp.Status {
-		log.Printf("FAIL: %s Tag failed: %s", name, tagResp)
-		return false
-	}
-
-	// Get changes, confirm that Revision is revision +1
-	changes, api, err = client.GetBlueprintsChangesV0(c.socket, []string{"test-tag-blueprint-v0"})
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err)
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s GetBlueprintsChanges failed: %s", name, api)
-		return false
-	}
-
-	if len(changes.BlueprintsChanges) != 1 {
-		log.Printf("FAIL: %s failed: No changes returned", name)
-		return false
-	}
-
-	if len(changes.BlueprintsChanges[0].Changes) < 1 {
-		log.Printf("FAIL: %s failed: Wrong number of changes returned", name)
-		return false
-	}
-
-	newRevision := changes.BlueprintsChanges[0].Changes[0].Revision
-	if newRevision == nil || *newRevision != *revision+1 {
-		log.Printf("FAIL: %s failed: Revision is not %d", name, *revision+1)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// Tag a non-existent blueprint
-func (c *checkBlueprintsV0) CheckNonBlueprintTagV0() bool {
-	name := "Tag a non-existent blueprint"
-
-	tagResp, err := client.TagBlueprintV0(c.socket, "test-tag-non-blueprint-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if tagResp.Status {
-		log.Printf("FAIL: %s failed to return an error", name)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// depsolve a blueprint with packages and modules
-func (c *checkBlueprintsV0) CheckBlueprintDepsolveV0() bool {
-	name := "Depsolve a blueprint"
-
-	bp := `{
-		"name": "test-deps-blueprint-v0",
-		"description": "CheckBlueprintDepsolveV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}]
-	}`
-
-	// Push a blueprint
-	resp, err := client.PostJSONBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s POST failed: %s", name, resp)
-		return false
-	}
-
-	// Depsolve the blueprint
-	deps, api, err := client.DepsolveBlueprintV0(c.socket, "test-deps-blueprint-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err.Error())
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s DepsolveBlueprint failed: %s", name, api)
-		return false
-	}
-
-	if len(deps.Blueprints) < 1 {
-		log.Printf("FAIL: %s failed: No blueprint dependencies returned", name)
-		return false
-	}
-
-	if len(deps.Blueprints[0].Dependencies) < 3 {
-		log.Printf("FAIL: %s failed: Not enough dependencies returned", name)
-		return false
-	}
-
-	// TODO
-	// Get the bash and util-linux dependencies and make sure their versions are not *
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// depsolve a non-existent blueprint
-func (c *checkBlueprintsV0) CheckNonBlueprintDepsolveV0() bool {
-	name := "Depsolve a non-existent blueprint"
-
-	resp, api, err := client.DepsolveBlueprintV0(c.socket, "test-deps-non-blueprint-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err.Error())
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s failed: %s", name, api)
-		return false
-	}
-	if len(resp.Errors) == 0 {
-		log.Printf("FAIL: %s failed with no error: %v", name, resp)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// freeze a blueprint
-func (c *checkBlueprintsV0) CheckBlueprintFreezeV0() bool {
-	name := "Freeze a blueprint"
-
-	bp := `{
-		"name": "test-freeze-blueprint-v0",
-		"description": "CheckBlueprintFreezeV0",
-		"version": "0.0.1",
-		"packages": [{"name": "bash", "version": "*"}],
-		"modules": [{"name": "util-linux", "version": "*"}]
-	}`
-
-	// Push a blueprint
-	resp, err := client.PostJSONBlueprintV0(c.socket, bp)
-	if err != nil {
-		log.Printf("FAIL: %s failed with a client error: %s", name, err)
-		return false
-	}
-	if !resp.Status {
-		log.Printf("FAIL: %s POST failed: %s", name, resp)
-		return false
-	}
-
-	// Freeze the blueprint
-	frozen, api, err := client.FreezeBlueprintV0(c.socket, "test-freeze-blueprint-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err.Error())
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s FreezeBlueprint failed: %s", name, api)
-		return false
-	}
-
-	if len(frozen.Blueprints) < 1 {
-		log.Printf("FAIL: %s failed: No frozen blueprints returned", name)
-		return false
-	}
-
-	if len(frozen.Blueprints[0].Blueprint.Packages) < 1 {
-		log.Printf("FAIL: %s failed: No frozen packages returned", name)
-		return false
-	}
-
-	if frozen.Blueprints[0].Blueprint.Packages[0].Name != "bash" ||
-		frozen.Blueprints[0].Blueprint.Packages[0].Version == "*" {
-		log.Printf("FAIL: %s failed: Incorrect frozen packages", name)
-		return false
-	}
-
-	if len(frozen.Blueprints[0].Blueprint.Modules) < 1 {
-		log.Printf("FAIL: %s failed: No frozen modules returned", name)
-		return false
-	}
-
-	if frozen.Blueprints[0].Blueprint.Modules[0].Name != "util-linux" ||
-		frozen.Blueprints[0].Blueprint.Modules[0].Version == "*" {
-		log.Printf("FAIL: %s failed: Incorrect frozen modules", name)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// freeze a non-existent blueprint
-func (c *checkBlueprintsV0) CheckNonBlueprintFreezeV0() bool {
-	name := "Freeze a non-existent blueprint"
-
-	resp, api, err := client.FreezeBlueprintV0(c.socket, "test-freeze-non-blueprint-v0")
-	if err != nil {
-		log.Printf("FAIL: %s failed: %s", name, err.Error())
-		return false
-	}
-	if api != nil {
-		log.Printf("FAIL: %s failed: %s", name, api)
-		return false
-	}
-	if len(resp.Errors) == 0 {
-		log.Printf("FAIL: %s failed with no error: %v", name, resp)
-		return false
-	}
-
-	log.Printf("OK: %s was successful", name)
-	return true
-}
-
-// diff of blueprint changes
-func (c *checkBlueprintsV0) CheckBlueprintDiffV0() bool {
-	name := "Diff of blueprint changes"
-	log.Printf("SKIP: %s was skipped, needs to be implemented", name)
-	return true
-}
diff --git a/internal/weldrcheck/check.go b/internal/weldrcheck/check.go
deleted file mode 100644
index 9a075908a..000000000
--- a/internal/weldrcheck/check.go
+++ /dev/null
@@ -1,104 +0,0 @@
-// Package weldrcheck contains functions used to run integration tests on a running API server
-// Copyright (C) 2020 by Red Hat, Inc.
-package weldrcheck
-
-import (
-	"log"
-	"net/http"
-	"os"
-	"sort"
-	"strconv"
-
-	"github.com/osbuild/osbuild-composer/internal/client"
-)
-
-// Checks should be self-contained and not depend on the state of the server
-// They should use their own blueprints, not the default blueprints
-// They should not assume version numbers for packages will match
-// They should run checks that depend on previous results from the same function
-// not from other functions.
-// The blueprint version number may get bumped if the server has had tests run before
-// do not assume the bp version will match unless first deleting the old one.
-
-// isStringInSlice returns true if the string is present, false if not
-// slice must be sorted
-// TODO decide if this belongs in a more widely useful package location
-func isStringInSlice(slice []string, s string) bool {
-	i := sort.SearchStrings(slice, s)
-	if i < len(slice) && slice[i] == s {
-		return true
-	}
-	return false
-}
-
-// Run the API V0 checks against the server
-// Return true if all the checks pass
-func runV0Checks(socket *http.Client) (pass bool) {
-	pass = true
-
-	bpv0 := checkBlueprintsV0{socket}
-	pass = bpv0.Run()
-
-	if pass {
-		log.Println("OK: ALL V0 API checks were successful")
-	} else {
-		log.Println("FAIL: One or more V0 API checks failed")
-	}
-	return pass
-}
-
-// Run the V1 checks against the server
-func runV1Checks(socket *http.Client) (pass bool) {
-	pass = true
-
-	if pass {
-		log.Println("OK: ALL V1 API checks were successful")
-	} else {
-		log.Println("FAIL: One or more V1 API checks failed")
-	}
-	return pass
-}
-
-// Run executes all of the weldr API checks against a running API server
-// This is designed to run against any WELDR API server, not just osbuild-composer
-func Run(socket *http.Client) {
-	log.Print("Running API check")
-
-	// Does the server respond to /api/status?
-	status, resp, err := client.GetStatusV0(socket)
-	if err != nil {
-		log.Printf("ERROR: status request failed with client error: %s", err)
-		// If status check fails there is no point in continuing
-		os.Exit(1)
-	}
-	if resp != nil {
-		log.Printf("ERROR: status request failed: %v", resp)
-		// If status check fails there is no point in continuing
-		os.Exit(1)
-	}
-	log.Print("OK: status request")
-	apiVersion, e := strconv.Atoi(status.API)
-	if e != nil {
-		log.Printf("ERROR: status API version error: %s", e)
-		log.Println("ERROR: Only running V0 checks")
-		apiVersion = 0
-	}
-	log.Printf("INFO: Running tests against: %s %s server using V%d API", status.Backend, status.Build, apiVersion)
-
-	// Run the V0 checks
-	log.Println("INFO: Running API V0 checks")
-	pass := runV0Checks(socket)
-
-	// Run the V1 checks if the server claims to support it
-	if apiVersion > 0 {
-		log.Println("INFO: Running API V1 checks")
-		passV1 := runV1Checks(socket)
-
-		pass = pass && passV1
-	}
-
-	if !pass {
-		os.Exit(1)
-	}
-	os.Exit(0)
-}
diff --git a/internal/weldrcheck/utils.go b/internal/weldrcheck/utils.go
new file mode 100644
index 000000000..9fec45263
--- /dev/null
+++ b/internal/weldrcheck/utils.go
@@ -0,0 +1,66 @@
+// Package weldrcheck contains functions used to run integration tests on a running API server
+// Copyright (C) 2020 by Red Hat, Inc.
+
+// +build integration
+
+// nolint: deadcode // These functions are used by the *_test.go code
+package weldrcheck
+
+import (
+	"context"
+	"fmt"
+	"net"
+	"net/http"
+	"sort"
+	"strconv"
+	"time"
+
+	"github.com/osbuild/osbuild-composer/internal/client"
+)
+
+type TestState struct {
+	socket     *http.Client
+	apiVersion int
+}
+
+// isStringInSlice returns true if the string is present, false if not
+// slice must be sorted
+// TODO decide if this belongs in a more widely useful package location
+func isStringInSlice(slice []string, s string) bool {
+	i := sort.SearchStrings(slice, s)
+	if i < len(slice) && slice[i] == s {
+		return true
+	}
+	return false
+}
+
+func setupTestState(socketPath string, timeout time.Duration) (*TestState, error) {
+	var state TestState
+	state.socket = &http.Client{
+		// TODO This may be too short/simple for downloading images
+		Timeout: timeout,
+		Transport: &http.Transport{
+			DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
+				return net.Dial("unix", socketPath)
+			},
+		},
+	}
+
+	// Make sure the server is running
+	status, resp, err := client.GetStatusV0(state.socket)
+	if err != nil {
+		return nil, fmt.Errorf("status request failed with client error: %s", err)
+	}
+	if resp != nil {
+		return nil, fmt.Errorf("status request failed: %v\n", resp)
+	}
+	apiVersion, e := strconv.Atoi(status.API)
+	if e != nil {
+		state.apiVersion = 0
+	} else {
+		state.apiVersion = apiVersion
+	}
+	fmt.Printf("Running tests against %s %s server using V%d API\n\n", status.Backend, status.Build, state.apiVersion)
+
+	return &state, nil
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 9c526fbc6..d7724680f 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -80,6 +80,7 @@ github.com/mattn/go-ieproxy
 github.com/pmezard/go-difflib/difflib
 # github.com/stretchr/testify v1.4.0
 github.com/stretchr/testify/assert
+github.com/stretchr/testify/require
 # golang.org/x/net v0.0.0-20200202094626-16171245cfb2
 golang.org/x/net/http/httpproxy
 golang.org/x/net/idna


Test patch:
diff --git a/cmd/osbuild-weldr-tests/main.go b/cmd/osbuild-weldr-tests/main.go
deleted file mode 100644
index d04171c2a..000000000
--- a/cmd/osbuild-weldr-tests/main.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// osbuild-tests runs all of the osbuild integration tests against a live server
-// Copyright (C) 2020 by Red Hat, Inc.
-package main
-
-import (
-	"context"
-	"net"
-	"net/http"
-	"time"
-
-	"github.com/osbuild/osbuild-composer/internal/weldrcheck"
-)
-
-func main() {
-	client := &http.Client{
-		// TODO This may be too short/simple for downloading images
-		Timeout: 60 * time.Second,
-		Transport: &http.Transport{
-			DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
-				return net.Dial("unix", "/run/weldr/api.socket")
-			},
-		},
-	}
-
-	weldrcheck.Run(client)
-}
diff --git a/internal/jobqueue/api_test.go b/internal/jobqueue/api_test.go
index 5940e6ed4..88a36338a 100644
--- a/internal/jobqueue/api_test.go
+++ b/internal/jobqueue/api_test.go
@@ -34,12 +34,11 @@ func TestBasic(t *testing.T) {
 	}
 
 	for _, c := range cases {
-		distroStruct := test_distro.New()
 		registry, err := distro_mock.NewDefaultRegistry()
 		if err != nil {
 			t.Fatal(err)
 		}
-		api := jobqueue.New(nil, store.New(nil, distroStruct, *registry))
+		api := jobqueue.New(nil, store.New(nil, *registry))
 
 		test.TestNonJsonRoute(t, api, false, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedResponse)
 	}
@@ -52,10 +51,10 @@ func TestCreate(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	store := store.New(nil, distroStruct, *registry)
+	store := store.New(nil, *registry)
 	api := jobqueue.New(nil, store)
 
-	err = store.PushCompose(id, &blueprint.Blueprint{}, nil, nil, "x86_64", "qcow2", 0, nil)
+	err = store.PushCompose(distroStruct, id, &blueprint.Blueprint{}, nil, nil, "x86_64", "qcow2", 0, nil)
 	if err != nil {
 		t.Fatalf("error pushing compose: %v", err)
 	}
@@ -71,11 +70,11 @@ func testUpdateTransition(t *testing.T, from, to string, expectedStatus int, exp
 	if err != nil {
 		t.Fatal(err)
 	}
-	store := store.New(nil, distroStruct, *registry)
+	store := store.New(nil, *registry)
 	api := jobqueue.New(nil, store)
 
 	if from != "VOID" {
-		err := store.PushCompose(id, &blueprint.Blueprint{}, nil, nil, "x86_64", "qcow2", 0, nil)
+		err := store.PushCompose(distroStruct, id, &blueprint.Blueprint{}, nil, nil, "x86_64", "qcow2", 0, nil)
 		if err != nil {
 			t.Fatalf("error pushing compose: %v", err)
 		}
diff --git a/internal/rcm/api_test.go b/internal/rcm/api_test.go
index d29d96ffe..95fe1c21e 100644
--- a/internal/rcm/api_test.go
+++ b/internal/rcm/api_test.go
@@ -9,7 +9,6 @@ import (
 	"regexp"
 	"testing"
 
-	"github.com/osbuild/osbuild-composer/internal/distro/fedoratest"
 	distro_mock "github.com/osbuild/osbuild-composer/internal/mocks/distro"
 	rpmmd_mock "github.com/osbuild/osbuild-composer/internal/mocks/rpmmd"
 	"github.com/osbuild/osbuild-composer/internal/rcm"
@@ -53,8 +52,7 @@ func TestBasicRcmAPI(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	distroStruct := fedoratest.New()
-	api := rcm.New(nil, store.New(nil, distroStruct, *registry), rpmmd_mock.NewRPMMDMock(rpmmd_mock.BaseFixture()))
+	api := rcm.New(nil, store.New(nil, *registry), rpmmd_mock.NewRPMMDMock(rpmmd_mock.BaseFixture()), registry)
 
 	for _, c := range cases {
 		resp := internalRequest(api, c.Method, c.Path, c.Body, c.ContentType)
@@ -76,12 +74,11 @@ func TestBasicRcmAPI(t *testing.T) {
 
 func TestSubmitCompose(t *testing.T) {
 	// Test the most basic use case: Submit a new job and get its status.
-	distroStruct := fedoratest.New()
 	registry, err := distro_mock.NewDefaultRegistry()
 	if err != nil {
 		t.Fatal(err)
 	}
-	api := rcm.New(nil, store.New(nil, distroStruct, *registry), rpmmd_mock.NewRPMMDMock(rpmmd_mock.BaseFixture()))
+	api := rcm.New(nil, store.New(nil, *registry), rpmmd_mock.NewRPMMDMock(rpmmd_mock.BaseFixture()), registry)
 
 	var submit_reply struct {
 		UUID uuid.UUID `json:"compose_id"`
diff --git a/internal/weldrcheck/blueprints_test.go b/internal/weldrcheck/blueprints_test.go
new file mode 100644
index 000000000..890eb0994
--- /dev/null
+++ b/internal/weldrcheck/blueprints_test.go
@@ -0,0 +1,757 @@
+// Package weldrcheck - blueprints contains functions to check the blueprints API
+// Copyright (C) 2020 by Red Hat, Inc.
+
+// Tests should be self-contained and not depend on the state of the server
+// They should use their own blueprints, not the default blueprints
+// They should not assume version numbers for packages will match
+// They should run tests that depend on previous results from the same function
+// not from other functions.
+// The blueprint version number may get bumped if the server has had tests run before
+// do not assume the bp version will match unless first deleting the old one.
+
+// +build integration
+
+package weldrcheck
+
+import (
+	"fmt"
+	"os"
+	"sort"
+	"testing"
+	"time"
+
+	"github.com/BurntSushi/toml"
+	"github.com/stretchr/testify/require"
+
+	"github.com/osbuild/osbuild-composer/internal/client"
+)
+
+// Hold test state to share between tests
+var testState *TestState
+
+// Setup the socket to use for running the tests
+// Also makes sure there is a running server to test against
+func TestMain(m *testing.M) {
+	var err error
+	testState, err = setupTestState("/run/weldr/api.socket", 60*time.Second)
+	if err != nil {
+		fmt.Printf("ERROR: Test setup failed: %s", err)
+		os.Exit(1)
+	}
+	os.Exit(m.Run())
+}
+
+// POST a new TOML blueprint
+func TestPostTOMLBlueprintV0(t *testing.T) {
+	bp := `
+		name="test-toml-blueprint-v0"
+		description="postTOMLBlueprintV0"
+		version="0.0.1"
+		[[packages]]
+		name="bash"
+		version="*"
+
+		[[modules]]
+		name="util-linux"
+		version="*"
+
+		[[customizations.user]]
+		name="root"
+		password="qweqweqwe"
+		`
+	resp, err := client.PostTOMLBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "failed with a client error")
+	require.True(t, resp.Status, "POST failed: %#v", resp)
+}
+
+// POST an invalid TOML blueprint
+func TestPostInvalidTOMLBlueprintV0(t *testing.T) {
+	// Use a blueprint that's missing a trailing ']' on package
+	bp := `
+		name="test-invalid-toml-blueprint-v0"
+		version="0.0.1"
+		[package
+		name="bash"
+		version="*"
+		`
+	resp, err := client.PostTOMLBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "failed with a client error")
+	require.False(t, resp.Status, "did not return an error")
+}
+
+// POST an empty TOML blueprint
+func TestPostEmptyTOMLBlueprintV0(t *testing.T) {
+	resp, err := client.PostTOMLBlueprintV0(testState.socket, "")
+	require.NoError(t, err, "failed with a client error")
+	require.False(t, resp.Status, "did not return an error")
+}
+
+// POST a new JSON blueprint
+func TestPostJSONBlueprintV0(t *testing.T) {
+	bp := `{
+		"name": "test-json-blueprint-v0",
+		"description": "postJSONBlueprintV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`
+
+	resp, err := client.PostJSONBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "failed with a client error")
+	require.True(t, resp.Status, "POST failed: %#v", resp)
+}
+
+// POST an invalid JSON blueprint
+func TestPostInvalidJSONBlueprintV0(t *testing.T) {
+	// Use a blueprint that's missing a trailing '"' on name
+	bp := `{
+		"name": "test-invalid-json-blueprint-v0",
+		"version": "0.0.1",
+		"modules": [{"name: "util-linux", "version": "*"}],
+	}`
+
+	resp, err := client.PostJSONBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "failed with a client error")
+	require.False(t, resp.Status, "did not return an error")
+}
+
+// POST an empty JSON blueprint
+func TestPostEmptyJSONBlueprintV0(t *testing.T) {
+	resp, err := client.PostJSONBlueprintV0(testState.socket, "")
+	require.NoError(t, err, "failed with a client error")
+	require.False(t, resp.Status, "did not return an error")
+}
+
+// POST a blueprint to the workspace as TOML
+func TestPostTOMLWorkspaceV0(t *testing.T) {
+	bp := `
+		name="test-toml-blueprint-ws-v0"
+		description="postTOMLBlueprintWSV0"
+		version="0.0.1"
+		[[packages]]
+		name="bash"
+		version="*"
+
+		[[modules]]
+		name="util-linux"
+		version="*"
+
+		[[customizations.user]]
+		name="root"
+		password="qweqweqwe"
+		`
+	resp, err := client.PostTOMLWorkspaceV0(testState.socket, bp)
+	require.NoError(t, err, "failed with a client error")
+	require.True(t, resp.Status, "POST failed: %#v", resp)
+}
+
+// POST an invalid TOML blueprint to the workspace
+func TestPostInvalidTOMLWorkspaceV0(t *testing.T) {
+	// Use a blueprint that's missing a trailing ']' on package
+	bp := `
+		name="test-invalid-toml-blueprint-ws-v0"
+		version="0.0.1"
+		[package
+		name="bash"
+		version="*"
+		`
+	resp, err := client.PostTOMLWorkspaceV0(testState.socket, bp)
+	require.NoError(t, err, "failed with a client error")
+	require.False(t, resp.Status, "did not return an error")
+}
+
+// POST an empty TOML blueprint to the workspace
+func TestPostEmptyTOMLWorkspaceV0(t *testing.T) {
+	resp, err := client.PostTOMLWorkspaceV0(testState.socket, "")
+	require.NoError(t, err, "failed with a client error")
+	require.False(t, resp.Status, "did not return an error")
+}
+
+// POST a blueprint to the workspace as JSON
+func TestPostJSONWorkspaceV0(t *testing.T) {
+	bp := `{
+		"name": "test-json-blueprint-ws-v0",
+		"description": "postJSONBlueprintWSV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`
+
+	resp, err := client.PostJSONWorkspaceV0(testState.socket, bp)
+	require.NoError(t, err, "failed with a client error")
+	require.True(t, resp.Status, "POST failed: %#v", resp)
+}
+
+// POST an invalid JSON blueprint to the workspace
+func TestPostInvalidJSONWorkspaceV0(t *testing.T) {
+	// Use a blueprint that's missing a trailing '"' on name
+	bp := `{
+		"name": "test-invalid-json-blueprint-ws-v0",
+		"version": "0.0.1",
+		"modules": [{"name: "util-linux", "version": "*"}],
+	}`
+
+	resp, err := client.PostJSONBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "failed with a client error")
+	require.False(t, resp.Status, "did not return an error")
+}
+
+// POST an empty JSON blueprint to the workspace
+func TestPostEmptyJSONWorkspaceV0(t *testing.T) {
+	resp, err := client.PostJSONBlueprintV0(testState.socket, "")
+	require.NoError(t, err, "failed with a client error")
+	require.False(t, resp.Status, "did not return an error")
+}
+
+// delete a blueprint
+func TestDeleteBlueprintV0(t *testing.T) {
+	// POST a blueprint to delete
+	bp := `{
+		"name": "test-delete-blueprint-v0",
+		"description": "deleteBlueprintV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`
+
+	resp, err := client.PostJSONBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "failed with a client error")
+	require.True(t, resp.Status, "POST failed: %#v", resp)
+
+	// Delete the blueprint
+	resp, err = client.DeleteBlueprintV0(testState.socket, "test-delete-blueprint-v0")
+	require.NoError(t, err, "DELETE failed with a client error")
+	require.True(t, resp.Status, "DELETE failed: %#v", resp)
+}
+
+// delete a non-existent blueprint
+func TestDeleteNonBlueprint0(t *testing.T) {
+	resp, err := client.DeleteBlueprintV0(testState.socket, "test-delete-non-blueprint-v0")
+	require.NoError(t, err, "failed with a client error")
+	require.False(t, resp.Status, "did not return an error")
+}
+
+// delete a new blueprint from the workspace
+func TestDeleteNewWorkspaceV0(t *testing.T) {
+	// POST a blueprint to delete
+	bp := `{
+		"name": "test-delete-new-blueprint-ws-v0",
+		"description": "deleteNewBlueprintWSV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`
+
+	resp, err := client.PostJSONWorkspaceV0(testState.socket, bp)
+	require.NoError(t, err, "POST failed with a client error")
+	require.True(t, resp.Status, "POST failed: %#v", resp)
+
+	// Delete the blueprint
+	resp, err = client.DeleteWorkspaceV0(testState.socket, "test-delete-new-blueprint-ws-v0")
+	require.NoError(t, err, "DELETE failed with a client error")
+	require.True(t, resp.Status, "DELETE failed: %#v", resp)
+}
+
+// delete blueprint changes from the workspace
+func TestDeleteChangesWorkspaceV0(t *testing.T) {
+	// POST a blueprint first
+	bp := `{
+		"name": "test-delete-blueprint-changes-ws-v0",
+		"description": "deleteBlueprintChangesWSV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`
+
+	resp, err := client.PostJSONBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "POST blueprint failed with a client error")
+	require.True(t, resp.Status, "POST blueprint failed: %#v", resp)
+
+	// Post blueprint changes to the workspace
+	bp = `{
+		"name": "test-delete-blueprint-changes-ws-v0",
+		"description": "workspace copy",
+		"version": "0.2.0",
+		"packages": [{"name": "frobozz", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`
+
+	resp, err = client.PostJSONWorkspaceV0(testState.socket, bp)
+	require.NoError(t, err, "POST workspace failed with a client error")
+	require.True(t, resp.Status, "POST workspace failed: %#v", resp)
+
+	// Get the blueprint, make sure it is the modified one and that changes = true
+	info, api, err := client.GetBlueprintsInfoJSONV0(testState.socket, "test-delete-blueprint-changes-ws-v0")
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "GET blueprint request failed: %#v", api)
+	require.Greater(t, len(info.Blueprints), 0, "No blueprints returned")
+	require.Greater(t, len(info.Changes), 0, "No change states returned")
+	require.Equal(t, "test-delete-blueprint-changes-ws-v0", info.Blueprints[0].Name, "wrong blueprint returned")
+	require.Equal(t, "test-delete-blueprint-changes-ws-v0", info.Changes[0].Name, "wrong change state returned")
+	require.True(t, info.Changes[0].Changed, "wrong change state returned (false)")
+	require.Equal(t, "workspace copy", info.Blueprints[0].Description, "workspace copy not returned")
+
+	// Delete the blueprint from the workspace
+	resp, err = client.DeleteWorkspaceV0(testState.socket, "test-delete-blueprint-changes-ws-v0")
+	require.NoError(t, err, "DELETE workspace failed with a client error")
+	require.True(t, resp.Status, "DELETE workspace failed: %#v", resp)
+
+	// Get the blueprint, make sure it is the un-modified one
+	info, api, err = client.GetBlueprintsInfoJSONV0(testState.socket, "test-delete-blueprint-changes-ws-v0")
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "GET blueprint request failed: %#v", api)
+	require.Greater(t, len(info.Blueprints), 0, "No blueprints returned")
+	require.Greater(t, len(info.Changes), 0, "No change states returned")
+	require.Equal(t, "test-delete-blueprint-changes-ws-v0", info.Blueprints[0].Name, "wrong blueprint returned")
+	require.Equal(t, "test-delete-blueprint-changes-ws-v0", info.Changes[0].Name, "wrong change state returned")
+	require.False(t, info.Changes[0].Changed, "wrong change state returned (true)")
+	require.Equal(t, "deleteBlueprintChangesWSV0", info.Blueprints[0].Description, "original blueprint not returned")
+}
+
+// list blueprints
+func TestListBlueprintsV0(t *testing.T) {
+	// Post a couple of blueprints
+	bps := []string{`{
+		"name": "test-list-blueprint-1-v0",
+		"description": "listBlueprintsV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`,
+		`{
+		"name": "test-list-blueprint-2-v0",
+		"description": "listBlueprintsV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`}
+
+	for i := range bps {
+		resp, err := client.PostJSONBlueprintV0(testState.socket, bps[i])
+		require.NoError(t, err, "POST blueprint failed with a client error")
+		require.True(t, resp.Status, "POST blueprint failed: %#v", resp)
+	}
+
+	// Get the list of blueprints
+	list, api, err := client.ListBlueprintsV0(testState.socket)
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "ListBlueprints failed: %#v", api)
+	require.Contains(t, list, "test-list-blueprint-1-v0")
+	require.Contains(t, list, "test-list-blueprint-2-v0")
+}
+
+// get blueprint contents as TOML
+func TestGetTOMLBlueprintV0(t *testing.T) {
+	bp := `{
+		"name": "test-get-blueprint-1-v0",
+		"description": "getTOMLBlueprintV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`
+
+	// Post a blueprint
+	resp, err := client.PostJSONBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "POST blueprint failed with a client error")
+	require.True(t, resp.Status, "POST blueprint failed: %#v", resp)
+
+	// Get it as TOML
+	body, api, err := client.GetBlueprintInfoTOMLV0(testState.socket, "test-get-blueprint-1-v0")
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "GetBlueprintInfoTOML failed: %#v", api)
+	require.Greater(t, len(body), 0, "body of response is empty")
+
+	// Can it be decoded as TOML?
+	var decoded interface{}
+	_, err = toml.Decode(body, &decoded)
+	require.NoError(t, err, "TOML decode failed")
+}
+
+// get non-existent blueprint contents as TOML
+func TestGetNonTOMLBlueprintV0(t *testing.T) {
+	_, api, err := client.GetBlueprintInfoTOMLV0(testState.socket, "test-get-non-blueprint-1-v0")
+	require.NoError(t, err, "failed with a client error")
+	require.NotNil(t, api, "did not return an error")
+	require.False(t, api.Status, "wrong Status (true)")
+}
+
+// get blueprint contents as JSON
+func TestGetJSONBlueprintV0(t *testing.T) {
+	bp := `{
+		"name": "test-get-blueprint-2-v0",
+		"description": "getJSONBlueprintV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`
+
+	// Post a blueprint
+	resp, err := client.PostJSONBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "POST blueprint failed with a client error")
+	require.True(t, resp.Status, "POST blueprint failed: %#v", resp)
+
+	// Get the blueprint and its changed state
+	info, api, err := client.GetBlueprintsInfoJSONV0(testState.socket, "test-get-blueprint-2-v0")
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "GetBlueprintInfoJSON failed: %#v", api)
+	require.Greater(t, len(info.Blueprints), 0, "No blueprints returned")
+	require.Greater(t, len(info.Changes), 0, "No change states returned")
+	require.Equal(t, "test-get-blueprint-2-v0", info.Blueprints[0].Name, "wrong blueprint returned")
+	require.Equal(t, "test-get-blueprint-2-v0", info.Changes[0].Name, "wrong change state returned")
+	require.False(t, info.Changes[0].Changed, "wrong change state returned (true)")
+}
+
+// get non-existent blueprint contents as JSON
+func TestGetNonJSONBkueprintV0(t *testing.T) {
+	resp, api, err := client.GetBlueprintsInfoJSONV0(testState.socket, "test-get-non-blueprint-1-v0")
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "ListBlueprints failed: %#v", api)
+	require.Greater(t, len(resp.Errors), 0, "failed with no error: %#v", resp)
+}
+
+// pushing the same blueprint bumps the version number returned by show
+func TestBumpBlueprintVersionV0(t *testing.T) {
+	bp := `{
+		"name": "test-bump-blueprint-1-v0",
+		"description": "bumpBlueprintVersionV0",
+		"version": "2.1.2",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`
+
+	// List blueprints
+	list, api, err := client.ListBlueprintsV0(testState.socket)
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "ListBlueprints failed: %#v", api)
+
+	// If the blueprint already exists it needs to be deleted to start from a known state
+	sorted := sort.StringSlice(list)
+	if isStringInSlice(sorted, "test-bump-blueprint-1-v0") {
+		// Delete this blueprint if it already exists
+		resp, err := client.DeleteBlueprintV0(testState.socket, "test-bump-blueprint-1-v0")
+		require.NoError(t, err, "DELETE blueprint failed with a client error")
+		require.True(t, resp.Status, "DELETE blueprint failed: %#v", resp)
+	}
+
+	// Post a blueprint
+	resp, err := client.PostJSONBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "POST blueprint failed with a client error")
+	require.True(t, resp.Status, "POST blueprint failed: %#v", resp)
+
+	// Post a blueprint again to bump verion to 2.1.3
+	resp, err = client.PostJSONBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "POST blueprint 2nd time failed with a client error")
+	require.True(t, resp.Status, "POST blueprint 2nd time failed: %#v", resp)
+
+	// Get the blueprint and its changed state
+	info, api, err := client.GetBlueprintsInfoJSONV0(testState.socket, "test-bump-blueprint-1-v0")
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "GetBlueprintsInfoJSON failed: %#v", api)
+	require.Greater(t, len(info.Blueprints), 0, "No blueprints returned")
+	require.Equal(t, "test-bump-blueprint-1-v0", info.Blueprints[0].Name, "wrong blueprint returned")
+	require.Equal(t, "2.1.3", info.Blueprints[0].Version, "wrong blueprint version")
+}
+
+// Make several changes to a blueprint and list the changes
+func TestBlueprintChangesV0(t *testing.T) {
+	bps := []string{`{
+		"name": "test-blueprint-changes-v0",
+		"description": "CheckBlueprintChangesV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}]
+	}`,
+		`{
+		"name": "test-blueprint-changes-v0",
+		"description": "CheckBlueprintChangesV0",
+		"version": "0.1.0",
+		"packages": [{"name": "bash", "version": "*"}, {"name": "tmux", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`,
+		`{
+		"name": "test-blueprint-changes-v0",
+		"description": "CheckBlueprintChangesV0",
+		"version": "0.1.1",
+		"packages": [{"name": "bash", "version": "*"}, {"name": "tmux", "version": "*"}],
+		"modules": [],
+		"customizations": {"user": [{"name": "root", "password": "asdasdasd"}]}
+	}`}
+
+	// Push 3 changes to the blueprint
+	for i := range bps {
+		resp, err := client.PostJSONBlueprintV0(testState.socket, bps[i])
+		require.NoError(t, err, "POST blueprint #%d failed with a client error")
+		require.True(t, resp.Status, "POST blueprint #%d failed: %#v", i, resp)
+	}
+
+	// List the changes
+	changes, api, err := client.GetBlueprintsChangesV0(testState.socket, []string{"test-blueprint-changes-v0"})
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "GetBlueprintsChanges failed: %#v", api)
+	require.Equal(t, 1, len(changes.BlueprintsChanges), "No changes returned")
+	require.Equal(t, "test-blueprint-changes-v0", changes.BlueprintsChanges[0].Name, "Wrong blueprint changes returned")
+	require.Greater(t, len(changes.BlueprintsChanges[0].Changes), 2, "Wrong number of changes returned")
+}
+
+// Get changes for a non-existent blueprint
+func TestBlueprintNonChangesV0(t *testing.T) {
+	resp, api, err := client.GetBlueprintsChangesV0(testState.socket, []string{"test-non-blueprint-changes-v0"})
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "GetBlueprintsChanges failed: %#v", api)
+	require.Greater(t, len(resp.Errors), 0, "failed with no error: %#v", resp)
+}
+
+// Undo blueprint changes
+func TestUndoBlueprintV0(t *testing.T) {
+	bps := []string{`{
+		"name": "test-undo-blueprint-v0",
+		"description": "CheckUndoBlueprintV0",
+		"version": "0.0.5",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`,
+		`{
+		"name": "test-undo-blueprint-v0",
+		"description": "CheckUndoBlueprintv0",
+		"version": "0.0.6",
+		"packages": [{"name": "bash", "version": "0.5.*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`}
+
+	// Push original version of the blueprint
+	resp, err := client.PostJSONBlueprintV0(testState.socket, bps[0])
+	require.NoError(t, err, "POST blueprint #0 failed with a client error")
+	require.True(t, resp.Status, "POST blueprint #0 failed: %#v", resp)
+
+	// Get the commit hash
+	changes, api, err := client.GetBlueprintsChangesV0(testState.socket, []string{"test-undo-blueprint-v0"})
+	require.NoError(t, err, "GET blueprint #0 failed with a client error")
+	require.Nil(t, api, "GetBlueprintsChanges #0 failed: %#v", api)
+	require.Equal(t, 1, len(changes.BlueprintsChanges), "No changes returned")
+	require.Greater(t, len(changes.BlueprintsChanges[0].Changes), 0, "Wrong number of changes returned")
+	commit := changes.BlueprintsChanges[0].Changes[0].Commit
+	require.NotEmpty(t, commit, "First commit is empty")
+
+	// Push the new version with wrong bash version
+	resp, err = client.PostJSONBlueprintV0(testState.socket, bps[1])
+	require.NoError(t, err, "POST blueprint #1 failed with a client error")
+	require.True(t, resp.Status, "POST blueprint #1 failed: %#v", resp)
+
+	// Get the blueprint, confirm bash version is '0.5.*'
+	info, api, err := client.GetBlueprintsInfoJSONV0(testState.socket, "test-undo-blueprint-v0")
+	require.NoError(t, err, "GET blueprint #1 failed with a client error")
+	require.Nil(t, api, "GetBlueprintsInfo #1 failed: %#v", api)
+	require.Greater(t, len(info.Blueprints), 0, "No blueprints returned")
+	require.Greater(t, len(info.Blueprints[0].Packages), 0, "No packages in the blueprint")
+	require.Equal(t, "bash", info.Blueprints[0].Packages[0].Name, "Wrong package in blueprint")
+	require.Equal(t, "0.5.*", info.Blueprints[0].Packages[0].Version, "Wrong version in blueprint")
+
+	// Revert the blueprint to the original version
+	resp, err = client.UndoBlueprintChangeV0(testState.socket, "test-undo-blueprint-v0", commit)
+	require.NoError(t, err, "Undo blueprint failed with a client error")
+	require.True(t, resp.Status, "Undo blueprint failed: %#v", resp)
+
+	// Get the blueprint, confirm bash version is '*'
+	info, api, err = client.GetBlueprintsInfoJSONV0(testState.socket, "test-undo-blueprint-v0")
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "GetBlueprintsInfo failed: %#v", api)
+	require.Greater(t, len(info.Blueprints), 0, "No blueprints returned")
+	require.Greater(t, len(info.Blueprints[0].Packages), 0, "No packages in the blueprint")
+	require.Equal(t, "bash", info.Blueprints[0].Packages[0].Name, "Wrong package in blueprint")
+	require.Equal(t, "*", info.Blueprints[0].Packages[0].Version, "Wrong version in blueprint")
+}
+
+// Undo non-existent commit blueprint changes
+func TestUndoBlueprintNonCommitV0(t *testing.T) {
+	bps := []string{`{
+		"name": "test-undo-blueprint-non-commit-v0",
+		"description": "CheckUndoBlueprintNonCommitV0",
+		"version": "0.0.5",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`,
+		`{
+		"name": "test-undo-blueprint-non-commit-v0",
+		"description": "CheckUndoBlueprintNonCommitv0",
+		"version": "0.0.6",
+		"packages": [{"name": "bash", "version": "0.5.*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`}
+
+	for i := range bps {
+		resp, err := client.PostJSONBlueprintV0(testState.socket, bps[i])
+		require.NoError(t, err, "POST blueprint #%d failed with a client error")
+		require.True(t, resp.Status, "POST blueprint #%d failed: %#v", i, resp)
+	}
+
+	resp, err := client.UndoBlueprintChangeV0(testState.socket, "test-undo-blueprint-non-commit-v0", "FFFF")
+	require.NoError(t, err, "POST blueprint failed with a client error")
+	require.False(t, resp.Status, "did not return an error")
+}
+
+// Undo non-existent blueprint changes
+func TestUndoNonBlueprintV0(t *testing.T) {
+	resp, err := client.UndoBlueprintChangeV0(testState.socket, "test-undo-non-blueprint-v0", "FFFF")
+	require.NoError(t, err, "blueprint failed with a client error")
+	require.False(t, resp.Status, "did not return an error")
+}
+
+// Tag a blueprint with a new revision
+// The blueprint revision tag cannot be reset, it always increments by one, and cannot be deleted.
+// So to test tagging we tag two blueprint changes and make sure the second is first +1
+func TestBlueprintTagV0(t *testing.T) {
+	bps := []string{`{
+		"name": "test-tag-blueprint-v0",
+		"description": "CheckBlueprintTagV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "0.1.*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`,
+		`{
+		"name": "test-tag-blueprint-v0",
+		"description": "CheckBlueprintTagV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "0.5.*"}],
+		"modules": [{"name": "util-linux", "version": "*"}],
+		"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
+	}`}
+
+	// Push a blueprint
+	resp, err := client.PostJSONBlueprintV0(testState.socket, bps[0])
+	require.NoError(t, err, "POST blueprint #0 failed with a client error")
+	require.True(t, resp.Status, "POST blueprint #0 failed: %#v", resp)
+
+	// Tag the blueprint
+	tagResp, err := client.TagBlueprintV0(testState.socket, "test-tag-blueprint-v0")
+	require.NoError(t, err, "Tag blueprint #0 failed with a client error")
+	require.True(t, tagResp.Status, "Tag blueprint #0 failed: %#v", resp)
+
+	// Get changes, get the blueprint's revision
+	changes, api, err := client.GetBlueprintsChangesV0(testState.socket, []string{"test-tag-blueprint-v0"})
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "GetBlueprintsChanges failed: %#v", api)
+	require.Equal(t, 1, len(changes.BlueprintsChanges), "No changes returned")
+	require.Greater(t, len(changes.BlueprintsChanges[0].Changes), 0, "Wrong number of changes returned")
+
+	revision := changes.BlueprintsChanges[0].Changes[0].Revision
+	require.NotNil(t, revision, "Revision is zero")
+	require.NotEqual(t, 0, *revision, "Revision is zero")
+
+	// Push a new version of the blueprint
+	resp, err = client.PostJSONBlueprintV0(testState.socket, bps[1])
+	require.NoError(t, err, "POST blueprint #1 failed with a client error")
+	require.True(t, resp.Status, "POST blueprint #1 failed: %#v", resp)
+
+	// Tag the blueprint
+	tagResp, err = client.TagBlueprintV0(testState.socket, "test-tag-blueprint-v0")
+	require.NoError(t, err, "Tag blueprint #1 failed with a client error")
+	require.True(t, tagResp.Status, "Tag blueprint #1 failed: %#v", resp)
+
+	// Get changes, confirm that Revision is revision +1
+	changes, api, err = client.GetBlueprintsChangesV0(testState.socket, []string{"test-tag-blueprint-v0"})
+	require.NoError(t, err, "GET blueprint failed with a client error")
+	require.Nil(t, api, "GetBlueprintsChanges failed: %#v", api)
+	require.Equal(t, 1, len(changes.BlueprintsChanges), "No changes returned")
+	require.Greater(t, len(changes.BlueprintsChanges[0].Changes), 0, "Wrong number of changes returned")
+
+	newRevision := changes.BlueprintsChanges[0].Changes[0].Revision
+	require.NotNil(t, newRevision, "Revision is not %d", *revision+1)
+	require.Equal(t, *revision+1, *newRevision, "Revision is not %d", *revision+1)
+}
+
+// Tag a non-existent blueprint
+func TestNonBlueprintTagV0(t *testing.T) {
+	tagResp, err := client.TagBlueprintV0(testState.socket, "test-tag-non-blueprint-v0")
+	require.NoError(t, err, "failed with a client error")
+	require.False(t, tagResp.Status, "did not return an error")
+}
+
+// depsolve a blueprint with packages and modules
+func TestBlueprintDepsolveV0(t *testing.T) {
+	bp := `{
+		"name": "test-deps-blueprint-v0",
+		"description": "CheckBlueprintDepsolveV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}]
+	}`
+
+	// Push a blueprint
+	resp, err := client.PostJSONBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "POST blueprint failed with a client error")
+	require.True(t, resp.Status, "POST blueprint failed: %#v", resp)
+
+	// Depsolve the blueprint
+	deps, api, err := client.DepsolveBlueprintV0(testState.socket, "test-deps-blueprint-v0")
+	require.NoError(t, err, "Depsolve blueprint failed with a client error")
+	require.Nil(t, api, "DepsolveBlueprint failed: %#v", api)
+	require.Greater(t, len(deps.Blueprints), 0, "No blueprint dependencies returned")
+	require.Greater(t, len(deps.Blueprints[0].Dependencies), 2, "Not enough dependencies returned")
+
+	// TODO
+	// Get the bash and util-linux dependencies and make sure their versions are not *
+
+}
+
+// depsolve a non-existent blueprint
+func TestNonBlueprintDepsolveV0(t *testing.T) {
+	resp, api, err := client.DepsolveBlueprintV0(testState.socket, "test-deps-non-blueprint-v0")
+	require.NoError(t, err, "Depsolve blueprint failed with a client error")
+	require.Nil(t, api, "DepsolveBlueprint failed: %#v", api)
+	require.Greater(t, len(resp.Errors), 0, "failed with no error: %#v", resp)
+}
+
+// freeze a blueprint
+func TestBlueprintFreezeV0(t *testing.T) {
+	bp := `{
+		"name": "test-freeze-blueprint-v0",
+		"description": "CheckBlueprintFreezeV0",
+		"version": "0.0.1",
+		"packages": [{"name": "bash", "version": "*"}],
+		"modules": [{"name": "util-linux", "version": "*"}]
+	}`
+
+	// Push a blueprint
+	resp, err := client.PostJSONBlueprintV0(testState.socket, bp)
+	require.NoError(t, err, "POST blueprint failed with a client error")
+	require.True(t, resp.Status, "POST blueprint failed: %#v", resp)
+
+	// Freeze the blueprint
+	frozen, api, err := client.FreezeBlueprintV0(testState.socket, "test-freeze-blueprint-v0")
+	require.NoError(t, err, "Freeze blueprint failed with a client error")
+	require.Nil(t, api, "FreezeBlueprint failed: %#v", api)
+	require.Greater(t, len(frozen.Blueprints), 0, "No frozen blueprints returned")
+	require.Greater(t, len(frozen.Blueprints[0].Blueprint.Packages), 0, "No frozen packages returned")
+	require.Equal(t, "bash", frozen.Blueprints[0].Blueprint.Packages[0].Name, "Wrong package in frozen blueprint")
+	require.NotEqual(t, "*", frozen.Blueprints[0].Blueprint.Packages[0].Version, "Wrong version in frozen blueprint")
+	require.Greater(t, len(frozen.Blueprints[0].Blueprint.Modules), 0, "No frozen modules returned")
+	require.Equal(t, "util-linux", frozen.Blueprints[0].Blueprint.Modules[0].Name, "Wrong module in frozen blueprint")
+	require.NotEqual(t, "*", frozen.Blueprints[0].Blueprint.Modules[0].Version, "Wrong version in frozen blueprint module")
+}
+
+// freeze a non-existent blueprint
+func TestNonBlueprintFreezeV0(t *testing.T) {
+	resp, api, err := client.FreezeBlueprintV0(testState.socket, "test-freeze-non-blueprint-v0")
+	require.NoError(t, err, "Freeze blueprint failed with a client error")
+	require.Nil(t, api, "FreezeBlueprint failed: %#v", api)
+	require.Greater(t, len(resp.Errors), 0, "failed with no error: %#v", resp)
+}
+
+// TODO diff of blueprint changes
diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go
new file mode 100644
index 000000000..169de3922
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/doc.go
@@ -0,0 +1,28 @@
+// Package require implements the same assertions as the `assert` package but
+// stops test execution when a test fails.
+//
+// Example Usage
+//
+// The following is a complete example using require in a standard test function:
+//    import (
+//      "testing"
+//      "github.com/stretchr/testify/require"
+//    )
+//
+//    func TestSomething(t *testing.T) {
+//
+//      var a string = "Hello"
+//      var b string = "Hello"
+//
+//      require.Equal(t, a, b, "The two words should be the same.")
+//
+//    }
+//
+// Assertions
+//
+// The `require` package have same global functions as in the `assert` package,
+// but instead of returning a boolean result they call `t.FailNow()`.
+//
+// Every assertion function also takes an optional string message as the final argument,
+// allowing custom error messages to be appended to the message the assertion method outputs.
+package require
diff --git a/vendor/github.com/stretchr/testify/require/forward_requirements.go b/vendor/github.com/stretchr/testify/require/forward_requirements.go
new file mode 100644
index 000000000..ac71d4058
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/forward_requirements.go
@@ -0,0 +1,16 @@
+package require
+
+// Assertions provides assertion methods around the
+// TestingT interface.
+type Assertions struct {
+	t TestingT
+}
+
+// New makes a new Assertions object for the specified TestingT.
+func New(t TestingT) *Assertions {
+	return &Assertions{
+		t: t,
+	}
+}
+
+//go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl -include-format-funcs
diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go
new file mode 100644
index 000000000..c5903f5db
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require.go
@@ -0,0 +1,1433 @@
+/*
+* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
+* THIS FILE MUST NOT BE EDITED BY HAND
+ */
+
+package require
+
+import (
+	assert "github.com/stretchr/testify/assert"
+	http "net/http"
+	url "net/url"
+	time "time"
+)
+
+// Condition uses a Comparison to assert a complex condition.
+func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Condition(t, comp, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Conditionf uses a Comparison to assert a complex condition.
+func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Conditionf(t, comp, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//    assert.Contains(t, "Hello World", "World")
+//    assert.Contains(t, ["Hello", "World"], "World")
+//    assert.Contains(t, {"Hello": "World"}, "Hello")
+func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Contains(t, s, contains, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Containsf asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//    assert.Containsf(t, "Hello World", "World", "error message %s", "formatted")
+//    assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
+//    assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
+func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Containsf(t, s, contains, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
+func DirExists(t TestingT, path string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.DirExists(t, path, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
+func DirExistsf(t TestingT, path string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.DirExistsf(t, path, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
+func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.ElementsMatch(t, listA, listB, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
+func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.ElementsMatchf(t, listA, listB, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  assert.Empty(t, obj)
+func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Empty(t, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Emptyf asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  assert.Emptyf(t, obj, "error message %s", "formatted")
+func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Emptyf(t, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Equal asserts that two objects are equal.
+//
+//    assert.Equal(t, 123, 123)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Equal(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   assert.EqualError(t, err,  expectedErrorString)
+func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.EqualError(t, theError, errString, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   assert.EqualErrorf(t, err,  expectedErrorString, "error message %s", "formatted")
+func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.EqualErrorf(t, theError, errString, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    assert.EqualValues(t, uint32(123), int32(123))
+func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.EqualValues(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// EqualValuesf asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123))
+func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.EqualValuesf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Equalf asserts that two objects are equal.
+//
+//    assert.Equalf(t, 123, 123, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Equalf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Error(t, err) {
+// 	   assert.Equal(t, expectedError, err)
+//   }
+func Error(t TestingT, err error, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Error(t, err, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Errorf asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Errorf(t, err, "error message %s", "formatted") {
+// 	   assert.Equal(t, expectedErrorf, err)
+//   }
+func Errorf(t TestingT, err error, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Errorf(t, err, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//    assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
+func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+	if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//    assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+	if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) {
+		return
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	t.FailNow()
+}
+
+// Exactly asserts that two objects are equal in value and type.
+//
+//    assert.Exactly(t, int32(123), int64(123))
+func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Exactly(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Exactlyf asserts that two objects are equal in value and type.
+//
+//    assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
+func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Exactlyf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Fail reports a failure through
+func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Fail(t, failureMessage, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// FailNow fails test
+func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.FailNow(t, failureMessage, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// FailNowf fails test
+func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.FailNowf(t, failureMessage, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Failf reports a failure through
+func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Failf(t, failureMessage, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// False asserts that the specified value is false.
+//
+//    assert.False(t, myBool)
+func False(t TestingT, value bool, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.False(t, value, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Falsef asserts that the specified value is false.
+//
+//    assert.Falsef(t, myBool, "error message %s", "formatted")
+func Falsef(t TestingT, value bool, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Falsef(t, value, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
+func FileExists(t TestingT, path string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.FileExists(t, path, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
+func FileExistsf(t TestingT, path string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.FileExistsf(t, path, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Greater asserts that the first element is greater than the second
+//
+//    assert.Greater(t, 2, 1)
+//    assert.Greater(t, float64(2), float64(1))
+//    assert.Greater(t, "b", "a")
+func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Greater(t, e1, e2, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+//    assert.GreaterOrEqual(t, 2, 1)
+//    assert.GreaterOrEqual(t, 2, 2)
+//    assert.GreaterOrEqual(t, "b", "a")
+//    assert.GreaterOrEqual(t, "b", "b")
+func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.GreaterOrEqual(t, e1, e2, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+//    assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
+//    assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
+//    assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
+//    assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
+func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.GreaterOrEqualf(t, e1, e2, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+//    assert.Greaterf(t, 2, 1, "error message %s", "formatted")
+//    assert.Greaterf(t, float64(2, "error message %s", "formatted"), float64(1))
+//    assert.Greaterf(t, "b", "a", "error message %s", "formatted")
+func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Greaterf(t, e1, e2, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//  assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPBodyContainsf asserts that a specified handler returns a
+// body that contains a string.
+//
+//  assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPBodyNotContainsf asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//  assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPError(t, handler, method, url, values, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPErrorf asserts that a specified handler returns an error status code.
+//
+//  assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
+func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPErrorf(t, handler, method, url, values, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//  assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPRedirectf asserts that a specified handler returns a redirect status code.
+//
+//  assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
+func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPRedirectf(t, handler, method, url, values, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//  assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPSuccessf asserts that a specified handler returns a success status code.
+//
+//  assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPSuccessf(t, handler, method, url, values, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//    assert.Implements(t, (*MyInterface)(nil), new(MyObject))
+func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Implements(t, interfaceObject, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Implementsf asserts that an object is implemented by the specified interface.
+//
+//    assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
+func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Implementsf(t, interfaceObject, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+// 	 assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
+func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func InDeltaMapValues(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InDeltaMapValuesf(t, expected, actual, delta, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InDeltaSlicef is the same as InDelta, except it compares two slices.
+func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InDeltaf asserts that the two numerals are within delta of each other.
+//
+// 	 assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
+func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InDeltaf(t, expected, actual, delta, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InEpsilonf asserts that expected and actual have a relative error less than epsilon
+func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsType asserts that the specified objects are of the same type.
+func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsType(t, expectedType, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsTypef asserts that the specified objects are of the same type.
+func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsTypef(t, expectedType, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+//  assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.JSONEq(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// JSONEqf asserts that two JSON strings are equivalent.
+//
+//  assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
+func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.JSONEqf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// YAMLEq asserts that two YAML strings are equivalent.
+func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.YAMLEq(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.YAMLEqf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//    assert.Len(t, mySlice, 3)
+func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Len(t, object, length, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Lenf asserts that the specified object has specific length.
+// Lenf also fails if the object has a type that len() not accept.
+//
+//    assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
+func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Lenf(t, object, length, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Less asserts that the first element is less than the second
+//
+//    assert.Less(t, 1, 2)
+//    assert.Less(t, float64(1), float64(2))
+//    assert.Less(t, "a", "b")
+func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Less(t, e1, e2, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+//    assert.LessOrEqual(t, 1, 2)
+//    assert.LessOrEqual(t, 2, 2)
+//    assert.LessOrEqual(t, "a", "b")
+//    assert.LessOrEqual(t, "b", "b")
+func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.LessOrEqual(t, e1, e2, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+//    assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
+//    assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
+//    assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
+//    assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
+func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.LessOrEqualf(t, e1, e2, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Lessf asserts that the first element is less than the second
+//
+//    assert.Lessf(t, 1, 2, "error message %s", "formatted")
+//    assert.Lessf(t, float64(1, "error message %s", "formatted"), float64(2))
+//    assert.Lessf(t, "a", "b", "error message %s", "formatted")
+func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Lessf(t, e1, e2, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Nil asserts that the specified object is nil.
+//
+//    assert.Nil(t, err)
+func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Nil(t, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Nilf asserts that the specified object is nil.
+//
+//    assert.Nilf(t, err, "error message %s", "formatted")
+func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Nilf(t, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.NoError(t, err) {
+// 	   assert.Equal(t, expectedObj, actualObj)
+//   }
+func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NoError(t, err, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NoErrorf asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.NoErrorf(t, err, "error message %s", "formatted") {
+// 	   assert.Equal(t, expectedObj, actualObj)
+//   }
+func NoErrorf(t TestingT, err error, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NoErrorf(t, err, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//    assert.NotContains(t, "Hello World", "Earth")
+//    assert.NotContains(t, ["Hello", "World"], "Earth")
+//    assert.NotContains(t, {"Hello": "World"}, "Earth")
+func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotContains(t, s, contains, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//    assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
+//    assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
+//    assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
+func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotContainsf(t, s, contains, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  if assert.NotEmpty(t, obj) {
+//    assert.Equal(t, "two", obj[1])
+//  }
+func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotEmpty(t, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotEmptyf asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
+//    assert.Equal(t, "two", obj[1])
+//  }
+func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotEmptyf(t, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//    assert.NotEqual(t, obj1, obj2)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotEqual(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotEqualf asserts that the specified values are NOT equal.
+//
+//    assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotEqualf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//    assert.NotNil(t, err)
+func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotNil(t, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotNilf asserts that the specified object is not nil.
+//
+//    assert.NotNilf(t, err, "error message %s", "formatted")
+func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotNilf(t, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   assert.NotPanics(t, func(){ RemainCalm() })
+func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotPanics(t, f, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
+func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotPanicsf(t, f, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//  assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
+//  assert.NotRegexp(t, "^start", "it's not starting")
+func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotRegexp(t, rx, str, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotRegexpf asserts that a specified regexp does not match a string.
+//
+//  assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
+//  assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
+func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotRegexpf(t, rx, str, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotSubset asserts that the specified list(array, slice...) contains not all
+// elements given in the specified subset(array, slice...).
+//
+//    assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
+func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotSubset(t, list, subset, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotSubsetf asserts that the specified list(array, slice...) contains not all
+// elements given in the specified subset(array, slice...).
+//
+//    assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
+func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotSubsetf(t, list, subset, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotZero asserts that i is not the zero value for its type.
+func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotZero(t, i, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotZerof asserts that i is not the zero value for its type.
+func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotZerof(t, i, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//   assert.Panics(t, func(){ GoCrazy() })
+func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Panics(t, f, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//   assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
+func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.PanicsWithValue(t, expected, f, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//   assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.PanicsWithValuef(t, expected, f, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Panicsf asserts that the code inside the specified PanicTestFunc panics.
+//
+//   assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
+func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Panicsf(t, f, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//  assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
+//  assert.Regexp(t, "start...$", "it's not starting")
+func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Regexp(t, rx, str, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Regexpf asserts that a specified regexp matches a string.
+//
+//  assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
+//  assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
+func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Regexpf(t, rx, str, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Same asserts that two pointers reference the same object.
+//
+//    assert.Same(t, ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Same(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Same(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+//    assert.Samef(t, ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Samef(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Subset asserts that the specified list(array, slice...) contains all
+// elements given in the specified subset(array, slice...).
+//
+//    assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
+func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Subset(t, list, subset, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Subsetf asserts that the specified list(array, slice...) contains all
+// elements given in the specified subset(array, slice...).
+//
+//    assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
+func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Subsetf(t, list, subset, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// True asserts that the specified value is true.
+//
+//    assert.True(t, myBool)
+func True(t TestingT, value bool, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.True(t, value, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Truef asserts that the specified value is true.
+//
+//    assert.Truef(t, myBool, "error message %s", "formatted")
+func Truef(t TestingT, value bool, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Truef(t, value, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//   assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
+func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// WithinDurationf asserts that the two times are within duration delta of each other.
+//
+//   assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
+func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.WithinDurationf(t, expected, actual, delta, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Zero asserts that i is the zero value for its type.
+func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Zero(t, i, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Zerof asserts that i is the zero value for its type.
+func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Zerof(t, i, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
diff --git a/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/stretchr/testify/require/require.go.tmpl
new file mode 100644
index 000000000..55e42ddeb
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require.go.tmpl
@@ -0,0 +1,6 @@
+{{.Comment}}
+func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
+	if h, ok := t.(tHelper); ok { h.Helper() }
+	if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
+	t.FailNow()
+}
diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go
new file mode 100644
index 000000000..804fae035
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require_forward.go
@@ -0,0 +1,1121 @@
+/*
+* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
+* THIS FILE MUST NOT BE EDITED BY HAND
+ */
+
+package require
+
+import (
+	assert "github.com/stretchr/testify/assert"
+	http "net/http"
+	url "net/url"
+	time "time"
+)
+
+// Condition uses a Comparison to assert a complex condition.
+func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Condition(a.t, comp, msgAndArgs...)
+}
+
+// Conditionf uses a Comparison to assert a complex condition.
+func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Conditionf(a.t, comp, msg, args...)
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//    a.Contains("Hello World", "World")
+//    a.Contains(["Hello", "World"], "World")
+//    a.Contains({"Hello": "World"}, "Hello")
+func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Contains(a.t, s, contains, msgAndArgs...)
+}
+
+// Containsf asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//    a.Containsf("Hello World", "World", "error message %s", "formatted")
+//    a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
+//    a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
+func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Containsf(a.t, s, contains, msg, args...)
+}
+
+// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
+func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	DirExists(a.t, path, msgAndArgs...)
+}
+
+// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
+func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	DirExistsf(a.t, path, msg, args...)
+}
+
+// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
+func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	ElementsMatch(a.t, listA, listB, msgAndArgs...)
+}
+
+// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
+func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	ElementsMatchf(a.t, listA, listB, msg, args...)
+}
+
+// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  a.Empty(obj)
+func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Empty(a.t, object, msgAndArgs...)
+}
+
+// Emptyf asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  a.Emptyf(obj, "error message %s", "formatted")
+func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Emptyf(a.t, object, msg, args...)
+}
+
+// Equal asserts that two objects are equal.
+//
+//    a.Equal(123, 123)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Equal(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   a.EqualError(err,  expectedErrorString)
+func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualError(a.t, theError, errString, msgAndArgs...)
+}
+
+// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   a.EqualErrorf(err,  expectedErrorString, "error message %s", "formatted")
+func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualErrorf(a.t, theError, errString, msg, args...)
+}
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    a.EqualValues(uint32(123), int32(123))
+func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualValuesf asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
+func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualValuesf(a.t, expected, actual, msg, args...)
+}
+
+// Equalf asserts that two objects are equal.
+//
+//    a.Equalf(123, 123, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Equalf(a.t, expected, actual, msg, args...)
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if a.Error(err) {
+// 	   assert.Equal(t, expectedError, err)
+//   }
+func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Error(a.t, err, msgAndArgs...)
+}
+
+// Errorf asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if a.Errorf(err, "error message %s", "formatted") {
+// 	   assert.Equal(t, expectedErrorf, err)
+//   }
+func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Errorf(a.t, err, msg, args...)
+}
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//    a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//    a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
+}
+
+// Exactly asserts that two objects are equal in value and type.
+//
+//    a.Exactly(int32(123), int64(123))
+func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Exactly(a.t, expected, actual, msgAndArgs...)
+}
+
+// Exactlyf asserts that two objects are equal in value and type.
+//
+//    a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
+func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Exactlyf(a.t, expected, actual, msg, args...)
+}
+
+// Fail reports a failure through
+func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Fail(a.t, failureMessage, msgAndArgs...)
+}
+
+// FailNow fails test
+func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	FailNow(a.t, failureMessage, msgAndArgs...)
+}
+
+// FailNowf fails test
+func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	FailNowf(a.t, failureMessage, msg, args...)
+}
+
+// Failf reports a failure through
+func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Failf(a.t, failureMessage, msg, args...)
+}
+
+// False asserts that the specified value is false.
+//
+//    a.False(myBool)
+func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	False(a.t, value, msgAndArgs...)
+}
+
+// Falsef asserts that the specified value is false.
+//
+//    a.Falsef(myBool, "error message %s", "formatted")
+func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Falsef(a.t, value, msg, args...)
+}
+
+// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
+func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	FileExists(a.t, path, msgAndArgs...)
+}
+
+// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
+func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	FileExistsf(a.t, path, msg, args...)
+}
+
+// Greater asserts that the first element is greater than the second
+//
+//    a.Greater(2, 1)
+//    a.Greater(float64(2), float64(1))
+//    a.Greater("b", "a")
+func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Greater(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+//    a.GreaterOrEqual(2, 1)
+//    a.GreaterOrEqual(2, 2)
+//    a.GreaterOrEqual("b", "a")
+//    a.GreaterOrEqual("b", "b")
+func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+//    a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
+//    a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
+//    a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
+//    a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	GreaterOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+//    a.Greaterf(2, 1, "error message %s", "formatted")
+//    a.Greaterf(float64(2, "error message %s", "formatted"), float64(1))
+//    a.Greaterf("b", "a", "error message %s", "formatted")
+func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Greaterf(a.t, e1, e2, msg, args...)
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//  a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
+}
+
+// HTTPBodyContainsf asserts that a specified handler returns a
+// body that contains a string.
+//
+//  a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
+}
+
+// HTTPBodyNotContainsf asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//  a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPError(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPErrorf asserts that a specified handler returns an error status code.
+//
+//  a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
+func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPErrorf(a.t, handler, method, url, values, msg, args...)
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//  a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPRedirectf asserts that a specified handler returns a redirect status code.
+//
+//  a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
+func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//  a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPSuccessf asserts that a specified handler returns a success status code.
+//
+//  a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//    a.Implements((*MyInterface)(nil), new(MyObject))
+func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Implements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+// Implementsf asserts that an object is implemented by the specified interface.
+//
+//    a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
+func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Implementsf(a.t, interfaceObject, object, msg, args...)
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+// 	 a.InDelta(math.Pi, (22 / 7.0), 0.01)
+func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDelta(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaSlicef is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
+}
+
+// InDeltaf asserts that the two numerals are within delta of each other.
+//
+// 	 a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
+func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaf(a.t, expected, actual, delta, msg, args...)
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
+func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
+}
+
+// InEpsilonf asserts that expected and actual have a relative error less than epsilon
+func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
+}
+
+// IsType asserts that the specified objects are of the same type.
+func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsType(a.t, expectedType, object, msgAndArgs...)
+}
+
+// IsTypef asserts that the specified objects are of the same type.
+func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsTypef(a.t, expectedType, object, msg, args...)
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+//  a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	JSONEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// JSONEqf asserts that two JSON strings are equivalent.
+//
+//  a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
+func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	JSONEqf(a.t, expected, actual, msg, args...)
+}
+
+// YAMLEq asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	YAMLEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	YAMLEqf(a.t, expected, actual, msg, args...)
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//    a.Len(mySlice, 3)
+func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Len(a.t, object, length, msgAndArgs...)
+}
+
+// Lenf asserts that the specified object has specific length.
+// Lenf also fails if the object has a type that len() not accept.
+//
+//    a.Lenf(mySlice, 3, "error message %s", "formatted")
+func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Lenf(a.t, object, length, msg, args...)
+}
+
+// Less asserts that the first element is less than the second
+//
+//    a.Less(1, 2)
+//    a.Less(float64(1), float64(2))
+//    a.Less("a", "b")
+func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Less(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+//    a.LessOrEqual(1, 2)
+//    a.LessOrEqual(2, 2)
+//    a.LessOrEqual("a", "b")
+//    a.LessOrEqual("b", "b")
+func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	LessOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+//    a.LessOrEqualf(1, 2, "error message %s", "formatted")
+//    a.LessOrEqualf(2, 2, "error message %s", "formatted")
+//    a.LessOrEqualf("a", "b", "error message %s", "formatted")
+//    a.LessOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	LessOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Lessf asserts that the first element is less than the second
+//
+//    a.Lessf(1, 2, "error message %s", "formatted")
+//    a.Lessf(float64(1, "error message %s", "formatted"), float64(2))
+//    a.Lessf("a", "b", "error message %s", "formatted")
+func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Lessf(a.t, e1, e2, msg, args...)
+}
+
+// Nil asserts that the specified object is nil.
+//
+//    a.Nil(err)
+func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Nil(a.t, object, msgAndArgs...)
+}
+
+// Nilf asserts that the specified object is nil.
+//
+//    a.Nilf(err, "error message %s", "formatted")
+func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Nilf(a.t, object, msg, args...)
+}
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if a.NoError(err) {
+// 	   assert.Equal(t, expectedObj, actualObj)
+//   }
+func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NoError(a.t, err, msgAndArgs...)
+}
+
+// NoErrorf asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if a.NoErrorf(err, "error message %s", "formatted") {
+// 	   assert.Equal(t, expectedObj, actualObj)
+//   }
+func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NoErrorf(a.t, err, msg, args...)
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//    a.NotContains("Hello World", "Earth")
+//    a.NotContains(["Hello", "World"], "Earth")
+//    a.NotContains({"Hello": "World"}, "Earth")
+func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotContains(a.t, s, contains, msgAndArgs...)
+}
+
+// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//    a.NotContainsf("Hello World", "Earth", "error message %s", "formatted")
+//    a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
+//    a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
+func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotContainsf(a.t, s, contains, msg, args...)
+}
+
+// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  if a.NotEmpty(obj) {
+//    assert.Equal(t, "two", obj[1])
+//  }
+func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEmpty(a.t, object, msgAndArgs...)
+}
+
+// NotEmptyf asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  if a.NotEmptyf(obj, "error message %s", "formatted") {
+//    assert.Equal(t, "two", obj[1])
+//  }
+func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEmptyf(a.t, object, msg, args...)
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//    a.NotEqual(obj1, obj2)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEqual(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotEqualf asserts that the specified values are NOT equal.
+//
+//    a.NotEqualf(obj1, obj2, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEqualf(a.t, expected, actual, msg, args...)
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//    a.NotNil(err)
+func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotNil(a.t, object, msgAndArgs...)
+}
+
+// NotNilf asserts that the specified object is not nil.
+//
+//    a.NotNilf(err, "error message %s", "formatted")
+func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotNilf(a.t, object, msg, args...)
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   a.NotPanics(func(){ RemainCalm() })
+func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotPanics(a.t, f, msgAndArgs...)
+}
+
+// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
+func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotPanicsf(a.t, f, msg, args...)
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//  a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
+//  a.NotRegexp("^start", "it's not starting")
+func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotRegexp(a.t, rx, str, msgAndArgs...)
+}
+
+// NotRegexpf asserts that a specified regexp does not match a string.
+//
+//  a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
+//  a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
+func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotRegexpf(a.t, rx, str, msg, args...)
+}
+
+// NotSubset asserts that the specified list(array, slice...) contains not all
+// elements given in the specified subset(array, slice...).
+//
+//    a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
+func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotSubset(a.t, list, subset, msgAndArgs...)
+}
+
+// NotSubsetf asserts that the specified list(array, slice...) contains not all
+// elements given in the specified subset(array, slice...).
+//
+//    a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
+func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotSubsetf(a.t, list, subset, msg, args...)
+}
+
+// NotZero asserts that i is not the zero value for its type.
+func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotZero(a.t, i, msgAndArgs...)
+}
+
+// NotZerof asserts that i is not the zero value for its type.
+func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotZerof(a.t, i, msg, args...)
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//   a.Panics(func(){ GoCrazy() })
+func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Panics(a.t, f, msgAndArgs...)
+}
+
+// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//   a.PanicsWithValue("crazy error", func(){ GoCrazy() })
+func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	PanicsWithValue(a.t, expected, f, msgAndArgs...)
+}
+
+// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//   a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	PanicsWithValuef(a.t, expected, f, msg, args...)
+}
+
+// Panicsf asserts that the code inside the specified PanicTestFunc panics.
+//
+//   a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Panicsf(a.t, f, msg, args...)
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//  a.Regexp(regexp.MustCompile("start"), "it's starting")
+//  a.Regexp("start...$", "it's not starting")
+func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Regexp(a.t, rx, str, msgAndArgs...)
+}
+
+// Regexpf asserts that a specified regexp matches a string.
+//
+//  a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
+//  a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
+func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Regexpf(a.t, rx, str, msg, args...)
+}
+
+// Same asserts that two pointers reference the same object.
+//
+//    a.Same(ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Same(a.t, expected, actual, msgAndArgs...)
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+//    a.Samef(ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Samef(a.t, expected, actual, msg, args...)
+}
+
+// Subset asserts that the specified list(array, slice...) contains all
+// elements given in the specified subset(array, slice...).
+//
+//    a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
+func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Subset(a.t, list, subset, msgAndArgs...)
+}
+
+// Subsetf asserts that the specified list(array, slice...) contains all
+// elements given in the specified subset(array, slice...).
+//
+//    a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
+func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Subsetf(a.t, list, subset, msg, args...)
+}
+
+// True asserts that the specified value is true.
+//
+//    a.True(myBool)
+func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	True(a.t, value, msgAndArgs...)
+}
+
+// Truef asserts that the specified value is true.
+//
+//    a.Truef(myBool, "error message %s", "formatted")
+func (a *Assertions) Truef(value bool, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Truef(a.t, value, msg, args...)
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//   a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
+func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// WithinDurationf asserts that the two times are within duration delta of each other.
+//
+//   a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
+func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	WithinDurationf(a.t, expected, actual, delta, msg, args...)
+}
+
+// Zero asserts that i is the zero value for its type.
+func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Zero(a.t, i, msgAndArgs...)
+}
+
+// Zerof asserts that i is the zero value for its type.
+func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Zerof(a.t, i, msg, args...)
+}
diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
new file mode 100644
index 000000000..54124df1d
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
@@ -0,0 +1,5 @@
+{{.CommentWithoutT "a"}}
+func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {
+	if h, ok := a.t.(tHelper); ok { h.Helper() }
+	{{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
+}
diff --git a/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/stretchr/testify/require/requirements.go
new file mode 100644
index 000000000..6b85c5ece
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/requirements.go
@@ -0,0 +1,29 @@
+package require
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+	Errorf(format string, args ...interface{})
+	FailNow()
+}
+
+type tHelper interface {
+	Helper()
+}
+
+// ComparisonAssertionFunc is a common function prototype when comparing two values.  Can be useful
+// for table driven tests.
+type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{})
+
+// ValueAssertionFunc is a common function prototype when validating a single value.  Can be useful
+// for table driven tests.
+type ValueAssertionFunc func(TestingT, interface{}, ...interface{})
+
+// BoolAssertionFunc is a common function prototype when validating a bool value.  Can be useful
+// for table driven tests.
+type BoolAssertionFunc func(TestingT, bool, ...interface{})
+
+// ErrorAssertionFunc is a common function prototype when validating an error value.  Can be useful
+// for table driven tests.
+type ErrorAssertionFunc func(TestingT, error, ...interface{})
+
+//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs