Skip to content

Commit

Permalink
HTML meta test (#3799)
Browse files Browse the repository at this point in the history
* wip

* note

* image

* wip

* ffmpeg

* sudo

* instance
  • Loading branch information
mei23 committed Jun 18, 2022
1 parent 15b584e commit 15829b1
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .config/example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ drive:
# Sign to ActivityPub GET request (default: false)
#signToActivityPubGet: true

# 最初に作成したユーザーを管理者にする (default: true)
# 最初に作成したユーザーを管理者にする (default: false)
autoAdmin: true

# アイコン等の設定
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- run: node cli/diag-environment.js
- run: sudo apt-get install -y ffmpeg
- run: yarn install
- run: git diff --exit-code yarn.lock
- run: yarn build
Expand Down
2 changes: 1 addition & 1 deletion src/misc/check-private-ip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as IPCIDR from 'ip-cidr';
const PrivateIp = require('private-ip');

export function checkPrivateIp(ip: string | undefined): boolean {
if ((process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') && !config.proxy && ip) {
if ((process.env.NODE_ENV === 'production') && !config.proxy && ip) {
// check exclusion
for (const net of config.allowedPrivateNetworks || []) {
const cidr = new IPCIDR(net);
Expand Down
217 changes: 215 additions & 2 deletions test/fetch-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ process.env.NODE_ENV = 'test';

import * as assert from 'assert';
import * as childProcess from 'child_process';
import { async, startServer, signup, post, api, simpleGet, port, shutdownServer } from './utils';
import { async, startServer, signup, post, api, simpleGet, port, shutdownServer, getDocument, uploadFile } from './utils';
import * as openapi from '@redocly/openapi-core';

const db = require('../built/db/mongodb').default;
Expand All @@ -31,8 +31,16 @@ const HTML = 'text/html; charset=utf-8';
describe('Fetch resource', () => {
let p: childProcess.ChildProcess;

let admin: any;
let instance: any;

let alice: any;
let avatar: any;
let alicesPost: any;
let image: any;
let alicesPostImage: any;
let video: any;
let alicesPostVideo: any;

before(async () => {
p = await startServer();
Expand All @@ -41,10 +49,66 @@ describe('Fetch resource', () => {
db.get('notes').drop(),
]);

// admin
admin = await signup({ username: 'admin' });

// update instance
await api('admin/update-meta', {
name: 'Instance Name',
description: 'Instance Desc',
}, admin);

instance = (await api('meta', {})).body;
//console.log('instance', instance);

// signup
alice = await signup({ username: 'alice' });
//console.log('alice', alice);

// upload avatar
avatar = await uploadFile(alice);
//console.log('avatar', avatar);

// update profile
const token = alice.token;

const res = await api('i/update', {
name: 'Alice',
description: 'Alice Desc',
avatarId: avatar.id,
}, alice);

alice = res.body;
alice.token = token; // tokenはsignup以外では返ってこない
//console.log('alice-2', alice);

// post
alicesPost = await post(alice, {
text: 'test'
text: 'test',
});
//console.log('alicesPost', alicesPost);

// upload image
image = await uploadFile(alice);
//console.log('image', image);

// post image
alicesPostImage = await post(alice, {
text: 'image',
fileIds: [ image.id ],
});
//console.log('alicesPostImage', alicesPostImage);

// upload video
video = await uploadFile(alice, 'anime.mp4');
//console.log('video', video);

// post video
alicesPostVideo = await post(alice, {
text: 'video',
fileIds: [ video.id ],
});
//console.log('alicesPostVideo', alicesPostVideo);
});

after(async () => {
Expand Down Expand Up @@ -195,4 +259,153 @@ describe('Fetch resource', () => {
assert.strictEqual(res.type, 'application/json; charset=utf-8');
}));
});

describe('HTML meta', () => {
const parse = (doc: Document) => {
return {
// Title
'title': doc.querySelector('title')?.textContent,
'og:title': doc.querySelector('meta[property="og:title"]')?.getAttribute('content'),
'og:site_name': doc.querySelector('meta[property="og:site_name"]')?.getAttribute('content'),

// Description
'description': doc.querySelector('meta[name=description]')?.getAttribute('content'),
'og:description': doc.querySelector('meta[property="og:description"]')?.getAttribute('content'),

// Twitter card
'twitter:card': doc.querySelector('meta[name="twitter:card"]')?.getAttribute('content'),

// Misskey
'misskey:user-username': doc.querySelector('meta[name="misskey:user-username"]')?.getAttribute('content'),
'misskey:user-id': doc.querySelector('meta[name="misskey:user-id"]')?.getAttribute('content'),

// Generic - og
'og:url': doc.querySelector('meta[property="og:url"]')?.getAttribute('content'),
'og:image': doc.querySelector('meta[property="og:image"]')?.getAttribute('content'),
//og:published_time': doc.querySelector('meta[property="og:published_time"]')?.getAttribute('content'),

// Player - Twitter
'twitter:player': doc.querySelector('meta[name="twitter:player"]')?.getAttribute('content'),
'twitter:player:width': doc.querySelector('meta[name="twitter:player:width"]')?.getAttribute('content'),
'twitter:player:height': doc.querySelector('meta[name="twitter:player:height"]')?.getAttribute('content'),
'twitter:player:stream': doc.querySelector('meta[name="twitter:player:stream"]')?.getAttribute('content'),
'twitter:player:stream:content_type': doc.querySelector('meta[name="twitter:player:stream:content_type"]')?.getAttribute('content'),
};
}

it('/', async(async () => {
const parsed = parse(await getDocument('/'));

assert.deepStrictEqual(parsed, {
'title': instance.name,
'og:title': instance.name,
'og:site_name': instance.name,
'description': instance.description,
'og:description': instance.description,
'twitter:card': 'summary',
'misskey:user-username': undefined,
'misskey:user-id': undefined,
'og:url': undefined,
'og:image': undefined,
//'og:published_time': undefined,
'twitter:player': undefined,
'twitter:player:width': undefined,
'twitter:player:height': undefined,
'twitter:player:stream': undefined,
'twitter:player:stream:content_type': undefined,
});
}));

it('user', async(async () => {
const parsed = parse(await getDocument(`/@${alice.username}`));

assert.deepStrictEqual(parsed, {
'title': `${alice.name} (@${alice.username}) | ${instance.name}`,
'og:title': `${alice.name} (@${alice.username})`,
'og:site_name': undefined,
'description': alice.description,
'og:description': alice.description,
'twitter:card': 'summary',
'misskey:user-username': alice.username,
'misskey:user-id': alice.id,
'og:url': `http://misskey.local/@${alice.username}`,
'og:image': alice.avatarUrl,
//'og:published_time': undefined,
'twitter:player': undefined,
'twitter:player:width': undefined,
'twitter:player:height': undefined,
'twitter:player:stream': undefined,
'twitter:player:stream:content_type': undefined,
});
}));

it('note', async(async () => {
const parsed = parse(await getDocument(`/notes/${alicesPost.id}`));

assert.deepStrictEqual(parsed, {
'title': `${alice.name} (@${alice.username}) | ${instance.name}`,
'og:title': `${alice.name} (@${alice.username})`,
'og:site_name': undefined,
'description': alicesPost.text,
'og:description': alicesPost.text,
'twitter:card': 'summary',
'misskey:user-username': alice.username,
'misskey:user-id': alice.id,
'og:url': `http://misskey.local/notes/${alicesPost.id}`,
'og:image': alice.avatarUrl,
//'og:published_time': alicesPost.createtAt,
'twitter:player': undefined,
'twitter:player:width': undefined,
'twitter:player:height': undefined,
'twitter:player:stream': undefined,
'twitter:player:stream:content_type': undefined,
});
}));

it('note with image', async(async () => {
const parsed = parse(await getDocument(`/notes/${alicesPostImage.id}`));

assert.deepStrictEqual(parsed, {
'title': `${alice.name} (@${alice.username}) | ${instance.name}`,
'og:title': `${alice.name} (@${alice.username})`,
'og:site_name': undefined,
'description': `${alicesPostImage.text} (1つのファイル)`,
'og:description': `${alicesPostImage.text} (1つのファイル)`,
'twitter:card': 'summary',
'misskey:user-username': alice.username,
'misskey:user-id': alice.id,
'og:url': `http://misskey.local/notes/${alicesPostImage.id}`,
'og:image': alicesPostImage.files[0].thumbnailUrl,
//'og:published_time': alicesPostImage.createtAt,
'twitter:player': undefined,
'twitter:player:width': undefined,
'twitter:player:height': undefined,
'twitter:player:stream': undefined,
'twitter:player:stream:content_type': undefined,
});
}));

it('note with video', async(async () => {
const parsed = parse(await getDocument(`/notes/${alicesPostVideo.id}`));

assert.deepStrictEqual(parsed, {
'title': `${alice.name} (@${alice.username}) | ${instance.name}`,
'og:title': `${alice.name} (@${alice.username})`,
'og:site_name': undefined,
'description': `${alicesPostVideo.text} (1つのファイル)`,
'og:description': `${alicesPostVideo.text} (1つのファイル)`,
'twitter:card': 'player',
'misskey:user-username': alice.username,
'misskey:user-id': alice.id,
'og:url': `http://misskey.local/notes/${alicesPostVideo.id}`,
'og:image': alicesPostVideo.files[0].thumbnailUrl,
//'og:published_time': alicesPostVideo.createtAt,
'twitter:player': `http://misskey.local/notes/${alicesPostVideo.id}/embed`,
'twitter:player:width': '530',
'twitter:player:height': '255',
'twitter:player:stream': alicesPostVideo.files[0].url,
'twitter:player:stream:content_type': alicesPostVideo.files[0].type,
});
}));
});
});
Binary file added test/resources/anime.mp4
Binary file not shown.
2 changes: 2 additions & 0 deletions test/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ mongodb:
redis:
host: localhost
port: 56310

autoAdmin: true
48 changes: 47 additions & 1 deletion test/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import * as childProcess from 'child_process';
import * as http from 'http';
import * as fs from 'fs';
import * as path from 'path';
import got from 'got';
import loadConfig from '../src/config/load';
import { SIGKILL } from 'constants';
import { getHtml } from '../src/misc/fetch';
import { JSDOM } from 'jsdom';
import * as FormData from 'form-data';

export const port = loadConfig().port;

Expand Down Expand Up @@ -77,8 +82,17 @@ export const api = async (endpoint: string, params: any, me?: any): Promise<{ bo
'Content-Type': 'application/json'
},
body: JSON.stringify(Object.assign(auth, params)),
timeout: 10 * 1000,
timeout: 30 * 1000,
retry: 0,
hooks: {
beforeError: [
error => {
const { response } = error;
if (response && response.body) console.warn(response.body);
return error;
}
]
},
});

const status = res.statusCode;
Expand Down Expand Up @@ -111,6 +125,31 @@ export const post = async (user: any, params?: any): Promise<any> => {
return res.body ? res.body.createdNote : null;
};

/**
* Upload file
* @param user User
* @param _path Optional, absolute path or relative from ./resources/
*/
export const uploadFile = async (user: any, _path?: string): Promise<any> => {
const absPath = _path == null ? `${__dirname}/resources/Lenna.jpg` : path.isAbsolute(_path) ? _path : `${__dirname}/resources/${_path}`;

const formData = new FormData();
formData.append('i', user.token);
formData.append('file', fs.createReadStream(absPath));
formData.append('force', 'true');

const res = await got<string>(`http://localhost:${port}/api/drive/files/create`, {
method: 'POST',
body: formData,
timeout: 30 * 1000,
retry: 0,
});

const body = res.statusCode !== 204 ? await JSON.parse(res.body) : null;

return body;
};

export const simpleGet = async (path: string, accept = '*/*'): Promise<{ status?: number, type?: string, location?: string }> => {
// node-fetchだと3xxを取れない
return await new Promise((resolve, reject) => {
Expand All @@ -133,3 +172,10 @@ export const simpleGet = async (path: string, accept = '*/*'): Promise<{ status?
req.end();
});
};

export const getDocument = async (path: string): Promise<Document> => {
const html = await getHtml(`http://localhost:${port}${path}`);
const { window } = new JSDOM(html);
const doc = window.document;
return doc;
};

0 comments on commit 15829b1

Please sign in to comment.