418 lines
11 KiB
Go
418 lines
11 KiB
Go
package datanode
|
|
|
|
import (
|
|
"io"
|
|
"io/fs"
|
|
"testing"
|
|
|
|
core "dappco.re/go/core"
|
|
coreio "dappco.re/go/core/io"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
var _ coreio.Medium = (*Medium)(nil)
|
|
|
|
func TestDataNode_ReadWrite_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
err := dataNodeMedium.Write("hello.txt", "world")
|
|
require.NoError(t, err)
|
|
|
|
got, err := dataNodeMedium.Read("hello.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "world", got)
|
|
}
|
|
|
|
func TestDataNode_ReadWrite_Bad(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
_, err := dataNodeMedium.Read("missing.txt")
|
|
assert.Error(t, err)
|
|
|
|
err = dataNodeMedium.Write("", "content")
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestDataNode_NestedPaths_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("a/b/c/deep.txt", "deep"))
|
|
|
|
got, err := dataNodeMedium.Read("a/b/c/deep.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "deep", got)
|
|
|
|
assert.True(t, dataNodeMedium.IsDir("a"))
|
|
assert.True(t, dataNodeMedium.IsDir("a/b"))
|
|
assert.True(t, dataNodeMedium.IsDir("a/b/c"))
|
|
}
|
|
|
|
func TestDataNode_LeadingSlash_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("/leading/file.txt", "stripped"))
|
|
got, err := dataNodeMedium.Read("leading/file.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "stripped", got)
|
|
|
|
got, err = dataNodeMedium.Read("/leading/file.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "stripped", got)
|
|
}
|
|
|
|
func TestDataNode_IsFile_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("file.go", "package main"))
|
|
|
|
assert.True(t, dataNodeMedium.IsFile("file.go"))
|
|
assert.False(t, dataNodeMedium.IsFile("missing.go"))
|
|
assert.False(t, dataNodeMedium.IsFile(""))
|
|
}
|
|
|
|
func TestDataNode_EnsureDir_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.EnsureDir("foo/bar/baz"))
|
|
|
|
assert.True(t, dataNodeMedium.IsDir("foo"))
|
|
assert.True(t, dataNodeMedium.IsDir("foo/bar"))
|
|
assert.True(t, dataNodeMedium.IsDir("foo/bar/baz"))
|
|
assert.True(t, dataNodeMedium.Exists("foo/bar/baz"))
|
|
}
|
|
|
|
func TestDataNode_Delete_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("delete-me.txt", "bye"))
|
|
assert.True(t, dataNodeMedium.Exists("delete-me.txt"))
|
|
|
|
require.NoError(t, dataNodeMedium.Delete("delete-me.txt"))
|
|
assert.False(t, dataNodeMedium.Exists("delete-me.txt"))
|
|
}
|
|
|
|
func TestDataNode_Delete_Bad(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
assert.Error(t, dataNodeMedium.Delete("ghost.txt"))
|
|
|
|
require.NoError(t, dataNodeMedium.Write("dir/file.txt", "content"))
|
|
assert.Error(t, dataNodeMedium.Delete("dir"))
|
|
}
|
|
|
|
func TestDataNode_Delete_DirectoryInspectionFailure_Bad(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
require.NoError(t, dataNodeMedium.Write("dir/file.txt", "content"))
|
|
|
|
original := dataNodeWalkDir
|
|
dataNodeWalkDir = func(_ fs.FS, _ string, _ fs.WalkDirFunc) error {
|
|
return core.NewError("walk failed")
|
|
}
|
|
t.Cleanup(func() {
|
|
dataNodeWalkDir = original
|
|
})
|
|
|
|
err := dataNodeMedium.Delete("dir")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "failed to inspect directory")
|
|
}
|
|
|
|
func TestDataNode_DeleteAll_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("tree/a.txt", "a"))
|
|
require.NoError(t, dataNodeMedium.Write("tree/sub/b.txt", "b"))
|
|
require.NoError(t, dataNodeMedium.Write("keep.txt", "keep"))
|
|
|
|
require.NoError(t, dataNodeMedium.DeleteAll("tree"))
|
|
|
|
assert.False(t, dataNodeMedium.Exists("tree/a.txt"))
|
|
assert.False(t, dataNodeMedium.Exists("tree/sub/b.txt"))
|
|
assert.True(t, dataNodeMedium.Exists("keep.txt"))
|
|
}
|
|
|
|
func TestDataNode_DeleteAll_WalkFailure_Bad(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
require.NoError(t, dataNodeMedium.Write("tree/a.txt", "a"))
|
|
|
|
original := dataNodeWalkDir
|
|
dataNodeWalkDir = func(_ fs.FS, _ string, _ fs.WalkDirFunc) error {
|
|
return core.NewError("walk failed")
|
|
}
|
|
t.Cleanup(func() {
|
|
dataNodeWalkDir = original
|
|
})
|
|
|
|
err := dataNodeMedium.DeleteAll("tree")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "failed to inspect tree")
|
|
}
|
|
|
|
func TestDataNode_Delete_RemoveFailure_Bad(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
require.NoError(t, dataNodeMedium.Write("keep.txt", "keep"))
|
|
require.NoError(t, dataNodeMedium.Write("bad.txt", "bad"))
|
|
|
|
original := dataNodeReadAll
|
|
dataNodeReadAll = func(_ io.Reader) ([]byte, error) {
|
|
return nil, core.NewError("read failed")
|
|
}
|
|
t.Cleanup(func() {
|
|
dataNodeReadAll = original
|
|
})
|
|
|
|
err := dataNodeMedium.Delete("bad.txt")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "failed to delete file")
|
|
}
|
|
|
|
func TestDataNode_Rename_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("old.txt", "content"))
|
|
require.NoError(t, dataNodeMedium.Rename("old.txt", "new.txt"))
|
|
|
|
assert.False(t, dataNodeMedium.Exists("old.txt"))
|
|
got, err := dataNodeMedium.Read("new.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "content", got)
|
|
}
|
|
|
|
func TestDataNode_RenameDir_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("src/a.go", "package a"))
|
|
require.NoError(t, dataNodeMedium.Write("src/sub/b.go", "package b"))
|
|
|
|
require.NoError(t, dataNodeMedium.Rename("src", "destination"))
|
|
|
|
assert.False(t, dataNodeMedium.Exists("src/a.go"))
|
|
|
|
got, err := dataNodeMedium.Read("destination/a.go")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "package a", got)
|
|
|
|
got, err = dataNodeMedium.Read("destination/sub/b.go")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "package b", got)
|
|
}
|
|
|
|
func TestDataNode_RenameDir_ReadFailure_Bad(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
require.NoError(t, dataNodeMedium.Write("src/a.go", "package a"))
|
|
|
|
original := dataNodeReadAll
|
|
dataNodeReadAll = func(_ io.Reader) ([]byte, error) {
|
|
return nil, core.NewError("read failed")
|
|
}
|
|
t.Cleanup(func() {
|
|
dataNodeReadAll = original
|
|
})
|
|
|
|
err := dataNodeMedium.Rename("src", "destination")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "failed to read source file")
|
|
}
|
|
|
|
func TestDataNode_List_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("root.txt", "r"))
|
|
require.NoError(t, dataNodeMedium.Write("pkg/a.go", "a"))
|
|
require.NoError(t, dataNodeMedium.Write("pkg/b.go", "b"))
|
|
require.NoError(t, dataNodeMedium.Write("pkg/sub/c.go", "c"))
|
|
|
|
entries, err := dataNodeMedium.List("")
|
|
require.NoError(t, err)
|
|
|
|
names := make([]string, len(entries))
|
|
for index, entry := range entries {
|
|
names[index] = entry.Name()
|
|
}
|
|
assert.Contains(t, names, "root.txt")
|
|
assert.Contains(t, names, "pkg")
|
|
|
|
entries, err = dataNodeMedium.List("pkg")
|
|
require.NoError(t, err)
|
|
names = make([]string, len(entries))
|
|
for index, entry := range entries {
|
|
names[index] = entry.Name()
|
|
}
|
|
assert.Contains(t, names, "a.go")
|
|
assert.Contains(t, names, "b.go")
|
|
assert.Contains(t, names, "sub")
|
|
}
|
|
|
|
func TestDataNode_Stat_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("stat.txt", "hello"))
|
|
|
|
info, err := dataNodeMedium.Stat("stat.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(5), info.Size())
|
|
assert.False(t, info.IsDir())
|
|
|
|
info, err = dataNodeMedium.Stat("")
|
|
require.NoError(t, err)
|
|
assert.True(t, info.IsDir())
|
|
}
|
|
|
|
func TestDataNode_Open_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("open.txt", "opened"))
|
|
|
|
file, err := dataNodeMedium.Open("open.txt")
|
|
require.NoError(t, err)
|
|
defer file.Close()
|
|
|
|
data, err := io.ReadAll(file)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "opened", string(data))
|
|
}
|
|
|
|
func TestDataNode_CreateAppend_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
writer, err := dataNodeMedium.Create("new.txt")
|
|
require.NoError(t, err)
|
|
_, _ = writer.Write([]byte("hello"))
|
|
require.NoError(t, writer.Close())
|
|
|
|
got, err := dataNodeMedium.Read("new.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "hello", got)
|
|
|
|
writer, err = dataNodeMedium.Append("new.txt")
|
|
require.NoError(t, err)
|
|
_, _ = writer.Write([]byte(" world"))
|
|
require.NoError(t, writer.Close())
|
|
|
|
got, err = dataNodeMedium.Read("new.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "hello world", got)
|
|
}
|
|
|
|
func TestDataNode_Append_ReadFailure_Bad(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
require.NoError(t, dataNodeMedium.Write("new.txt", "hello"))
|
|
|
|
original := dataNodeReadAll
|
|
dataNodeReadAll = func(_ io.Reader) ([]byte, error) {
|
|
return nil, core.NewError("read failed")
|
|
}
|
|
t.Cleanup(func() {
|
|
dataNodeReadAll = original
|
|
})
|
|
|
|
_, err := dataNodeMedium.Append("new.txt")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "failed to read existing content")
|
|
}
|
|
|
|
func TestDataNode_Streams_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
writeStream, err := dataNodeMedium.WriteStream("stream.txt")
|
|
require.NoError(t, err)
|
|
_, _ = writeStream.Write([]byte("streamed"))
|
|
require.NoError(t, writeStream.Close())
|
|
|
|
readStream, err := dataNodeMedium.ReadStream("stream.txt")
|
|
require.NoError(t, err)
|
|
data, err := io.ReadAll(readStream)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "streamed", string(data))
|
|
require.NoError(t, readStream.Close())
|
|
}
|
|
|
|
func TestDataNode_SnapshotRestore_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("a.txt", "alpha"))
|
|
require.NoError(t, dataNodeMedium.Write("b/c.txt", "charlie"))
|
|
|
|
snapshotData, err := dataNodeMedium.Snapshot()
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, snapshotData)
|
|
|
|
restoredNode, err := FromTar(snapshotData)
|
|
require.NoError(t, err)
|
|
|
|
got, err := restoredNode.Read("a.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "alpha", got)
|
|
|
|
got, err = restoredNode.Read("b/c.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "charlie", got)
|
|
}
|
|
|
|
func TestDataNode_Restore_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("original.txt", "before"))
|
|
|
|
snapshotData, err := dataNodeMedium.Snapshot()
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, dataNodeMedium.Write("original.txt", "after"))
|
|
require.NoError(t, dataNodeMedium.Write("extra.txt", "extra"))
|
|
|
|
require.NoError(t, dataNodeMedium.Restore(snapshotData))
|
|
|
|
got, err := dataNodeMedium.Read("original.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "before", got)
|
|
|
|
assert.False(t, dataNodeMedium.Exists("extra.txt"))
|
|
}
|
|
|
|
func TestDataNode_DataNode_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("test.txt", "borg"))
|
|
|
|
dataNode := dataNodeMedium.DataNode()
|
|
assert.NotNil(t, dataNode)
|
|
|
|
file, err := dataNode.Open("test.txt")
|
|
require.NoError(t, err)
|
|
defer file.Close()
|
|
|
|
data, err := io.ReadAll(file)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "borg", string(data))
|
|
}
|
|
|
|
func TestDataNode_Overwrite_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("file.txt", "v1"))
|
|
require.NoError(t, dataNodeMedium.Write("file.txt", "v2"))
|
|
|
|
got, err := dataNodeMedium.Read("file.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "v2", got)
|
|
}
|
|
|
|
func TestDataNode_Exists_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
assert.True(t, dataNodeMedium.Exists(""))
|
|
assert.False(t, dataNodeMedium.Exists("x"))
|
|
|
|
require.NoError(t, dataNodeMedium.Write("x", "y"))
|
|
assert.True(t, dataNodeMedium.Exists("x"))
|
|
}
|
|
|
|
func TestDataNode_ReadExistingFile_Good(t *testing.T) {
|
|
dataNodeMedium := New()
|
|
|
|
require.NoError(t, dataNodeMedium.Write("file.txt", "content"))
|
|
got, err := dataNodeMedium.Read("file.txt")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "content", got)
|
|
}
|