randomayzer/tests/vk-smoke-provider-mode.test.ts

115 lines
6.3 KiB
TypeScript

import { execFile } from 'node:child_process';
import { createServer } from 'node:http';
import { mkdtemp, writeFile, rm } from 'node:fs/promises';
import path from 'node:path';
import { promisify } from 'node:util';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { NextRequest } from 'next/server';
import { ProviderFactory } from '../src/providers/factory';
import { VkProvider } from '../src/providers/vk/vk-provider';
import { POST as previewPost } from '../src/app/api/posts/preview/route';
import { defaultSessionStore, SESSION_COOKIE_NAME } from '../src/lib/auth/session';
import { generalApiRateLimiter } from '../src/lib/rate-limiter';
const run = promisify(execFile);
afterEach(() => { vi.restoreAllMocks(); vi.unstubAllEnvs(); generalApiRateLimiter.reset(); });
describe('live smoke cannot accept generated VK data', () => {
it('rejects explicit mock configuration in production even with a service token', () => {
vi.stubEnv('NODE_ENV', 'production');
vi.stubEnv('USE_VK_MOCK', 'true');
vi.stubEnv('VK_SERVICE_TOKEN', 'FAKE_UNUSED_SERVICE_TOKEN');
expect(() => ProviderFactory.getVkProvider()).toThrow(/forbidden in production/);
});
it('labels an actual mock provider preview despite its SERVICE auth metadata', async () => {
vi.stubEnv('NODE_ENV', 'test');
vi.stubEnv('USE_VK_MOCK', 'true');
const id = await defaultSessionStore.createSession({ id: 'fake-smoke-mode-user', vkUserId: '9001' });
try {
const response = await previewPost(new NextRequest('http://localhost/api/posts/preview', {
method: 'POST', headers: { cookie: `${SESSION_COOKIE_NAME}=${id}`, 'content-type': 'application/json' },
body: JSON.stringify({ url: 'https://vk.com/wall-1_1' }),
}));
const body = await response.json();
expect(response.status).toBe(200);
expect(body.effectiveCapabilities.accessMode).toBe('PUBLIC_SERVICE');
expect(body.providerMode).toBe('MOCK');
} finally { await defaultSessionStore.destroySession(id); }
});
it('labels a real provider instance without exposing its token', async () => {
vi.stubEnv('NODE_ENV', 'test');
vi.stubEnv('USE_VK_MOCK', 'false');
vi.stubEnv('VK_SERVICE_TOKEN', 'FAKE_LIVE_MODE_MARKER_TOKEN');
vi.spyOn(VkProvider.prototype, 'fetchPost').mockResolvedValue({
platform: 'VK', ownerId: '-1', postId: '1', sourceUrl: 'https://vk.com/wall-1_1',
title: 'Fake response', text: '', likesCount: 2, commentsCount: 0, repostsCount: 0, resolvedAuthType: 'SERVICE',
});
const id = await defaultSessionStore.createSession({ id: 'fake-live-mode-user', vkUserId: '9002' });
try {
const response = await previewPost(new NextRequest('http://localhost/api/posts/preview', {
method: 'POST', headers: { cookie: `${SESSION_COOKIE_NAME}=${id}`, 'content-type': 'application/json' },
body: JSON.stringify({ url: 'https://vk.com/wall-1_1' }),
}));
const text = await response.text();
expect(response.status).toBe(200);
expect(JSON.parse(text).providerMode).toBe('LIVE');
expect(text).not.toContain('FAKE_LIVE_MODE_MARKER_TOKEN');
} finally { await defaultSessionStore.destroySession(id); }
});
it.each([
{ mode: 'MOCK', count: 2, expected: 1 },
{ mode: 'LIVE', count: 0, expected: 1 },
{ mode: 'LIVE', count: 2, expected: 0 },
])('smoke exits $expected for $mode mode with $count participants', async ({ mode, count, expected }) => {
let createCalls = 0;
let importCalls = 0;
const server = createServer((req, res) => {
req.resume();
if (req.url === '/api/auth/vk/start') {
res.writeHead(307, { location: 'https://id.vk.com/authorize?code_challenge_method=S256' }); res.end(); return;
}
res.setHeader('content-type', 'application/json');
if (req.url === '/api/auth/me') { res.end(JSON.stringify({ authenticated: true, user: { id: 'fake-user' } })); return; }
if (req.url === '/api/posts/preview') {
res.end(JSON.stringify({ success: true, providerMode: mode,
effectiveCapabilities: { accessMode: 'PUBLIC_SERVICE' }, post: { sourceUrl: 'https://vk.com/wall-1_1', resolvedAuthType: 'SERVICE' } })); return;
}
if (req.url === '/api/giveaways') {
createCalls++; res.statusCode = 201; res.end(JSON.stringify({ success: true, giveaway: { id: 'fake-giveaway' } })); return;
}
if (req.url === '/api/giveaways/fake-giveaway/participants') {
importCalls++; res.end(JSON.stringify({ success: true, providerMode: mode, totalCount: count })); return;
}
res.statusCode = 404; res.end('{}');
});
await new Promise<void>(resolve => server.listen(0, '127.0.0.1', resolve));
// Keep all local scratch material under the agent's permitted notes area.
const dir = await mkdtemp(path.resolve('agents/codex/notes/.smoke-regression-'));
try {
const port = (server.address() as { port: number }).port;
const file = path.join(dir, '.env.local');
await writeFile(file, `VK_SMOKE_BASE_URL=http://127.0.0.1:${port}\nVK_SMOKE_SESSION_COOKIE=randomayzer_session=FAKE_SMOKE_COOKIE\nVK_SMOKE_PUBLIC_POST_URL=https://vk.com/wall-1_1\nVK_SMOKE_GROUP_ID=42\nVK_SMOKE_CREATE_GIVEAWAY=YES\n`, { mode: 0o600 });
let stdout = '', exitCode = 0;
try { stdout = (await run('bash', [path.resolve('tools/vk-smoke.sh'), file], { timeout: 20000 })).stdout; }
catch (error) { const failure = error as { code: number; stdout: string }; exitCode = failure.code; stdout = failure.stdout; }
expect(exitCode).toBe(expected);
expect(stdout).toContain('MANUAL B');
expect(stdout).not.toContain('FAKE_SMOKE_COOKIE');
if (mode === 'MOCK') {
expect(stdout).toContain('FAIL D'); expect(stdout).not.toContain('PASS G'); expect(stdout).not.toContain('PASS H');
expect(createCalls).toBe(0); expect(importCalls).toBe(0);
} else if (count === 0) {
expect(stdout).toContain('FAIL G'); expect(stdout).toContain('FAIL H');
} else {
expect(stdout).toContain('PASS D'); expect(stdout).toContain('PASS G'); expect(stdout).toContain('PASS H');
expect(importCalls).toBe(2);
}
} finally {
await rm(dir, { recursive: true, force: true });
await new Promise<void>((resolve, reject) => server.close(err => err ? reject(err) : resolve()));
}
});
});