Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 15 additions & 30 deletions archive_escape_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,30 @@ import (
"os"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestSafeComponent(t *testing.T) {
valid := []string{"file", "dir1", "a.b", "..foo", "foo..", "name with space"}
for _, n := range valid {
if err := safeComponent(n); err != nil {
t.Errorf("safeComponent(%q) = %v, want nil", n, err)
}
assert.NoError(t, safeComponent(n), "safeComponent(%q)", n)
}
invalid := []string{"", ".", "..", "evil/passwd", "a/b", "/abs", `a\b`, `\abs`}
for _, n := range invalid {
if err := safeComponent(n); err == nil {
t.Errorf("safeComponent(%q) = nil, want error", n)
}
assert.Error(t, safeComponent(n), "safeComponent(%q)", n)
}
}

func TestConfined(t *testing.T) {
in := []string{".", "a", "a/b", "a/../b", "./a"}
for _, p := range in {
if !confined(p) {
t.Errorf("confined(%q) = false, want true", p)
}
assert.True(t, confined(p), "confined(%q)", p)
}
out := []string{"..", "../x", "a/../..", "/abs", "/"}
for _, p := range out {
if confined(p) {
t.Errorf("confined(%q) = true, want false", p)
}
assert.False(t, confined(p), "confined(%q)", p)
}
}

Expand All @@ -52,35 +47,25 @@ func TestArchiveDecoderRejectsEmbeddedSlash(t *testing.T) {
Mode: os.ModeDir | 0755,
MTime: time.Unix(0, 0),
}
if _, err := enc.Encode(entry); err != nil {
t.Fatal(err)
}
_, err := enc.Encode(entry)
require.NoError(t, err)
name := "evil/passwd"
fn := FormatFilename{
FormatHeader: FormatHeader{Size: uint64(16 + len(name) + 1), Type: CaFormatFilename},
Name: name,
}
if _, err := enc.Encode(fn); err != nil {
t.Fatal(err)
}
_, err = enc.Encode(fn)
require.NoError(t, err)

d := NewArchiveDecoder(&buf)

// First node is the (unnamed) root directory.
v, err := d.Next()
if err != nil {
t.Fatalf("decoding root: %v", err)
}
if _, ok := v.(NodeDirectory); !ok {
t.Fatalf("expected NodeDirectory, got %T", v)
}
require.NoError(t, err, "decoding root")
require.IsType(t, NodeDirectory{}, v)

// The embedded-slash filename must be rejected.
_, err = d.Next()
if err == nil {
t.Fatal("expected error for embedded-slash filename, got nil")
}
if _, ok := err.(InvalidFormat); !ok {
t.Fatalf("expected InvalidFormat, got %T: %v", err, err)
}
require.Error(t, err, "expected error for embedded-slash filename")
require.IsType(t, InvalidFormat{}, err)
}
43 changes: 12 additions & 31 deletions archive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ package desync
import (
"os"
"path"
"reflect"
"testing"

"github.com/stretchr/testify/require"
)

