Spaces:
Sleeping
Sleeping
assafvayner HF Staff
fix(storage): skip integration suite safely, tighten list contract, drop expand
d594446 Download tests/unit/storage/prefixed-store.test.ts from assafvayner/splitwise: direct link, hf CLI and curl.
- Browser
- Download file 2.9 kB
-
https://huggingface.co/spaces/assafvayner/splitwise/resolve/main/tests/unit/storage/prefixed-store.test.ts
- Command line
-
hf download hf://spaces/assafvayner/splitwise/tests/unit/storage/prefixed-store.test.ts
-
curl -L -o prefixed-store.test.ts https://huggingface.co/spaces/assafvayner/splitwise/resolve/main/tests/unit/storage/prefixed-store.test.ts
2.9 kB
| import { mkdtemp, rm } from 'node:fs/promises'; | |
| import { tmpdir } from 'node:os'; | |
| import { join } from 'node:path'; | |
| import { afterEach, beforeEach, describe, expect, it } from 'vitest'; | |
| import { LocalFsStore } from '../../../src/lib/server/storage/local-fs-store'; | |
| import { PrefixedStore } from '../../../src/lib/server/storage/prefixed-store'; | |
| import { decodeText, encodeText } from '../../../src/lib/server/storage/store'; | |
| describe('PrefixedStore', () => { | |
| let dir: string; | |
| let inner: LocalFsStore; | |
| let a: PrefixedStore; | |
| let b: PrefixedStore; | |
| beforeEach(async () => { | |
| dir = await mkdtemp(join(tmpdir(), 'splitwise-prefixed-')); | |
| inner = new LocalFsStore(dir); | |
| a = new PrefixedStore(inner, 'tenants/a'); | |
| b = new PrefixedStore(inner, '/tenants/b/'); | |
| }); | |
| afterEach(() => rm(dir, { recursive: true, force: true })); | |
| it('stores objects under the prefix and reads them back', async () => { | |
| await a.put('users.json', encodeText('A'), 'application/json'); | |
| expect(decodeText((await a.get('users.json'))!)).toBe('A'); | |
| expect(decodeText((await inner.get('tenants/a/users.json'))!)).toBe('A'); | |
| expect(await b.get('users.json')).toBeNull(); | |
| }); | |
| it('lists with the prefix stripped and never leaks other prefixes', async () => { | |
| await a.put('events/1.json', encodeText('1')); | |
| await a.put('events/2.json', encodeText('2')); | |
| await b.put('events/9.json', encodeText('9')); | |
| expect((await a.list('events/')).map((e) => e.path)).toEqual(['events/1.json', 'events/2.json']); | |
| expect((await a.list('')).map((e) => e.path)).toEqual(['events/1.json', 'events/2.json']); | |
| expect((await b.list('events/')).map((e) => e.path)).toEqual(['events/9.json']); | |
| }); | |
| it('rejects a list prefix without a trailing slash', async () => { | |
| await expect(a.list('events')).rejects.toThrow(/Invalid prefix/); | |
| }); | |
| it('appends, copies and deletes inside the prefix', async () => { | |
| await a.append('ledger.jsonl', encodeText('x\n')); | |
| await a.append('ledger.jsonl', encodeText('y\n')); | |
| await a.copy('ledger.jsonl', 'backups/l.jsonl'); | |
| expect(decodeText((await inner.get('tenants/a/backups/l.jsonl'))!)).toBe('x\ny\n'); | |
| await a.delete(['ledger.jsonl', 'missing.txt']); | |
| expect(await a.get('ledger.jsonl')).toBeNull(); | |
| }); | |
| it('wipe removes only its own subtree', async () => { | |
| await a.put('x.txt', encodeText('x')); | |
| await a.put('deep/y.txt', encodeText('y')); | |
| await b.put('z.txt', encodeText('z')); | |
| expect(await a.wipe()).toBe(2); | |
| expect(await a.list('')).toEqual([]); | |
| expect(await b.get('z.txt')).not.toBeNull(); | |
| }); | |
| it('rejects invalid prefixes', () => { | |
| expect(() => new PrefixedStore(inner, '')).toThrow(); | |
| expect(() => new PrefixedStore(inner, '../x')).toThrow(); | |
| }); | |
| it('rejects paths that escape the prefix', async () => { | |
| await expect(a.get('../b/z.txt')).rejects.toThrow(); | |
| await expect(a.put('../../x', encodeText('x'))).rejects.toThrow(); | |
| }); | |
| }); | |