mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-05-07 17:25:31 +02:00
feat: track incoming requests by id, analytics increment for some metrics, ignore repeated requests by id
closes #12574
This commit is contained in:
154
test/activitypub/analytics.js
Normal file
154
test/activitypub/analytics.js
Normal file
@@ -0,0 +1,154 @@
|
||||
'use strict';
|
||||
|
||||
const nconf = require('nconf');
|
||||
const assert = require('assert');
|
||||
|
||||
const db = require('../../src/database');
|
||||
const controllers = require('../../src/controllers');
|
||||
const middleware = require('../../src/middleware');
|
||||
const activitypub = require('../../src/activitypub');
|
||||
const utils = require('../../src/utils');
|
||||
const user = require('../../src/user');
|
||||
const categories = require('../../src/categories');
|
||||
const topics = require('../../src/topics');
|
||||
const analytics = require('../../src/analytics');
|
||||
const api = require('../../src/api');
|
||||
|
||||
describe('Analytics', () => {
|
||||
let cid;
|
||||
let uid;
|
||||
let postData;
|
||||
|
||||
before(async () => {
|
||||
nconf.set('runJobs', 1);
|
||||
({ cid } = await categories.create({ name: utils.generateUUID().slice(0, 8) }));
|
||||
const remoteUser = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: 'https://example.org/user/foobar',
|
||||
url: 'https://example.org/user/foobar',
|
||||
|
||||
type: 'Person',
|
||||
name: 'Foo Bar',
|
||||
preferredUsername: 'foobar',
|
||||
publicKey: {
|
||||
id: 'https://example.org/user/foobar#key',
|
||||
owner: 'https://example.org/user/foobar',
|
||||
publicKeyPem: 'publickey',
|
||||
},
|
||||
};
|
||||
activitypub._cache.set(`0;https://example.org/user/foobar`, remoteUser);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
nconf.set('runJobs', undefined);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
uid = await user.create({ username: utils.generateUUID().slice(0, 8) });
|
||||
({ postData } = await topics.post({
|
||||
uid,
|
||||
cid,
|
||||
title: utils.generateUUID(),
|
||||
content: utils.generateUUID(),
|
||||
}));
|
||||
});
|
||||
|
||||
it('should record the incoming activity if successfully processed', async () => {
|
||||
const id = `https://example.org/activity/${utils.generateUUID()}`;
|
||||
await controllers.activitypub.postInbox({
|
||||
body: {
|
||||
id,
|
||||
type: 'Like',
|
||||
actor: 'https://example.org/user/foobar',
|
||||
object: {
|
||||
type: 'Note',
|
||||
id: `${nconf.get('url')}/post/${postData.pid}`,
|
||||
},
|
||||
},
|
||||
}, { sendStatus: () => {} });
|
||||
const processed = await db.isSortedSetMember('activities:datetime', id);
|
||||
|
||||
assert(processed);
|
||||
});
|
||||
|
||||
it('should not process the activity if received again', async () => {
|
||||
// Specifically, the controller would update the score, but the request should be caught in middlewares and ignored
|
||||
const id = `https://example.org/activity/${utils.generateUUID()}`;
|
||||
await controllers.activitypub.postInbox({
|
||||
body: {
|
||||
id,
|
||||
type: 'Like',
|
||||
actor: 'https://example.org/user/foobar',
|
||||
object: {
|
||||
type: 'Note',
|
||||
id: `${nconf.get('url')}/post/${postData.pid}`,
|
||||
},
|
||||
},
|
||||
}, { sendStatus: () => {} });
|
||||
|
||||
await middleware.activitypub.validate({
|
||||
body: {
|
||||
id,
|
||||
type: 'Like',
|
||||
actor: 'https://example.org/user/foobar',
|
||||
object: {
|
||||
type: 'Note',
|
||||
id: `${nconf.get('url')}/post/${postData.pid}`,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
sendStatus: (statusCode) => {
|
||||
assert.strictEqual(statusCode, 200);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should increment the last seen time of that domain', async () => {
|
||||
const id = `https://example.org/activity/${utils.generateUUID()}`;
|
||||
const before = await db.sortedSetScore('domains:lastSeen', 'example.org');
|
||||
await controllers.activitypub.postInbox({
|
||||
body: {
|
||||
id,
|
||||
type: 'Like',
|
||||
actor: 'https://example.org/user/foobar',
|
||||
object: {
|
||||
type: 'Note',
|
||||
id: `${nconf.get('url')}/post/${postData.pid}`,
|
||||
},
|
||||
},
|
||||
}, { sendStatus: () => {} });
|
||||
|
||||
const after = await db.sortedSetScore('domains:lastSeen', 'example.org');
|
||||
|
||||
assert(before && after);
|
||||
assert(before < after);
|
||||
});
|
||||
|
||||
it('should increment various metrics', async () => {
|
||||
let counters;
|
||||
({ counters } = analytics.peek());
|
||||
const before = { ...counters };
|
||||
|
||||
const id = `https://example.org/activity/${utils.generateUUID()}`;
|
||||
await controllers.activitypub.postInbox({
|
||||
body: {
|
||||
id,
|
||||
type: 'Like',
|
||||
actor: 'https://example.org/user/foobar',
|
||||
object: {
|
||||
type: 'Note',
|
||||
id: `${nconf.get('url')}/post/${postData.pid}`,
|
||||
},
|
||||
},
|
||||
}, { sendStatus: () => {} });
|
||||
|
||||
({ counters } = analytics.peek());
|
||||
const after = { ...counters };
|
||||
|
||||
const metrics = ['activities', 'activities:byType:Like', 'activities:byHost:example.org'];
|
||||
metrics.forEach((metric) => {
|
||||
assert(before[metric] && after[metric]);
|
||||
assert(before[metric] < after[metric]);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user