Blame cmd/osbuild-composer-cli-tests/main_test.go

Packit Service 509fd4
// +build integration
Packit Service 509fd4
Packit Service 509fd4
package main
Packit Service 509fd4
Packit Service 509fd4
import (
Packit Service 509fd4
	"bytes"
Packit Service 509fd4
	"encoding/json"
Packit Service 15f37d
	"fmt"
Packit Service 509fd4
	"io/ioutil"
Packit Service 509fd4
	"log"
Packit Service 509fd4
	"os"
Packit Service 509fd4
	"os/exec"
Packit Service 15f37d
	"strings"
Packit Service 509fd4
	"time"
Packit Service 509fd4
Packit Service 509fd4
	"github.com/BurntSushi/toml"
Packit Service 509fd4
	"github.com/google/uuid"
Packit Service 509fd4
	"github.com/stretchr/testify/assert"
Packit Service 509fd4
	"github.com/stretchr/testify/require"
Packit Service 509fd4
Packit Service 509fd4
	"github.com/osbuild/osbuild-composer/internal/blueprint"
Packit Service 509fd4
	"github.com/osbuild/osbuild-composer/internal/weldr"
Packit Service 509fd4
Packit Service 509fd4
	"testing"
Packit Service 509fd4
)
Packit Service 509fd4
Packit Service 509fd4
func TestComposeCommands(t *testing.T) {
Packit Service 509fd4
	// common setup
Packit Service 509fd4
	tmpdir := NewTemporaryWorkDir(t, "osbuild-tests-")
Packit Service 509fd4
	defer tmpdir.Close(t)
Packit Service 509fd4
Packit Service 509fd4
	bp := blueprint.Blueprint{
Packit Service 509fd4
		Name:        "empty",
Packit Service 509fd4
		Description: "Test blueprint in toml format",
Packit Service 509fd4
		Packages: []blueprint.Package{{Name: "bash", Version: "*"}},
Packit Service 509fd4
	}
Packit Service 509fd4
	pushBlueprint(t, &bp)
Packit Service 509fd4
	defer deleteBlueprint(t, &bp)
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "blueprints", "save", "empty")
Packit Service 509fd4
	_, err := os.Stat("empty.toml")
Packit Service 509fd4
	require.NoError(t, err, "Error accessing 'empty.toml: %v'", err)
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "compose", "types")
Packit Service 509fd4
	runComposer(t, "compose", "status")
Packit Service 509fd4
	runComposer(t, "compose", "list")
Packit Service 509fd4
	runComposer(t, "compose", "list", "waiting")
Packit Service 509fd4
	runComposer(t, "compose", "list", "running")
Packit Service 509fd4
	runComposer(t, "compose", "list", "finished")
Packit Service 509fd4
	runComposer(t, "compose", "list", "failed")
Packit Service 509fd4
Packit Service 509fd4
	// Full integration tests
Packit Service 509fd4
	uuid := buildCompose(t, "empty", "qcow2")
Packit Service 509fd4
	defer deleteCompose(t, uuid)
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "compose", "info", uuid.String())
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "compose", "metadata", uuid.String())
Packit Service 509fd4
	_, err = os.Stat(uuid.String() + "-metadata.tar")
Packit Service 509fd4
	require.NoError(t, err, "'%s-metadata.tar' not found", uuid.String())
Packit Service 509fd4
	defer os.Remove(uuid.String() + "-metadata.tar")
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "compose", "results", uuid.String())
Packit Service 509fd4
	_, err = os.Stat(uuid.String() + ".tar")
Packit Service 509fd4
	require.NoError(t, err, "'%s.tar' not found", uuid.String())
Packit Service 509fd4
	defer os.Remove(uuid.String() + ".tar")
Packit Service 509fd4
Packit Service 509fd4
	// Just assert that result wasn't empty
Packit Service 509fd4
	result := runComposer(t, "compose", "log", uuid.String())
Packit Service 509fd4
	require.NotNil(t, result)
Packit Service 509fd4
	result = runComposer(t, "compose", "log", uuid.String(), "1024")
Packit Service 509fd4
	require.NotNil(t, result)
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "compose", "logs", uuid.String())
Packit Service 509fd4
	_, err = os.Stat(uuid.String() + "-logs.tar")
Packit Service 509fd4
	require.NoError(t, err, "'%s-logs.tar' not found", uuid.String())
