Refactor error handling in the client code

client errors are now returned as an 'error', API errors as APIResponse.
This commit is contained in:
Brian C. Lane 2020-02-27 16:56:58 -08:00 committed by Tom Gundersen
parent 57f0892d93
commit 9dafb3337b
6 changed files with 436 additions and 268 deletions

View file

@ -10,158 +10,158 @@ import (
// PostTOMLBlueprintV0 sends a TOML blueprint string to the API
// and returns an APIResponse
func PostTOMLBlueprintV0(socket, blueprint string) *APIResponse {
body, err := PostTOML(socket, "/api/v0/blueprints/new", blueprint)
if err != nil {
return err
func PostTOMLBlueprintV0(socket, blueprint string) (*APIResponse, error) {
body, resp, err := PostTOML(socket, "/api/v0/blueprints/new", blueprint)
if resp != nil || err != nil {
return resp, err
}
return NewAPIResponse(body)
}
// PostTOMLWorkspaceV0 sends a TOML blueprint string to the API
// and returns an APIResponse
func PostTOMLWorkspaceV0(socket, blueprint string) *APIResponse {
body, err := PostTOML(socket, "/api/v0/blueprints/workspace", blueprint)
if err != nil {
return err
func PostTOMLWorkspaceV0(socket, blueprint string) (*APIResponse, error) {
body, resp, err := PostTOML(socket, "/api/v0/blueprints/workspace", blueprint)
if resp != nil || err != nil {
return resp, err
}
return NewAPIResponse(body)
}
// PostJSONBlueprintV0 sends a JSON blueprint string to the API
// and returns an APIResponse
func PostJSONBlueprintV0(socket, blueprint string) *APIResponse {
body, err := PostJSON(socket, "/api/v0/blueprints/new", blueprint)
if err != nil {
return err
func PostJSONBlueprintV0(socket, blueprint string) (*APIResponse, error) {
body, resp, err := PostJSON(socket, "/api/v0/blueprints/new", blueprint)
if resp != nil || err != nil {
return resp, err
}
return NewAPIResponse(body)
}
// PostJSONWorkspaceV0 sends a JSON blueprint string to the API
// and returns an APIResponse
func PostJSONWorkspaceV0(socket, blueprint string) *APIResponse {
body, err := PostJSON(socket, "/api/v0/blueprints/workspace", blueprint)
if err != nil {
return err
func PostJSONWorkspaceV0(socket, blueprint string) (*APIResponse, error) {
body, resp, err := PostJSON(socket, "/api/v0/blueprints/workspace", blueprint)
if resp != nil || err != nil {
return resp, err
}
return NewAPIResponse(body)
}
// DeleteBlueprintV0 deletes the named blueprint and returns an APIResponse
func DeleteBlueprintV0(socket, bpName string) *APIResponse {
body, err := DeleteRaw(socket, "/api/v0/blueprints/delete/"+bpName)
if err != nil {
return err
func DeleteBlueprintV0(socket, bpName string) (*APIResponse, error) {
body, resp, err := DeleteRaw(socket, "/api/v0/blueprints/delete/"+bpName)
if resp != nil || err != nil {
return resp, err
}
return NewAPIResponse(body)
}
// DeleteWorkspaceV0 deletes the named blueprint's workspace and returns an APIResponse
func DeleteWorkspaceV0(socket, bpName string) *APIResponse {
body, err := DeleteRaw(socket, "/api/v0/blueprints/workspace/"+bpName)
if err != nil {
return err
func DeleteWorkspaceV0(socket, bpName string) (*APIResponse, error) {
body, resp, err := DeleteRaw(socket, "/api/v0/blueprints/workspace/"+bpName)
if resp != nil || err != nil {
return resp, err
}
return NewAPIResponse(body)
}
// ListBlueprintsV0 returns a list of blueprint names
func ListBlueprintsV0(socket string) ([]string, *APIResponse) {
body, err := GetJSONAll(socket, "/api/v0/blueprints/list")
func ListBlueprintsV0(socket string) ([]string, *APIResponse, error) {
body, resp, err := GetJSONAll(socket, "/api/v0/blueprints/list")
if resp != nil || err != nil {
return nil, resp, err
}
var list BlueprintsListV0
err = json.Unmarshal(body, &list)
if err != nil {
return nil, err
return nil, nil, err
}
var resp BlueprintsListV0
jerr := json.Unmarshal(body, &resp)
if jerr != nil {
return nil, clientError(err)
}
return resp.Blueprints, nil
return list.Blueprints, nil, nil
}
// GetBlueprintInfoTOMLV0 returns the requested blueprint as a TOML string
func GetBlueprintInfoTOMLV0(socket, bpName string) (string, *APIResponse) {
body, err := GetRaw(socket, "GET", "/api/v0/blueprints/info/"+bpName+"?format=toml")
if err != nil {
return "", err
func GetBlueprintInfoTOMLV0(socket, bpName string) (string, *APIResponse, error) {
body, resp, err := GetRaw(socket, "GET", "/api/v0/blueprints/info/"+bpName+"?format=toml")
if resp != nil || err != nil {
return "", resp, err
}
return string(body), nil
return string(body), nil, nil
}
// GetBlueprintsInfoJSONV0 returns the requested blueprints and their changed state
func GetBlueprintsInfoJSONV0(socket, bpName string) (BlueprintsInfoV0, *APIResponse) {
body, err := GetRaw(socket, "GET", "/api/v0/blueprints/info/"+bpName)
func GetBlueprintsInfoJSONV0(socket, bpName string) (BlueprintsInfoV0, *APIResponse, error) {
body, resp, err := GetRaw(socket, "GET", "/api/v0/blueprints/info/"+bpName)
if resp != nil || err != nil {
return BlueprintsInfoV0{}, resp, err
}
var info BlueprintsInfoV0
err = json.Unmarshal(body, &info)
if err != nil {
return BlueprintsInfoV0{}, err
return BlueprintsInfoV0{}, nil, err
}
var resp BlueprintsInfoV0
jerr := json.Unmarshal(body, &resp)
if jerr != nil {
return BlueprintsInfoV0{}, clientError(err)
}
return resp, nil
return info, nil, nil
}
// GetBlueprintsChangesV0 returns the changes to the listed blueprints
func GetBlueprintsChangesV0(socket string, bpNames []string) (BlueprintsChangesV0, *APIResponse) {
func GetBlueprintsChangesV0(socket string, bpNames []string) (BlueprintsChangesV0, *APIResponse, error) {
names := strings.Join(bpNames, ",")
body, err := GetRaw(socket, "GET", "/api/v0/blueprints/changes/"+names)
body, resp, err := GetRaw(socket, "GET", "/api/v0/blueprints/changes/"+names)
if resp != nil || err != nil {
return BlueprintsChangesV0{}, resp, err
}
var changes BlueprintsChangesV0
err = json.Unmarshal(body, &changes)
if err != nil {
return BlueprintsChangesV0{}, err
return BlueprintsChangesV0{}, nil, err
}
var resp BlueprintsChangesV0
jerr := json.Unmarshal(body, &resp)
if jerr != nil {
return BlueprintsChangesV0{}, clientError(err)
}
return resp, nil
return changes, nil, nil
}
// UndoBlueprintChangeV0 reverts a blueprint to a previous commit
func UndoBlueprintChangeV0(socket, blueprint, commit string) *APIResponse {
func UndoBlueprintChangeV0(socket, blueprint, commit string) (*APIResponse, error) {
request := fmt.Sprintf("/api/v0/blueprints/undo/%s/%s", blueprint, commit)
body, err := PostRaw(socket, request, "", nil)
if err != nil {
return err
body, resp, err := PostRaw(socket, request, "", nil)
if resp != nil || err != nil {
return resp, err
}
return NewAPIResponse(body)
}
// TagBlueprintV0 tags the current blueprint commit as a new revision
func TagBlueprintV0(socket, blueprint string) *APIResponse {
body, err := PostRaw(socket, "/api/v0/blueprints/tag/"+blueprint, "", nil)
if err != nil {
return err
func TagBlueprintV0(socket, blueprint string) (*APIResponse, error) {
body, resp, err := PostRaw(socket, "/api/v0/blueprints/tag/"+blueprint, "", nil)
if resp != nil || err != nil {
return resp, err
}
return NewAPIResponse(body)
}
// DepsolveBlueprintV0 depsolves the listed blueprint
func DepsolveBlueprintV0(socket, blueprint string) (BlueprintsDepsolveV0, *APIResponse) {
body, err := GetRaw(socket, "GET", "/api/v0/blueprints/depsolve/"+blueprint)
func DepsolveBlueprintV0(socket, blueprint string) (BlueprintsDepsolveV0, *APIResponse, error) {
body, resp, err := GetRaw(socket, "GET", "/api/v0/blueprints/depsolve/"+blueprint)
if resp != nil || err != nil {
return BlueprintsDepsolveV0{}, resp, err
}
var deps BlueprintsDepsolveV0
err = json.Unmarshal(body, &deps)
if err != nil {
return BlueprintsDepsolveV0{}, err
return BlueprintsDepsolveV0{}, nil, err
}
var resp BlueprintsDepsolveV0
jerr := json.Unmarshal(body, &resp)
if jerr != nil {
return BlueprintsDepsolveV0{}, clientError(err)
}
return resp, nil
return deps, nil, nil
}
// FreezeBlueprintV0 depsolves the listed blueprint and returns the blueprint with frozen package
// versions
func FreezeBlueprintV0(socket, blueprint string) (BlueprintsFreezeV0, *APIResponse) {
body, err := GetRaw(socket, "GET", "/api/v0/blueprints/freeze/"+blueprint)
func FreezeBlueprintV0(socket, blueprint string) (BlueprintsFreezeV0, *APIResponse, error) {
body, resp, err := GetRaw(socket, "GET", "/api/v0/blueprints/freeze/"+blueprint)
if resp != nil || err != nil {
return BlueprintsFreezeV0{}, resp, err
}
var frozen BlueprintsFreezeV0
err = json.Unmarshal(body, &frozen)
if err != nil {
return BlueprintsFreezeV0{}, err
return BlueprintsFreezeV0{}, nil, err
}
var resp BlueprintsFreezeV0
jerr := json.Unmarshal(body, &resp)
if jerr != nil {
return BlueprintsFreezeV0{}, clientError(err)
}
return resp, nil
return frozen, nil, nil
}

View file

@ -61,17 +61,17 @@ func (r *APIErrorMsg) String() string {
return fmt.Sprintf("%s: %s", r.ID, r.Msg)
}
// APIResponse is returned with status code 400 and may contain a list of errors
// APIResponse is returned by some requests to indicate success or failure.
// It is always returned when the status code is 400, indicating some kind of error with the request.
// If Status is true the Errors list will not be included or will be empty.
// When Status is false it will include at least one APIErrorMsg with details about the error.
// It also implements the error interface so that it can be used in place of error
type APIResponse struct {
Status bool `json:"status"`
Errors []APIErrorMsg `json:"errors,omitempty"`
}
// Error returns the description of the first error
func (r *APIResponse) Error() string {
// String returns the description of the first error, if there is one
func (r *APIResponse) String() string {
if len(r.Errors) == 0 {
return ""
}
@ -86,83 +86,75 @@ func (r *APIResponse) AllErrors() (all []string) {
return all
}
// clientError converts an error into an APIResponse with ID set to ClientError
// This is used to return golang function errors to callers of the client functions
func clientError(err error) *APIResponse {
return &APIResponse{
Status: false,
Errors: []APIErrorMsg{{ID: "ClientError", Msg: err.Error()}},
}
}
// NewAPIResponse converts the response body to a status response
func NewAPIResponse(body []byte) *APIResponse {
func NewAPIResponse(body []byte) (*APIResponse, error) {
var status APIResponse
err := json.Unmarshal(body, &status)
if err != nil {
return clientError(err)
return nil, err
}
return &status
return &status, nil
}
// apiError converts an API error 400 JSON to a status response
//
// The response body should alway be of the form:
// {"status": false, "errors": [{"id": ERROR_ID, "msg": ERROR_MESSAGE}, ...]}
func apiError(resp *http.Response) *APIResponse {
func apiError(resp *http.Response) (*APIResponse, error) {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return clientError(err)
return nil, err
}
return NewAPIResponse(body)
}
// GetRaw returns raw data from a GET request
// Errors from the client and from the API are returned as an APIResponse
func GetRaw(socket, method, path string) ([]byte, *APIResponse) {
// Errors from the API are returned as an APIResponse, client errors are returned as error
func GetRaw(socket, method, path string) ([]byte, *APIResponse, error) {
resp, err := Request(socket, method, path, "", map[string]string{})
if err != nil {
return nil, clientError(err)
return nil, nil, err
}
// Convert the API's JSON error response to an error type and return it
if resp.StatusCode == 400 {
return nil, apiError(resp)
apiResponse, err := apiError(resp)
return nil, apiResponse, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, clientError(err)
return nil, nil, err
}
return body, nil
return body, nil, nil
}
// GetJSONAll returns all JSON results from a GET request using offset/limit
// This function makes 2 requests, the first with limit=0 to get the total number of results,
// and then with limit=TOTAL to fetch all of the results.
// The path passed to GetJSONAll should not include the limit or offset query parameters
// Errors from the client and from the API are returned as an APIResponse
func GetJSONAll(socket, path string) ([]byte, *APIResponse) {
body, err := GetRaw(socket, "GET", path+"?limit=0")
if err != nil {
return nil, err
// Errors from the API are returned as an APIResponse, client errors are returned as error
func GetJSONAll(socket, path string) ([]byte, *APIResponse, error) {
body, api, err := GetRaw(socket, "GET", path+"?limit=0")
if api != nil || err != nil {
return nil, api, err
}
// We just want the total
var j interface{}
jerr := json.Unmarshal(body, &j)
if jerr != nil {
return nil, clientError(jerr)
err = json.Unmarshal(body, &j)
if err != nil {
return nil, nil, err
}
m := j.(map[string]interface{})
var v interface{}
var ok bool
if v, ok = m["total"]; !ok {
return nil, clientError(errors.New("Response is missing the total value"))
return nil, nil, errors.New("Response is missing the total value")
}
switch total := v.(type) {
@ -170,63 +162,65 @@ func GetJSONAll(socket, path string) ([]byte, *APIResponse) {
allResults := fmt.Sprintf("%s?limit=%v", path, total)
return GetRaw(socket, "GET", allResults)
}
return nil, clientError(errors.New("Response 'total' is wrong type"))
return nil, nil, errors.New("Response 'total' is not a float64")
}
// PostRaw sends a POST with raw data and returns the raw response body
// Errors from the client and from the API are returned as an APIResponse
func PostRaw(socket, path, body string, headers map[string]string) ([]byte, *APIResponse) {
// Errors from the API are returned as an APIResponse, client errors are returned as error
func PostRaw(socket, path, body string, headers map[string]string) ([]byte, *APIResponse, error) {
resp, err := Request(socket, "POST", path, body, headers)
if err != nil {
return nil, clientError(err)
return nil, nil, err
}
// Convert the API's JSON error response to an error type and return it
// Convert the API's JSON error response to an APIResponse
if resp.StatusCode == 400 {
return nil, apiError(resp)
apiResponse, err := apiError(resp)
return nil, apiResponse, err
}
defer resp.Body.Close()
responseBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, clientError(err)
return nil, nil, err
}
return responseBody, nil
return responseBody, nil, nil
}
// PostTOML sends a POST with TOML data and the Content-Type header set to "text/x-toml"
// It returns the raw response data or errors as an APIResponse
func PostTOML(socket, path, body string) ([]byte, *APIResponse) {
// Errors from the API are returned as an APIResponse, client errors are returned as error
func PostTOML(socket, path, body string) ([]byte, *APIResponse, error) {
headers := map[string]string{"Content-Type": "text/x-toml"}
return PostRaw(socket, path, body, headers)
}
// PostJSON sends a POST with JSON data and the Content-Type header set to "application/json"
// It returns the raw response data or errors as an APIResponse
func PostJSON(socket, path, body string) ([]byte, *APIResponse) {
// Errors from the API are returned as an APIResponse, client errors are returned as error
func PostJSON(socket, path, body string) ([]byte, *APIResponse, error) {
headers := map[string]string{"Content-Type": "application/json"}
return PostRaw(socket, path, body, headers)
}
// DeleteRaw sends a DELETE request
// It returns the raw response data or errors as an APIResponse
func DeleteRaw(socket, path string) ([]byte, *APIResponse) {
// Errors from the API are returned as an APIResponse, client errors are returned as error
func DeleteRaw(socket, path string) ([]byte, *APIResponse, error) {
resp, err := Request(socket, "DELETE", path, "", nil)
if err != nil {
return nil, clientError(err)
return nil, nil, err
}
// Convert the API's JSON error response to an error type and return it
// Convert the API's JSON error response to an APIResponse
if resp.StatusCode == 400 {
return nil, apiError(resp)
apiResponse, err := apiError(resp)
return nil, apiResponse, err
}
defer resp.Body.Close()
responseBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, clientError(err)
return nil, nil, err
}
return responseBody, nil
return responseBody, nil, nil
}

View file

@ -3,7 +3,6 @@
package client
import (
"errors"
"io/ioutil"
"log"
"net"
@ -41,15 +40,10 @@ func TestRequest(t *testing.T) {
t.Fatalf("Request bad route: %d != 404", resp.StatusCode)
}
// Test that apiError returns ClientError when trying to parse non-JSON response
aerr := apiError(resp)
if aerr.Status != false {
t.Fatalf("apiError of 404 status is != false: %#v", aerr)
}
if len(aerr.AllErrors()) < 1 {
t.Fatalf("apiError of 404 did not return error message: %#v", aerr)
} else if aerr.Errors[0].ID != "ClientError" {
t.Fatalf("apiError of 404 ID is not ClientError: %#v", aerr)
// Test that apiError returns an error when trying to parse non-JSON response
_, err = apiError(resp)
if err == nil {
t.Fatalf("apiError of a 404 response did not return an error")
}
// Make a request with a bad offset to trigger a JSON response with Status set to 400
@ -71,8 +65,8 @@ func TestAPIErrorMsg(t *testing.T) {
func TestAPIResponse(t *testing.T) {
resp := APIResponse{Status: true}
if resp.Error() != "" {
t.Fatalf("Empty APIResponse Errors doesn't return empty string: %v", resp.Error())
if resp.String() != "" {
t.Fatalf("Empty APIResponse Errors doesn't return empty string: %v", resp.String())
}
resp = APIResponse{Status: false,
@ -80,7 +74,7 @@ func TestAPIResponse(t *testing.T) {
{ID: "ONE_ERROR", Msg: "First message"},
{ID: "TWO_ERROR", Msg: "Second message"}},
}
if diff := cmp.Diff(resp.Error(), "ONE_ERROR: First message"); diff != "" {
if diff := cmp.Diff(resp.String(), "ONE_ERROR: First message"); diff != "" {
t.Fatalf("APIResponse.Error: %s", diff)
}
if diff := cmp.Diff(resp.AllErrors(), []string{"ONE_ERROR: First message", "TWO_ERROR: Second message"}); diff != "" {
@ -88,74 +82,75 @@ func TestAPIResponse(t *testing.T) {
}
}
func TestClientError(t *testing.T) {
err := errors.New("a local client error happened")
cerr := clientError(err)
if cerr.Status != false {
t.Fatal("clientError status != false")
}
if diff := cmp.Diff(cerr.Error(), "ClientError: a local client error happened"); diff != "" {
t.Fatalf("clientError message failed: %s", diff)
}
}
func TestGetRaw(t *testing.T) {
// Get raw data
b, err := GetRaw(socketPath, "GET", "/api/status")
b, resp, err := GetRaw(socketPath, "GET", "/api/status")
if err != nil {
t.Fatalf("GetRaw failed: %v", err)
t.Fatalf("GetRaw failed with a client error: %v", err)
}
if resp != nil {
t.Fatalf("GetRaw request failed: %v", err)
}
if len(b) == 0 {
t.Fatal("GetRaw returned an empty string")
}
// Get an API error
b, err = GetRaw(socketPath, "GET", "/api/v0/blueprints/list?offset=bad")
if err == nil {
t.Fatalf("GetRaw error request did not return an error: %v", b)
b, resp, err = GetRaw(socketPath, "GET", "/api/v0/blueprints/list?offset=bad")
if err != nil {
t.Fatalf("GetRaw bad request failed with a client error: %v", err)
}
if err.Status != false {
t.Fatalf("Status != false: %#v", err)
if resp == nil {
t.Fatalf("GetRaw bad request did not return an error: %v", b)
}
if len(err.AllErrors()) < 1 {
t.Fatalf("GetRaw error did not return error message: %#v", err)
} else if err.Errors[0].ID != "BadLimitOrOffset" {
t.Fatalf("GetRaw error ID is not BadLimitOrOffset: %#v", err)
if resp.Status != false {
t.Fatalf("Status != false: %#v", resp)
}
if len(resp.AllErrors()) < 1 {
t.Fatalf("GetRaw error did not return error message: %#v", resp)
} else if resp.Errors[0].ID != "BadLimitOrOffset" {
t.Fatalf("GetRaw error ID is not BadLimitOrOffset: %#v", resp)
}
}
func TestGetJSONAll(t *testing.T) {
// Get all the projects
b, err := GetJSONAll(socketPath, "/api/v0/projects/list")
b, resp, err := GetJSONAll(socketPath, "/api/v0/projects/list")
if err != nil {
t.Fatalf("GetJSONAll failed: %v", err)
t.Fatalf("GetJSONAll failed with a client error: %v", err)
}
if resp != nil {
t.Fatalf("GetJSONAll request failed: %v", resp)
}
if len(b) < 100 {
t.Fatalf("GetJSONAll response is too short: %#v", b)
}
// Run it on a route that doesn't support offset/limit
b, err = GetJSONAll(socketPath, "/api/status")
b, resp, err = GetJSONAll(socketPath, "/api/status")
if err == nil {
t.Fatalf("GetJSONAll bad route failed: %v", b)
}
if err.Error() != "ClientError: Response is missing the total value" {
t.Fatalf("GetJSONAll bad route has unexpected total value: %v", err)
if err.Error() != "Response is missing the total value" {
t.Fatalf("GetJSONAll bad route has unexpected total value: %v", resp)
}
}
func TestPostRaw(t *testing.T) {
// There are no routes that accept raw POST w/o Content-Type so this ends up testing the error path
b, err := PostRaw(socketPath, "/api/v0/blueprints/new", "nobody", nil)
if err == nil {
b, resp, err := PostRaw(socketPath, "/api/v0/blueprints/new", "nobody", nil)
if err != nil {
t.Fatalf("PostRaw bad request failed with a client error: %v", err)
}
if resp == nil {
t.Fatalf("PostRaw bad request did not return an error: %v", b)
}
if err.Status != false {
t.Fatalf("PostRaw bad request status != false: %#v", err)
if resp.Status != false {
t.Fatalf("PostRaw bad request status != false: %#v", resp)
}
if len(err.AllErrors()) < 1 {
t.Fatalf("GetRaw error did not return error message: %#v", err)
} else if err.Errors[0].ID != "BlueprintsError" {
t.Fatalf("GetRaw error ID is not BlueprintsError: %#v", err)
if len(resp.AllErrors()) < 1 {
t.Fatalf("GetRaw error did not return error message: %#v", resp)
} else if resp.Errors[0].ID != "BlueprintsError" {
t.Fatalf("GetRaw error ID is not BlueprintsError: %#v", resp)
}
}
@ -163,9 +158,12 @@ func TestPostTOML(t *testing.T) {
blueprint := `name = "test-blueprint"
description = "TOML test blueprint"
version = "0.0.1"`
b, err := PostTOML(socketPath, "/api/v0/blueprints/new", blueprint)
b, resp, err := PostTOML(socketPath, "/api/v0/blueprints/new", blueprint)
if err != nil {
t.Fatalf("PostTOML failed: %v", err)
t.Fatalf("PostTOML client failed: %v", err)
}
if resp != nil {
t.Fatalf("PostTOML request failed: %v", resp)
}
if !strings.Contains(string(b), "true") {
t.Fatalf("PostTOML failed: %#v", string(b))
@ -176,9 +174,12 @@ func TestPostJSON(t *testing.T) {
blueprint := `{"name": "test-blueprint",
"description": "JSON test blueprint",
"version": "0.0.1"}`
b, err := PostJSON(socketPath, "/api/v0/blueprints/new", blueprint)
b, resp, err := PostJSON(socketPath, "/api/v0/blueprints/new", blueprint)
if err != nil {
t.Fatalf("PostJSON failed: %v", err)
t.Fatalf("PostJSON client failed: %v", err)
}
if resp != nil {
t.Fatalf("PostJSON request failed: %v", resp)
}
if !strings.Contains(string(b), "true") {
t.Fatalf("PostJSON failed: %#v", string(b))

View file

@ -7,14 +7,14 @@ import (
)
// GetStatusV0 makes a GET request to /api/status and returns the v0 response as a StatusResponseV0
func GetStatusV0(socket string) (reply StatusV0, err *APIResponse) {
body, err := GetRaw(socket, "GET", "/api/status")
func GetStatusV0(socket string) (reply StatusV0, resp *APIResponse, err error) {
body, resp, err := GetRaw(socket, "GET", "/api/status")
if resp != nil || err != nil {
return reply, resp, err
}
err = json.Unmarshal(body, &reply)
if err != nil {
return reply, err
return reply, nil, err
}
jerr := json.Unmarshal(body, &reply)
if jerr != nil {
return reply, clientError(jerr)
}
return reply, nil
return reply, nil, nil
}

View file

@ -72,9 +72,13 @@ func (c *checkBlueprintsV0) CheckPostTOML() bool {
name="root"
password="qweqweqwe"
`
resp := client.PostTOMLBlueprintV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
log.Printf("OK: %s was successful", name)
@ -94,9 +98,13 @@ func (c *checkBlueprintsV0) CheckPostJSON() bool {
"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
}`
resp := client.PostJSONBlueprintV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
log.Printf("OK: %s was successful", name)
@ -123,9 +131,13 @@ func (c *checkBlueprintsV0) CheckPostTOMLWS() bool {
name="root"
password="qweqweqwe"
`
resp := client.PostTOMLWorkspaceV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
log.Printf("OK: %s was successful", name)
@ -145,9 +157,13 @@ func (c *checkBlueprintsV0) CheckPostJSONWS() bool {
"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
}`
resp := client.PostJSONWorkspaceV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
log.Printf("OK: %s was successful", name)
@ -168,16 +184,24 @@ func (c *checkBlueprintsV0) CheckDelete() bool {
"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
}`
resp := client.PostJSONBlueprintV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
// Delete the blueprint
resp = client.DeleteBlueprintV0(c.socket, "test-delete-blueprint-v0")
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
@ -199,16 +223,24 @@ func (c *checkBlueprintsV0) CheckDeleteNewWS() bool {
"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
}`
resp := client.PostJSONWorkspaceV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
// Delete the blueprint
resp = client.DeleteWorkspaceV0(c.socket, "test-delete-new-blueprint-ws-v0")
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
@ -230,9 +262,13 @@ func (c *checkBlueprintsV0) CheckDeleteChangesWS() bool {
"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
}`
resp := client.PostJSONBlueprintV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
@ -246,16 +282,24 @@ func (c *checkBlueprintsV0) CheckDeleteChangesWS() bool {
"customizations": {"user": [{"name": "root", "password": "qweqweqwe"}]}
}`
resp = client.PostJSONWorkspaceV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
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, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-delete-blueprint-changes-ws-v0")
info, api, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-delete-blueprint-changes-ws-v0")
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err)
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
}
@ -290,18 +334,26 @@ func (c *checkBlueprintsV0) CheckDeleteChangesWS() bool {
}
// Delete the blueprint from the workspace
resp = client.DeleteWorkspaceV0(c.socket, "test-delete-blueprint-changes-ws-v0")
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
// Get the blueprint, make sure it is the un-modified one
info, err = client.GetBlueprintsInfoJSONV0(c.socket, "test-delete-blueprint-changes-ws-v0")
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)
@ -359,17 +411,25 @@ func (c *checkBlueprintsV0) CheckList() bool {
}`}
for i := range bps {
resp := client.PostJSONBlueprintV0(c.socket, bps[i])
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
}
// Get the list of blueprints
list, err := client.ListBlueprintsV0(c.socket)
list, api, err := client.ListBlueprintsV0(c.socket)
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err.Error())
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
}
@ -398,18 +458,26 @@ func (c *checkBlueprintsV0) CheckGetTOML() bool {
}`
// Post a blueprint
resp := client.PostJSONBlueprintV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
// Get it as TOML
body, err := client.GetBlueprintInfoTOMLV0(c.socket, "test-get-blueprint-1-v0")
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)
@ -440,18 +508,26 @@ func (c *checkBlueprintsV0) CheckGetJSON() bool {
}`
// Post a blueprint
resp := client.PostJSONBlueprintV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
// Get the blueprint and its changed state
info, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-get-blueprint-2-v0")
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)
@ -495,43 +571,63 @@ func (c *checkBlueprintsV0) CheckBumpVersion() bool {
}`
// List blueprints
list, err := client.ListBlueprintsV0(c.socket)
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 := client.DeleteBlueprintV0(c.socket, "test-bump-blueprint-1-v0")
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
}
// Post a blueprint
resp := client.PostJSONBlueprintV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
// Post a blueprint again to bump verion to 2.1.3
resp = client.PostJSONBlueprintV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
// Get the blueprint and its changed state
info, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-bump-blueprint-1-v0")
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)
@ -582,19 +678,27 @@ func (c *checkBlueprintsV0) CheckBlueprintChangesV0() bool {
// Push 3 changes to the blueprint
for i := range bps {
resp := client.PostJSONBlueprintV0(c.socket, bps[i])
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
}
// List the changes
changes, err := client.GetBlueprintsChangesV0(c.socket, []string{"test-blueprint-changes-v0"})
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)
@ -637,18 +741,26 @@ func (c *checkBlueprintsV0) CheckUndoBlueprintV0() bool {
}`}
// Push original version of the blueprint
resp := client.PostJSONBlueprintV0(c.socket, bps[0])
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
// Get the commit hash
changes, err := client.GetBlueprintsChangesV0(c.socket, []string{"test-undo-blueprint-v0"})
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)
@ -667,18 +779,26 @@ func (c *checkBlueprintsV0) CheckUndoBlueprintV0() bool {
}
// Push the new version with wrong bash version
resp = client.PostJSONBlueprintV0(c.socket, bps[1])
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
// Get the blueprint, confirm bash version is '0.5.*'
info, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-undo-blueprint-v0")
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)
@ -698,18 +818,26 @@ func (c *checkBlueprintsV0) CheckUndoBlueprintV0() bool {
}
// Revert the blueprint to the original version
resp = client.UndoBlueprintChangeV0(c.socket, "test-undo-blueprint-v0", commit)
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 != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
log.Printf("FAIL: %s failed: %s", name, resp)
return false
}
// Get the blueprint, confirm bash version is '*'
info, err = client.GetBlueprintsInfoJSONV0(c.socket, "test-undo-blueprint-v0")
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)
@ -756,23 +884,35 @@ func (c *checkBlueprintsV0) CheckBlueprintTagV0() bool {
}`}
// Push a blueprint
resp := client.PostJSONBlueprintV0(c.socket, bps[0])
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 != true {
log.Printf("FAIL: %s POST failed: %s", name, resp.Error())
log.Printf("FAIL: %s POST failed: %s", name, resp)
return false
}
// Tag the blueprint
tagResp := client.TagBlueprintV0(c.socket, "test-tag-blueprint-v0")
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 != true {
log.Printf("FAIL: %s Tag failed: %s", name, tagResp.Error())
log.Printf("FAIL: %s Tag failed: %s", name, tagResp)
return false
}
// Get changes, get the blueprint's revision
changes, err := client.GetBlueprintsChangesV0(c.socket, []string{"test-tag-blueprint-v0"})
changes, api, err := client.GetBlueprintsChangesV0(c.socket, []string{"test-tag-blueprint-v0"})
if err != nil {
log.Printf("FAIL: %s GET changes failed: %s", name, err)
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
}
@ -793,25 +933,37 @@ func (c *checkBlueprintsV0) CheckBlueprintTagV0() bool {
}
// Push a new version of the blueprint
resp = client.PostJSONBlueprintV0(c.socket, bps[1])
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 != true {
log.Printf("FAIL: %s POST failed: %s", name, resp.Error())
log.Printf("FAIL: %s POST failed: %s", name, resp)
return false
}
// Tag the blueprint
tagResp = client.TagBlueprintV0(c.socket, "test-tag-blueprint-v0")
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 != true {
log.Printf("FAIL: %s Tag failed: %s", name, tagResp.Error())
log.Printf("FAIL: %s Tag failed: %s", name, tagResp)
return false
}
// Get changes, confirm that Revision is revision +1
changes, err = client.GetBlueprintsChangesV0(c.socket, []string{"test-tag-blueprint-v0"})
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)
@ -846,18 +998,26 @@ func (c *checkBlueprintsV0) CheckBlueprintDepsolveV0() bool {
}`
// Push a blueprint
resp := client.PostJSONBlueprintV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s POST failed: %s", name, resp.Error())
log.Printf("FAIL: %s POST failed: %s", name, resp)
return false
}
// Depsolve the blueprint
deps, err := client.DepsolveBlueprintV0(c.socket, "test-deps-blueprint-v0")
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)
@ -889,18 +1049,26 @@ func (c *checkBlueprintsV0) CheckBlueprintFreezeV0() bool {
}`
// Push a blueprint
resp := client.PostJSONBlueprintV0(c.socket, bp)
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 != true {
log.Printf("FAIL: %s POST failed: %s", name, resp.Error())
log.Printf("FAIL: %s POST failed: %s", name, resp)
return false
}
// Freeze the blueprint
frozen, err := client.FreezeBlueprintV0(c.socket, "test-freeze-blueprint-v0")
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)

View file

@ -69,9 +69,14 @@ func Run(socket string) {
os.Exit(1)
}
// Does the server respond to /api/status?
status, err := client.GetStatusV0(socket)
status, resp, err := client.GetStatusV0(socket)
if err != nil {
log.Printf("ERROR: status request failed: %s", err)
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)
}