func TestArchiveDecoderTypes(t *testing.T) {
f, err := os.Open("testdata/flat.catar")
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
defer f.Close()

d := NewArchiveDecoder(f)
Expand All @@ -28,20 +27,14 @@ func TestArchiveDecoderTypes(t *testing.T) {

for _, exp := range expected {
v, err := d.Next()
if err != nil {
t.Fatal(err)
}
if reflect.TypeOf(exp) != reflect.TypeOf(v) {
t.Fatalf("expected %s, got %s", reflect.TypeOf(exp), reflect.TypeOf(v))
}
require.NoError(t, err)
require.IsType(t, exp, v)
}
}

func TestArchiveDecoderNesting(t *testing.T) {
f, err := os.Open("testdata/nested.catar")
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
defer f.Close()

d := NewArchiveDecoder(f)
Expand All @@ -67,30 +60,18 @@ func TestArchiveDecoderNesting(t *testing.T) {

for _, e := range expected {
v, err := d.Next()
if err != nil {
t.Fatal(err)
}
if reflect.TypeOf(e.Type) != reflect.TypeOf(v) {
t.Fatalf("expected %s, got %s", reflect.TypeOf(e.Type), reflect.TypeOf(v))
}
require.NoError(t, err)
require.IsType(t, e.Type, v)
if e.Type == nil {
break
}
switch val := v.(type) {
case NodeDirectory:
if val.Name != e.Name {
t.Fatalf("expected name '%s', got '%s'", e.Name, val.Name)
}
if val.UID != e.UID {
t.Fatalf("expected uid '%d', got '%d'", e.UID, val.UID)
}
require.Equal(t, e.Name, val.Name)
require.Equal(t, e.UID, val.UID)
case NodeFile:
if val.Name != e.Name {
t.Fatalf("expected name '%s', got '%s'", e.Name, val.Name)
}
if val.UID != e.UID {
t.Fatalf("expected uid '%d', got '%d'", e.UID, val.UID)
}
require.Equal(t, e.Name, val.Name)
require.Equal(t, e.UID, val.UID)
}
}
}
135 changes: 35 additions & 100 deletions chunker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"crypto/sha512"
"os"
"testing"

"github.com/stretchr/testify/require"
)

const (
Expand All @@ -15,9 +17,7 @@ const (

func TestChunkerLargeFile(t *testing.T) {
f, err := os.Open("testdata/chunker.input")
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
defer f.Close()

expected := []struct {
Expand Down Expand Up @@ -48,73 +48,42 @@ func TestChunkerLargeFile(t *testing.T) {
}

c, err := NewChunker(f, ChunkSizeMinDefault, ChunkSizeAvgDefault, ChunkSizeMaxDefault)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)

for i, e := range expected {
start, buf, err := c.Next()
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
chunkID := ChunkID(sha512.Sum512_256(buf))
hash := (&chunkID).String()
if hash != e.ID {
t.Fatalf("chunk #%d, unexpected hash %s, expected %s", i+1, hash, e.ID)
}
if start != e.Start {
t.Fatalf("chunk #%d, unexpected start %d, expected %d", i+1, start, e.Start)
}
if uint64(len(buf)) != e.Size {
t.Fatalf("chunk #%d, unexpected size %d, expected %d", i+1, uint64(len(buf)), e.Size)
}
require.Equal(t, e.ID, chunkID.String(), "chunk #%d hash", i+1)
require.Equal(t, e.Start, start, "chunk #%d start", i+1)
require.Equal(t, e.Size, uint64(len(buf)), "chunk #%d size", i+1)
}
// Should get a size of 0 at the end
_, buf, err := c.Next()
if err != nil {
t.Fatal(err)
}
if len(buf) != 0 {
t.Fatalf("expected size 0 at the end, got %d", len(buf))
}
require.NoError(t, err)
require.Empty(t, buf, "expected size 0 at the end")
}

func TestChunkerEmptyFile(t *testing.T) {
r := bytes.NewReader([]byte{})
c, err := NewChunker(r, ChunkSizeMinDefault, ChunkSizeAvgDefault, ChunkSizeMaxDefault)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
start, buf, err := c.Next()
if err != nil {
t.Fatal(err)
}
if len(buf) != 0 {
t.Fatalf("unexpected size %d, expected 0", len(buf))
}
if start != 0 {
t.Fatalf("unexpected start position %d, expected 0", start)
}
require.NoError(t, err)
require.Empty(t, buf)
require.Equal(t, uint64(0), start)
}

func TestChunkerSmallFile(t *testing.T) {
b := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
r := bytes.NewReader(b)
c, err := NewChunker(r, ChunkSizeMinDefault, ChunkSizeAvgDefault, ChunkSizeMaxDefault)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)

start, buf, err := c.Next()
if err != nil {
t.Fatal(err)
}
if len(buf) != len(b) {
t.Fatalf("unexpected size %d, expected %d", len(buf), len(b))
}
if start != 0 {
t.Fatalf("unexpected start position %d, expected 0", start)
}
require.NoError(t, err)
require.Len(t, buf, len(b))
require.Equal(t, uint64(0), start)
}

// There are no chunk boundaries when all data is nil, make sure we get the
Expand All @@ -123,23 +92,15 @@ func TestChunkerNoBoundary(t *testing.T) {
b := make([]byte, 1024*1024)
r := bytes.NewReader(b)
c, err := NewChunker(r, ChunkSizeMinDefault, ChunkSizeAvgDefault, ChunkSizeMaxDefault)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
for {
start, buf, err := c.Next()
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
if len(buf) == 0 {
break
}
if uint64(len(buf)) != ChunkSizeMaxDefault {
t.Fatalf("unexpected size %d, expected %d", len(buf), ChunkSizeMaxDefault)
}
if start%ChunkSizeMaxDefault != 0 {
t.Fatalf("unexpected start position %d, expected 0", start)
}
require.Equal(t, ChunkSizeMaxDefault, uint64(len(buf)))
require.Zero(t, start%ChunkSizeMaxDefault, "unexpected start position %d", start)
}
}

Expand All @@ -157,20 +118,12 @@ func TestChunkerBounds(t *testing.T) {
b := make([]byte, c.size)
r := bytes.NewReader(b)
c, err := NewChunker(r, ChunkSizeMinDefault, ChunkSizeAvgDefault, ChunkSizeMaxDefault)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)

start, buf, err := c.Next()
if err != nil {
t.Fatal(err)
}
if len(buf) != len(b) {
t.Fatalf("unexpected size %d, expected %d", len(buf), len(b))
}
if start != 0 {
t.Fatalf("unexpected start position %d, expected 0", start)
}
require.NoError(t, err)
require.Len(t, buf, len(b))
require.Equal(t, uint64(0), start)
})
}
}
Expand All @@ -195,46 +148,28 @@ func TestChunkerAdvance(t *testing.T) {
input := join(nullChunk.Data, dataA, nullChunk.Data, dataB)

c, err := NewChunker(bytes.NewReader(input), ChunkSizeMinDefault, ChunkSizeAvgDefault, ChunkSizeMaxDefault)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)

// Chunk the first part, this should be a null chunk
_, buf, err := c.Next()
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(buf, nullChunk.Data) {
t.Fatal("expected null chunk")
}
require.NoError(t, err)
require.Equal(t, nullChunk.Data, buf, "expected null chunk")

// Now skip the dataA slice
if err := c.Advance(len(dataA)); err != nil {
t.Fatal(err)
}
require.NoError(t, c.Advance(len(dataA)))

// Read the 2nd null chunk
_, buf, err = c.Next()
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(buf, nullChunk.Data) {
t.Fatal("expected null chunk")
}
require.NoError(t, err)
require.Equal(t, nullChunk.Data, buf, "expected null chunk")

// Skip over dataB
if err := c.Advance(len(dataB)); err != nil {
t.Fatal(err)
}
require.NoError(t, c.Advance(len(dataB)))

// Should be at the end, nothing more to chunk
_, buf, err = c.Next()
if err != nil {
t.Fatal(err)
}
if len(buf) != 0 {
t.Fatal("expected end of input")
}
require.NoError(t, err)
require.Empty(t, buf, "expected end of input")
}

// Global vars used for results during the benchmark to prevent optimizer
Expand Down
Loading
Loading