Packit Service 509fd4
	defer os.Remove(uuid.String() + "-logs.tar")
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "compose", "image", uuid.String())
Packit Service 509fd4
	_, err = os.Stat(uuid.String() + "-disk.qcow2")
Packit Service 509fd4
	require.NoError(t, err, "'%s-disk.qcow2' not found", uuid.String())
Packit Service 509fd4
	defer os.Remove(uuid.String() + "-disk.qcow2")
Packit Service 509fd4
Packit Service 509fd4
	// workers ask the composer every 15 seconds if a compose was canceled.
Packit Service 509fd4
	// Use 20 seconds here to be sure this is hit.
Packit Service 509fd4
	uuid = startCompose(t, "empty", "qcow2")
Packit Service 509fd4
	defer deleteCompose(t, uuid)
Packit Service 509fd4
	runComposer(t, "compose", "cancel", uuid.String())
Packit Service 509fd4
	time.Sleep(20 * time.Second)
Packit Service 509fd4
	status := waitForCompose(t, uuid)
Packit Service 509fd4
	assert.Equal(t, "FAILED", status)
Packit Service 509fd4
Packit Service 509fd4
	// Check that reusing the cache works ok
Packit Service 509fd4
	uuid = buildCompose(t, "empty", "qcow2")
Packit Service 509fd4
	defer deleteCompose(t, uuid)
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func TestBlueprintCommands(t *testing.T) {
Packit Service 509fd4
	// common setup
Packit Service 509fd4
	tmpdir := NewTemporaryWorkDir(t, "osbuild-tests-")
Packit Service 509fd4
	defer tmpdir.Close(t)
Packit Service 509fd4
Packit Service 509fd4
	bp := blueprint.Blueprint{
Packit Service 509fd4
		Name:        "empty",
Packit Service 509fd4
		Description: "Test empty blueprint in toml format",
Packit Service 509fd4
	}
Packit Service 509fd4
	pushBlueprint(t, &bp)
Packit Service 509fd4
	defer deleteBlueprint(t, &bp)
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "blueprints", "list")
Packit Service 509fd4
	runComposer(t, "blueprints", "show", "empty")
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "blueprints", "changes", "empty")
Packit Service 509fd4
	runComposer(t, "blueprints", "diff", "empty", "NEWEST", "WORKSPACE")
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "blueprints", "save", "empty")
Packit Service 509fd4
	_, err := os.Stat("empty.toml")
Packit Service 509fd4
	require.NoError(t, err, "'empty.toml' not found")
Packit Service 509fd4
	defer os.Remove("empty.toml")
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "blueprints", "depsolve", "empty")
Packit Service 509fd4
	runComposer(t, "blueprints", "freeze", "empty")
Packit Service 509fd4
	runComposer(t, "blueprints", "freeze", "show", "empty")
Packit Service 509fd4
	runComposer(t, "blueprints", "freeze", "save", "empty")
Packit Service 509fd4
	_, err = os.Stat("empty.frozen.toml")
Packit Service 509fd4
	require.NoError(t, err, "'empty.frozen.toml' not found")
Packit Service 509fd4
	defer os.Remove("empty.frozen.toml")
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "blueprints", "tag", "empty")
Packit Service 509fd4
Packit Service 509fd4
	// undo the latest commit we can find
Packit Service 509fd4
	var changes weldr.BlueprintsChangesV0
Packit Service 509fd4
	rawReply := runComposerJSON(t, "blueprints", "changes", "empty")
Packit Service 509fd4
	err = json.Unmarshal(rawReply, &changes)
Packit Service 509fd4
	require.Nilf(t, err, "Error searching for commits to undo: %v", err)
