Repository: osbuild/osbuild-composer
Pull request #39 (2019-10-21 15:40:33)

More blueprint unittests
This is a follow up to PR #38.


Patch:
diff --git a/internal/blueprint/blueprint.go b/internal/blueprint/blueprint.go
index bd12bcab6..2aaa01059 100644
--- a/internal/blueprint/blueprint.go
+++ b/internal/blueprint/blueprint.go
@@ -3,10 +3,13 @@
 package blueprint
 
 import (
-	"github.com/osbuild/osbuild-composer/internal/pipeline"
 	"sort"
+
+	"github.com/osbuild/osbuild-composer/internal/pipeline"
 )
 
+// An InvalidOutputFormatError is returned when a requested output format is
+// not supported. The requested format is included as the error message.
 type InvalidOutputFormatError struct {
 	message string
 }
diff --git a/internal/blueprint/pipelines/ext4_empty_blueprint.json b/internal/blueprint/pipelines/ext4_empty_blueprint.json
new file mode 100644
index 000000000..6574e323a
--- /dev/null
+++ b/internal/blueprint/pipelines/ext4_empty_blueprint.json
@@ -0,0 +1,80 @@
+{
+  "build": {
+    "stages": [
+      {
+        "name": "org.osbuild.dnf",
+        "options": {
+          "repos": [
+            {
+              "metalink": "https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch",
+              "gpgkey": "F1D8 EC98 F241 AAF2 0DF6  9420 EF3C 111F CFC6 59B9",
+              "checksum": "sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"
+            }
+          ],
+          "packages": [
+            "dnf",
+            "e2fsprogs",
+            "policycoreutils",
+            "qemu-img",
+            "systemd",
+            "grub2-pc",
+            "tar"
+          ],
+          "releasever": "30",
+          "basearch": "x86_64"
+        }
+      }
+    ]
+  },
+  "stages": [
+    {
+      "name": "org.osbuild.dnf",
+      "options": {
+        "repos": [
+          {
+            "metalink": "https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch",
+            "gpgkey": "F1D8 EC98 F241 AAF2 0DF6  9420 EF3C 111F CFC6 59B9",
+            "checksum": "sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"
+          }
+        ],
+        "packages": [
+          "@Core",
+          "chrony",
+          "kernel",
+          "selinux-policy-targeted",
+          "grub2-pc",
+          "spice-vdagent",
+          "qemu-guest-agent",
+          "xen-libs",
+          "langpacks-en"
+        ],
+        "releasever": "30",
+        "basearch": "x86_64"
+      }
+    },
+    {
+      "name": "org.osbuild.fix-bls",
+      "options": {}
+    },
+    {
+      "name": "org.osbuild.locale",
+      "options": {
+        "language": "en_US"
+      }
+    },
+    {
+      "name": "org.osbuild.selinux",
+      "options": {
+        "file_contexts": "etc/selinux/targeted/contexts/files/file_contexts"
+      }
+    }
+  ],
+  "assembler": {
+    "name": "org.osbuild.rawfs",
+    "options": {
+      "filename": "image.img",
+      "root_fs_uuid": "76a22bf4-f153-4541-b6c7-0332c0dfaeac",
+      "size": 3221225472
+    }
+  }
+}
diff --git a/internal/pipeline/assembler.go b/internal/pipeline/assembler.go
index 0af5ca6f8..bbf5c2c7a 100644
--- a/internal/pipeline/assembler.go
+++ b/internal/pipeline/assembler.go
@@ -36,6 +36,8 @@ func (assembler *Assembler) UnmarshalJSON(data []byte) error {
 		options = new(TarAssemblerOptions)
 	case "org.osbuild.qemu":
 		options = new(QEMUAssemblerOptions)
+	case "org.osbuild.rawfs":
+		options = new(RawFSAssemblerOptions)
 	default:
 		return errors.New("unexpected assembler name")
 	}


