Files
openmaic/OpenMAIC/tests/app/api/makelore-runtime-binding.test.ts

61 lines
2.5 KiB
TypeScript

import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { NextRequest } from 'next/server';
import { POST } from '@/app/api/runtime/v1/bindings/validate/route';
describe('Makelore Learning Runtime binding', () => {
let root = '';
const previousStore = process.env.MAKELORE_COURSE_STORE_DIR;
const previousToken = process.env.MAKELORE_RUNTIME_TOKEN;
beforeEach(async () => {
root = await mkdtemp(join(tmpdir(), 'makelore-runtime-'));
process.env.MAKELORE_COURSE_STORE_DIR = root;
process.env.MAKELORE_RUNTIME_TOKEN = 'runtime-secret';
});
afterEach(async () => {
await rm(root, { recursive: true, force: true });
if (previousStore === undefined) delete process.env.MAKELORE_COURSE_STORE_DIR;
else process.env.MAKELORE_COURSE_STORE_DIR = previousStore;
if (previousToken === undefined) delete process.env.MAKELORE_RUNTIME_TOKEN;
else process.env.MAKELORE_RUNTIME_TOKEN = previousToken;
});
it('accepts only a retained course with the exact immutable hash', async () => {
const hash = 'a'.repeat(64);
await mkdir(root, { recursive: true });
await writeFile(join(root, 'course-1.json'), JSON.stringify({
schemaVersion: 1,
courseId: 'course-1',
contentHash: hash,
title: 'Python 基础入门',
classroom: { stage: { id: 'stage-1', name: 'Python 基础入门' }, scenes: [] },
}));
const request = new NextRequest('http://localhost/api/runtime/v1/bindings/validate', {
method: 'POST',
headers: { Authorization: 'Bearer runtime-secret', 'Content-Type': 'application/json' },
body: JSON.stringify({
session_id: 'session-1', owner_user_id: 'user-1', runtime: 'learning', runtime_version: 'v1',
binding: { kind: 'learning-course', key: `course-1:${hash}` },
}),
});
const response = await POST(request);
expect(response.status).toBe(200);
await expect(response.json()).resolves.toMatchObject({
type: 'learning.course.snapshot',
payload: { courseId: 'course-1', contentHash: hash, sceneCount: 0 },
});
});
it('rejects calls without the private runtime token', async () => {
const response = await POST(new NextRequest('http://localhost/api/runtime/v1/bindings/validate', {
method: 'POST', body: '{}', headers: { 'Content-Type': 'application/json' },
}));
expect(response.status).toBe(401);
});
});