Packit Service 509fd4
	runComposer(t, "blueprints", "undo", "empty", changes.BlueprintsChanges[0].Changes[0].Commit)
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "blueprints", "workspace", "empty")
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func TestModulesCommands(t *testing.T) {
Packit Service 509fd4
	runComposer(t, "modules", "list")
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func TestProjectsCommands(t *testing.T) {
Packit Service 509fd4
	runComposer(t, "projects", "list")
Packit Service 509fd4
	runComposer(t, "projects", "info", "filesystem")
Packit Service 509fd4
	runComposer(t, "projects", "info", "filesystem", "kernel")
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func TestStatusCommands(t *testing.T) {
Packit Service 509fd4
	runComposer(t, "status", "show")
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func TestSourcesCommands(t *testing.T) {
Packit Service 509fd4
	sources_toml, err := ioutil.TempFile("", "SOURCES-*.TOML")
Packit Service 509fd4
	require.NoErrorf(t, err, "Could not create temporary file: %v", err)
Packit Service 509fd4
	defer os.Remove(sources_toml.Name())
Packit Service 509fd4
Packit Service 509fd4
	_, err = sources_toml.Write([]byte(`id = "osbuild-test-addon-source"
Packit Service 509fd4
name = "Testing sources add command"
Packit Service 509fd4
url = "file://REPO-PATH"
Packit Service 509fd4
type = "yum-baseurl"
Packit Service 509fd4
proxy = "https://proxy-url/"
Packit Service 509fd4
check_ssl = true
Packit Service 509fd4
check_gpg = true
Packit Service 509fd4
gpgkey_urls = ["https://url/path/to/gpg-key"]
Packit Service 509fd4
`))
Packit Service 509fd4
	require.NoError(t, err)
Packit Service 509fd4
Packit Service 509fd4
	runComposer(t, "sources", "list")
Packit Service 509fd4
	runComposer(t, "sources", "add", sources_toml.Name())
Packit Service 509fd4
	runComposer(t, "sources", "info", "osbuild-test-addon-source")
Packit Service 509fd4
	runComposer(t, "sources", "change", sources_toml.Name())
Packit Service 509fd4
	runComposer(t, "sources", "delete", "osbuild-test-addon-source")
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func buildCompose(t *testing.T, bpName string, outputType string) uuid.UUID {
Packit Service 509fd4
	uuid := startCompose(t, bpName, outputType)
Packit Service 509fd4
	status := waitForCompose(t, uuid)
Packit Service 509fd4
	logs := getLogs(t, uuid)
Packit Service 509fd4
	assert.NotEmpty(t, logs, "logs are empty after the build is finished/failed")
Packit Service 509fd4
Packit Service 509fd4
	if !assert.Equalf(t, "FINISHED", status, "Unexpected compose result: %s", status) {
Packit Service 509fd4
		log.Print("logs from the build: ", logs)
Packit Service 509fd4
		t.FailNow()
Packit Service 509fd4
	}
Packit Service 509fd4
Packit Service 509fd4
	return uuid
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func startCompose(t *testing.T, name, outputType string) uuid.UUID {
Packit Service 509fd4
	var reply struct {
Packit Service 509fd4
		BuildID uuid.UUID `json:"build_id"`
Packit Service 509fd4
		Status  bool      `json:"status"`
Packit Service 509fd4
	}
Packit Service 509fd4
	rawReply := runComposerJSON(t, "compose", "start", name, outputType)
Packit Service 509fd4
	err := json.Unmarshal(rawReply, &reply)
Packit Service 509fd4
	require.Nilf(t, err, "Unexpected reply: %v", err)
Packit Service 509fd4
	require.Truef(t, reply.Status, "Unexpected status %v", reply.Status)
Packit Service 509fd4
Packit Service 509fd4
	return reply.BuildID
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func deleteCompose(t *testing.T, id uuid.UUID) {
Packit Service 509fd4
	type deleteUUID struct {
Packit Service 509fd4
		ID     uuid.UUID `json:"uuid"`
Packit Service 509fd4
		Status bool      `json:"status"`
Packit Service 509fd4
	}
Packit Service 509fd4
	var reply struct {
Packit Service 509fd4
		IDs    []deleteUUID  `json:"uuids"`
Packit Service 509fd4
		Errors []interface{} `json:"errors"`
Packit Service 509fd4
	}
Packit Service 509fd4
	rawReply := runComposerJSON(t, "compose", "delete", id.String())
Packit Service 509fd4
	err := json.Unmarshal(rawReply, &reply)
Packit Service 509fd4
	require.Nilf(t, err, "Unexpected reply: %v", err)
Packit Service 509fd4
	require.Zerof(t, len(reply.Errors), "Unexpected errors")
Packit Service 509fd4
	require.Equalf(t, 1, len(reply.IDs), "Unexpected number of UUIDs returned: %d", len(reply.IDs))
Packit Service 509fd4
	require.Truef(t, reply.IDs[0].Status, "Unexpected status %v", reply.IDs[0].Status)
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func waitForCompose(t *testing.T, uuid uuid.UUID) string {
Packit Service 509fd4
	for {
Packit Service 509fd4
		status := getComposeStatus(t, uuid)
Packit Service 509fd4
		if status == "FINISHED" || status == "FAILED" {
Packit Service 509fd4
			return status
Packit Service 509fd4
		}
Packit Service 509fd4
		time.Sleep(time.Second)
Packit Service 509fd4
	}
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func getComposeStatus(t *testing.T, uuid uuid.UUID) string {
Packit Service 509fd4
	var reply struct {
Packit Service 509fd4
		QueueStatus string `json:"queue_status"`
Packit Service 509fd4
	}
Packit Service 509fd4
	rawReply := runComposerJSON(t, "compose", "info", uuid.String())
Packit Service 509fd4
	err := json.Unmarshal(rawReply, &reply)
Packit Service 509fd4
	require.Nilf(t, err, "Unexpected reply: %v", err)
Packit Service 509fd4
Packit Service 509fd4
	return reply.QueueStatus
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func getLogs(t *testing.T, uuid uuid.UUID) string {
Packit Service 509fd4
	cmd := exec.Command("composer-cli", "compose", "log", uuid.String())
Packit Service 509fd4
	cmd.Stderr = os.Stderr
Packit Service 509fd4
	stdoutReader, err := cmd.StdoutPipe()
Packit Service 509fd4
	require.NoError(t, err)
Packit Service 509fd4
Packit Service 509fd4
	err = cmd.Start()
Packit Service 509fd4
	require.NoError(t, err)
Packit Service 509fd4
Packit Service 509fd4
	var buffer bytes.Buffer
Packit Service 509fd4
	_, err = buffer.ReadFrom(stdoutReader)
Packit Service 509fd4
	require.NoError(t, err)
Packit Service 509fd4
Packit Service 509fd4
	err = cmd.Wait()
Packit Service 509fd4
	require.NoError(t, err)
Packit Service 509fd4
Packit Service 509fd4
	return buffer.String()
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func pushBlueprint(t *testing.T, bp *blueprint.Blueprint) {
Packit Service 509fd4
	tmpfile, err := ioutil.TempFile("", "osbuild-test-")
Packit Service 509fd4
	require.Nilf(t, err, "Could not create temporary file: %v", err)
Packit Service 509fd4
	defer os.Remove(tmpfile.Name())
Packit Service 509fd4
Packit Service 509fd4
	err = toml.NewEncoder(tmpfile).Encode(bp)
Packit Service 509fd4
	require.Nilf(t, err, "Could not marshal blueprint TOML: %v", err)
Packit Service 509fd4
	err = tmpfile.Close()
Packit Service 509fd4
	require.Nilf(t, err, "Could not close toml file: %v", err)
Packit Service 509fd4
Packit Service 509fd4
	var reply struct {
Packit Service 509fd4
		Status bool `json:"status"`
Packit Service 509fd4
	}
Packit Service 509fd4
	rawReply := runComposerJSON(t, "blueprints", "push", tmpfile.Name())
Packit Service 509fd4
	err = json.Unmarshal(rawReply, &reply)
Packit Service 509fd4
	require.Nilf(t, err, "Unexpected reply: %v", err)
Packit Service 509fd4
	require.Truef(t, reply.Status, "Unexpected status %v", reply.Status)
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func deleteBlueprint(t *testing.T, bp *blueprint.Blueprint) {
Packit Service 509fd4
	var reply struct {
Packit Service 509fd4
		Status bool `json:"status"`
Packit Service 509fd4
	}
Packit Service 509fd4
	rawReply := runComposerJSON(t, "blueprints", "delete", bp.Name)
Packit Service 509fd4
	err := json.Unmarshal(rawReply, &reply)
Packit Service 509fd4
	require.Nilf(t, err, "Unexpected reply: %v", err)
Packit Service 509fd4
	require.Truef(t, reply.Status, "Unexpected status %v", reply.Status)
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func runComposer(t *testing.T, command ...string) []byte {
Packit Service 15f37d
	fmt.Printf("Running composer-cli %s\n", strings.Join(command, " "))
Packit Service 509fd4
	cmd := exec.Command("composer-cli", command...)
Packit Service 509fd4
	stdout, err := cmd.StdoutPipe()
Packit Service 509fd4
	require.Nilf(t, err, "Could not create command: %v", err)
Packit Service 15f37d
	stderr, err := cmd.StderrPipe()
Packit Service 15f37d
	require.Nilf(t, err, "Could not create command: %v", err)
Packit Service 509fd4
Packit Service 509fd4
	err = cmd.Start()
Packit Service 509fd4
	require.Nilf(t, err, "Could not start command: %v", err)
Packit Service 509fd4
Packit Service 509fd4
	contents, err := ioutil.ReadAll(stdout)
Packit Service 509fd4
	require.NoError(t, err, "Could not read stdout from command")
Packit Service 509fd4
Packit Service 15f37d
	errcontents, err := ioutil.ReadAll(stderr)
Packit Service 15f37d
	require.NoError(t, err, "Could not read stderr from command")
Packit Service 15f37d
Packit Service 509fd4
	err = cmd.Wait()
Packit Service 15f37d
	require.NoErrorf(t, err, "Command failed (%v): %v", err, string(errcontents))
Packit Service 509fd4
Packit Service 509fd4
	return contents
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
func runComposerJSON(t *testing.T, command ...string) json.RawMessage {
Packit Service 509fd4
	command = append([]string{"--json"}, command...)
Packit Service 509fd4
	contents := runComposer(t, command...)
Packit Service 509fd4
Packit Service 509fd4
	var result json.RawMessage
Packit Service 509fd4
Packit Service 509fd4
	if len(contents) != 0 {
Packit Service 509fd4
		err := json.Unmarshal(contents, &result)
Packit Service 509fd4
		if err != nil {
Packit Service 509fd4
			// We did not get JSON, try interpreting it as TOML
Packit Service 509fd4
			var data interface{}
Packit Service 509fd4
			err = toml.Unmarshal(contents, &data)
Packit Service 509fd4
			require.Nilf(t, err, "Could not parse output: %v", err)
Packit Service 509fd4
			buffer := bytes.Buffer{}
Packit Service 509fd4
			err = json.NewEncoder(&buffer).Encode(data)
Packit Service 509fd4
			require.Nilf(t, err, "Could not remarshal TOML to JSON: %v", err)
Packit Service 509fd4
			err = json.NewDecoder(&buffer).Decode(&result)
Packit Service 509fd4
			require.Nilf(t, err, "Could not decode the remarshalled JSON: %v", err)
Packit Service 509fd4
		}
Packit Service 509fd4
	}
Packit Service 509fd4
Packit Service 509fd4
	buffer := bytes.Buffer{}
Packit Service 509fd4
	encoder := json.NewEncoder(&buffer)
Packit Service 509fd4
	encoder.SetIndent("", "  ")
Packit Service 509fd4
	err := encoder.Encode(result)
Packit Service 509fd4
	require.Nilf(t, err, "Could not remarshal the recevied JSON: %v", err)
Packit Service 509fd4
Packit Service 509fd4
	return result
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
type TemporaryWorkDir struct {
Packit Service 509fd4
	OldWorkDir string
Packit Service 509fd4
	Path       string
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
// Creates a new temporary directory based on pattern and changes the current
Packit Service 509fd4
// working directory to it.
Packit Service 509fd4
//
Packit Service 509fd4
// Example:
Packit Service 509fd4
//   d := NewTemporaryWorkDir(t, "foo-*")
Packit Service 509fd4
//   defer d.Close(t)
Packit Service 509fd4
func NewTemporaryWorkDir(t *testing.T, pattern string) TemporaryWorkDir {
Packit Service 509fd4
	var d TemporaryWorkDir
Packit Service 509fd4
	var err error
Packit Service 509fd4
Packit Service 509fd4
	d.OldWorkDir, err = os.Getwd()
Packit Service 509fd4
	require.Nilf(t, err, "os.GetWd: %v", err)
Packit Service 509fd4
Packit Service 509fd4
	d.Path, err = ioutil.TempDir("", pattern)
Packit Service 509fd4
	require.Nilf(t, err, "ioutil.TempDir: %v", err)
Packit Service 509fd4
Packit Service 509fd4
	err = os.Chdir(d.Path)
Packit Service 509fd4
	require.Nilf(t, err, "os.ChDir: %v", err)
Packit Service 509fd4
Packit Service 509fd4
	return d
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
// Change back to the previous working directory and removes the temporary one.
Packit Service 509fd4
func (d *TemporaryWorkDir) Close(t *testing.T) {
Packit Service 509fd4
	var err error
Packit Service 509fd4
Packit Service 509fd4
	err = os.Chdir(d.OldWorkDir)
Packit Service 509fd4
	require.Nilf(t, err, "os.ChDir: %v", err)
Packit Service 509fd4
Packit Service 509fd4
	err = os.RemoveAll(d.Path)
Packit Service 509fd4
	require.Nilf(t, err, "os.RemoveAll: %v", err)
Packit Service 509fd4
}