File: filereader_test.go

package info (click to toggle)
docker-registry 2.8.1%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 3,148 kB
  • sloc: sh: 331; makefile: 82
file content (193 lines) | stat: -rw-r--r-- 5,246 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package storage

import (
	"bytes"
	"io"
	mrand "math/rand"
	"testing"

	"github.com/docker/distribution/context"
	"github.com/docker/distribution/registry/storage/driver/inmemory"
	"github.com/opencontainers/go-digest"
)

func TestSimpleRead(t *testing.T) {
	ctx := context.Background()
	content := make([]byte, 1<<20)
	n, err := mrand.Read(content)
	if err != nil {
		t.Fatalf("unexpected error building random data: %v", err)
	}

	if n != len(content) {
		t.Fatalf("random read didn't fill buffer")
	}

	dgst, err := digest.FromReader(bytes.NewReader(content))
	if err != nil {
		t.Fatalf("unexpected error digesting random content: %v", err)
	}

	driver := inmemory.New()
	path := "/random"

	if err := driver.PutContent(ctx, path, content); err != nil {
		t.Fatalf("error putting patterned content: %v", err)
	}

	fr, err := newFileReader(ctx, driver, path, int64(len(content)))
	if err != nil {
		t.Fatalf("error allocating file reader: %v", err)
	}

	verifier := dgst.Verifier()
	io.Copy(verifier, fr)

	if !verifier.Verified() {
		t.Fatalf("unable to verify read data")
	}
}

func TestFileReaderSeek(t *testing.T) {
	driver := inmemory.New()
	pattern := "01234567890ab" // prime length block
	repititions := 1024
	path := "/patterned"
	content := bytes.Repeat([]byte(pattern), repititions)
	ctx := context.Background()

	if err := driver.PutContent(ctx, path, content); err != nil {
		t.Fatalf("error putting patterned content: %v", err)
	}

	fr, err := newFileReader(ctx, driver, path, int64(len(content)))

	if err != nil {
		t.Fatalf("unexpected error creating file reader: %v", err)
	}

	// Seek all over the place, in blocks of pattern size and make sure we get
	// the right data.
	for _, repitition := range mrand.Perm(repititions - 1) {
		targetOffset := int64(len(pattern) * repitition)
		// Seek to a multiple of pattern size and read pattern size bytes
		offset, err := fr.Seek(targetOffset, io.SeekStart)
		if err != nil {
			t.Fatalf("unexpected error seeking: %v", err)
		}

		if offset != targetOffset {
			t.Fatalf("did not seek to correct offset: %d != %d", offset, targetOffset)
		}

		p := make([]byte, len(pattern))

		n, err := fr.Read(p)
		if err != nil {
			t.Fatalf("error reading pattern: %v", err)
		}

		if n != len(pattern) {
			t.Fatalf("incorrect read length: %d != %d", n, len(pattern))
		}

		if string(p) != pattern {
			t.Fatalf("incorrect read content: %q != %q", p, pattern)
		}

		// Check offset
		current, err := fr.Seek(0, io.SeekCurrent)
		if err != nil {
			t.Fatalf("error checking current offset: %v", err)
		}

		if current != targetOffset+int64(len(pattern)) {
			t.Fatalf("unexpected offset after read: %v", err)
		}
	}

	start, err := fr.Seek(0, io.SeekStart)
	if err != nil {
		t.Fatalf("error seeking to start: %v", err)
	}

	if start != 0 {
		t.Fatalf("expected to seek to start: %v != 0", start)
	}

	end, err := fr.Seek(0, io.SeekEnd)
	if err != nil {
		t.Fatalf("error checking current offset: %v", err)
	}

	if end != int64(len(content)) {
		t.Fatalf("expected to seek to end: %v != %v", end, len(content))
	}

	// 4. Seek before start, ensure error.

	// seek before start
	before, err := fr.Seek(-1, io.SeekStart)
	if err == nil {
		t.Fatalf("error expected, returned offset=%v", before)
	}

	// 5. Seek after end,
	after, err := fr.Seek(1, io.SeekEnd)
	if err != nil {
		t.Fatalf("unexpected error expected, returned offset=%v", after)
	}

	p := make([]byte, 16)
	n, err := fr.Read(p)

	if n != 0 {
		t.Fatalf("bytes reads %d != %d", n, 0)
	}

	if err != io.EOF {
		t.Fatalf("expected io.EOF, got %v", err)
	}
}

// TestFileReaderNonExistentFile ensures the reader behaves as expected with a
// missing or zero-length remote file. While the file may not exist, the
// reader should not error out on creation and should return 0-bytes from the
// read method, with an io.EOF error.
func TestFileReaderNonExistentFile(t *testing.T) {
	driver := inmemory.New()
	fr, err := newFileReader(context.Background(), driver, "/doesnotexist", 10)
	if err != nil {
		t.Fatalf("unexpected error initializing reader: %v", err)
	}

	var buf [1024]byte

	n, err := fr.Read(buf[:])
	if n != 0 {
		t.Fatalf("non-zero byte read reported: %d != 0", n)
	}

	if err != io.EOF {
		t.Fatalf("read on missing file should return io.EOF, got %v", err)
	}
}

// TestLayerReadErrors covers the various error return type for different
// conditions that can arise when reading a layer.
func TestFileReaderErrors(t *testing.T) {
	// TODO(stevvooe): We need to cover error return types, driven by the
	// errors returned via the HTTP API. For now, here is an incomplete list:
	//
	// 	1. Layer Not Found: returned when layer is not found or access is
	//        denied.
	//	2. Layer Unavailable: returned when link references are unresolved,
	//     but layer is known to the registry.
	//  3. Layer Invalid: This may more split into more errors, but should be
	//     returned when name or tarsum does not reference a valid error. We
	//     may also need something to communication layer verification errors
	//     for the inline tarsum check.
	//	4. Timeout: timeouts to backend. Need to better understand these
	//     failure cases and how the storage driver propagates these errors
	//     up the stack.
}