store/json: add some basic tests

In the process clarify the code a bit to make it easter to
test/understand.

Signed-off-by: Tom Gundersen <teg@jklm.no>
This commit is contained in:
Tom Gundersen 2020-05-12 12:52:09 +02:00
parent fba2af5f51
commit cdc4b1bd53
3 changed files with 305 additions and 60 deletions

View file

@ -105,6 +105,90 @@ func FixtureBase() *Store {
return s
}
func FixtureFinished() *Store {
var bName = "test"
var b = blueprint.Blueprint{
Name: bName,
Version: "0.0.0",
Packages: []blueprint.Package{},
Modules: []blueprint.Package{},
Groups: []blueprint.Group{},
Customizations: nil,
}
var date = time.Date(2019, 11, 27, 13, 19, 0, 0, time.FixedZone("UTC+1", 60*60))
var localTarget = &target.Target{
Uuid: uuid.MustParse("20000000-0000-0000-0000-000000000000"),
Name: "org.osbuild.local",
ImageName: "localimage",
Created: date,
Status: common.IBWaiting,
Options: &target.LocalTargetOptions{},
}
var awsTarget = &target.Target{
Uuid: uuid.MustParse("10000000-0000-0000-0000-000000000000"),
Name: "org.osbuild.aws",
ImageName: "awsimage",
Created: date,
Status: common.IBWaiting,
Options: &target.AWSTargetOptions{
Region: "frankfurt",
AccessKeyID: "accesskey",
SecretAccessKey: "secretkey",
Bucket: "clay",
Key: "imagekey",
},
}
d := fedoratest.New()
arch, err := d.GetArch("x86_64")
if err != nil {
panic("invalid architecture x86_64 for fedoratest")
}
imgType, err := arch.GetImageType("qcow2")
if err != nil {
panic("invalid image type qcow2 for x86_64 @ fedoratest")
}
s := New(nil, arch, nil)
s.blueprints[bName] = b
s.composes = map[uuid.UUID]Compose{
uuid.MustParse("30000000-0000-0000-0000-000000000000"): Compose{
Blueprint: &b,
ImageBuild: ImageBuild{
QueueStatus: common.IBFinished,
ImageType: imgType,
Targets: []*target.Target{localTarget, awsTarget},
JobCreated: date,
},
},
uuid.MustParse("30000000-0000-0000-0000-000000000001"): Compose{
Blueprint: &b,
ImageBuild: ImageBuild{
QueueStatus: common.IBFinished,
ImageType: imgType,
Targets: []*target.Target{localTarget},
JobCreated: date,
JobStarted: date,
},
},
uuid.MustParse("30000000-0000-0000-0000-000000000003"): Compose{
Blueprint: &b,
ImageBuild: ImageBuild{
QueueStatus: common.IBFailed,
ImageType: imgType,
Targets: []*target.Target{localTarget, awsTarget},
JobCreated: date,
JobStarted: date,
JobFinished: date,
},
},
}
return s
}
func FixtureEmpty() *Store {
var bName = "test"

View file

@ -107,33 +107,40 @@ func newComposesFromV0(composesStruct composesV0, arch distro.Arch) map[uuid.UUI
return composes
}
func newImageBuildFromV0(imageBuildStruct imageBuildV0, arch distro.Arch) (ImageBuild, error) {
imgType := imageTypeFromCompatString(imageBuildStruct.ImageType, arch)
if imgType == nil {
// Invalid type strings in serialization format, this may happen
// on upgrades.
return ImageBuild{}, errors.New("invalid Image Type string")
}
return ImageBuild{
ID: imageBuildStruct.ID,
ImageType: imgType,
Manifest: imageBuildStruct.Manifest,
Targets: imageBuildStruct.Targets,
JobCreated: imageBuildStruct.JobCreated,
JobStarted: imageBuildStruct.JobStarted,
JobFinished: imageBuildStruct.JobFinished,
Size: imageBuildStruct.Size,
JobID: imageBuildStruct.JobID,
QueueStatus: imageBuildStruct.QueueStatus,
}, nil
}
func newComposeFromV0(composeStruct composeV0, arch distro.Arch) (Compose, error) {
c := Compose{
Blueprint: composeStruct.Blueprint,
if len(composeStruct.ImageBuilds) != 1 {
return Compose{}, errors.New("compose with unsupported number of image builds")
}
for _, imgBuild := range composeStruct.ImageBuilds {
imgType := imageTypeFromCompatString(imgBuild.ImageType, arch)
if imgType == nil {
// Invalid type strings in serialization format, this may happen
// on upgrades.
return Compose{}, errors.New("Invalid Image Type string.")
}
ib := ImageBuild{
ID: imgBuild.ID,
ImageType: imgType,
Manifest: imgBuild.Manifest,
Targets: imgBuild.Targets,
JobCreated: imgBuild.JobCreated,
JobStarted: imgBuild.JobStarted,
JobFinished: imgBuild.JobFinished,
Size: imgBuild.Size,
JobID: imgBuild.JobID,
QueueStatus: imgBuild.QueueStatus,
}
c.ImageBuild = ib
return c, nil
ib, err := newImageBuildFromV0(composeStruct.ImageBuilds[0], arch)
if err != nil {
return Compose{}, err
}
return Compose{}, errors.New("No valid image build found in compose.")
bp := composeStruct.Blueprint.DeepCopy()
return Compose{
Blueprint: &bp,
ImageBuild: ib,
}, nil
}
func newSourceConfigsFromV0(sourcesStruct sourcesV0) map[string]SourceConfig {
@ -168,7 +175,7 @@ func newChangesFromV0(changesStruct changesV0) map[string]map[string]blueprint.C
func newCommitsFromV0(commitsStruct commitsV0) map[string][]string {
commits := make(map[string][]string)
for name, changes := range commitsStruct {
commits[name] = changes
commits[name] = changes // TODO: deep copy
}
return commits
}
@ -239,30 +246,47 @@ func newStoreFromV0(storeStruct storeV0, arch distro.Arch) *Store {
return &store
}
func newBlueprintsV0(blueprints map[string]blueprint.Blueprint) blueprintsV0 {
blueprintsStruct := make(blueprintsV0)
for name, blueprint := range blueprints {
blueprintsStruct[name] = blueprint.DeepCopy()
}
return blueprintsStruct
}
func newWorkspaceV0(workspace map[string]blueprint.Blueprint) workspaceV0 {
workspaceStruct := make(workspaceV0)
for name, blueprint := range workspace {
workspaceStruct[name] = blueprint.DeepCopy()
}
return workspaceStruct
}
func newComposeV0(compose Compose) composeV0 {
bp := compose.Blueprint.DeepCopy()
return composeV0{
Blueprint: &bp,
ImageBuilds: []imageBuildV0{
imageBuildV0{
ID: compose.ImageBuild.ID,
ImageType: imageTypeToCompatString(compose.ImageBuild.ImageType),
Manifest: compose.ImageBuild.Manifest,
Targets: compose.ImageBuild.Targets,
JobCreated: compose.ImageBuild.JobCreated,
JobStarted: compose.ImageBuild.JobStarted,
JobFinished: compose.ImageBuild.JobFinished,
Size: compose.ImageBuild.Size,
JobID: compose.ImageBuild.JobID,
QueueStatus: compose.ImageBuild.QueueStatus,
},
},
}
}
func newComposesV0(composes map[uuid.UUID]Compose) composesV0 {
composesStruct := make(composesV0)
for composeID, compose := range composes {
c := composeV0{
Blueprint: compose.Blueprint,
}
imgType := imageTypeToCompatString(compose.ImageBuild.ImageType)
if imgType == "" {
panic("invalid image type: " + compose.ImageBuild.ImageType.Name())
}
ib := imageBuildV0{
ID: compose.ImageBuild.ID,
ImageType: imgType,
Manifest: compose.ImageBuild.Manifest,
Targets: compose.ImageBuild.Targets,
JobCreated: compose.ImageBuild.JobCreated,
JobStarted: compose.ImageBuild.JobStarted,
JobFinished: compose.ImageBuild.JobFinished,
Size: compose.ImageBuild.Size,
JobID: compose.ImageBuild.JobID,
QueueStatus: compose.ImageBuild.QueueStatus,
}
c.ImageBuilds = append(c.ImageBuilds, ib)
composesStruct[composeID] = c
composesStruct[composeID] = newComposeV0(compose)
}
return composesStruct
}
@ -302,8 +326,8 @@ func newCommitsV0(commits map[string][]string) commitsV0 {
func (store *Store) toStoreV0() *storeV0 {
return &storeV0{
Blueprints: store.blueprints,
Workspace: store.workspace,
Blueprints: newBlueprintsV0(store.blueprints),
Workspace: newWorkspaceV0(store.workspace),
Composes: newComposesV0(store.composes),
Sources: newSourcesV0(store.sources),
Changes: newChangesV0(store.blueprintsChanges),
@ -312,20 +336,25 @@ func (store *Store) toStoreV0() *storeV0 {
}
var imageTypeCompatMapping = map[string]string{
"vhd": "Azure",
"ami": "AWS",
"liveiso": "LiveISO",
"openstack": "OpenStack",
"qcow2": "qcow2",
"vmdk": "VMWare",
"ext4-filesystem": "Raw-filesystem",
"partitioned-disk": "Partitioned-disk",
"tar": "Tar",
"test_type": "test_type",
"vhd": "Azure",
"ami": "AWS",
"liveiso": "LiveISO",
"openstack": "OpenStack",
"qcow2": "qcow2",
"vmdk": "VMWare",
"ext4-filesystem": "Raw-filesystem",
"partitioned-disk": "Partitioned-disk",
"tar": "Tar",
"test_type": "test_type", // used only in json_test.go
"test_type_invalid": "test_type_invalid", // used only in json_test.go
}
func imageTypeToCompatString(imgType distro.ImageType) string {
return imageTypeCompatMapping[imgType.Name()]
imgTypeString, exists := imageTypeCompatMapping[imgType.Name()]
if !exists {
panic("No mapping exists for " + imgType.Name())
}
return imgTypeString
}
func imageTypeFromCompatString(input string, arch distro.Arch) distro.ImageType {

View file

@ -1,9 +1,13 @@
package store
import (
"reflect"
"testing"
"github.com/google/uuid"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/distro/fedoratest"
"github.com/osbuild/osbuild-composer/internal/distro/test_distro"
)
@ -53,13 +57,21 @@ func Test_imageTypeFromCompatString(t *testing.T) {
want: &test_distro.TestImageType{},
},
{
name: "invalid",
name: "invalid mapping",
args: args{
input: "foo",
arch: &test_distro.TestArch{},
},
want: nil,
},
{
name: "invalid distro name",
args: args{
input: "test_type_invalid",
arch: &test_distro.TestArch{},
},
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -70,3 +82,123 @@ func Test_imageTypeFromCompatString(t *testing.T) {
})
}
}
func TestMarshalEmpty(t *testing.T) {
d := fedoratest.New()
arch, err := d.GetArch("x86_64")
if err != nil {
panic("invalid architecture x86_64 for fedoratest")
}
store1 := FixtureEmpty()
storeV0 := store1.toStoreV0()
store2 := newStoreFromV0(*storeV0, arch, nil)
if !reflect.DeepEqual(store1, store2) {
t.Errorf("marshal/unmarshal roundtrip not a noop for empty store: %v != %v", store1, store2)
}
}
func TestMarshalFinished(t *testing.T) {
d := fedoratest.New()
arch, err := d.GetArch("x86_64")
if err != nil {
panic("invalid architecture x86_64 for fedoratest")
}
store1 := FixtureFinished()
storeV0 := store1.toStoreV0()
store2 := newStoreFromV0(*storeV0, arch, nil)
if !reflect.DeepEqual(store1, store2) {
t.Errorf("marshal/unmarshal roundtrip not a noop for base store: %v != %v", store1, store2)
}
}
func TestStore_toStoreV0(t *testing.T) {
type fields struct {
blueprints map[string]blueprint.Blueprint
workspace map[string]blueprint.Blueprint
composes map[uuid.UUID]Compose
sources map[string]SourceConfig
blueprintsChanges map[string]map[string]blueprint.Change
blueprintsCommits map[string][]string
}
tests := []struct {
name string
fields fields
want *storeV0
}{
{
name: "empty",
fields: fields{},
want: &storeV0{
Blueprints: make(blueprintsV0),
Workspace: make(workspaceV0),
Composes: make(composesV0),
Sources: make(sourcesV0),
Changes: make(changesV0),
Commits: make(commitsV0),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
store := &Store{
blueprints: tt.fields.blueprints,
workspace: tt.fields.workspace,
composes: tt.fields.composes,
sources: tt.fields.sources,
blueprintsChanges: tt.fields.blueprintsChanges,
blueprintsCommits: tt.fields.blueprintsCommits,
}
if got := store.toStoreV0(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Store.toStoreV0() = %v, want %v", got, tt.want)
}
})
}
}
func Test_newStoreFromV0(t *testing.T) {
type args struct {
storeStruct storeV0
arch distro.Arch
}
tests := []struct {
name string
args args
want *Store
}{
{
name: "empty",
args: args{
storeStruct: storeV0{},
arch: &test_distro.TestArch{},
},
want: New(nil, &test_distro.TestArch{}),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := newStoreFromV0(tt.args.storeStruct, tt.args.arch); !reflect.DeepEqual(got, tt.want) {
t.Errorf("newStoreFromV0() = %v, want %v", got, tt.want)
}
})
}
}
func Test_newCommitsV0(t *testing.T) {
type args struct {
commits map[string][]string
}
tests := []struct {
name string
args args
want commitsV0
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := newCommitsV0(tt.args.commits); !reflect.DeepEqual(got, tt.want) {
t.Errorf("newCommitsV0() = %v, want %v", got, tt.want)
}
})
}
}