Test patch:
diff --git a/internal/blueprint/ami_output_test.go b/internal/blueprint/ami_output_test.go
new file mode 100644
index 000000000..aadcb08cf
--- /dev/null
+++ b/internal/blueprint/ami_output_test.go
@@ -0,0 +1,81 @@
+package blueprint
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"reflect"
+	"testing"
+
+	"github.com/osbuild/osbuild-composer/internal/pipeline"
+)
+
+func Test_amiOutput_translate(t *testing.T) {
+	type args struct {
+		b *Blueprint
+	}
+	tests := []struct {
+		name string
+		t    *amiOutput
+		args args
+		want string
+	}{
+		{
+			name: "empty-blueprint",
+			t:    &amiOutput{},
+			args: args{&Blueprint{}},
+			want: "pipelines/ami_empty_blueprint.json",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			file, _ := ioutil.ReadFile(tt.want)
+			var want pipeline.Pipeline
+			json.Unmarshal([]byte(file), &want)
+			if got := tt.t.translate(tt.args.b); !reflect.DeepEqual(got, &want) {
+				t.Errorf("amiOutput.translate() = %v, want %v", got, &want)
+			}
+		})
+	}
+}
+
+func Test_amiOutput_getName(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *amiOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &amiOutput{},
+			want: "image.ami",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getName(); got != tt.want {
+				t.Errorf("amiOutput.getName() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_amiOutput_getMime(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *amiOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &amiOutput{},
+			want: "application/x-qemu-disk",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getMime(); got != tt.want {
+				t.Errorf("amiOutput.getMime() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/internal/blueprint/blueprint_test.go b/internal/blueprint/blueprint_test.go
new file mode 100644
index 000000000..974ca14bf
--- /dev/null
+++ b/internal/blueprint/blueprint_test.go
@@ -0,0 +1,247 @@
+package blueprint_test
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"reflect"
+	"testing"
+
+	"github.com/osbuild/osbuild-composer/internal/blueprint"
+	"github.com/osbuild/osbuild-composer/internal/pipeline"
+)
+
+func TestInvalidOutputFormatError_Error(t *testing.T) {
+	tests := []struct {
+		name string
+		want string
+	}{
+		{
+			name: "basic",
+			want: "",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			e := &blueprint.InvalidOutputFormatError{}
+			if got := e.Error(); got != tt.want {
+				t.Errorf("InvalidOutputFormatError.Error() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestListOutputFormats(t *testing.T) {
+	tests := []struct {
+		name string
+		want []string
+	}{
+		{
+			name: "basic",
+			want: []string{
+				"ami",
+				"ext4-filesystem",
+				"live-iso",
+				"openstack",
+				"partitioned-disk",
+				"qcow2",
+				"tar",
+				"vhd",
+				"vmdk",
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := blueprint.ListOutputFormats(); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("ListOutputFormats() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestBlueprint_ToPipeline(t *testing.T) {
+	type fields struct {
+		Name        string
+		Description string
+		Version     string
+		Packages    []blueprint.Package
+		Modules     []blueprint.Package
+		Groups      []blueprint.Package
+	}
+	type args struct {
+		outputFormat string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    string
+		wantErr bool
+	}{
+		{
+			name: "ami",
+			args: args{"ami"},
+			want: "pipelines/ami_empty_blueprint.json",
+		},
+		{
+			name: "ext4",
+			args: args{"ext4-filesystem"},
+			want: "pipelines/ext4_empty_blueprint.json",
+		},
+		{
+			name: "live-iso",
+			args: args{"live-iso"},
+			want: "pipelines/liveiso_empty_blueprint.json",
+		},
+		{
+			name: "openstack",
+			args: args{"openstack"},
+			want: "pipelines/openstack_empty_blueprint.json",
+		},
+		{
+			name: "partitioned-disk",
+			args: args{"partitioned-disk"},
+			want: "pipelines/disk_empty_blueprint.json",
+		},
+		{
+			name: "qcow2",
+			args: args{"qcow2"},
+			want: "pipelines/qcow2_empty_blueprint.json",
+		},
+		{
+			name: "tar",
+			args: args{"tar"},
+			want: "pipelines/tar_empty_blueprint.json",
+		},
+		{
+			name: "vhd",
+			args: args{"vhd"},
+			want: "pipelines/vhd_empty_blueprint.json",
+		},
+		{
+			name: "vmdk",
+			args: args{"vmdk"},
+			want: "pipelines/vmdk_empty_blueprint.json",
+		},
+		{
+			name:    "invalid-output-type",
+			args:    args{"foobar"},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			b := &blueprint.Blueprint{
+				Name:        tt.fields.Name,
+				Description: tt.fields.Description,
+				Version:     tt.fields.Version,
+				Packages:    tt.fields.Packages,
+				Modules:     tt.fields.Modules,
+				Groups:      tt.fields.Groups,
+			}
+			file, _ := ioutil.ReadFile(tt.want)
+			var want pipeline.Pipeline
+			json.Unmarshal([]byte(file), &want)
+			got, err := b.ToPipeline(tt.args.outputFormat)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Blueprint.ToPipeline() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !tt.wantErr {
+				if !reflect.DeepEqual(got, &want) {
+					t.Errorf("Blueprint.ToPipeline() = %v, want %v", got, &want)
+				}
+			}
+		})
+	}
+}
+
+func TestFilenameFromType(t *testing.T) {
+	type args struct {
+		outputFormat string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    string
+		want1   string
+		wantErr bool
+	}{
+		{
+			name:  "ami",
+			args:  args{"ami"},
+			want:  "image.ami",
+			want1: "application/x-qemu-disk",
+		},
+		{
+			name:  "ext4",
+			args:  args{"ext4-filesystem"},
+			want:  "image.img",
+			want1: "application/octet-stream",
+		},
+		{
+			name:  "live-iso",
+			args:  args{"live-iso"},
+			want:  "image.iso",
+			want1: "application/x-iso9660-image",
+		},
+		{
+			name:  "openstack",
+			args:  args{"openstack"},
+			want:  "image.qcow2",
+			want1: "application/x-qemu-disk",
+		},
+		{
+			name:  "partitioned-disk",
+			args:  args{"partitioned-disk"},
+			want:  "image.img",
+			want1: "application/octet-stream",
+		},
+		{
+			name:  "qcow2",
+			args:  args{"qcow2"},
+			want:  "image.qcow2",
+			want1: "application/x-qemu-disk",
+		},
+		{
+			name:  "tar",
+			args:  args{"tar"},
+			want:  "image.tar",
+			want1: "application/x-tar",
+		},
+		{
+			name:  "vhd",
+			args:  args{"vhd"},
+			want:  "image.vhd",
+			want1: "application/x-vhd",
+		},
+		{
+			name:  "vmdk",
+			args:  args{"vmdk"},
+			want:  "image.vmdk",
+			want1: "application/x-vmdk",
+		},
+		{
+			name:    "invalid-output-type",
+			args:    args{"foobar"},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, got1, err := blueprint.FilenameFromType(tt.args.outputFormat)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("FilenameFromType() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !tt.wantErr {
+				if got != tt.want {
+					t.Errorf("FilenameFromType() got = %v, want %v", got, tt.want)
+				}
+				if got1 != tt.want1 {
+					t.Errorf("FilenameFromType() got1 = %v, want %v", got1, tt.want1)
+				}
+			}
+		})
+	}
+}
diff --git a/internal/blueprint/disk_output_test.go b/internal/blueprint/disk_output_test.go
new file mode 100644
index 000000000..e4eca70ac
--- /dev/null
+++ b/internal/blueprint/disk_output_test.go
@@ -0,0 +1,81 @@
+package blueprint
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"reflect"
+	"testing"
+
+	"github.com/osbuild/osbuild-composer/internal/pipeline"
+)
+
+func Test_diskOutput_translate(t *testing.T) {
+	type args struct {
+		b *Blueprint
+	}
+	tests := []struct {
+		name string
+		t    *diskOutput
+		args args
+		want string
+	}{
+		{
+			name: "empty-blueprint",
+			t:    &diskOutput{},
+			args: args{&Blueprint{}},
+			want: "pipelines/disk_empty_blueprint.json",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			file, _ := ioutil.ReadFile(tt.want)
+			var want pipeline.Pipeline
+			json.Unmarshal([]byte(file), &want)
+			if got := tt.t.translate(tt.args.b); !reflect.DeepEqual(got, &want) {
+				t.Errorf("diskOutput.translate() = %v, want %v", got, &want)
+			}
+		})
+	}
+}
+
+func Test_diskOutput_getName(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *diskOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &diskOutput{},
+			want: "image.img",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getName(); got != tt.want {
+				t.Errorf("diskOutput.getName() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_diskOutput_getMime(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *diskOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &diskOutput{},
+			want: "application/octet-stream",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getMime(); got != tt.want {
+				t.Errorf("diskOutput.getMime() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/internal/blueprint/ext4_output_test.go b/internal/blueprint/ext4_output_test.go
new file mode 100644
index 000000000..c7ad518d2
--- /dev/null
+++ b/internal/blueprint/ext4_output_test.go
@@ -0,0 +1,81 @@
+package blueprint
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"reflect"
+	"testing"
+
+	"github.com/osbuild/osbuild-composer/internal/pipeline"
+)
+
+func Test_ext4Output_translate(t *testing.T) {
+	type args struct {
+		b *Blueprint
+	}
+	tests := []struct {
+		name string
+		t    *ext4Output
+		args args
+		want string
+	}{
+		{
+			name: "empty-blueprint",
+			t:    &ext4Output{},
+			args: args{&Blueprint{}},
+			want: "pipelines/ext4_empty_blueprint.json",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			file, _ := ioutil.ReadFile(tt.want)
+			var want pipeline.Pipeline
+			json.Unmarshal([]byte(file), &want)
+			if got := tt.t.translate(tt.args.b); !reflect.DeepEqual(got, &want) {
+				t.Errorf("ext4Output.translate() = %v, want %v", got, &want)
+			}
+		})
+	}
+}
+
+func Test_ext4Output_getName(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *ext4Output
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &ext4Output{},
+			want: "image.img",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getName(); got != tt.want {
+				t.Errorf("ext4Output.getName() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_ext4Output_getMime(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *ext4Output
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &ext4Output{},
+			want: "application/octet-stream",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getMime(); got != tt.want {
+				t.Errorf("ext4Output.getMime() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/internal/blueprint/liveiso_output_test.go b/internal/blueprint/liveiso_output_test.go
new file mode 100644
index 000000000..30ab8b205
--- /dev/null
+++ b/internal/blueprint/liveiso_output_test.go
@@ -0,0 +1,81 @@
+package blueprint
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"reflect"
+	"testing"
+
+	"github.com/osbuild/osbuild-composer/internal/pipeline"
+)
+
+func Test_liveIsoOutput_translate(t *testing.T) {
+	type args struct {
+		b *Blueprint
+	}
+	tests := []struct {
+		name string
+		t    *liveIsoOutput
+		args args
+		want string
+	}{
+		{
+			name: "empty-blueprint",
+			t:    &liveIsoOutput{},
+			args: args{&Blueprint{}},
+			want: "pipelines/liveiso_empty_blueprint.json",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			file, _ := ioutil.ReadFile(tt.want)
+			var want pipeline.Pipeline
+			json.Unmarshal([]byte(file), &want)
+			if got := tt.t.translate(tt.args.b); !reflect.DeepEqual(got, &want) {
+				t.Errorf("liveIsoOutput.translate() = %v, want %v", got, &want)
+			}
+		})
+	}
+}
+
+func Test_liveIsoOutput_getName(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *liveIsoOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &liveIsoOutput{},
+			want: "image.iso",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getName(); got != tt.want {
+				t.Errorf("liveIsoOutput.getName() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_liveIsoOutput_getMime(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *liveIsoOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &liveIsoOutput{},
+			want: "application/x-iso9660-image",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getMime(); got != tt.want {
+				t.Errorf("liveIsoOutput.getMime() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/internal/blueprint/openstack_output_test.go b/internal/blueprint/openstack_output_test.go
new file mode 100644
index 000000000..23f1fadbb
--- /dev/null
+++ b/internal/blueprint/openstack_output_test.go
@@ -0,0 +1,81 @@
+package blueprint
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"reflect"
+	"testing"
+
+	"github.com/osbuild/osbuild-composer/internal/pipeline"
+)
+
+func Test_openstackOutput_translate(t *testing.T) {
+	type args struct {
+		b *Blueprint
+	}
+	tests := []struct {
+		name string
+		t    *openstackOutput
+		args args
+		want string
+	}{
+		{
+			name: "empty-blueprint",
+			t:    &openstackOutput{},
+			args: args{&Blueprint{}},
+			want: "pipelines/openstack_empty_blueprint.json",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			file, _ := ioutil.ReadFile(tt.want)
+			var want pipeline.Pipeline
+			json.Unmarshal([]byte(file), &want)
+			if got := tt.t.translate(tt.args.b); !reflect.DeepEqual(got, &want) {
+				t.Errorf("openstackOutput.translate() = %v, want %v", got, &want)
+			}
+		})
+	}
+}
+
+func Test_openstackOutput_getName(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *openstackOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &openstackOutput{},
+			want: "image.qcow2",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getName(); got != tt.want {
+				t.Errorf("openstackOutput.getName() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_openstackOutput_getMime(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *openstackOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &openstackOutput{},
+			want: "application/x-qemu-disk",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getMime(); got != tt.want {
+				t.Errorf("openstackOutput.getMime() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/internal/blueprint/tar_output_test.go b/internal/blueprint/tar_output_test.go
new file mode 100644
index 000000000..66bea2bcb
--- /dev/null
+++ b/internal/blueprint/tar_output_test.go
@@ -0,0 +1,81 @@
+package blueprint
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"reflect"
+	"testing"
+
+	"github.com/osbuild/osbuild-composer/internal/pipeline"
+)
+
+func Test_tarOutput_translate(t *testing.T) {
+	type args struct {
+		b *Blueprint
+	}
+	tests := []struct {
+		name string
+		t    *tarOutput
+		args args
+		want string
+	}{
+		{
+			name: "empty-blueprint",
+			t:    &tarOutput{},
+			args: args{&Blueprint{}},
+			want: "pipelines/tar_empty_blueprint.json",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			file, _ := ioutil.ReadFile(tt.want)
+			var want pipeline.Pipeline
+			json.Unmarshal([]byte(file), &want)
+			if got := tt.t.translate(tt.args.b); !reflect.DeepEqual(got, &want) {
+				t.Errorf("tarOutput.translate() = %v, want %v", got, &want)
+			}
+		})
+	}
+}
+
+func Test_tarOutput_getName(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *tarOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &tarOutput{},
+			want: "image.tar",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getName(); got != tt.want {
+				t.Errorf("tarOutput.getName() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_tarOutput_getMime(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *tarOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &tarOutput{},
+			want: "application/x-tar",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getMime(); got != tt.want {
+				t.Errorf("tarOutput.getMime() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/internal/blueprint/vhd_output_test.go b/internal/blueprint/vhd_output_test.go
new file mode 100644
index 000000000..5d167d91c
--- /dev/null
+++ b/internal/blueprint/vhd_output_test.go
@@ -0,0 +1,81 @@
+package blueprint
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"reflect"
+	"testing"
+
+	"github.com/osbuild/osbuild-composer/internal/pipeline"
+)
+
+func Test_vhdOutput_translate(t *testing.T) {
+	type args struct {
+		b *Blueprint
+	}
+	tests := []struct {
+		name string
+		t    *vhdOutput
+		args args
+		want string
+	}{
+		{
+			name: "empty-blueprint",
+			t:    &vhdOutput{},
+			args: args{&Blueprint{}},
+			want: "pipelines/vhd_empty_blueprint.json",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			file, _ := ioutil.ReadFile(tt.want)
+			var want pipeline.Pipeline
+			json.Unmarshal([]byte(file), &want)
+			if got := tt.t.translate(tt.args.b); !reflect.DeepEqual(got, &want) {
+				t.Errorf("vhdOutput.translate() = %v, want %v", got, &want)
+			}
+		})
+	}
+}
+
+func Test_vhdOutput_getName(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *vhdOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &vhdOutput{},
+			want: "image.vhd",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getName(); got != tt.want {
+				t.Errorf("vhdOutput.getName() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_vhdOutput_getMime(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *vhdOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &vhdOutput{},
+			want: "application/x-vhd",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getMime(); got != tt.want {
+				t.Errorf("vhdOutput.getMime() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/internal/blueprint/vmdk_output_test.go b/internal/blueprint/vmdk_output_test.go
new file mode 100644
index 000000000..07fd2f05f
--- /dev/null
+++ b/internal/blueprint/vmdk_output_test.go
@@ -0,0 +1,81 @@
+package blueprint
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"reflect"
+	"testing"
+
+	"github.com/osbuild/osbuild-composer/internal/pipeline"
+)
+
+func Test_vmdkOutput_translate(t *testing.T) {
+	type args struct {
+		b *Blueprint
+	}
+	tests := []struct {
+		name string
+		t    *vmdkOutput
+		args args
+		want string
+	}{
+		{
+			name: "empty-blueprint",
+			t:    &vmdkOutput{},
+			args: args{&Blueprint{}},
+			want: "pipelines/vmdk_empty_blueprint.json",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			file, _ := ioutil.ReadFile(tt.want)
+			var want pipeline.Pipeline
+			json.Unmarshal([]byte(file), &want)
+			if got := tt.t.translate(tt.args.b); !reflect.DeepEqual(got, &want) {
+				t.Errorf("vmdkOutput.translate() = %v, want %v", got, &want)
+			}
+		})
+	}
+}
+
+func Test_vmdkOutput_getName(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *vmdkOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &vmdkOutput{},
+			want: "image.vmdk",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getName(); got != tt.want {
+				t.Errorf("vmdkOutput.getName() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_vmdkOutput_getMime(t *testing.T) {
+	tests := []struct {
+		name string
+		t    *vmdkOutput
+		want string
+	}{
+		{
+			name: "basic",
+			t:    &vmdkOutput{},
+			want: "application/x-vmdk",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.t.getMime(); got != tt.want {
+				t.Errorf("vmdkOutput.getMime() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}