Skip to content

Commit 9b39b24

Browse files
committed
test: cache cleanup
1 parent da928c8 commit 9b39b24

File tree

5 files changed

+80
-2
lines changed

5 files changed

+80
-2
lines changed

lib/storage/drivers/filesystem.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ export const FilesystemStorageDriver = {
7474
},
7575

7676
async createReadStream(cacheFileName) {
77-
return createReadStream(path.join(rootFolder, BASE_FOLDER, cacheFileName))
77+
const filePath = path.join(rootFolder, BASE_FOLDER, cacheFileName)
78+
if (!(await fs.stat(filePath))) return null
79+
80+
return createReadStream(filePath)
7881
},
7982
}
8083
},

lib/storage/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export const useStorageAdapter = createSingletonPromise(async () => {
3636
const db = await useDB()
3737

3838
return {
39+
driver,
3940
async reserveCache({ key, version }: { key: string; version: string }) {
4041
logger.debug('Reserve:', { key, version })
4142

lib/storage/storage-driver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const UPLOAD_FOLDER = '.uploads'
99

1010
export interface StorageDriver {
1111
delete: (cacheFileNames: CacheFileName[]) => Promise<void>
12-
createReadStream: (cacheFileName: CacheFileName) => Promise<ReadableStream | Readable>
12+
createReadStream: (cacheFileName: CacheFileName) => Promise<ReadableStream | Readable | null>
1313
createDownloadUrl?: (cacheFileName: CacheFileName) => Promise<string>
1414
uploadPart: (opts: {
1515
uploadId: string

routes/download/[random]/[cacheFileName].ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ export default defineEventHandler(async (event) => {
1919

2020
const adapter = await useStorageAdapter()
2121
const stream = await adapter.download(cacheFileName as CacheFileName)
22+
if (!stream)
23+
throw createError({
24+
statusCode: 404,
25+
message: 'Cache file not found',
26+
})
2227

2328
return sendStream(event, stream)
2429
})

tests/e2e.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ import crypto from 'node:crypto'
22
import fs from 'node:fs/promises'
33
import path from 'node:path'
44

5+
import { Readable } from 'node:stream'
56
import { restoreCache, saveCache } from '@actions/cache'
67
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
8+
import { useStorageAdapter } from '~/lib/storage'
9+
import { getCacheFileName } from '~/lib/utils'
710

811
const TEST_TEMP_DIR = path.join(import.meta.dirname, 'temp')
912
await fs.mkdir(TEST_TEMP_DIR, { recursive: true })
@@ -44,3 +47,69 @@ for (const version of versions) {
4447
})
4548
})
4649
}
50+
51+
test(
52+
'pruning cache',
53+
{
54+
timeout: 60_000,
55+
},
56+
async () => {
57+
const storage = await useStorageAdapter()
58+
59+
const { cacheId } = await storage.reserveCache({
60+
key: 'cache-a',
61+
version: '1',
62+
})
63+
if (!cacheId) throw new Error('Failed to reserve cache')
64+
65+
// random 100MB ReadableStream
66+
const stream = new ReadableStream<Buffer>({
67+
start(controller) {
68+
const chunkSize = 1024 * 1024 // 1MB
69+
for (let i = 0; i < 100; i++) {
70+
const chunk = Buffer.alloc(chunkSize)
71+
controller.enqueue(chunk)
72+
}
73+
controller.close()
74+
},
75+
})
76+
await storage.uploadChunk({
77+
uploadId: cacheId,
78+
chunkIndex: 0,
79+
chunkStart: 0,
80+
chunkStream: stream,
81+
})
82+
await storage.commitCache(cacheId)
83+
84+
// exists
85+
expect(
86+
await storage.getCacheEntry({
87+
keys: ['cache-a'],
88+
version: '1',
89+
}),
90+
).toStrictEqual({
91+
archiveLocation: expect.stringMatching(
92+
new RegExp(
93+
`http:\/\/localhost:3000\/download\/[^\/]+\/${getCacheFileName('cache-a', '1')}`,
94+
),
95+
),
96+
cacheKey: 'cache-a',
97+
})
98+
expect(
99+
await storage.driver.createReadStream(getCacheFileName('cache-a', '1')).catch(() => null),
100+
).toBeInstanceOf(Readable)
101+
102+
await storage.pruneCaches()
103+
104+
// doesn't exist
105+
expect(
106+
await storage.getCacheEntry({
107+
keys: ['cache-a'],
108+
version: '1',
109+
}),
110+
).toBeNull()
111+
expect(
112+
await storage.driver.createReadStream(getCacheFileName('cache-a', '1')).catch(() => null),
113+
).toBe(null)
114+
},
115+
)

0 commit comments

Comments
 (0)