Blame cmd/osbuild-image-tests/main_test.go

Packit 63bb0d
// +build integration
Packit 63bb0d
Packit 63bb0d
package main
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"bytes"
Packit 63bb0d
	"context"
Packit 63bb0d
	"encoding/json"
Packit 63bb0d
	"flag"
Packit 63bb0d
	"fmt"
Packit 63bb0d
	"io"
Packit 63bb0d
	"io/ioutil"
Packit 63bb0d
	"log"
Packit 63bb0d
	"os"
Packit 63bb0d
	"os/exec"
Packit 63bb0d
	"path"
Packit Service 15f37d
	"path/filepath"
Packit 63bb0d
	"strings"
Packit 63bb0d
	"testing"
Packit 63bb0d
	"time"
Packit 63bb0d
Packit 63bb0d
	"github.com/gophercloud/gophercloud"
Packit 63bb0d
	"github.com/gophercloud/gophercloud/openstack"
Packit 63bb0d
	"github.com/stretchr/testify/assert"
Packit 63bb0d
	"github.com/stretchr/testify/require"
Packit 63bb0d
Packit 63bb0d
	"github.com/osbuild/osbuild-composer/cmd/osbuild-image-tests/constants"
Packit Service 509fd4
	"github.com/osbuild/osbuild-composer/internal/boot"
Packit Service 509fd4
	"github.com/osbuild/osbuild-composer/internal/boot/azuretest"
Packit Service 509fd4
	"github.com/osbuild/osbuild-composer/internal/boot/openstacktest"
Packit Service 509fd4
	"github.com/osbuild/osbuild-composer/internal/boot/vmwaretest"
Packit 63bb0d
	"github.com/osbuild/osbuild-composer/internal/common"
Packit Service 509fd4
	"github.com/osbuild/osbuild-composer/internal/test"
Packit Service 509fd4
	"github.com/osbuild/osbuild-composer/internal/upload/vmware"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
