Skip to content

Commit 6fb2328

Browse files
committed
Happy path implementations + testing
1 parent c417c42 commit 6fb2328

File tree

9 files changed

+487
-69
lines changed

9 files changed

+487
-69
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
dist
22
node_modules
3+
tmp*
34
.npmrc

.replit

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
1-
run = "npm run test:watch"
1+
run = "npm run test"
22

33
entrypoint = "src/index.ts"
44
modules = ["nodejs-20:v12-20231130-57acee0"]
55

66
[nix]
77
channel = "stable-23_11"
88

9-
[deployment]
10-
run = ["tsx", "index.ts"]
11-
deploymentTarget = "cloudrun"
12-
ignorePorts = false
13-
149
[[ports]]
1510
localPort = 24678
1611
externalPort = 80
1712

13+
[objectStorage]
14+
defaultBucketID = "replit-objstore-ea9e4157-6777-4678-abca-becea84b6153"
15+
1816

1917
# disabled for now until multiple LSPs are properly supported
2018
# [languages.eslint]
@@ -46,4 +44,4 @@ externalPort = 80
4644
# location = "separateLine"
4745
# commentStyle = "line"
4846
# [languages.eslint.languageServer.configuration.codeAction.showDocumentation]
49-
# enable = true
47+
# enable = true

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/client.int.test.ts

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
import * as fs from 'fs';
2+
import { PassThrough } from 'stream';
3+
4+
import { afterAll, beforeAll, describe, expect, test } from 'vitest';
5+
6+
import { Client } from './client';
7+
8+
let client: Client;
9+
const testDir = crypto.randomUUID();
10+
const testFileContents = 'Hello World!';
11+
12+
const getLocalTestDir = () =>
13+
new Promise<string>((resolve) => {
14+
fs.mkdtemp(`${process.cwd()}/tmp`, (err, tmpDir) => {
15+
if (err) throw err;
16+
resolve(tmpDir);
17+
});
18+
});
19+
20+
beforeAll(() => {
21+
client = new Client();
22+
});
23+
24+
describe('copy', () => {
25+
test('upload then copy', async () => {
26+
const objectName1 = `${testDir}/copy-1.txt`;
27+
const objectName2 = `${testDir}/copy-2.txt`;
28+
await client.uploadFromText(objectName1, testFileContents);
29+
const initialUploadSuccess = await client.exists(objectName1);
30+
expect(initialUploadSuccess).toBeTruthy();
31+
32+
const { ok, value } = await client.copy(objectName1, objectName2);
33+
expect(ok).toBeTruthy();
34+
expect(value).toBeNull();
35+
36+
const copySuccess = await client.exists(objectName2);
37+
expect(copySuccess).toBeTruthy();
38+
});
39+
40+
test('does not exist', async () => {
41+
try {
42+
await client.copy('bad-object-1', 'should-never-happen');
43+
} catch (error) {
44+
expect(error.code).toBe(404);
45+
}
46+
});
47+
});
48+
49+
describe('delete', () => {
50+
test('upload then delete', async () => {
51+
const objectName = `${testDir}/delete-1.txt`;
52+
await client.uploadFromText(objectName, testFileContents);
53+
const initialUploadSuccess = await client.exists(objectName);
54+
expect(initialUploadSuccess).toBeTruthy();
55+
56+
const deleteResult = await client.delete(objectName);
57+
expect(deleteResult.ok).toBeTruthy();
58+
expect(deleteResult.value).toBeNull();
59+
60+
const existsResult = await client.exists(objectName);
61+
expect(existsResult.ok).toBeTruthy();
62+
expect(existsResult.value).toBeFalsy();
63+
});
64+
});
65+
66+
describe('downloadAsBytes', () => {
67+
test('upload then download', async () => {
68+
const objectName = `${testDir}/download-as-bytes-1.txt`;
69+
await client.uploadFromText(objectName, testFileContents);
70+
71+
const { ok, value: buffer } = await client.downloadAsBytes(objectName);
72+
expect(ok).toBeTruthy();
73+
expect(buffer.toString()).toBe(testFileContents);
74+
});
75+
});
76+
77+
describe('downloadAsText', () => {
78+
test('upload then download', async () => {
79+
const objectName = `${testDir}/download-as-text-1.txt`;
80+
await client.uploadFromText(objectName, testFileContents);
81+
82+
const { ok, value: text } = await client.downloadAsText(objectName);
83+
expect(ok).toBeTruthy();
84+
expect(text).toBe(testFileContents);
85+
});
86+
});
87+
88+
describe('downloadToFilename', () => {
89+
test('upload then download', async () => {
90+
const localTestDir = await getLocalTestDir();
91+
92+
const objectName = `${testDir}/download-to-filename-1.txt`;
93+
await client.uploadFromText(objectName, testFileContents);
94+
95+
const filename = `${localTestDir}/download-to-filename-1.txt`;
96+
const result = await client.downloadToFilename(objectName, filename);
97+
expect(result.ok).toBeTruthy();
98+
99+
const contents = fs.readFileSync(filename);
100+
expect(contents.toString()).toBe(testFileContents);
101+
102+
fs.rmdirSync(localTestDir, { recursive: true });
103+
});
104+
});
105+
106+
describe('downloadAsStream', () => {
107+
test('upload then download', async () => {
108+
const objectName = `${testDir}/download-as-stream-1.txt`;
109+
await client.uploadFromText(objectName, testFileContents);
110+
111+
let contents = '';
112+
const { ok, value: stream } = client.downloadAsStream(objectName);
113+
expect(ok).toBeTruthy();
114+
await stream.forEach((chunk: string) => {
115+
contents += chunk.toString();
116+
});
117+
expect(contents).toBe(testFileContents);
118+
});
119+
});
120+
121+
describe('exists', () => {
122+
test('does not exist', async () => {
123+
const { ok, value: exists } = await client.exists(
124+
`${testDir}/exists-1.txt`,
125+
);
126+
expect(ok).toBeTruthy();
127+
expect(exists).toBeFalsy();
128+
});
129+
130+
test('does exist', async () => {
131+
const objectName = `${testDir}/exists-2.txt`;
132+
await client.uploadFromText(objectName, testFileContents);
133+
134+
const { ok, value: exists } = await client.exists(objectName);
135+
expect(ok).toBeTruthy();
136+
expect(exists).toBeTruthy();
137+
});
138+
});
139+
140+
describe('list', () => {
141+
test('upload multiple then list', async () => {
142+
const objectName1 = `${testDir}/list/list1-1.txt`;
143+
const objectName2 = `${testDir}/list/list1-2.txt`;
144+
await client.uploadFromText(objectName1, testFileContents);
145+
await client.uploadFromText(objectName2, testFileContents);
146+
147+
const { ok, value: files } = await client.list({
148+
prefix: `${testDir}/list`,
149+
});
150+
expect(ok).toBeTruthy();
151+
expect(files).toEqual([{ name: objectName1 }, { name: objectName2 }]);
152+
});
153+
});
154+
155+
describe('uploadFromBytes', () => {
156+
test('upload then download', async () => {
157+
const objectName = `${testDir}/upload-from-bytes-1.txt`;
158+
const { ok, value } = await client.uploadFromBytes(
159+
objectName,
160+
Buffer.from(testFileContents),
161+
);
162+
expect(ok).toBeTruthy();
163+
expect(value).toBeNull();
164+
165+
const { value: output } = await client.downloadAsText(objectName);
166+
expect(output).toBe(testFileContents);
167+
});
168+
});
169+
170+
describe('uploadFromText', () => {
171+
test('upload then download', async () => {
172+
const objectName = `${testDir}/upload-from-text-1.txt`;
173+
const { ok, value } = await client.uploadFromText(
174+
objectName,
175+
testFileContents,
176+
);
177+
expect(ok).toBeTruthy();
178+
expect(value).toBeNull();
179+
180+
const { value: text } = await client.downloadAsText(objectName);
181+
expect(text).toBe(testFileContents);
182+
});
183+
});
184+
185+
describe('uploadFromFilename', () => {
186+
test('upload then download', async () => {
187+
const localTestDir = await getLocalTestDir();
188+
const filename = `${localTestDir}/upload-from-filename-1.txt`;
189+
fs.writeFileSync(filename, testFileContents);
190+
191+
const objectName = `${testDir}/upload-from-filename-1.txt`;
192+
const { ok, value } = await client.uploadFromFilename(objectName, filename);
193+
expect(ok).toBeTruthy();
194+
expect(value).toBeNull();
195+
196+
const { value: text } = await client.downloadAsText(objectName);
197+
expect(text).toBe(testFileContents);
198+
199+
fs.rmdirSync(localTestDir, { recursive: true });
200+
});
201+
});
202+
203+
describe('uploadFromStream', () => {
204+
test('upload then download', async () => {
205+
const objectName = `${testDir}/upload-from-stream-1.txt`;
206+
207+
const stream = new PassThrough();
208+
stream.end(testFileContents);
209+
await client.uploadFromStream(objectName, stream);
210+
211+
const { value: text } = await client.downloadAsText(objectName);
212+
expect(text).toBe(testFileContents);
213+
});
214+
});
215+
216+
afterAll(async () => {
217+
const { value: files } = await client.list();
218+
const deletions = files.map((file) => client.delete(file));
219+
await Promise.all(deletions);
220+
});

src/client.test.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)