package distrodef import ( "os" "path/filepath" "slices" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) const testDefLocation = "../data/defs" func TestLoadSimple(t *testing.T) { def, err := LoadImageDef([]string{testDefLocation}, "debian", "trixie", "qcow2") require.NoError(t, err) assert.NotEmpty(t, def.Packages) } func TestLoadFuzzy(t *testing.T) { def, err := LoadImageDef([]string{testDefLocation}, "debian", "trixie", "qcow2") require.NoError(t, err) assert.NotEmpty(t, def.Packages) } func TestLoadUnhappy(t *testing.T) { _, err := LoadImageDef([]string{testDefLocation}, "ubuntu", "22.04", "qcow2") assert.ErrorContains(t, err, "could not find def file for distro ubuntu-22.04") _, err = LoadImageDef([]string{testDefLocation}, "debian", "0", "qcow2") assert.ErrorContains(t, err, "could not find def file for distro debian-0") _, err = LoadImageDef([]string{testDefLocation}, "debian", "trixie", "unsupported-type") assert.ErrorContains(t, err, "could not find def for distro debian and image type unsupported-type") _, err = LoadImageDef([]string{testDefLocation}, "debian", "xxx", "qcow2") assert.ErrorContains(t, err, `cannot parse wanted version string: `) } const fakeDefFileContent = `qcow2: packages: - base-files - systemd - linux-image-amd64 - grub-common - bootc - apt-ostree ami: packages: - base-files - systemd - linux-image-amd64 - grub-common - cloud-guest-utils - bootc - apt-ostree vmdk: packages: - base-files - systemd - linux-image-amd64 - grub-common - open-vm-tools - bootc - apt-ostree debian-installer: packages: - base-files - systemd - linux-image-amd64 - debian-installer - bootc - apt-ostree calamares: packages: - base-files - systemd - linux-image-amd64 - calamares - bootc - apt-ostree ` func makeFakeDistrodefRoot(t *testing.T, defFiles []string) (searchPaths []string) { tmp := t.TempDir() for _, defFile := range defFiles { p := filepath.Join(tmp, defFile) err := os.MkdirAll(filepath.Dir(p), 0755) require.NoError(t, err) err = os.WriteFile(p, []byte(fakeDefFileContent), 0644) require.NoError(t, err) if !slices.Contains(searchPaths, filepath.Dir(p)) { searchPaths = append(searchPaths, filepath.Dir(p)) } } return searchPaths } func TestFindDistroDefMultiDirs(t *testing.T) { defDirs := makeFakeDistrodefRoot(t, []string{ "a/debian-12.yaml", "b/debian-13.yaml", "c/debian-13.yaml", }) assert.Equal(t, 3, len(defDirs)) def, err := findDistroDef(defDirs, "debian", "13") assert.NoError(t, err) assert.True(t, strings.HasSuffix(def, "b/debian-13.yaml")) } func TestFindDistroDefMultiDirsIgnoreENOENT(t *testing.T) { defDirs := makeFakeDistrodefRoot(t, []string{ "a/debian-13.yaml", }) defDirs = append([]string{"/no/such/path"}, defDirs...) def, err := findDistroDef(defDirs, "debian", "13") assert.NoError(t, err) assert.True(t, strings.HasSuffix(def, "a/debian-13.yaml")) } func TestFindDistroDefMultiFuzzy(t *testing.T) { defDirs := makeFakeDistrodefRoot(t, []string{ "a/debian-12.yaml", "b/debian-13.yaml", "b/b/debian-14.yaml", "c/debian-13.yaml", }) // no debian-99, pick the closest def, err := findDistroDef(defDirs, "debian", "99") assert.NoError(t, err) assert.True(t, strings.HasSuffix(def, "b/b/debian-14.yaml")) } func TestFindDistroDefMultiFuzzyMinorReleases(t *testing.T) { defDirs := makeFakeDistrodefRoot(t, []string{ "a/debian-12.1.yaml", "b/debian-11.yaml", "c/debian-13.1.yaml", "d/debian-13.1.1.yaml", "b/b/debian-13.10.yaml", }) def, err := findDistroDef(defDirs, "debian", "13.11") assert.NoError(t, err) assert.True(t, strings.HasSuffix(def, "b/b/debian-13.10.yaml"), def) } func TestFindDistroDefMultiFuzzyMinorReleasesIsZero(t *testing.T) { defDirs := makeFakeDistrodefRoot(t, []string{ "a/debian-13.yaml", "a/debian-14.yaml", }) def, err := findDistroDef(defDirs, "debian", "14.0") assert.NoError(t, err) assert.True(t, strings.HasSuffix(def, "a/debian-14.yaml"), def) } func TestFindDistroDefMultiFuzzyError(t *testing.T) { defDirs := makeFakeDistrodefRoot(t, []string{ "a/debian-13.yaml", }) // the best version we have is newer than what is requested, this // is an error _, err := findDistroDef(defDirs, "debian", "10") assert.ErrorContains(t, err, "could not find def file for distro debian-10") } func TestFindDistroDefBadNumberIgnoresBadFiles(t *testing.T) { defDirs := makeFakeDistrodefRoot(t, []string{ "a/debian-NaN.yaml", }) _, err := findDistroDef(defDirs, "debian", "13") assert.ErrorContains(t, err, "could not find def file for distro debian-13") } func TestFindDistroDefCornerCases(t *testing.T) { defDirs := makeFakeDistrodefRoot(t, []string{ "a/debian-.yaml", "b/debian-1.yaml", "c/debian.yaml", }) def, err := findDistroDef(defDirs, "debian", "2") assert.NoError(t, err) assert.True(t, strings.HasSuffix(def, "b/debian-1.yaml")) } func TestLoadImageDefWithDifferentImageTypes(t *testing.T) { defDirs := makeFakeDistrodefRoot(t, []string{ "a/debian-13.yaml", }) // Test qcow2 image type def, err := LoadImageDef(defDirs, "debian", "trixie", "qcow2") assert.NoError(t, err) assert.NotEmpty(t, def.Packages) assert.Contains(t, def.Packages, "base-files") assert.Contains(t, def.Packages, "systemd") assert.Contains(t, def.Packages, "bootc") // Test ami image type def, err = LoadImageDef(defDirs, "debian", "13", "ami") assert.NoError(t, err) assert.NotEmpty(t, def.Packages) assert.Contains(t, def.Packages, "cloud-guest-utils") // Test vmdk image type def, err = LoadImageDef(defDirs, "debian", "13", "vmdk") assert.NoError(t, err) assert.NotEmpty(t, def.Packages) assert.Contains(t, def.Packages, "open-vm-tools") // Test debian-installer image type def, err = LoadImageDef(defDirs, "debian", "13", "debian-installer") assert.NoError(t, err) assert.NotEmpty(t, def.Packages) assert.Contains(t, def.Packages, "debian-installer") // Test calamares image type def, err = LoadImageDef(defDirs, "debian", "13", "calamares") assert.NoError(t, err) assert.NotEmpty(t, def.Packages) assert.Contains(t, def.Packages, "calamares") } func TestLoadImageDefWithCodenames(t *testing.T) { defDirs := makeFakeDistrodefRoot(t, []string{ "a/debian-trixie.yaml", "b/debian-bookworm.yaml", "c/debian-sid.yaml", }) // Test with codename def, err := LoadImageDef(defDirs, "debian", "trixie", "qcow2") assert.NoError(t, err) assert.NotEmpty(t, def.Packages) // Test with numeric version def, err = LoadImageDef(defDirs, "debian", "13", "qcow2") assert.NoError(t, err) assert.NotEmpty(t, def.Packages) // Test with stable codename def, err = LoadImageDef(defDirs, "debian", "stable", "qcow2") assert.NoError(t, err) assert.NotEmpty(t, def.Packages) }