UNPKG

13.2 kBJavaScriptView Raw
1const tape = require('tape')
2const create = require('./helpers/create')
3const Replicator = require('./helpers/replicator')
4
5tape('basic fd read', function (t) {
6 const drive = create()
7 const content = Buffer.alloc(10000).fill('0123456789abcdefghijklmnopqrstuvwxyz')
8
9 drive.writeFile('hi', content, function (err) {
10 t.error(err, 'no error')
11
12 drive.open('hi', 'r', function (err, fd) {
13 t.error(err, 'no error')
14 t.same(typeof fd, 'number')
15 t.ok(fd > 5)
16
17 const underflow = 37
18 const buf = Buffer.alloc(content.length - underflow)
19 let pos = 0
20
21 drive.read(fd, buf, 0, buf.length, 0, function (err, bytesRead) {
22 t.error(err, 'no error')
23 pos += bytesRead
24 t.same(bytesRead, buf.length, 'filled the buffer')
25 t.same(buf, content.slice(0, buf.length))
26
27 drive.read(fd, buf, 0, buf.length, pos, function (err, bytesRead) {
28 t.error(err, 'no error')
29 pos += bytesRead
30 t.same(bytesRead, underflow, 'read missing bytes')
31 t.same(buf.slice(0, underflow), content.slice(content.length - underflow))
32 t.same(pos, content.length, 'read full file')
33
34 drive.read(fd, buf, 0, buf.length, pos, function (err, bytesRead) {
35 t.error(err, 'no error')
36 t.same(bytesRead, 0, 'no more to read')
37
38 drive.close(fd, function (err) {
39 t.error(err, 'no error')
40 t.end()
41 })
42 })
43 })
44 })
45 })
46 })
47})
48
49tape('basic fd read with implicit position', function (t) {
50 const drive = create()
51 const content = Buffer.alloc(10000).fill('0123456789abcdefghijklmnopqrstuvwxyz')
52
53 drive.writeFile('hi', content, function (err) {
54 t.error(err, 'no error')
55
56 drive.open('hi', 'r', function (err, fd) {
57 t.error(err, 'no error')
58 t.same(typeof fd, 'number')
59 t.ok(fd > 5)
60
61 const underflow = 37
62 const buf = Buffer.alloc(content.length - underflow)
63 let pos = 0
64
65 drive.read(fd, buf, 0, buf.length, function (err, bytesRead) {
66 t.error(err, 'no error')
67 pos += bytesRead
68 t.same(bytesRead, buf.length, 'filled the buffer')
69 t.same(buf, content.slice(0, buf.length))
70
71 drive.read(fd, buf, 0, buf.length, function (err, bytesRead) {
72 t.error(err, 'no error')
73 pos += bytesRead
74 t.same(bytesRead, underflow, 'read missing bytes')
75 t.same(buf.slice(0, underflow), content.slice(content.length - underflow))
76 t.same(pos, content.length, 'read full file')
77
78 drive.read(fd, buf, 0, buf.length, function (err, bytesRead) {
79 t.error(err, 'no error')
80 t.same(bytesRead, 0, 'no more to read')
81
82 drive.close(fd, function (err) {
83 t.error(err, 'no error')
84 t.end()
85 })
86 })
87 })
88 })
89 })
90 })
91})
92
93tape('fd read with zero length', function (t) {
94 const drive = create()
95 const content = Buffer.alloc(10000).fill('0123456789abcdefghijklmnopqrstuvwxyz')
96
97 drive.writeFile('hi', content, function (err) {
98 t.error(err, 'no error')
99
100 drive.open('hi', 'r', function (err, fd) {
101 t.error(err, 'no error')
102
103 const buf = Buffer.alloc(content.length)
104
105 drive.read(fd, buf, 0, 0, function (err, bytesRead) {
106 t.error(err, 'no error')
107 t.same(bytesRead, 0)
108 t.end()
109 })
110 })
111 })
112})
113
114tape('fd read with out-of-bounds offset', function (t) {
115 const drive = create()
116 const content = Buffer.alloc(10000).fill('0123456789abcdefghijklmnopqrstuvwxyz')
117
118 drive.writeFile('hi', content, function (err) {
119 t.error(err, 'no error')
120
121 drive.open('hi', 'r', function (err, fd) {
122 t.error(err, 'no error')
123
124 const buf = Buffer.alloc(content.length)
125
126 drive.read(fd, buf, content.length, 10, function (err, bytesRead) {
127 t.error(err, 'no error')
128 t.same(bytesRead, 0)
129 t.end()
130 })
131 })
132 })
133})
134
135tape('fd read with out-of-bounds length', function (t) {
136 const drive = create()
137 const content = Buffer.alloc(10000).fill('0123456789abcdefghijklmnopqrstuvwxyz')
138
139 drive.writeFile('hi', content, function (err) {
140 t.error(err, 'no error')
141
142 drive.open('hi', 'r', function (err, fd) {
143 t.error(err, 'no error')
144
145 const buf = Buffer.alloc(content.length)
146
147 drive.read(fd, buf, 0, content.length + 1, function (err, bytesRead) {
148 t.error(err, 'no error')
149 t.same(bytesRead, content.length)
150 t.end()
151 })
152 })
153 })
154})
155
156tape('fd read of empty drive', function (t) {
157 const drive = create()
158 drive.open('hi', 'r', function (err, fd) {
159 t.true(err)
160 t.same(err.errno, 2)
161 t.end()
162 })
163})
164
165tape('fd read of invalid file', function (t) {
166 const drive = create()
167 const content = Buffer.alloc(10000).fill('0123456789abcdefghijklmnopqrstuvwxyz')
168
169 drive.writeFile('hi', content, function (err) {
170 t.error(err, 'no error')
171 drive.open('hello', 'r', function (err, fd) {
172 t.true(err)
173 t.same(err.errno, 2)
174 t.end()
175 })
176 })
177})
178
179tape('fd basic write, creating file', function (t) {
180 const drive = create()
181 const content = Buffer.alloc(10000).fill('0123456789abcdefghijklmnopqrstuvwxyz')
182 drive.open('hello', 'w+', function (err, fd) {
183 t.error(err, 'no error')
184 drive.write(fd, content, 0, content.length, 0, function (err, bytesWritten) {
185 t.error(err, 'no error')
186 t.same(bytesWritten, content.length)
187 drive.close(fd, err => {
188 t.error(err, 'no error')
189 drive.readFile('hello', function (err, readContent) {
190 t.error(err, 'no error')
191 t.true(readContent.equals(content))
192 t.end()
193 })
194 })
195 })
196 })
197})
198
199tape('fd basic write, appending file', function (t) {
200 const drive = create()
201 const content = Buffer.alloc(10000).fill('0123456789abcdefghijklmnopqrstuvwxyz')
202 let first = content.slice(0, 2000)
203 let second = content.slice(2000)
204
205 drive.writeFile('hello', first, err => {
206 t.error(err, 'no error')
207 writeSecond()
208 })
209
210 function writeSecond () {
211 drive.open('hello', 'a', function (err, fd) {
212 t.error(err, 'no error')
213 drive.write(fd, second, 0, second.length, first.length, function (err, bytesWritten) {
214 t.error(err, 'no error')
215 t.same(bytesWritten, second.length)
216 drive.close(fd, err => {
217 t.error(err, 'no error')
218 drive.readFile('hello', function (err, readContent) {
219 t.error(err, 'no error')
220 t.true(readContent.equals(content))
221 t.end()
222 })
223 })
224 })
225 })
226 }
227})
228
229tape('fd basic write, overwrite file', function (t) {
230 const drive = create()
231 const content = Buffer.alloc(10000).fill('0123456789abcdefghijklmnopqrstuvwxyz')
232 let first = content.slice(0, 2000)
233 let second = content.slice(2000)
234
235 drive.writeFile('hello', first, err => {
236 t.error(err, 'no error')
237 writeSecond()
238 })
239
240 function writeSecond () {
241 drive.open('hello', 'w', function (err, fd) {
242 t.error(err, 'no error')
243 drive.write(fd, second, 0, second.length, 0, function (err, bytesWritten) {
244 t.error(err, 'no error')
245 t.same(bytesWritten, second.length)
246 drive.close(fd, err => {
247 t.error(err, 'no error')
248 drive.readFile('hello', function (err, readContent) {
249 t.error(err, 'no error')
250 t.true(readContent.equals(second))
251 t.end()
252 })
253 })
254 })
255 })
256 }
257})
258
259tape('fd stateful write', function (t) {
260 const drive = create()
261 const content = Buffer.alloc(10000).fill('0123456789abcdefghijklmnopqrstuvwxyz')
262 let first = content.slice(0, 2000)
263 let second = content.slice(2000)
264
265 drive.open('hello', 'w', function (err, fd) {
266 t.error(err, 'no error')
267 drive.write(fd, first, 0, first.length, 0, function (err) {
268 t.error(err, 'no error')
269 drive.write(fd, second, 0, second.length, first.length, function (err) {
270 t.error(err, 'no error')
271 drive.close(fd, err => {
272 t.error(err, 'no error')
273 drive.readFile('hello', function (err, readContent) {
274 t.error(err, 'no error')
275 t.true(readContent.equals(content))
276 t.end()
277 })
278 })
279 })
280 })
281 })
282})
283
284tape('huge stateful write + stateless read', function (t) {
285 const NUM_SLICES = 1000
286 const SLICE_SIZE = 4096
287 const READ_SIZE = Math.floor(4096 * 2.75)
288
289 const drive = create()
290
291 const content = Buffer.alloc(SLICE_SIZE * NUM_SLICES).fill('0123456789abcdefghijklmnopqrstuvwxyz')
292 let slices = new Array(NUM_SLICES).fill(0).map((_, i) => content.slice(SLICE_SIZE * i, SLICE_SIZE * (i + 1)))
293
294 drive.open('hello', 'w+', function (err, fd) {
295 t.error(err, 'no error')
296 writeSlices(drive, fd, err => {
297 t.error(err, 'no errors during write')
298 drive.open('hello', 'r', function (err, fd) {
299 t.error(err, 'no error')
300 compareSlices(drive, fd)
301 })
302 })
303 })
304
305 function compareSlices (drive, fd) {
306 let read = 0
307 readNext()
308
309 function readNext () {
310 const buf = Buffer.alloc(READ_SIZE)
311 const pos = read * READ_SIZE
312 drive.read(fd, buf, 0, READ_SIZE, pos, (err, bytesRead) => {
313 if (err) return t.fail(err)
314 if (!buf.slice(0, bytesRead).equals(content.slice(pos, pos + READ_SIZE))) {
315 return t.fail(`Slices do not match at position: ${read}`)
316 }
317 if (++read * READ_SIZE >= NUM_SLICES * SLICE_SIZE) {
318 return t.end()
319 }
320 return readNext(drive, fd)
321 })
322 }
323 }
324
325 function writeSlices (drive, fd, cb) {
326 let written = 0
327 writeNext()
328
329 function writeNext () {
330 const buf = slices[written]
331 drive.write(fd, buf, 0, SLICE_SIZE, err => {
332 if (err) return cb(err)
333 if (++written === NUM_SLICES) return drive.close(fd, cb)
334 return writeNext()
335 })
336 }
337 }
338})
339
340tape('fd random-access write fails', function (t) {
341 const drive = create()
342 const content = Buffer.alloc(10000).fill('0123456789abcdefghijklmnopqrstuvwxyz')
343 let first = content.slice(0, 2000)
344 let second = content.slice(2000)
345
346 drive.open('hello', 'w', function (err, fd) {
347 t.error(err, 'no error')
348 drive.write(fd, first, 0, first.length, 0, function (err) {
349 t.error(err, 'no error')
350 drive.write(fd, second, 0, second.length, first.length - 500, function (err) {
351 t.true(err)
352 t.same(err.errno, 9)
353 t.end()
354 })
355 })
356 })
357})
358
359tape('fd parallel reads', function (t) {
360 t.plan(3 * 2 + 1)
361
362 const drive = create()
363 const ws = drive.createWriteStream('test')
364
365 ws.write('foo')
366 setImmediate(function () {
367 ws.write('bar')
368 setImmediate(function () {
369 ws.write('baz')
370 setImmediate(function () {
371 ws.write('quux')
372 setImmediate(function () {
373 ws.write('www')
374 ws.end(function () {
375 drive.open('test', 'r', function (err, fd) {
376 t.error(err, 'no error')
377
378 drive.read(fd, Buffer.alloc(13), 0, 13, 0, function (err, read, buf) {
379 t.error(err, 'no error')
380 t.same(read, 13)
381 t.same(buf, Buffer.from('foobarbazquux'))
382 })
383 drive.read(fd, Buffer.alloc(7), 0, 7, 9, function (err, read, buf) {
384 t.error(err, 'no error')
385 t.same(read, 7)
386 t.same(buf, Buffer.from('quuxwww'))
387 })
388 })
389 })
390 })
391 })
392 })
393 })
394})
395
396tape('fd close cancels pending reads', function (t) {
397 const r = new Replicator(t)
398
399 var drive = create()
400 var clone = null
401 var stream = null
402 var totalRead = null
403
404 drive.on('ready', function () {
405 clone = create(drive.key)
406 drive.writeFile('/hello.txt', 'hello', function (err) {
407 const [s1, s2] = r.replicate(drive, clone)
408 stream = s1
409 s1.on('error', () => {})
410 s2.on('error', () => {})
411 return onwrite()
412 })
413 })
414
415 function onwrite () {
416 clone.open('/hello.txt', 'r', (err, descriptor) => {
417 stream.destroy()
418 stream.on('close', () => {
419 // This read should hang without a timeout.
420 var totalRead = null
421 clone.read(descriptor, Buffer.allocUnsafe(64), 1024, 0, (err, total, buf) => {
422 t.true(err, 'read errored')
423 totalRead = total
424 t.end()
425 })
426 setImmediate(() => {
427 // This should cancel the above read.
428 clone.close(descriptor, err => {
429 t.error(err, 'no error')
430 t.false(totalRead)
431 })
432 })
433 })
434 })
435 }
436})
437
438tape('opening a writable fd on a read-only drive errors', function (t) {
439 const r = new Replicator(t)
440
441 var drive = create()
442 var clone = null
443 var stream = null
444 var totalRead = null
445
446 drive.on('ready', function () {
447 clone = create(drive.key)
448 drive.writeFile('hello', 'world', () => {
449 const [s1, s2] = r.replicate(drive, clone)
450 stream = s1
451 s1.on('error', () => {})
452 s2.on('error', () => {})
453 clone.open('hello', 'w+', (err, fd) => {
454 t.true(err, 'writable fd open failed correctly')
455 t.end()
456 })
457 })
458 })
459})