fix: FanoutTimelineServiceにリストが空の場合のみダミーIDを挿入するinjectDummyIfEmptyメソッドを追加しました。
This commit is contained in:
parent
33bd93ca40
commit
3fe1d27927
|
|
@ -231,7 +231,7 @@ export class FanoutTimelineEndpointService {
|
|||
Promise.all(ps.redisTimelines.map((tl, i) => {
|
||||
// 有効なソースかつ結果が空だった場合のみダミーを入れる
|
||||
if (redisResult[i] && redisResult[i].length === 0) {
|
||||
return this.fanoutTimelineService.injectDummy(tl, dummyId);
|
||||
return this.fanoutTimelineService.injectDummyIfEmpty(tl, dummyId);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -109,10 +109,20 @@ export class FanoutTimelineService {
|
|||
}
|
||||
|
||||
@bindThis
|
||||
public injectDummy(tl: FanoutTimelineName, id: string) {
|
||||
injectDummy(tl: FanoutTimelineName, id: string) {
|
||||
return this.redisForTimelines.lpush('list:' + tl, id);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public injectDummyIfEmpty(tl: FanoutTimelineName, id: string): Promise<boolean> {
|
||||
return this.redisForTimelines.eval(
|
||||
'if redis.call("LLEN", KEYS[1]) == 0 then redis.call("LPUSH", KEYS[1], ARGV[1]) return 1 else return 0 end',
|
||||
1,
|
||||
'list:' + tl,
|
||||
id,
|
||||
).then(res => res === 1);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public purge(name: FanoutTimelineName) {
|
||||
return this.redisForTimelines.del('list:' + name);
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ describe('FanoutTimelineEndpointService', () => {
|
|||
.useValue({
|
||||
getMulti: jest.fn(),
|
||||
injectDummy: jest.fn(),
|
||||
injectDummyIfEmpty: jest.fn(),
|
||||
})
|
||||
.compile();
|
||||
|
||||
|
|
@ -266,9 +267,9 @@ describe('FanoutTimelineEndpointService', () => {
|
|||
|
||||
expect(result).toEqual([]);
|
||||
// Should have tried to inject dummy ID for both empty timelines
|
||||
expect(fanoutTimelineService.injectDummy).toHaveBeenCalledTimes(2);
|
||||
expect(fanoutTimelineService.injectDummy).toHaveBeenCalledWith(`homeTimeline:${alice.id}`, expect.any(String));
|
||||
expect(fanoutTimelineService.injectDummy).toHaveBeenCalledWith('localTimeline', expect.any(String));
|
||||
expect(fanoutTimelineService.injectDummyIfEmpty).toHaveBeenCalledTimes(2);
|
||||
expect(fanoutTimelineService.injectDummyIfEmpty).toHaveBeenCalledWith(`homeTimeline:${alice.id}`, expect.any(String));
|
||||
expect(fanoutTimelineService.injectDummyIfEmpty).toHaveBeenCalledWith('localTimeline', expect.any(String));
|
||||
});
|
||||
|
||||
// Test for behavior when dummy ID exists
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { describe, jest, test, expect, afterEach, beforeAll, afterAll } from '@jest/globals';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import * as Redis from 'ioredis';
|
||||
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
|
||||
describe('FanoutTimelineService', () => {
|
||||
let app: TestingModule;
|
||||
let service: FanoutTimelineService;
|
||||
let redisForTimelines: jest.Mocked<Redis.Redis>;
|
||||
let idService: IdService;
|
||||
|
||||
beforeAll(async () => {
|
||||
app = await Test.createTestingModule({
|
||||
providers: [
|
||||
FanoutTimelineService,
|
||||
{
|
||||
provide: IdService,
|
||||
useValue: {
|
||||
parse: jest.fn(),
|
||||
gen: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: DI.redisForTimelines,
|
||||
useValue: {
|
||||
eval: jest.fn(),
|
||||
lpush: jest.fn(),
|
||||
lrange: jest.fn(),
|
||||
del: jest.fn(),
|
||||
pipeline: jest.fn(() => ({
|
||||
lpush: jest.fn(),
|
||||
ltrim: jest.fn(),
|
||||
lrange: jest.fn(),
|
||||
exec: jest.fn(),
|
||||
})),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
app.enableShutdownHooks();
|
||||
|
||||
service = app.get<FanoutTimelineService>(FanoutTimelineService);
|
||||
redisForTimelines = app.get(DI.redisForTimelines);
|
||||
idService = app.get<IdService>(IdService);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('injectDummyIfEmpty should call Redis EVAL with correct script', async () => {
|
||||
redisForTimelines.eval.mockResolvedValue(1);
|
||||
|
||||
const result = await service.injectDummyIfEmpty('homeTimeline:123', 'dummyId');
|
||||
|
||||
expect(redisForTimelines.eval).toHaveBeenCalledWith(
|
||||
expect.stringContaining('if redis.call("LLEN", KEYS[1]) == 0 then'),
|
||||
1,
|
||||
'list:homeTimeline:123',
|
||||
'dummyId',
|
||||
);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test('injectDummyIfEmpty should return false if list is not empty', async () => {
|
||||
redisForTimelines.eval.mockResolvedValue(0);
|
||||
|
||||
const result = await service.injectDummyIfEmpty('homeTimeline:123', 'dummyId');
|
||||
|
||||
expect(redisForTimelines.eval).toHaveBeenCalled();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue