debian-forge-composer/internal/osbuild/fsnode_test.go
Tomáš Hozza 9bebd98d5b osbuild/fsnode: default to removing destination for custom files
Default to always remove the destination before copying when generating
the copy stage options for custom files in the image. This will ensure
that if the destination is an existing symlink to another file, it won't
be followed.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
2023-02-22 12:17:36 +01:00

272 lines
7.4 KiB
Go

package osbuild
import (
"crypto/sha256"
"fmt"
"os"
"testing"
"github.com/osbuild/osbuild-composer/internal/common"
"github.com/osbuild/osbuild-composer/internal/fsnode"
"github.com/stretchr/testify/assert"
)
func TestGenFileNodesStages(t *testing.T) {
fileData1 := []byte("hello world")
fileData2 := []byte("hello world 2")
ensureFileCreation := func(file *fsnode.File, err error) *fsnode.File {
t.Helper()
assert.NoError(t, err)
assert.NotNil(t, file)
return file
}
testCases := []struct {
name string
files []*fsnode.File
expected []*Stage
}{
{
name: "empty-files-list",
files: []*fsnode.File{},
expected: nil,
},
{
name: "nil-files-list",
files: nil,
expected: nil,
},
{
name: "single-file-simple",
files: []*fsnode.File{
ensureFileCreation(fsnode.NewFile("/etc/file", nil, nil, nil, []byte(fileData1))),
},
expected: []*Stage{
NewCopyStageSimple(&CopyStageOptions{
Paths: []CopyStagePath{
{
From: fmt.Sprintf("input://file-%[1]x/sha256:%[1]x", sha256.Sum256(fileData1)),
To: "tree:///etc/file",
RemoveDestination: true,
},
},
}, &CopyStageFilesInputs{
fmt.Sprintf("file-%x", sha256.Sum256(fileData1)): NewFilesInput(NewFilesInputSourceArrayRef([]FilesInputSourceArrayRefEntry{
NewFilesInputSourceArrayRefEntry(fmt.Sprintf("%x", sha256.Sum256(fileData1)), nil),
})),
}),
},
},
{
name: "multiple-files-simple",
files: []*fsnode.File{
ensureFileCreation(fsnode.NewFile("/etc/file", nil, nil, nil, []byte(fileData1))),
ensureFileCreation(fsnode.NewFile("/etc/file2", nil, nil, nil, []byte(fileData2))),
},
expected: []*Stage{
NewCopyStageSimple(&CopyStageOptions{
Paths: []CopyStagePath{
{
From: fmt.Sprintf("input://file-%[1]x/sha256:%[1]x", sha256.Sum256(fileData1)),
To: "tree:///etc/file",
RemoveDestination: true,
},
{
From: fmt.Sprintf("input://file-%[1]x/sha256:%[1]x", sha256.Sum256(fileData2)),
To: "tree:///etc/file2",
RemoveDestination: true,
},
},
}, &CopyStageFilesInputs{
fmt.Sprintf("file-%x", sha256.Sum256(fileData1)): NewFilesInput(NewFilesInputSourceArrayRef([]FilesInputSourceArrayRefEntry{
NewFilesInputSourceArrayRefEntry(fmt.Sprintf("%x", sha256.Sum256(fileData1)), nil),
})),
fmt.Sprintf("file-%x", sha256.Sum256(fileData2)): NewFilesInput(NewFilesInputSourceArrayRef([]FilesInputSourceArrayRefEntry{
NewFilesInputSourceArrayRefEntry(fmt.Sprintf("%x", sha256.Sum256(fileData2)), nil),
})),
}),
},
},
{
name: "multiple-files-with-all-options",
files: []*fsnode.File{
ensureFileCreation(fsnode.NewFile("/etc/file", common.ToPtr(os.FileMode(0644)), "root", int64(12345), []byte(fileData1))),
ensureFileCreation(fsnode.NewFile("/etc/file2", common.ToPtr(os.FileMode(0755)), int64(12345), "root", []byte(fileData2))),
},
expected: []*Stage{
NewCopyStageSimple(&CopyStageOptions{
Paths: []CopyStagePath{
{
From: fmt.Sprintf("input://file-%[1]x/sha256:%[1]x", sha256.Sum256(fileData1)),
To: "tree:///etc/file",
RemoveDestination: true,
},
{
From: fmt.Sprintf("input://file-%[1]x/sha256:%[1]x", sha256.Sum256(fileData2)),
To: "tree:///etc/file2",
RemoveDestination: true,
},
},
}, &CopyStageFilesInputs{
fmt.Sprintf("file-%x", sha256.Sum256(fileData1)): NewFilesInput(NewFilesInputSourceArrayRef([]FilesInputSourceArrayRefEntry{
NewFilesInputSourceArrayRefEntry(fmt.Sprintf("%x", sha256.Sum256(fileData1)), nil),
})),
fmt.Sprintf("file-%x", sha256.Sum256(fileData2)): NewFilesInput(NewFilesInputSourceArrayRef([]FilesInputSourceArrayRefEntry{
NewFilesInputSourceArrayRefEntry(fmt.Sprintf("%x", sha256.Sum256(fileData2)), nil),
})),
}),
NewChmodStage(&ChmodStageOptions{
Items: map[string]ChmodStagePathOptions{
"/etc/file": {
Mode: fmt.Sprintf("%#o", os.FileMode(0644)),
},
"/etc/file2": {
Mode: fmt.Sprintf("%#o", os.FileMode(0755)),
},
},
}),
NewChownStage(&ChownStageOptions{
Items: map[string]ChownStagePathOptions{
"/etc/file": {
User: "root",
Group: int64(12345),
},
"/etc/file2": {
User: int64(12345),
Group: "root",
},
},
}),
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
gotStages := GenFileNodesStages(tc.files)
assert.EqualValues(t, tc.expected, gotStages)
})
}
}
func TestGenDirectoryNodesStages(t *testing.T) {
ensureDirCreation := func(dir *fsnode.Directory, err error) *fsnode.Directory {
t.Helper()
assert.NoError(t, err)
assert.NotNil(t, dir)
return dir
}
testCases := []struct {
name string
dirs []*fsnode.Directory
expected []*Stage
}{
{
name: "empty-dirs-list",
dirs: []*fsnode.Directory{},
expected: nil,
},
{
name: "nil-dirs-list",
dirs: nil,
expected: nil,
},
{
name: "single-dir-simple",
dirs: []*fsnode.Directory{
ensureDirCreation(fsnode.NewDirectory("/etc/dir", nil, nil, nil, false)),
},
expected: []*Stage{
NewMkdirStage(&MkdirStageOptions{
Paths: []MkdirStagePath{
{
Path: "/etc/dir",
ExistOk: true,
},
},
}),
},
},
{
name: "multiple-dirs-simple",
dirs: []*fsnode.Directory{
ensureDirCreation(fsnode.NewDirectory("/etc/dir", nil, nil, nil, false)),
ensureDirCreation(fsnode.NewDirectory("/etc/dir2", nil, nil, nil, false)),
},
expected: []*Stage{
NewMkdirStage(&MkdirStageOptions{
Paths: []MkdirStagePath{
{
Path: "/etc/dir",
ExistOk: true,
},
{
Path: "/etc/dir2",
ExistOk: true,
},
},
}),
},
},
{
name: "multiple-dirs-with-all-options",
dirs: []*fsnode.Directory{
ensureDirCreation(fsnode.NewDirectory("/etc/dir", common.ToPtr(os.FileMode(0700)), "root", int64(12345), true)),
ensureDirCreation(fsnode.NewDirectory("/etc/dir2", common.ToPtr(os.FileMode(0755)), int64(12345), "root", false)),
ensureDirCreation(fsnode.NewDirectory("/etc/dir3", nil, nil, nil, true)),
},
expected: []*Stage{
NewMkdirStage(&MkdirStageOptions{
Paths: []MkdirStagePath{
{
Path: "/etc/dir",
Parents: true,
ExistOk: false,
},
{
Path: "/etc/dir2",
ExistOk: false,
},
{
Path: "/etc/dir3",
Parents: true,
ExistOk: true,
},
},
}),
NewChmodStage(&ChmodStageOptions{
Items: map[string]ChmodStagePathOptions{
"/etc/dir": {
Mode: fmt.Sprintf("%#o", os.FileMode(0700)),
},
"/etc/dir2": {
Mode: fmt.Sprintf("%#o", os.FileMode(0755)),
},
},
}),
NewChownStage(&ChownStageOptions{
Items: map[string]ChownStagePathOptions{
"/etc/dir": {
User: "root",
Group: int64(12345),
},
"/etc/dir2": {
User: int64(12345),
Group: "root",
},
},
}),
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
gotStages := GenDirectoryNodesStages(tc.dirs)
assert.EqualValues(t, tc.expected, gotStages)
})
}
}