summaryrefslogtreecommitdiff
path: root/packages/backend/test/utils.ts
diff options
context:
space:
mode:
authorKagami Sascha Rosylight <saschanaz@outlook.com>2023-03-03 03:13:12 +0100
committerGitHub <noreply@github.com>2023-03-03 11:13:12 +0900
commit61215e50ff9e4c84787c8d99c75fd36dafbd8815 (patch)
tree36419e8a3ec97afa0a3a0011d523d80addf8e724 /packages/backend/test/utils.ts
parentfix(server): チャンネルでミュートが正しく機能していない... (diff)
downloadmisskey-61215e50ff9e4c84787c8d99c75fd36dafbd8815.tar.gz
misskey-61215e50ff9e4c84787c8d99c75fd36dafbd8815.tar.bz2
misskey-61215e50ff9e4c84787c8d99c75fd36dafbd8815.zip
test(backend): APIテストの復活 (#10163)
* Revert 1c5291f8185651c231903129ee7c1cee263f9f03 * APIテストの復活 * apiテストの移行 * moduleNameMapper修正 * simpleGetでthrowしないように status確認しているので要らない * longer timeout * ローカルでは問題ないのになんで * case sensitive * Run Nest instance within the current process * Skip some setIntervals * wait for 5 seconds * kill them all!! * logHeapUsage: true * detectOpenHandlesがじゃましているらしい * maxWorkers=1? * restore drive api tests * workerIdleMemoryLimit: 500MB * 1024MiB * Wait what
Diffstat (limited to 'packages/backend/test/utils.ts')
-rw-r--r--packages/backend/test/utils.ts240
1 files changed, 240 insertions, 0 deletions
diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts
index b813362893..8203e49359 100644
--- a/packages/backend/test/utils.ts
+++ b/packages/backend/test/utils.ts
@@ -1,3 +1,243 @@
+import { readFile } from 'node:fs/promises';
+import { isAbsolute, basename } from 'node:path';
+import WebSocket from 'ws';
+import fetch, { Blob, File, RequestInit } from 'node-fetch';
+import { DataSource } from 'typeorm';
+import { entities } from '../src/postgres.js';
+import { loadConfig } from '../src/config.js';
+import type * as misskey from 'misskey-js';
+
+export { server as startServer } from '@/boot/common.js';
+
+const config = loadConfig();
+export const port = config.port;
+
+export const api = async (endpoint: string, params: any, me?: any) => {
+ const normalized = endpoint.replace(/^\//, '');
+ return await request(`api/${normalized}`, params, me);
+};
+
+const request = async (path: string, params: any, me?: any): Promise<{ body: any, status: number }> => {
+ const auth = me ? {
+ i: me.token,
+ } : {};
+
+ const res = await relativeFetch(path, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(Object.assign(auth, params)),
+ redirect: 'manual',
+ });
+
+ const status = res.status;
+ const body = res.headers.get('content-type') === 'application/json; charset=utf-8'
+ ? await res.json()
+ : null;
+
+ return {
+ body, status,
+ };
+};
+
+const relativeFetch = async (path: string, init?: RequestInit | undefined) => {
+ return await fetch(new URL(path, `http://127.0.0.1:${port}/`).toString(), init);
+};
+
+export const signup = async (params?: any): Promise<any> => {
+ const q = Object.assign({
+ username: 'test',
+ password: 'test',
+ }, params);
+
+ const res = await api('signup', q);
+
+ return res.body;
+};
+
+export const post = async (user: any, params?: misskey.Endpoints['notes/create']['req']): Promise<misskey.entities.Note> => {
+ const q = Object.assign({
+ text: 'test',
+ }, params);
+
+ const res = await api('notes/create', q, user);
+
+ return res.body ? res.body.createdNote : null;
+};
+
+export const react = async (user: any, note: any, reaction: string): Promise<any> => {
+ await api('notes/reactions/create', {
+ noteId: note.id,
+ reaction: reaction,
+ }, user);
+};
+
+interface UploadOptions {
+ /** Optional, absolute path or relative from ./resources/ */
+ path?: string | URL;
+ /** The name to be used for the file upload */
+ name?: string;
+ /** A Blob can be provided instead of path */
+ blob?: Blob;
+}
+
+/**
+ * Upload file
+ * @param user User
+ */
+export const uploadFile = async (user: any, { path, name, blob }: UploadOptions = {}): Promise<any> => {
+ const absPath = path == null
+ ? new URL('resources/Lenna.jpg', import.meta.url)
+ : isAbsolute(path.toString())
+ ? new URL(path)
+ : new URL(path, new URL('resources/', import.meta.url));
+
+ const formData = new FormData();
+ formData.append('i', user.token);
+ formData.append('file', blob ??
+ new File([await readFile(absPath)], basename(absPath.toString())));
+ formData.append('force', 'true');
+ if (name) {
+ formData.append('name', name);
+ }
+
+ const res = await relativeFetch('api/drive/files/create', {
+ method: 'POST',
+ body: formData,
+ });
+
+ const body = res.status !== 204 ? await res.json() : null;
+
+ return {
+ status: res.status,
+ body,
+ };
+};
+
+export const uploadUrl = async (user: any, url: string) => {
+ let file: any;
+ const marker = Math.random().toString();
+
+ const ws = await connectStream(user, 'main', (msg) => {
+ if (msg.type === 'urlUploadFinished' && msg.body.marker === marker) {
+ file = msg.body.file;
+ }
+ });
+
+ await api('drive/files/upload-from-url', {
+ url,
+ marker,
+ force: true,
+ }, user);
+
+ await sleep(7000);
+ ws.close();
+
+ return file;
+};
+
+export function connectStream(user: any, channel: string, listener: (message: Record<string, any>) => any, params?: any): Promise<WebSocket> {
+ return new Promise((res, rej) => {
+ const ws = new WebSocket(`ws://127.0.0.1:${port}/streaming?i=${user.token}`);
+
+ ws.on('open', () => {
+ ws.on('message', data => {
+ const msg = JSON.parse(data.toString());
+ if (msg.type === 'channel' && msg.body.id === 'a') {
+ listener(msg.body);
+ } else if (msg.type === 'connected' && msg.body.id === 'a') {
+ res(ws);
+ }
+ });
+
+ ws.send(JSON.stringify({
+ type: 'connect',
+ body: {
+ channel: channel,
+ id: 'a',
+ pong: true,
+ params: params,
+ },
+ }));
+ });
+ });
+}
+
+export const waitFire = async (user: any, channel: string, trgr: () => any, cond: (msg: Record<string, any>) => boolean, params?: any) => {
+ return new Promise<boolean>(async (res, rej) => {
+ let timer: NodeJS.Timeout | null = null;
+
+ let ws: WebSocket;
+ try {
+ ws = await connectStream(user, channel, msg => {
+ if (cond(msg)) {
+ ws.close();
+ if (timer) clearTimeout(timer);
+ res(true);
+ }
+ }, params);
+ } catch (e) {
+ rej(e);
+ }
+
+ if (!ws!) return;
+
+ timer = setTimeout(() => {
+ ws.close();
+ res(false);
+ }, 3000);
+
+ try {
+ await trgr();
+ } catch (e) {
+ ws.close();
+ if (timer) clearTimeout(timer);
+ rej(e);
+ }
+ });
+};
+
+export const simpleGet = async (path: string, accept = '*/*'): Promise<{ status: number, body: any, type: string | null, location: string | null }> => {
+ const res = await relativeFetch(path, {
+ headers: {
+ Accept: accept,
+ },
+ redirect: 'manual',
+ });
+
+ const body = res.headers.get('content-type') === 'application/json; charset=utf-8'
+ ? await res.json()
+ : null;
+
+ return {
+ status: res.status,
+ body,
+ type: res.headers.get('content-type'),
+ location: res.headers.get('location'),
+ };
+};
+
+export async function initTestDb(justBorrow = false, initEntities?: any[]) {
+ if (process.env.NODE_ENV !== 'test') throw 'NODE_ENV is not a test';
+
+ const db = new DataSource({
+ type: 'postgres',
+ host: config.db.host,
+ port: config.db.port,
+ username: config.db.user,
+ password: config.db.pass,
+ database: config.db.db,
+ synchronize: true && !justBorrow,
+ dropSchema: true && !justBorrow,
+ entities: initEntities ?? entities,
+ });
+
+ await db.initialize();
+
+ return db;
+}
+
export function sleep(msec: number) {
return new Promise<void>(res => {
setTimeout(() => {