489 lines
14 KiB
Go
489 lines
14 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestDirResolveUser(t *testing.T) {
|
|
configTmp := createTestConfig("/tmp")
|
|
|
|
ctx := context.Background()
|
|
admin := context.WithValue(ctx, authInfoKey, &AuthInfo{Username: "admin", Authenticated: true})
|
|
user1 := context.WithValue(ctx, authInfoKey, &AuthInfo{Username: "user1", Authenticated: true})
|
|
anon := context.WithValue(ctx, authInfoKey, &AuthInfo{Username: "user1", Authenticated: false})
|
|
|
|
tests := []struct {
|
|
name string
|
|
ctx context.Context
|
|
want string
|
|
}{
|
|
{"", admin, "admin"},
|
|
{"", user1, "user1"},
|
|
{"", anon, ""},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
d := Dir{
|
|
Config: configTmp,
|
|
}
|
|
if got := d.resolveUser(tt.ctx); got != tt.want {
|
|
t.Errorf("Dir.resolveUser() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// This is a nearly concrete copy of the function TestDirResolve of golang.org/x/net/webdav/file_test.go
|
|
// just with prefixes and configuration details.
|
|
func TestDirResolve(t *testing.T) {
|
|
configTmp := createTestConfig("/tmp")
|
|
configRoot := createTestConfig("/")
|
|
configCurrentDir := createTestConfig(".")
|
|
configEmpty := createTestConfig("")
|
|
|
|
ctx := context.Background()
|
|
admin := context.WithValue(ctx, authInfoKey, &AuthInfo{Username: "admin", Authenticated: true})
|
|
user1 := context.WithValue(ctx, authInfoKey, &AuthInfo{Username: "user1", Authenticated: true})
|
|
user2 := context.WithValue(ctx, authInfoKey, &AuthInfo{Username: "user2", Authenticated: true})
|
|
|
|
tests := []struct {
|
|
cfg *Config
|
|
name string
|
|
ctx context.Context
|
|
want string
|
|
}{
|
|
{configTmp, "", admin, "/tmp"},
|
|
{configTmp, ".", admin, "/tmp"},
|
|
{configTmp, "/", admin, "/tmp"},
|
|
{configTmp, "./a", admin, "/tmp/a"},
|
|
{configTmp, "..", admin, "/tmp"},
|
|
{configTmp, "../", admin, "/tmp"},
|
|
{configTmp, "../.", admin, "/tmp"},
|
|
{configTmp, "../a", admin, "/tmp/a"},
|
|
{configTmp, "../..", admin, "/tmp"},
|
|
{configTmp, "../bar/a", admin, "/tmp/bar/a"},
|
|
{configTmp, "../baz/a", admin, "/tmp/baz/a"},
|
|
{configTmp, "...", admin, "/tmp/..."},
|
|
{configTmp, ".../a", admin, "/tmp/.../a"},
|
|
{configTmp, ".../..", admin, "/tmp"},
|
|
{configTmp, "a", admin, "/tmp/a"},
|
|
{configTmp, "a/./b", admin, "/tmp/a/b"},
|
|
{configTmp, "a/../../b", admin, "/tmp/b"},
|
|
{configTmp, "a/../b", admin, "/tmp/b"},
|
|
{configTmp, "a/b", admin, "/tmp/a/b"},
|
|
{configTmp, "a/b/c/../../d", admin, "/tmp/a/d"},
|
|
{configTmp, "a/b/c/../../../d", admin, "/tmp/d"},
|
|
{configTmp, "a/b/c/../../../../d", admin, "/tmp/d"},
|
|
{configTmp, "a/b/c/d", admin, "/tmp/a/b/c/d"},
|
|
{configTmp, "/a/b/c/d", admin, "/tmp/a/b/c/d"},
|
|
|
|
{configTmp, "ab/c\x00d/ef", admin, ""},
|
|
|
|
{configRoot, "", admin, "/"},
|
|
{configRoot, ".", admin, "/"},
|
|
{configRoot, "/", admin, "/"},
|
|
{configRoot, "./a", admin, "/a"},
|
|
{configRoot, "..", admin, "/"},
|
|
{configRoot, "../", admin, "/"},
|
|
{configRoot, "../.", admin, "/"},
|
|
{configRoot, "../a", admin, "/a"},
|
|
{configRoot, "../..", admin, "/"},
|
|
{configRoot, "../bar/a", admin, "/bar/a"},
|
|
{configRoot, "../baz/a", admin, "/baz/a"},
|
|
{configRoot, "...", admin, "/..."},
|
|
{configRoot, ".../a", admin, "/.../a"},
|
|
{configRoot, ".../..", admin, "/"},
|
|
{configRoot, "a", admin, "/a"},
|
|
{configRoot, "a/./b", admin, "/a/b"},
|
|
{configRoot, "a/../../b", admin, "/b"},
|
|
{configRoot, "a/../b", admin, "/b"},
|
|
{configRoot, "a/b", admin, "/a/b"},
|
|
{configRoot, "a/b/c/../../d", admin, "/a/d"},
|
|
{configRoot, "a/b/c/../../../d", admin, "/d"},
|
|
{configRoot, "a/b/c/../../../../d", admin, "/d"},
|
|
{configRoot, "a/b/c/d", admin, "/a/b/c/d"},
|
|
{configRoot, "/a/b/c/d", admin, "/a/b/c/d"},
|
|
|
|
{configCurrentDir, "", admin, "."},
|
|
{configCurrentDir, ".", admin, "."},
|
|
{configCurrentDir, "/", admin, "."},
|
|
{configCurrentDir, "./a", admin, "a"},
|
|
{configCurrentDir, "..", admin, "."},
|
|
{configCurrentDir, "../", admin, "."},
|
|
{configCurrentDir, "../.", admin, "."},
|
|
{configCurrentDir, "../a", admin, "a"},
|
|
{configCurrentDir, "../..", admin, "."},
|
|
{configCurrentDir, "../bar/a", admin, "bar/a"},
|
|
{configCurrentDir, "../baz/a", admin, "baz/a"},
|
|
{configCurrentDir, "...", admin, "..."},
|
|
{configCurrentDir, ".../a", admin, ".../a"},
|
|
{configCurrentDir, ".../..", admin, "."},
|
|
{configCurrentDir, "a", admin, "a"},
|
|
{configCurrentDir, "a/./b", admin, "a/b"},
|
|
{configCurrentDir, "a/../../b", admin, "b"},
|
|
{configCurrentDir, "a/../b", admin, "b"},
|
|
{configCurrentDir, "a/b", admin, "a/b"},
|
|
{configCurrentDir, "a/b/c/../../d", admin, "a/d"},
|
|
{configCurrentDir, "a/b/c/../../../d", admin, "d"},
|
|
{configCurrentDir, "a/b/c/../../../../d", admin, "d"},
|
|
{configCurrentDir, "a/b/c/d", admin, "a/b/c/d"},
|
|
{configCurrentDir, "/a/b/c/d", admin, "a/b/c/d"},
|
|
|
|
{configEmpty, "", admin, "."},
|
|
|
|
{configTmp, "", user1, "/tmp/subdir1"},
|
|
{configTmp, ".", user1, "/tmp/subdir1"},
|
|
{configTmp, "/", user1, "/tmp/subdir1"},
|
|
{configTmp, "./a", user1, "/tmp/subdir1/a"},
|
|
{configTmp, "..", user1, "/tmp/subdir1"},
|
|
{configTmp, "../", user1, "/tmp/subdir1"},
|
|
{configTmp, "../.", user1, "/tmp/subdir1"},
|
|
{configTmp, "../a", user1, "/tmp/subdir1/a"},
|
|
{configTmp, "../..", user1, "/tmp/subdir1"},
|
|
{configTmp, "../bar/a", user1, "/tmp/subdir1/bar/a"},
|
|
{configTmp, "../baz/a", user1, "/tmp/subdir1/baz/a"},
|
|
{configTmp, "...", user1, "/tmp/subdir1/..."},
|
|
{configTmp, ".../a", user1, "/tmp/subdir1/.../a"},
|
|
{configTmp, ".../..", user1, "/tmp/subdir1"},
|
|
{configTmp, "a", user1, "/tmp/subdir1/a"},
|
|
{configTmp, "a/./b", user1, "/tmp/subdir1/a/b"},
|
|
{configTmp, "a/../../b", user1, "/tmp/subdir1/b"},
|
|
{configTmp, "a/../b", user1, "/tmp/subdir1/b"},
|
|
{configTmp, "a/b", user1, "/tmp/subdir1/a/b"},
|
|
{configTmp, "a/b/c/../../d", user1, "/tmp/subdir1/a/d"},
|
|
{configTmp, "a/b/c/../../../d", user1, "/tmp/subdir1/d"},
|
|
{configTmp, "a/b/c/../../../../d", user1, "/tmp/subdir1/d"},
|
|
{configTmp, "a/b/c/d", user1, "/tmp/subdir1/a/b/c/d"},
|
|
{configTmp, "/a/b/c/d", user1, "/tmp/subdir1/a/b/c/d"},
|
|
{configTmp, "", user2, "/tmp/subdir2"},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
d := Dir{
|
|
Config: tt.cfg,
|
|
}
|
|
if got := d.resolve(tt.ctx, tt.name); got != tt.want {
|
|
t.Errorf("Dir.resolve() = %v, want %v. Base dir is %v", got, tt.want, tt.cfg.Dir)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDirMkdir(t *testing.T) {
|
|
tmpDir := filepath.Join(os.TempDir(), "dave__"+strconv.FormatInt(time.Now().UnixNano(), 10))
|
|
os.Mkdir(tmpDir, 0700)
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
t.Logf("using test dir: %s", tmpDir)
|
|
configTmp := createTestConfig(tmpDir)
|
|
|
|
ctx := context.Background()
|
|
admin := context.WithValue(ctx, authInfoKey, &AuthInfo{Username: "admin", Authenticated: true})
|
|
|
|
tests := []struct {
|
|
name string
|
|
perm os.FileMode
|
|
wantErr bool
|
|
}{
|
|
{"a", 0700, false},
|
|
{"/a/", 0700, true}, // already exists
|
|
{"ab/c\x00d/ef", 0700, true},
|
|
{"/a/a/a/a", 0700, true},
|
|
{"a/a/a/a", 0700, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
d := Dir{
|
|
Config: configTmp,
|
|
}
|
|
if err := d.Mkdir(admin, tt.name, tt.perm); (err != nil) != tt.wantErr {
|
|
t.Errorf("Dir.Mkdir() name = %v, error = %v, wantErr %v", tt.name, err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDirOpenFile(t *testing.T) {
|
|
tmpDir := filepath.Join(os.TempDir(), "dave__"+strconv.FormatInt(time.Now().UnixNano(), 10))
|
|
os.Mkdir(tmpDir, 0700)
|
|
defer os.RemoveAll(tmpDir)
|
|
configTmp := createTestConfig(tmpDir)
|
|
|
|
ctx := context.Background()
|
|
admin := context.WithValue(ctx, authInfoKey, &AuthInfo{Username: "admin", Authenticated: true})
|
|
|
|
tests := []struct {
|
|
name string
|
|
flag int
|
|
perm os.FileMode
|
|
wantErr bool
|
|
}{
|
|
{"foo", os.O_RDWR, 0644, true},
|
|
{"foo", os.O_RDWR | os.O_CREATE, 0644, false},
|
|
{"ab/c\x00d/ef", os.O_RDWR, 0700, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
d := Dir{
|
|
Config: configTmp,
|
|
}
|
|
got, err := d.OpenFile(admin, tt.name, tt.flag, tt.perm)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("Dir.OpenFile() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if !tt.wantErr {
|
|
wantFileInfo, err := os.Stat(filepath.Join(tmpDir, tt.name))
|
|
if err != nil {
|
|
t.Errorf("Dir.OpenFile() error = %v", err)
|
|
}
|
|
|
|
gotFileInfo, _ := got.Stat()
|
|
|
|
if !reflect.DeepEqual(gotFileInfo, wantFileInfo) {
|
|
t.Errorf("Dir.OpenFile() = %v, want %v", gotFileInfo, wantFileInfo)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRemoveDir(t *testing.T) {
|
|
tmpDir := filepath.Join(os.TempDir(), "dave__"+strconv.FormatInt(time.Now().UnixNano(), 10))
|
|
os.Mkdir(tmpDir, 0700)
|
|
defer os.RemoveAll(tmpDir)
|
|
configTmp := createTestConfig(tmpDir)
|
|
|
|
ctx := context.Background()
|
|
admin := context.WithValue(ctx, authInfoKey, &AuthInfo{Username: "admin", Authenticated: true})
|
|
|
|
tests := []struct {
|
|
name string
|
|
wantErr bool
|
|
}{
|
|
{"a", false},
|
|
{"a/b/c", false},
|
|
{"/a/b/c", false},
|
|
{"ab/c\x00d/ef", true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
d := Dir{
|
|
Config: configTmp,
|
|
}
|
|
|
|
file := filepath.Join(tmpDir, tt.name)
|
|
if !tt.wantErr {
|
|
err := os.MkdirAll(file, 0700)
|
|
if err != nil {
|
|
t.Errorf("Dir.RemoveAll() pre condition failed. name = %v, error = %v", tt.name, err)
|
|
}
|
|
}
|
|
|
|
if err := d.RemoveAll(admin, tt.name); (err != nil) != tt.wantErr {
|
|
t.Errorf("Dir.RemoveAll() name = %v, error = %v, wantErr %v", tt.name, err, tt.wantErr)
|
|
}
|
|
|
|
if !tt.wantErr {
|
|
if _, err := os.Stat(file); err == nil {
|
|
t.Errorf("Dir.RemoveAll() post condition failed. name = %v, error = %v", tt.name, err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDirRemoveAll(t *testing.T) {
|
|
ctx := context.Background()
|
|
admin := context.WithValue(ctx, authInfoKey, &AuthInfo{Username: "admin", Authenticated: true})
|
|
tmpDir := filepath.Join(os.TempDir(), "dave__"+strconv.FormatInt(time.Now().UnixNano(), 10))
|
|
os.Mkdir(tmpDir, 0700)
|
|
defer os.RemoveAll(tmpDir)
|
|
configTmp := createTestConfig(tmpDir)
|
|
|
|
tests := []struct {
|
|
name string
|
|
removeName string
|
|
wantErr bool
|
|
}{
|
|
{"a/b/c", "a", false},
|
|
{"a/b/c", "a/b", false},
|
|
{"a/b/c", "a/b/c", false},
|
|
{"/a/b/c", "a", false},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
d := Dir{
|
|
Config: configTmp,
|
|
}
|
|
|
|
err := os.MkdirAll(filepath.Join(tmpDir, tt.name), 0700)
|
|
if err != nil {
|
|
t.Errorf("Dir.RemoveAll() error creating dir error = %v, name %v", err, tt.name)
|
|
return
|
|
}
|
|
|
|
if err := d.RemoveAll(admin, tt.removeName); (err != nil) != tt.wantErr {
|
|
t.Errorf("Dir.RemoveAll() removeName = %v, error = %v, wantErr %v", tt.removeName, err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if _, err := os.Stat(filepath.Join(tmpDir, tt.removeName)); err == nil {
|
|
t.Errorf("Dir.RemoveAll() file or directory not deleted = %v, removeName %v", err, tt.removeName)
|
|
return
|
|
}
|
|
|
|
if _, err := os.Stat(filepath.Join(tmpDir, tt.removeName, "/..")); err != nil {
|
|
t.Errorf("Dir.RemoveAll() parent directory deleted = %v, removeName %v", err, tt.removeName)
|
|
return
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRename(t *testing.T) {
|
|
tmpDir := filepath.Join(os.TempDir(), "dave__"+strconv.FormatInt(time.Now().UnixNano(), 10))
|
|
os.Mkdir(tmpDir, 0700)
|
|
defer os.RemoveAll(tmpDir)
|
|
configTmp := createTestConfig(tmpDir)
|
|
|
|
ctx := context.Background()
|
|
admin := context.WithValue(ctx, authInfoKey, &AuthInfo{Username: "admin", Authenticated: true})
|
|
|
|
tests := []struct {
|
|
name string
|
|
oldName string
|
|
newName string
|
|
create bool
|
|
wantError bool
|
|
}{
|
|
{"a", "a", "b", false, true},
|
|
{"a", "a", "b", true, false},
|
|
{"\x00d", "\x00da", "foo", false, true},
|
|
{"\x00d", "foo", "\x00da", false, true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
d := Dir{
|
|
Config: configTmp,
|
|
}
|
|
|
|
if tt.create {
|
|
_, err := d.OpenFile(admin, tt.oldName, os.O_RDWR|os.O_CREATE, 0700)
|
|
if err != nil {
|
|
t.Errorf("Dir.Rename() pre condition failed. name = %v, error = %v", tt.name, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
if err := d.Rename(admin, tt.oldName, tt.newName); (err != nil) != tt.wantError {
|
|
t.Errorf("Dir.Rename() error = %v, wantErr %v", err, tt.wantError)
|
|
return
|
|
}
|
|
|
|
if _, err := os.Stat(filepath.Join(tmpDir, tt.oldName)); err == nil {
|
|
t.Errorf("Dir.Rename() oldName still remained. oldName = %v, newName = %v", tt.oldName, tt.newName)
|
|
return
|
|
}
|
|
|
|
join := filepath.Join(tmpDir, tt.newName)
|
|
fmt.Println(join)
|
|
if _, err := os.Stat(join); err != nil {
|
|
if !tt.create {
|
|
// If no file should be created, there can't be anything
|
|
return
|
|
}
|
|
t.Errorf("Dir.Rename() newName not present. oldName = %v, newName = %v", tt.oldName, tt.newName)
|
|
return
|
|
}
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDirStat(t *testing.T) {
|
|
tmpDir := filepath.Join(os.TempDir(), "dave__"+strconv.FormatInt(time.Now().UnixNano(), 10))
|
|
os.Mkdir(tmpDir, 0700)
|
|
defer os.RemoveAll(tmpDir)
|
|
configTmp := createTestConfig(tmpDir)
|
|
|
|
ctx := context.Background()
|
|
admin := context.WithValue(ctx, authInfoKey, &AuthInfo{Username: "admin", Authenticated: true})
|
|
|
|
tests := []struct {
|
|
name string
|
|
kind string
|
|
wantErr bool
|
|
}{
|
|
{"/a", "dir", false},
|
|
{"/a/b", "file", false},
|
|
{"\x00da", "file", true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
d := Dir{
|
|
Config: configTmp,
|
|
}
|
|
|
|
fp := filepath.Join(tmpDir, tt.name)
|
|
if tt.kind == "dir" {
|
|
err := os.MkdirAll(fp, 0700)
|
|
if err != nil {
|
|
t.Errorf("Dir.Stat() error creating dir. error = %v", err)
|
|
return
|
|
}
|
|
} else if !tt.wantErr {
|
|
_, err := os.OpenFile(fp, os.O_RDWR|os.O_CREATE, 0644)
|
|
if err != nil {
|
|
t.Errorf("Dir.Stat() error creating file. error = %v", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
got, err := d.Stat(admin, tt.name)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("Dir.Stat() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
want, _ := os.Stat(filepath.Join(tmpDir, tt.name))
|
|
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Errorf("Dir.Stat() = %v, want %v", got, want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func createTestConfig(dir string) *Config {
|
|
subdirs := [2]string{"subdir1", "subdir2"}
|
|
userInfos := map[string]*UserInfo{
|
|
"admin": {},
|
|
"user1": {
|
|
Subdir: &subdirs[0],
|
|
},
|
|
"user2": {
|
|
Subdir: &subdirs[1],
|
|
},
|
|
}
|
|
config := &Config{
|
|
Dir: dir,
|
|
Users: userInfos,
|
|
Log: Logging{
|
|
Error: true,
|
|
Create: true,
|
|
Read: true,
|
|
Update: true,
|
|
Delete: true,
|
|
},
|
|
}
|
|
return config
|
|
}
|