mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 16:03:17 +00:00
159 lines
5.2 KiB
JavaScript
159 lines
5.2 KiB
JavaScript
import { createHash } from 'node:crypto'
|
|
import { mkdir, mkdtemp, readFile, readdir, realpath, rm } from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { materializeSshRelayRuntimeDraftReadback } from './ssh-relay-runtime-draft-readback.mjs'
|
|
|
|
const REPO = 'stablyai/orca'
|
|
const RELEASE_ID = 42
|
|
const TAG = 'v1.4.140-rc.1'
|
|
const TOKEN = 'secret-token'
|
|
const NAME = 'orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.xz'
|
|
const BYTES = Buffer.from('immutable release bytes')
|
|
const SECOND_NAME = 'orca-ssh-relay-runtime-manifest.json'
|
|
const SECOND_BYTES = Buffer.from('immutable manifest bytes')
|
|
|
|
let root
|
|
|
|
function expectedAsset(name = NAME, bytes = BYTES) {
|
|
return {
|
|
name,
|
|
sha256: `sha256:${createHash('sha256').update(bytes).digest('hex')}`,
|
|
size: bytes.length
|
|
}
|
|
}
|
|
|
|
function release(expectedAssets) {
|
|
return {
|
|
id: RELEASE_ID,
|
|
tag_name: TAG,
|
|
draft: true,
|
|
assets: expectedAssets.map((asset, index) => ({
|
|
id: 101 + index,
|
|
name: asset.name,
|
|
state: 'uploaded',
|
|
size: asset.size
|
|
}))
|
|
}
|
|
}
|
|
|
|
function fetchFixture(expectedAssets, assetResponses) {
|
|
const fetchImpl = vi.fn().mockResolvedValueOnce(Response.json(release(expectedAssets)))
|
|
for (const response of assetResponses) {
|
|
fetchImpl.mockResolvedValueOnce(response)
|
|
}
|
|
return fetchImpl
|
|
}
|
|
|
|
function input(expectedAssets, fetchImpl, overrides = {}) {
|
|
return {
|
|
repo: REPO,
|
|
releaseId: RELEASE_ID,
|
|
tag: TAG,
|
|
token: TOKEN,
|
|
expectedAssets,
|
|
outputDirectory: join(root, 'readback'),
|
|
fetchImpl,
|
|
...overrides
|
|
}
|
|
}
|
|
|
|
beforeEach(async () => {
|
|
root = await mkdtemp(join(tmpdir(), 'orca-relay-draft-readback-'))
|
|
})
|
|
|
|
afterEach(async () => {
|
|
await rm(root, { recursive: true, force: true })
|
|
vi.restoreAllMocks()
|
|
})
|
|
|
|
describe('SSH relay runtime draft read-back materialization', () => {
|
|
it('streams each asset once and exposes its final name only after exact verification', async () => {
|
|
const expected = expectedAsset()
|
|
let finish
|
|
const body = new ReadableStream({
|
|
start(controller) {
|
|
controller.enqueue(BYTES.subarray(0, 5))
|
|
finish = () => {
|
|
controller.enqueue(BYTES.subarray(5))
|
|
controller.close()
|
|
}
|
|
}
|
|
})
|
|
const fetchImpl = fetchFixture([expected], [new Response(body)])
|
|
const outputDirectory = join(root, 'readback')
|
|
const physicalOutput = join(await realpath(root), 'readback')
|
|
const materialization = materializeSshRelayRuntimeDraftReadback(
|
|
input([expected], fetchImpl, { outputDirectory })
|
|
)
|
|
|
|
await vi.waitFor(async () => expect((await readdir(outputDirectory)).length).toBe(1))
|
|
const namesDuringDownload = await readdir(outputDirectory)
|
|
expect(namesDuringDownload).not.toContain(NAME)
|
|
finish()
|
|
|
|
await expect(materialization).resolves.toEqual({
|
|
releaseId: RELEASE_ID,
|
|
tag: TAG,
|
|
materializedAssets: [{ ...expected, path: join(physicalOutput, NAME) }]
|
|
})
|
|
expect(fetchImpl).toHaveBeenCalledTimes(2)
|
|
expect(await readdir(outputDirectory)).toEqual([NAME])
|
|
expect(await readFile(join(outputDirectory, NAME))).toEqual(BYTES)
|
|
})
|
|
|
|
it('requires an absent output directory below an existing real parent before requesting GitHub', async () => {
|
|
const expected = expectedAsset()
|
|
const existingOutput = join(root, 'existing')
|
|
await mkdir(existingOutput)
|
|
|
|
for (const outputDirectory of [existingOutput, join(root, 'missing-parent', 'readback')]) {
|
|
const fetchImpl = vi.fn()
|
|
await expect(
|
|
materializeSshRelayRuntimeDraftReadback(input([expected], fetchImpl, { outputDirectory }))
|
|
).rejects.toThrow(/absent|parent|no such file/i)
|
|
expect(fetchImpl).not.toHaveBeenCalled()
|
|
}
|
|
})
|
|
|
|
it('removes the entire output when a later asset fails verification', async () => {
|
|
const expectedAssets = [expectedAsset(), expectedAsset(SECOND_NAME, SECOND_BYTES)]
|
|
const fetchImpl = fetchFixture(expectedAssets, [
|
|
new Response(BYTES),
|
|
new Response(Buffer.from('changed manifest bytes'))
|
|
])
|
|
const outputDirectory = join(root, 'readback')
|
|
|
|
await expect(
|
|
materializeSshRelayRuntimeDraftReadback(input(expectedAssets, fetchImpl, { outputDirectory }))
|
|
).rejects.toThrow(/size|sha-?256/i)
|
|
await expect(readdir(outputDirectory)).rejects.toMatchObject({ code: 'ENOENT' })
|
|
})
|
|
|
|
it('removes partial bytes when cancellation interrupts a streamed asset', async () => {
|
|
const expected = expectedAsset()
|
|
const controller = new AbortController()
|
|
const body = new ReadableStream({
|
|
start(stream) {
|
|
stream.enqueue(BYTES.subarray(0, 5))
|
|
}
|
|
})
|
|
const outputDirectory = join(root, 'readback')
|
|
const materialization = materializeSshRelayRuntimeDraftReadback(
|
|
input([expected], fetchFixture([expected], [new Response(body)]), {
|
|
outputDirectory,
|
|
signal: controller.signal
|
|
})
|
|
)
|
|
|
|
await vi.waitFor(async () => expect((await readdir(outputDirectory)).length).toBe(1))
|
|
controller.abort(new Error('cancel materialization'))
|
|
|
|
await expect(materialization).rejects.toThrow(/cancel materialization/i)
|
|
await expect(readdir(outputDirectory)).rejects.toMatchObject({ code: 'ENOENT' })
|
|
})
|
|
})
|