type testcaseStruct struct {
Packit 63bb0d
	ComposeRequest struct {
Packit 63bb0d
		Distro   string
Packit 63bb0d
		Arch     string
Packit 63bb0d
		Filename string
Packit 63bb0d
	} `json:"compose-request"`
Packit 63bb0d
	Manifest  json.RawMessage
Packit 63bb0d
	ImageInfo json.RawMessage `json:"image-info"`
Packit 63bb0d
	Boot      *struct {
Packit 63bb0d
		Type string
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
var disableLocalBoot = flag.Bool("disable-local-boot", false, "when this flag is given, no images are booted locally using qemu (this does not affect testing in clouds)")
Packit Service 509fd4
var failLocalBoot = flag.Bool("fail-local-boot", true, "when this flag is on (default), local boot will fail. Usually indicates missing cloud credentials")
Packit 63bb0d
Packit 63bb0d
// runOsbuild runs osbuild with the specified manifest and output-directory.
Packit Service 15f37d
func runOsbuild(manifest []byte, store, outputDirectory string, exports []string) error {
Packit Service 15f37d
	cmd := constants.GetOsbuildCommand(store, outputDirectory, exports)
Packit 63bb0d
Packit 63bb0d
	cmd.Stdin = bytes.NewReader(manifest)
Packit 63bb0d
	var outBuffer bytes.Buffer
Packit 63bb0d
	cmd.Stdout = &outBuffer
Packit 63bb0d
	cmd.Stderr = &outBuffer
Packit 63bb0d
Packit 63bb0d
	err := cmd.Run()
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		// Pretty print the osbuild error output.
Packit 63bb0d
		buf := new(bytes.Buffer)
Packit 63bb0d
		_ = json.Indent(buf, outBuffer.Bytes(), "", "    ")
Packit 63bb0d
		fmt.Println(buf)
Packit 63bb0d
Packit 63bb0d
		return fmt.Errorf("running osbuild failed: %v", err)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// testImageInfo runs image-info on image specified by imageImage and
Packit 63bb0d
// compares the result with expected image info
Packit 63bb0d
func testImageInfo(t *testing.T, imagePath string, rawImageInfoExpected []byte) {
Packit 63bb0d
	var imageInfoExpected interface{}
Packit 63bb0d
	err := json.Unmarshal(rawImageInfoExpected, &imageInfoExpected)
Packit Service 509fd4
	require.NoErrorf(t, err, "cannot decode expected image info: %v", err)
Packit 63bb0d
Packit 63bb0d
	cmd := constants.GetImageInfoCommand(imagePath)
Packit 63bb0d
	cmd.Stderr = os.Stderr
Packit 63bb0d
	reader, writer := io.Pipe()
Packit 63bb0d
	cmd.Stdout = writer
Packit 63bb0d
Packit 63bb0d
	err = cmd.Start()
Packit Service 509fd4
	require.NoErrorf(t, err, "image-info cannot start: %v", err)
Packit 63bb0d
Packit 63bb0d
	var imageInfoGot interface{}
Packit 63bb0d
	err = json.NewDecoder(reader).Decode(&imageInfoGot)
Packit Service 509fd4
	require.NoErrorf(t, err, "decoding image-info output failed: %v", err)
Packit 63bb0d
Packit 63bb0d
	err = cmd.Wait()
Packit Service 509fd4
	require.NoErrorf(t, err, "running image-info failed: %v", err)
Packit 63bb0d
Packit 63bb0d
	assert.Equal(t, imageInfoExpected, imageInfoGot)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
type timeoutError struct{}
Packit 63bb0d
Packit 63bb0d
func (*timeoutError) Error() string { return "" }
Packit 63bb0d
Packit 63bb0d
// trySSHOnce tries to test the running image using ssh once
Packit 63bb0d
// It returns timeoutError if ssh command returns 255, if it runs for more
Packit 63bb0d
// that 10 seconds or if systemd-is-running returns starting.
Packit 63bb0d
// It returns nil if systemd-is-running returns running or degraded.
Packit 63bb0d
// It can also return other errors in other error cases.
Packit Service 509fd4
func trySSHOnce(address string, privateKey string, ns *boot.NetNS) error {
Packit 63bb0d
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
Packit 63bb0d
	defer cancel()
Packit 63bb0d
Packit 63bb0d
	cmdName := "ssh"
Packit 63bb0d
	cmdArgs := []string{
Packit 63bb0d
		"-p", "22",
Packit 63bb0d
		"-i", privateKey,
Packit 63bb0d
		"-o", "StrictHostKeyChecking=no",
Packit 63bb0d
		"-o", "UserKnownHostsFile=/dev/null",
Packit 63bb0d
		"redhat@" + address,
Packit 63bb0d
		"systemctl --wait is-system-running",
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	var cmd *exec.Cmd
Packit 63bb0d
Packit 63bb0d
	if ns != nil {
Packit 63bb0d
		cmd = ns.NamespacedCommandContext(ctx, cmdName, cmdArgs...)
Packit 63bb0d
	} else {
Packit 63bb0d
		cmd = exec.CommandContext(ctx, cmdName, cmdArgs...)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	output, err := cmd.Output()
Packit 63bb0d
Packit 63bb0d
	if ctx.Err() == context.DeadlineExceeded {
Packit 63bb0d
		return &timeoutError{}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		if exitError, ok := err.(*exec.ExitError); ok {
Packit 63bb0d
			if exitError.ExitCode() == 255 {
Packit 63bb0d
				return &timeoutError{}
Packit 63bb0d
			}
Packit 63bb0d
		} else {
Packit Service 509fd4
			return fmt.Errorf("ssh command failed from unknown reason: %v", err)
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	outputString := strings.TrimSpace(string(output))
Packit 63bb0d
	switch outputString {
Packit 63bb0d
	case "running":
Packit 63bb0d
		return nil
Packit 63bb0d
	case "degraded":
Packit 63bb0d
		log.Print("ssh test passed, but the system is degraded")
Packit 63bb0d
		return nil
Packit 63bb0d
	case "starting":
Packit 63bb0d
		return &timeoutError{}
Packit 63bb0d
	default:
Packit 63bb0d
		return fmt.Errorf("ssh test failed, system status is: %s", outputString)
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// testSSH tests the running image using ssh.
Packit 63bb0d
// It tries 20 attempts before giving up. If a major error occurs, it might
Packit 63bb0d
// return earlier.
Packit Service 509fd4
func testSSH(t *testing.T, address string, privateKey string, ns *boot.NetNS) {
Packit 63bb0d
	const attempts = 20
Packit 63bb0d
	for i := 0; i < attempts; i++ {
Packit 63bb0d
		err := trySSHOnce(address, privateKey, ns)
Packit 63bb0d
		if err == nil {
Packit 63bb0d
			// pass the test
Packit 63bb0d
			return
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		// if any other error than the timeout one happened, fail the test immediately
Packit 63bb0d
		if _, ok := err.(*timeoutError); !ok {
Packit 63bb0d
			t.Fatal(err)
Packit 63bb0d
		}
Packit 63bb0d
Packit Service 509fd4
		fmt.Println(err)
Packit 63bb0d
		time.Sleep(10 * time.Second)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	t.Errorf("ssh test failure, %d attempts were made", attempts)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func testBootUsingQemu(t *testing.T, imagePath string) {
Packit Service 509fd4
	if *failLocalBoot {
Packit Service 509fd4
		t.Fatal("-fail-local-boot specified. Check missing cloud credentials!")
Packit Service 509fd4
	}
Packit Service 509fd4
Packit Service 509fd4
	bootWithQemu(t, imagePath)
Packit Service 509fd4
}
Packit Service 509fd4
Packit Service 509fd4
// will not fail even if -fail-local-boot is specified
Packit Service 509fd4
func bootWithQemu(t *testing.T, imagePath string) {
Packit 63bb0d
	if *disableLocalBoot {
Packit 63bb0d
		t.Skip("local booting was disabled by -disable-local-boot, skipping")
Packit 63bb0d
	}
Packit Service 509fd4
	err := boot.WithNetworkNamespace(func(ns boot.NetNS) error {
Packit Service 509fd4
		return boot.WithBootedQemuImage(imagePath, ns, func() error {
Packit 63bb0d
			testSSH(t, "localhost", constants.TestPaths.PrivateKey, &ns)
Packit 63bb0d
			return nil
Packit 63bb0d
		})
Packit 63bb0d
	})
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func testBootUsingNspawnImage(t *testing.T, imagePath string) {
Packit Service 509fd4
	err := boot.WithNetworkNamespace(func(ns boot.NetNS) error {
Packit Service 509fd4
		return boot.WithBootedNspawnImage(imagePath, ns, func() error {
Packit 63bb0d
			testSSH(t, "localhost", constants.TestPaths.PrivateKey, &ns)
Packit 63bb0d
			return nil
Packit 63bb0d
		})
Packit 63bb0d
	})
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func testBootUsingNspawnDirectory(t *testing.T, imagePath string) {
Packit Service 509fd4
	err := boot.WithNetworkNamespace(func(ns boot.NetNS) error {
Packit Service 509fd4
		return boot.WithExtractedTarArchive(imagePath, func(dir string) error {
Packit Service 509fd4
			return boot.WithBootedNspawnDirectory(dir, ns, func() error {
Packit 63bb0d
				testSSH(t, "localhost", constants.TestPaths.PrivateKey, &ns)
Packit 63bb0d
				return nil
Packit 63bb0d
			})
Packit 63bb0d
		})
Packit 63bb0d
	})
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func testBootUsingAWS(t *testing.T, imagePath string) {
Packit Service 509fd4
	creds, err := boot.GetAWSCredentialsFromEnv()
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
Packit 63bb0d
	// if no credentials are given, fall back to qemu
Packit 63bb0d
	if creds == nil {
Packit 63bb0d
		log.Print("no AWS credentials given, falling back to booting using qemu")
Packit 63bb0d
		testBootUsingQemu(t, imagePath)
Packit 63bb0d
		return
Packit 63bb0d
Packit 63bb0d
	}
Packit 63bb0d
Packit Service 509fd4
	imageName, err := test.GenerateCIArtifactName("osbuild-image-tests-image-")
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
Packit Service 509fd4
	e, err := boot.NewEC2(creds)
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
Packit 63bb0d
	// the following line should be done by osbuild-composer at some point
Packit Service 509fd4
	err = boot.UploadImageToAWS(creds, imagePath, imageName)
Packit 63bb0d
	require.NoErrorf(t, err, "upload to amazon failed, resources could have been leaked")
Packit 63bb0d
Packit Service 509fd4
	imageDesc, err := boot.DescribeEC2Image(e, imageName)
Packit 63bb0d
	require.NoErrorf(t, err, "cannot describe the ec2 image")
Packit 63bb0d
Packit 63bb0d
	// delete the image after the test is over
Packit 63bb0d
	defer func() {
Packit Service 509fd4
		err = boot.DeleteEC2Image(e, imageDesc)
Packit 63bb0d
		require.NoErrorf(t, err, "cannot delete the ec2 image, resources could have been leaked")
Packit 63bb0d
	}()
Packit 63bb0d
Packit Service 509fd4
	securityGroupName, err := test.GenerateCIArtifactName("osbuild-image-tests-security-group-")
Packit Service 509fd4
	require.NoError(t, err)
Packit Service 509fd4
Packit Service 509fd4
	instanceTypeForArch := map[string]string{
Packit Service 509fd4
		"x86_64":  "t3.micro",
Packit Service 509fd4
		"aarch64": "t4g.micro",
Packit Service 509fd4
	}
Packit Service 509fd4
Packit Service 509fd4
	instanceType, exists := instanceTypeForArch[common.CurrentArch()]
Packit Service 509fd4
	if !exists {
Packit Service 509fd4
		panic("unsupported AWS arch")
Packit Service 509fd4
	}
Packit Service 509fd4
Packit 63bb0d
	// boot the uploaded image and try to connect to it
Packit Service 509fd4
	err = boot.WithSSHKeyPair(func(privateKey, publicKey string) error {
Packit Service 509fd4
		return boot.WithBootedImageInEC2(e, securityGroupName, imageDesc, publicKey, instanceType, func(address string) error {
Packit 63bb0d
			testSSH(t, address, privateKey, nil)
Packit 63bb0d
			return nil
Packit 63bb0d
		})
Packit 63bb0d
	})
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func testBootUsingAzure(t *testing.T, imagePath string) {
Packit 63bb0d
	creds, err := azuretest.GetAzureCredentialsFromEnv()
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
Packit 63bb0d
	// if no credentials are given, fall back to qemu
Packit 63bb0d
	if creds == nil {
Packit 63bb0d
		log.Print("no Azure credentials given, falling back to booting using qemu")
Packit 63bb0d
		testBootUsingQemu(t, imagePath)
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// create a random test id to name all the resources used in this test
Packit Service 509fd4
	testId, err := test.GenerateCIArtifactName("")
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
Packit 63bb0d
	imageName := "image-" + testId + ".vhd"
Packit 63bb0d
Packit 63bb0d
	// the following line should be done by osbuild-composer at some point
Packit 63bb0d
	err = azuretest.UploadImageToAzure(creds, imagePath, imageName)
Packit 63bb0d
	require.NoErrorf(t, err, "upload to azure failed, resources could have been leaked")
Packit 63bb0d
Packit 63bb0d
	// delete the image after the test is over
Packit 63bb0d
	defer func() {
Packit 63bb0d
		err = azuretest.DeleteImageFromAzure(creds, imageName)
Packit 63bb0d
		require.NoErrorf(t, err, "cannot delete the azure image, resources could have been leaked")
Packit 63bb0d
	}()
Packit 63bb0d
Packit 63bb0d
	// boot the uploaded image and try to connect to it
Packit Service 509fd4
	err = boot.WithSSHKeyPair(func(privateKey, publicKey string) error {
Packit 63bb0d
		return azuretest.WithBootedImageInAzure(creds, imageName, testId, publicKey, func(address string) error {
Packit 63bb0d
			testSSH(t, address, privateKey, nil)
Packit 63bb0d
			return nil
Packit 63bb0d
		})
Packit 63bb0d
	})
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func testBootUsingOpenStack(t *testing.T, imagePath string) {
Packit 63bb0d
	creds, err := openstack.AuthOptionsFromEnv()
Packit 63bb0d
Packit 63bb0d
	// if no credentials are given, fall back to qemu
Packit 63bb0d
	if (creds == gophercloud.AuthOptions{}) {
Packit 63bb0d
		log.Print("No OpenStack credentials given, falling back to booting using qemu")
Packit 63bb0d
		testBootUsingQemu(t, imagePath)
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
Packit 63bb0d
	// provider is the top-level client that all OpenStack services derive from
Packit 63bb0d
	provider, err := openstack.AuthenticatedClient(creds)
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
Packit 63bb0d
	// create a random test id to name all the resources used in this test
Packit Service 509fd4
	imageName, err := test.GenerateCIArtifactName("osbuild-image-tests-openstack-image-")
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
Packit 63bb0d
	// the following line should be done by osbuild-composer at some point
Packit 63bb0d
	image, err := openstacktest.UploadImageToOpenStack(provider, imagePath, imageName)
Packit 63bb0d
	require.NoErrorf(t, err, "Upload to OpenStack failed, resources could have been leaked")
Packit 63bb0d
	require.NotNil(t, image)
Packit 63bb0d
Packit 63bb0d
	// delete the image after the test is over
Packit 63bb0d
	defer func() {
Packit 63bb0d
		err = openstacktest.DeleteImageFromOpenStack(provider, image.ID)
Packit 63bb0d
		require.NoErrorf(t, err, "Cannot delete OpenStack image, resources could have been leaked")
Packit 63bb0d
	}()
Packit 63bb0d
Packit 63bb0d
	// boot the uploaded image and try to connect to it
Packit Service 509fd4
	err = boot.WithSSHKeyPair(func(privateKey, publicKey string) error {
Packit Service 509fd4
		userData, err := boot.CreateUserData(publicKey)
Packit 63bb0d
		require.NoErrorf(t, err, "Creating user data failed: %v", err)
Packit 63bb0d
Packit 63bb0d
		return openstacktest.WithBootedImageInOpenStack(provider, image.ID, userData, func(address string) error {
Packit 63bb0d
			testSSH(t, address, privateKey, nil)
Packit 63bb0d
			return nil
Packit 63bb0d
		})
Packit 63bb0d
	})
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func testBootUsingVMware(t *testing.T, imagePath string) {
Packit 63bb0d
	creds, err := vmwaretest.AuthOptionsFromEnv()
Packit 63bb0d
Packit 63bb0d
	// if no credentials are given, fall back to qemu
Packit Service 509fd4
	if creds == nil {
Packit 63bb0d
		log.Print("No vCenter credentials given, falling back to booting using qemu")
Packit 63bb0d
		log.Printf("Error=%v", err)
Packit 63bb0d
		testBootUsingQemu(t, imagePath)
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
Packit 63bb0d
	// convert to streamOptimized vmdk
Packit Service 509fd4
	imageF, err := vmware.OpenAsStreamOptimizedVmdk(imagePath)
Packit 63bb0d
	require.NoError(t, err)
Packit Service 509fd4
	// we don't need the file descriptor to be opened b/c import.vmdk operates
Packit Service 509fd4
	// on the file path
Packit Service 509fd4
	imageF.Close()
Packit Service 509fd4
	imagePath = imageF.Name()
Packit 63bb0d
	require.NotEqual(t, "", imagePath)
Packit 63bb0d
	defer os.Remove(imagePath)
Packit 63bb0d
Packit 63bb0d
	// create a random test id to name all the resources used in this test
Packit Service 509fd4
	imageName, err := test.GenerateCIArtifactName("osbuild-image-tests-vmware-image-")
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
Packit 63bb0d
	// the following line should be done by osbuild-composer at some point
Packit 63bb0d
	err = vmwaretest.ImportImage(creds, imagePath, imageName)
Packit 63bb0d
	require.NoErrorf(t, err, "Upload to vCenter failed, resources could have been leaked")
Packit 63bb0d
Packit 63bb0d
	// delete the image after the test is over
Packit 63bb0d
	defer func() {
Packit 63bb0d
		err = vmwaretest.DeleteImage(creds, imageName)
Packit 63bb0d
		require.NoErrorf(t, err, "Cannot delete image from vCenter, resources could have been leaked")
Packit 63bb0d
	}()
Packit 63bb0d
Packit 63bb0d
	// boot the uploaded image and try to connect to it
Packit 63bb0d
	err = vmwaretest.WithSSHKeyPair(func(privateKey, publicKey string) error {
Packit 63bb0d
		return vmwaretest.WithBootedImage(creds, imagePath, imageName, publicKey, func(address string) error {
Packit 63bb0d
			testSSH(t, address, privateKey, nil)
Packit 63bb0d
			return nil
Packit 63bb0d
		})
Packit 63bb0d
	})
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// testBoot tests if the image is able to successfully boot
Packit 63bb0d
// Before the test it boots the image respecting the specified bootType.
Packit 63bb0d
// The test passes if the function is able to connect to the image via ssh
Packit 63bb0d
// in defined number of attempts and systemd-is-running returns running
Packit 63bb0d
// or degraded status.
Packit 63bb0d
func testBoot(t *testing.T, imagePath string, bootType string) {
Packit 63bb0d
	switch bootType {
Packit 63bb0d
	case "qemu":
Packit Service 509fd4
		bootWithQemu(t, imagePath)
Packit 63bb0d
Packit 63bb0d
	case "nspawn":
Packit 63bb0d
		testBootUsingNspawnImage(t, imagePath)
Packit 63bb0d
Packit 63bb0d
	case "nspawn-extract":
Packit 63bb0d
		testBootUsingNspawnDirectory(t, imagePath)
Packit 63bb0d
Packit 63bb0d
	case "aws":
Packit 63bb0d
		testBootUsingAWS(t, imagePath)
Packit 63bb0d
Packit 63bb0d
	case "azure":
Packit 63bb0d
		testBootUsingAzure(t, imagePath)
Packit 63bb0d
Packit 63bb0d
	case "openstack":
Packit 63bb0d
		testBootUsingOpenStack(t, imagePath)
Packit 63bb0d
Packit 63bb0d
	case "vmware":
Packit 63bb0d
		testBootUsingVMware(t, imagePath)
Packit 63bb0d
Packit 63bb0d
	default:
Packit 63bb0d
		panic("unknown boot type!")
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// testImage performs a series of tests specified in the testcase
Packit 63bb0d
// on an image
Packit 63bb0d
func testImage(t *testing.T, testcase testcaseStruct, imagePath string) {
Packit 63bb0d
	if testcase.ImageInfo != nil {
Packit 63bb0d
		t.Run("image info", func(t *testing.T) {
Packit 63bb0d
			testImageInfo(t, imagePath, testcase.ImageInfo)
Packit 63bb0d
		})
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if testcase.Boot != nil {
Packit 63bb0d
		t.Run("boot", func(t *testing.T) {
Packit 63bb0d
			testBoot(t, imagePath, testcase.Boot.Type)
Packit 63bb0d
		})
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// runTestcase builds the pipeline specified in the testcase and then it
Packit 63bb0d
// tests the result
Packit 63bb0d
func runTestcase(t *testing.T, testcase testcaseStruct, store string) {
Packit 63bb0d
	_ = os.Mkdir("/var/lib/osbuild-composer-tests", 0755)
Packit 63bb0d
	outputDirectory, err := ioutil.TempDir("/var/lib/osbuild-composer-tests", "osbuild-image-tests-*")
Packit 63bb0d
	require.NoError(t, err, "error creating temporary output directory")
Packit 63bb0d
Packit 63bb0d
	defer func() {
Packit 63bb0d
		err := os.RemoveAll(outputDirectory)
Packit 63bb0d
		require.NoError(t, err, "error removing temporary output directory")
Packit 63bb0d
	}()
Packit 63bb0d
Packit Service 15f37d
	// NOTE(akoutsou) 1to2t: new v2 manifests name their last pipeline
Packit Service 15f37d
	// "assembler" for compatibility with v1
Packit Service 15f37d
	exports := []string{"assembler"}
Packit Service 15f37d
	err = runOsbuild(testcase.Manifest, store, outputDirectory, exports)
Packit 63bb0d
	require.NoError(t, err)
Packit 63bb0d
Packit Service 15f37d
	for _, export := range exports {
Packit Service 15f37d
		imagePath := filepath.Join(outputDirectory, export, testcase.ComposeRequest.Filename)
Packit Service 15f37d
		testImage(t, testcase, imagePath)
Packit Service 15f37d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// getAllCases returns paths to all testcases in the testcase directory
Packit 63bb0d
func getAllCases() ([]string, error) {
Packit 63bb0d
	cases, err := ioutil.ReadDir(constants.TestPaths.TestCasesDirectory)
Packit 63bb0d
	if err != nil {
Packit Service 509fd4
		return nil, fmt.Errorf("cannot list test cases: %v", err)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	casesPaths := []string{}
Packit 63bb0d
	for _, c := range cases {
Packit 63bb0d
		if c.IsDir() {
Packit 63bb0d
			continue
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		casePath := fmt.Sprintf("%s/%s", constants.TestPaths.TestCasesDirectory, c.Name())
Packit 63bb0d
		casesPaths = append(casesPaths, casePath)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return casesPaths, nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// runTests opens, parses and runs all the specified testcases
Packit 63bb0d
func runTests(t *testing.T, cases []string) {
Packit 63bb0d
	_ = os.Mkdir("/var/lib/osbuild-composer-tests", 0755)
Packit 63bb0d
	store, err := ioutil.TempDir("/var/lib/osbuild-composer-tests", "osbuild-image-tests-*")
Packit 63bb0d
	require.NoError(t, err, "error creating temporary store")
Packit 63bb0d
Packit 63bb0d
	defer func() {
Packit 63bb0d
		err := os.RemoveAll(store)
Packit 63bb0d
		require.NoError(t, err, "error removing temporary store")
Packit 63bb0d
	}()
Packit 63bb0d
Packit 63bb0d
	for _, p := range cases {
Packit 63bb0d
		t.Run(path.Base(p), func(t *testing.T) {
Packit 63bb0d
			f, err := os.Open(p)
Packit 63bb0d
			if err != nil {
Packit Service 509fd4
				t.Skipf("%s: cannot open test case: %v", p, err)
Packit 63bb0d
			}
Packit 63bb0d
Packit 63bb0d
			var testcase testcaseStruct
Packit 63bb0d
			err = json.NewDecoder(f).Decode(&testcase)
Packit 63bb0d
			require.NoErrorf(t, err, "%s: cannot decode test case", p)
Packit 63bb0d
Packit 63bb0d
			currentArch := common.CurrentArch()
Packit 63bb0d
			if testcase.ComposeRequest.Arch != currentArch {
Packit 63bb0d
				t.Skipf("the required arch is %s, the current arch is %s", testcase.ComposeRequest.Arch, currentArch)
Packit 63bb0d
			}
Packit 63bb0d
Packit 63bb0d
			runTestcase(t, testcase, store)
Packit 63bb0d
		})
Packit 63bb0d
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func TestImages(t *testing.T) {
Packit 63bb0d
	cases := flag.Args()
Packit 63bb0d
	// if no cases were specified, run the default set
Packit 63bb0d
	if len(cases) == 0 {
Packit 63bb0d
		var err error
Packit 63bb0d
		cases, err = getAllCases()
Packit 63bb0d
		require.NoError(t, err)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	runTests(t, cases)
Packit 63bb0d
}