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-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/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/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/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/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 +}