Add weldrcheck package to hold the integration tests

These tests build on the client functions to run integration tests on a
running API server.

It uses the reflect module to examine the methods attached to the
checkBlueprintsV0 struct and run the ones with names that start with
'Check', also checking the type signature of the functions and failing
the test if any of them don't match.

This will make it easier to add more checks without needing to add
boilerplate call/registration of the functions in the top level runner.
Just add the new function with the right name and signature and it will
be run when checkBlueprintsV0.Run() is called.

Checks for other API routes should be added to their own modules. There
will be some duplication of the Run function in each, but I think that
it will help keep things more manageable by separating them instead of
putting them all into a single giant Run() call.
This commit is contained in:
Brian C. Lane 2020-02-13 17:28:37 -08:00 committed by Tom Gundersen
parent ea1b633d3a
commit f298fed16d
2 changed files with 1044 additions and 0 deletions

View file

@ -0,0 +1,941 @@
// Package weldrcheck - blueprints contains functions to check the blueprints API
// Copyright (C) 2020 by Red Hat, Inc.
package weldrcheck
import (
"log"
"reflect"
"sort"
"strings"
"github.com/BurntSushi/toml"
"github.com/osbuild/osbuild-composer/internal/client"
)
type checkBlueprintsV0 struct {
socket string
}
// 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 := client.PostTOMLBlueprintV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
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 := client.PostJSONBlueprintV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
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 := client.PostTOMLWorkspaceV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
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 := client.PostJSONWorkspaceV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
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 := client.PostJSONBlueprintV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
return false
}
// Delete the blueprint
resp = client.DeleteBlueprintV0(c.socket, "test-delete-blueprint-v0")
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
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 := client.PostJSONWorkspaceV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
return false
}
// Delete the blueprint
resp = client.DeleteWorkspaceV0(c.socket, "test-delete-new-blueprint-ws-v0")
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
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 := client.PostJSONBlueprintV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
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 = client.PostJSONWorkspaceV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
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")
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err)
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 != true {
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 = client.DeleteWorkspaceV0(c.socket, "test-delete-blueprint-changes-ws-v0")
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
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")
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err)
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 != false {
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 := client.PostJSONBlueprintV0(c.socket, bps[i])
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
return false
}
}
// Get the list of blueprints
list, err := client.ListBlueprintsV0(c.socket)
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err.Error())
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 := client.PostJSONBlueprintV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
return false
}
// Get it as TOML
body, err := client.GetBlueprintInfoTOMLV0(c.socket, "test-get-blueprint-1-v0")
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err)
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 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 := client.PostJSONBlueprintV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
return false
}
// Get the blueprint and its changed state
info, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-get-blueprint-2-v0")
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err)
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 != false {
log.Printf("FAIL: %s failed: unexpected changes", name)
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, err := client.ListBlueprintsV0(c.socket)
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err.Error())
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")
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
return false
}
}
// Post a blueprint
resp := client.PostJSONBlueprintV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
return false
}
// Post a blueprint again to bump verion to 2.1.3
resp = client.PostJSONBlueprintV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
return false
}
// Get the blueprint and its changed state
info, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-bump-blueprint-1-v0")
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err)
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 := client.PostJSONBlueprintV0(c.socket, bps[i])
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
return false
}
}
// List the changes
changes, err := client.GetBlueprintsChangesV0(c.socket, []string{"test-blueprint-changes-v0"})
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err)
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
}
// 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 := client.PostJSONBlueprintV0(c.socket, bps[0])
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
return false
}
// Get the commit hash
changes, err := client.GetBlueprintsChangesV0(c.socket, []string{"test-undo-blueprint-v0"})
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err)
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 = client.PostJSONBlueprintV0(c.socket, bps[1])
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
return false
}
// Get the blueprint, confirm bash version is '0.5.*'
info, err := client.GetBlueprintsInfoJSONV0(c.socket, "test-undo-blueprint-v0")
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err)
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 = client.UndoBlueprintChangeV0(c.socket, "test-undo-blueprint-v0", commit)
if resp.Status != true {
log.Printf("FAIL: %s failed: %s", name, resp.Error())
return false
}
// Get the blueprint, confirm bash version is '*'
info, err = client.GetBlueprintsInfoJSONV0(c.socket, "test-undo-blueprint-v0")
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err)
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
}
// 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 := client.PostJSONBlueprintV0(c.socket, bps[0])
if resp.Status != true {
log.Printf("FAIL: %s POST failed: %s", name, resp.Error())
return false
}
// Tag the blueprint
tagResp := client.TagBlueprintV0(c.socket, "test-tag-blueprint-v0")
if tagResp.Status != true {
log.Printf("FAIL: %s Tag failed: %s", name, tagResp.Error())
return false
}
// Get changes, get the blueprint's revision
changes, err := client.GetBlueprintsChangesV0(c.socket, []string{"test-tag-blueprint-v0"})
if err != nil {
log.Printf("FAIL: %s GET changes failed: %s", name, err)
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 = client.PostJSONBlueprintV0(c.socket, bps[1])
if resp.Status != true {
log.Printf("FAIL: %s POST failed: %s", name, resp.Error())
return false
}
// Tag the blueprint
tagResp = client.TagBlueprintV0(c.socket, "test-tag-blueprint-v0")
if tagResp.Status != true {
log.Printf("FAIL: %s Tag failed: %s", name, tagResp.Error())
return false
}
// Get changes, confirm that Revision is revision +1
changes, err = client.GetBlueprintsChangesV0(c.socket, []string{"test-tag-blueprint-v0"})
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err)
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
}
// 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 := client.PostJSONBlueprintV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s POST failed: %s", name, resp.Error())
return false
}
// Depsolve the blueprint
deps, err := client.DepsolveBlueprintV0(c.socket, "test-deps-blueprint-v0")
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err.Error())
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
}
// 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 := client.PostJSONBlueprintV0(c.socket, bp)
if resp.Status != true {
log.Printf("FAIL: %s POST failed: %s", name, resp.Error())
return false
}
// Freeze the blueprint
frozen, err := client.FreezeBlueprintV0(c.socket, "test-freeze-blueprint-v0")
if err != nil {
log.Printf("FAIL: %s failed: %s", name, err.Error())
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
}
// 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
}

View file

@ -0,0 +1,103 @@
// 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"
"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 string) (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 string) (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 string) {
log.Printf("Running API check on %s", socket)
// Does the socket exist?
if _, err := os.Stat(socket); os.IsNotExist(err) {
log.Printf("ERROR: API socket %s is missing", socket)
os.Exit(1)
}
// Does the server respond to /api/status?
status, err := client.GetStatusV0(socket)
if err != nil {
log.Printf("ERROR: status request failed: %s", err)
// 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)
}