File size: 5,488 Bytes
4e23b01
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
// test/compaction-internal.test.ts
//
// White-box boundary tests for the compaction helpers (copyFileRange /
// fsyncDir) that are hard to reach through the public MiniDb API. Both are
// exported from src/compaction.ts for this purpose but are NOT re-exported
// from the package entry point.
//
// Fault-injection tests (mocked fs) live in compaction-fault.test.ts so that
// their dynamic imports + query-string cache busting do not distort the
// coverage report of this file (Node's coverage keys scripts by URL).

import { expect, test } from 'vitest';
import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { copyFileRange, fsyncDir } from '../src/compaction.js';

async function tmpDir(): Promise<string> {
  return fs.mkdtemp(path.join(os.tmpdir(), 'minidb-copy-'));
}

// --- copyFileRange: happy path ------------------------------------------------

test('copyFileRange copies an arbitrary byte range verbatim', async () => {
  const dir = await tmpDir();
  try {
    const src = path.join(dir, 'src');
    const dst = path.join(dir, 'dst');
    const data = Buffer.alloc(8192);
    for (let i = 0; i < data.length; i++) data[i] = (i * 7) % 256;
    await fs.writeFile(src, data);

    await copyFileRange(src, dst, 1000, 6000);

    const out = await fs.readFile(dst);
    assert.equal(out.length, 5000);
    assert.ok(out.equals(data.subarray(1000, 6000)));
  } finally {
    await fs.rm(dir, { recursive: true, force: true });
  }
});

test('copyFileRange copies a range larger than one internal chunk', async () => {
  // COPY_CHUNK is 1 MiB; copy 2.5 MiB to exercise the multi-chunk loop.
  const dir = await tmpDir();
  try {
    const src = path.join(dir, 'src');
    const dst = path.join(dir, 'dst');
    const size = (5 << 20) / 2; // 2.5 MiB
    const data = Buffer.alloc(size);
    for (let i = 0; i < data.length; i++) data[i] = i % 251;
    await fs.writeFile(src, data);

    await copyFileRange(src, dst, 0, data.length);

    const out = await fs.readFile(dst);
    assert.equal(out.length, data.length);
    assert.ok(out.equals(data));
  } finally {
    await fs.rm(dir, { recursive: true, force: true });
  }
});

// --- copyFileRange: EOF / empty-range boundaries -----------------------------

test('copyFileRange stops at EOF when end exceeds the source size', async () => {
  // Exercises the `bytesRead === 0` break: the source is shorter than the
  // requested range, so read() returns 0 and the loop terminates early.
  const dir = await tmpDir();
  try {
    const src = path.join(dir, 'src');
    const dst = path.join(dir, 'dst');
    await fs.writeFile(src, Buffer.from('hello')); // 5 bytes

    await copyFileRange(src, dst, 0, 1000); // ask for far more than exists

    const out = await fs.readFile(dst);
    assert.ok(out.equals(Buffer.from('hello')));
  } finally {
    await fs.rm(dir, { recursive: true, force: true });
  }
});

test('copyFileRange with start===end creates an empty file in create mode', async () => {
  const dir = await tmpDir();
  try {
    const src = path.join(dir, 'src');
    const dst = path.join(dir, 'dst');
    await fs.writeFile(src, Buffer.from('data'));
    await fs.writeFile(dst, Buffer.from('preexisting-to-be-truncated'));

    await copyFileRange(src, dst, 2, 2); // empty range, 'w' truncates

    const out = await fs.readFile(dst);
    assert.equal(out.length, 0);
  } finally {
    await fs.rm(dir, { recursive: true, force: true });
  }
});

test('copyFileRange with start===end in append mode leaves existing content intact', async () => {
  const dir = await tmpDir();
  try {
    const src = path.join(dir, 'src');
    const dst = path.join(dir, 'dst');
    await fs.writeFile(src, Buffer.from('source'));
    await fs.writeFile(dst, Buffer.from('existing'));

    await copyFileRange(src, dst, 3, 3, { append: true });

    const out = await fs.readFile(dst);
    assert.ok(out.equals(Buffer.from('existing'))); // unchanged
  } finally {
    await fs.rm(dir, { recursive: true, force: true });
  }
});

test('copyFileRange in append mode appends the range to existing content', async () => {
  const dir = await tmpDir();
  try {
    const src = path.join(dir, 'src');
    const dst = path.join(dir, 'dst');
    await fs.writeFile(src, Buffer.from('0123456789'));
    await fs.writeFile(dst, Buffer.from('abc'));

    await copyFileRange(src, dst, 2, 5, { append: true });

    const out = await fs.readFile(dst);
    assert.ok(out.equals(Buffer.from('abc234')));
  } finally {
    await fs.rm(dir, { recursive: true, force: true });
  }
});

test('copyFileRange rejects end < start', async () => {
  await assert.rejects(() => copyFileRange('/tmp/a', '/tmp/b', 10, 5), /end \(5\) < start \(10\)/);
});

// --- fsyncDir ----------------------------------------------------------------

test('fsyncDir syncs an existing directory without throwing', async () => {
  const dir = await tmpDir();
  try {
    await expect(fsyncDir(dir)).resolves.toBeUndefined();
  } finally {
    await fs.rm(dir, { recursive: true, force: true });
  }
});

test('fsyncDir swallows errors when the directory cannot be opened', async () => {
  // A non-existent path makes fs.open reject → the catch branch runs and the
  // finally closes nothing (fh is null). Best-effort semantics.
  const bogus = path.join(os.tmpdir(), `minidb-no-such-dir-${Date.now()}`);
  await expect(fsyncDir(bogus)).resolves.toBeUndefined();
});