mirror of
https://github.com/djdevin/recflare.git
synced 2026-10-25 15:09:18 -07:00
133 lines
4.5 KiB
TypeScript
133 lines
4.5 KiB
TypeScript
import { env, SELF } from 'cloudflare:test'
|
|
import { beforeEach, expect, it } from 'vitest'
|
|
|
|
import type { Env } from '../../context'
|
|
|
|
declare module 'cloudflare:test' {
|
|
interface ProvidedEnv extends Env {}
|
|
}
|
|
|
|
const origin = 'https://example.com/1/apps/template-fixture'
|
|
beforeEach(async () => {
|
|
env.STUDIO_DISTRIBUTION_MANIFEST = 'distribution/catalog.json'
|
|
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode('template-fixture'))
|
|
await env.CDN_ASSETS.put(
|
|
env.STUDIO_DISTRIBUTION_MANIFEST,
|
|
JSON.stringify({
|
|
appSecretSha256: Array.from(new Uint8Array(digest), (b) =>
|
|
b.toString(16).padStart(2, '0')
|
|
).join(''),
|
|
latest: 170,
|
|
legacySummaries: { '169': { files: [{ path: 'original.tgz', hash: '87654321', size: 80 }] } },
|
|
releases: [
|
|
{
|
|
version: 170,
|
|
label: 'v170',
|
|
partSize: 32,
|
|
contentUrl: 'https://cdn.example.test/template.zip',
|
|
summary: {
|
|
hash_code: 'a'.repeat(64),
|
|
compression_method: 'zip',
|
|
size: 50,
|
|
files: [{ path: 'patched.tgz', hash: '12345678', size: 80 }],
|
|
chunks: { size: 32, hashes: ['12345678', '87654321'] },
|
|
},
|
|
},
|
|
],
|
|
})
|
|
)
|
|
})
|
|
it('serves the prepatched v170 catalog and complete multipart download contract', async () => {
|
|
expect(await (await SELF.fetch(origin + '/changelog')).json()).toEqual({
|
|
versions: [{ vid: 170, label: 'v170', changelog: 'v170' }],
|
|
})
|
|
expect(await (await SELF.fetch(origin + '/versions/latest/id')).json()).toEqual({ id: 170 })
|
|
expect(await (await SELF.fetch(origin)).json()).toMatchObject({
|
|
current_version: 170,
|
|
use_keys: false,
|
|
})
|
|
expect(await (await SELF.fetch(origin + '/versions/170')).json()).toMatchObject({
|
|
id: 170,
|
|
label: 'v170',
|
|
patch_links: { incoming: [], outgoing: [] },
|
|
content_guid: 'a'.repeat(64),
|
|
})
|
|
expect(await (await SELF.fetch(origin + '/versions/170/content_urls')).json()).toEqual([
|
|
{ url: 'https://cdn.example.test/template.zip', part_size: 32 },
|
|
])
|
|
expect(await (await SELF.fetch(origin + '/versions/170/content_summary')).json()).toMatchObject({
|
|
compression_method: 'zip',
|
|
chunks: { hashes: ['12345678', '87654321'] },
|
|
})
|
|
})
|
|
|
|
it('rejects malformed or unsafe catalogs without caching a broken update response', async () => {
|
|
const key = env.STUDIO_DISTRIBUTION_MANIFEST!
|
|
const original = await (await env.CDN_ASSETS.get(key))!.text()
|
|
for (const change of [
|
|
(c: any) => {
|
|
c.latest = 171
|
|
},
|
|
(c: any) => {
|
|
c.releases.push(c.releases[0])
|
|
},
|
|
(c: any) => {
|
|
c.legacySummaries['170'] = c.legacySummaries['169']
|
|
},
|
|
(c: any) => {
|
|
c.releases[0].contentUrl = 'http://cdn.example.test/content.zip'
|
|
},
|
|
(c: any) => {
|
|
c.releases[0].summary.files[0].path = '../outside'
|
|
},
|
|
(c: any) => {
|
|
c.releases[0].summary.files = null
|
|
},
|
|
(c: any) => {
|
|
delete c.releases[0].summary.hash_code
|
|
},
|
|
(c: any) => {
|
|
c.releases[0].summary.chunks.hashes = []
|
|
},
|
|
]) {
|
|
const catalog = JSON.parse(original)
|
|
change(catalog)
|
|
await env.CDN_ASSETS.put(key, JSON.stringify(catalog))
|
|
const response = await SELF.fetch(origin + '/versions/170/diff_summary')
|
|
expect(response.status).toBe(503)
|
|
expect(response.headers.get('Cache-Control')).toBe('no-store')
|
|
}
|
|
await env.CDN_ASSETS.put(key, '{')
|
|
expect((await SELF.fetch(origin)).status).toBe(503)
|
|
await env.CDN_ASSETS.put(key, ' '.repeat(8 * 1024 * 1024 + 1))
|
|
expect((await SELF.fetch(origin)).status).toBe(503)
|
|
})
|
|
it('does not route other applications, missing versions, or disabled catalogs', async () => {
|
|
expect((await SELF.fetch('https://example.com/1/apps/unrelated/versions/latest/id')).status).toBe(
|
|
404
|
|
)
|
|
expect(await (await SELF.fetch(origin + '/versions/169')).json()).toMatchObject({
|
|
id: 169,
|
|
label: 'v169',
|
|
})
|
|
expect((await SELF.fetch(origin + '/versions/168')).status).toBe(404)
|
|
expect((await SELF.fetch(origin + '/versions/169/content_urls')).status).toBe(404)
|
|
delete env.STUDIO_DISTRIBUTION_MANIFEST
|
|
expect((await SELF.fetch(origin + '/versions/latest/id')).status).toBe(404)
|
|
})
|
|
|
|
it('provides cached comparison and full-replacement update metadata without legacy downloads', async () => {
|
|
expect(await (await SELF.fetch(origin + '/versions/169/content_summary')).json()).toMatchObject({
|
|
files: [{ path: 'original.tgz', hash: '87654321' }],
|
|
})
|
|
expect(await (await SELF.fetch(origin + '/versions/170/diff_summary')).json()).toMatchObject({
|
|
compression_method: 'zip',
|
|
added_files: ['patched.tgz'],
|
|
modified_files: [],
|
|
unchanged_files: [],
|
|
})
|
|
expect(await (await SELF.fetch(origin + '/versions/170/diff_urls')).json()).toEqual([
|
|
{ url: 'https://cdn.example.test/template.zip', part_size: 32 },
|
|
])
|
|
})
|