Skip to content

Commit 75cb5cb

Browse files
committed
test(docs): execute native examples against streaming and binary responses
1 parent c32d75a commit 75cb5cb

1 file changed

Lines changed: 91 additions & 0 deletions

File tree

‎apps/docs/scripts/verify-api-samples.ts‎

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ const cases = [
114114
{ name: 'quoted', reference: quotedReference },
115115
]
116116
let activeCase = ''
117+
let holdStream = false
118+
let finishStream: (() => void) | undefined
117119
const captured: Array<{ method?: string; url: string; body: string; contentType: string }> = []
118120
const binary = new Uint8Array([0, 255, 254, 65, 128, 10])
119121
const eventStream = 'data: {"ok":true}\n\n'
@@ -143,6 +145,11 @@ const server = createServer(async (request, response) => {
143145
? 'text/event-stream'
144146
: 'application/json'
145147
)
148+
if (activeCase === 'streaming' && holdStream) {
149+
finishStream = () => response.end(eventStream)
150+
response.write(eventStream)
151+
return
152+
}
146153
response.end(
147154
activeCase === 'binary' ? binary : activeCase === 'streaming' ? eventStream : '{"ok":true}'
148155
)
@@ -245,6 +252,90 @@ try {
245252
`${language} compilation failed: ${result.error?.message ?? (result.stderr || result.stdout)}`
246253
)
247254
})
255+
if (
256+
(scenario.name === 'streaming' || scenario.name === 'binary') &&
257+
(language === 'go' || language === 'java' || language === 'csharp')
258+
) {
259+
await check(`${scenario.name}: ${language} live response bytes`, async () => {
260+
const runtimeFolder = join(folder, 'runtime')
261+
await mkdir(runtimeFolder, { recursive: true })
262+
const runtimeFile = join(runtimeFolder, filename)
263+
await writeFile(
264+
runtimeFile,
265+
sample.code.replaceAll('https://www.sim.ai', `http://127.0.0.1:${address.port}`)
266+
)
267+
if (language === 'csharp')
268+
await writeFile(
269+
join(runtimeFolder, 'Example.csproj'),
270+
'<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0</TargetFramework></PropertyGroup></Project>\n'
271+
)
272+
const compile = {
273+
go: ['go', 'build', '-o', join(runtimeFolder, 'example'), runtimeFile],
274+
java: ['javac', runtimeFile],
275+
csharp: [
276+
'dotnet',
277+
'build',
278+
join(runtimeFolder, 'Example.csproj'),
279+
'--nologo',
280+
'--verbosity',
281+
'quiet',
282+
],
283+
}[language]
284+
const compiled = spawnSync(compile[0], compile.slice(1), {
285+
encoding: 'utf8',
286+
timeout: 60000,
287+
maxBuffer: 1024 * 1024,
288+
})
289+
assert(
290+
compiled.status === 0,
291+
`${language} runtime fixture failed to compile: ${compiled.error?.message ?? (compiled.stderr || compiled.stdout)}`
292+
)
293+
const command = {
294+
go: [join(runtimeFolder, 'example')],
295+
java: ['java', '-cp', runtimeFolder, 'Example'],
296+
csharp: ['dotnet', join(runtimeFolder, 'bin/Debug/net8.0/Example.dll')],
297+
}[language]
298+
activeCase = scenario.name
299+
holdStream = scenario.name === 'streaming'
300+
const child = Bun.spawn(command, { stdout: 'pipe', stderr: 'pipe' })
301+
const reader = child.stdout.getReader()
302+
const deadline = setTimeout(() => child.kill(), 10000)
303+
const stderr = new Response(child.stderr).text()
304+
const chunks: Uint8Array[] = []
305+
let bytes = 0
306+
let earlyOutput = false
307+
try {
308+
while (true) {
309+
const next = await reader.read()
310+
if (next.done) break
311+
const chunk = next.value
312+
chunks.push(chunk)
313+
bytes += chunk.byteLength
314+
assert(bytes <= 65536, 'Native sample output exceeded 64KiB')
315+
if (holdStream && !earlyOutput && Buffer.concat(chunks).includes(eventStream)) {
316+
assert(finishStream, 'Output arrived before the fixture request')
317+
earlyOutput = true
318+
finishStream()
319+
finishStream = undefined
320+
}
321+
}
322+
const status = await child.exited
323+
assert(!holdStream || earlyOutput, 'No event reached stdout before stream completion')
324+
assert(status === 0, `${language} exited ${status}: ${await stderr}`)
325+
const expected = holdStream ? Buffer.from(eventStream.repeat(2)) : Buffer.from(binary)
326+
assert(Buffer.concat(chunks).equals(expected), 'Native response bytes changed')
327+
} finally {
328+
clearTimeout(deadline)
329+
reader.releaseLock()
330+
finishStream?.()
331+
finishStream = undefined
332+
holdStream = false
333+
child.kill()
334+
await child.exited
335+
await stderr
336+
}
337+
})
338+
}
248339
}
249340
fixtures.push({ name: scenario.name, operationId: scenario.reference.operationId, files })
250341
await check(

0 commit comments

Comments
 (0)