Add an internal API for working with custom FS nodes such as Files and
Directories. This implementation is agnostic to external API, such as
Weldr API, Cloud API or osbuild stages. The purpose of it is to be the
common translation layer between all of these "external" APIs and
osbuild.
In this stage, the representation for Files and Directories is added.
The functionality is not yet used by any existing code.
Note about user/group type being `interface{}`:
I considered using the internal `users` representation for users and
groups, but it contains additional information, which are not relevant
for FS node user / group ownership representation. Therefore I didn't
use it. I also considered using separate variables for user / group
name (string) and uid / gid (int64). However, the implementation would
need to ensure that only one of these typed values is set for user /
group or ensure that it refers to the same group / user. My estimate
was that the code ensuring that only one of these typed values is set
would be probably as complex as the current implementation that checks
the types stored in `interface{}` typed variable. And ensuring that
the set user / group name and uid / gid is referring to the same user
/ group is nearly impossible to get right without actually building
the image.
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
163 lines
2.4 KiB
Go
163 lines
2.4 KiB
Go
package fsnode
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/osbuild/osbuild-composer/internal/common"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestBaseFsNodeValidate(t *testing.T) {
|
|
testCases := []struct {
|
|
Node baseFsNode
|
|
Error bool
|
|
}{
|
|
// PATH
|
|
// relative path is not allowed
|
|
{
|
|
Node: baseFsNode{
|
|
path: "relative/path/file",
|
|
},
|
|
Error: true,
|
|
},
|
|
// path ending with slash is not allowed
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/dir/with/trailing/slash/",
|
|
},
|
|
Error: true,
|
|
},
|
|
// empty path is not allowed
|
|
{
|
|
Node: baseFsNode{
|
|
path: "",
|
|
},
|
|
Error: true,
|
|
},
|
|
// path must be canonical
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/dir/../file",
|
|
},
|
|
Error: true,
|
|
},
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/dir/./file",
|
|
},
|
|
Error: true,
|
|
},
|
|
// valid paths
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
},
|
|
},
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/dir",
|
|
},
|
|
},
|
|
// MODE
|
|
// invalid mode
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
mode: common.ToPtr(os.FileMode(os.ModeDir)),
|
|
},
|
|
Error: true,
|
|
},
|
|
// valid mode
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
mode: common.ToPtr(os.FileMode(0o644)),
|
|
},
|
|
},
|
|
// USER
|
|
// invalid user
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
user: "",
|
|
},
|
|
Error: true,
|
|
},
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
user: "invalid@@@user",
|
|
},
|
|
Error: true,
|
|
},
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
user: int64(-1),
|
|
},
|
|
Error: true,
|
|
},
|
|
// valid user
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
user: "osbuild",
|
|
},
|
|
},
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
user: int64(0),
|
|
},
|
|
},
|
|
// GROUP
|
|
// invalid group
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
group: "",
|
|
},
|
|
Error: true,
|
|
},
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
group: "invalid@@@group",
|
|
},
|
|
Error: true,
|
|
},
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
group: int64(-1),
|
|
},
|
|
Error: true,
|
|
},
|
|
// valid group
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
group: "osbuild",
|
|
},
|
|
},
|
|
{
|
|
Node: baseFsNode{
|
|
path: "/etc/file",
|
|
group: int64(0),
|
|
},
|
|
},
|
|
}
|
|
|
|
for idx, testCase := range testCases {
|
|
t.Run(fmt.Sprintf("case #%d", idx), func(t *testing.T) {
|
|
err := testCase.Node.validate()
|
|
if testCase.Error {
|
|
assert.Error(t, err)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|