fix(queue): extract shared arr cache helper, annotate season packs, null-guard flatMap (closes #61)
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) 2026 Gordon Bolton. MIT License.
|
||||
// Tests for the shared `buildArrQueueCache` helper (Issue #61).
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { createRequire } from 'module';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { buildArrQueueCache } = require('../../../server/utils/arrQueueHelpers');
|
||||
|
||||
const sonarrInstances = [
|
||||
{ id: 's1', url: 'http://sonarr-1', apiKey: 'KEY_S1', name: 'Sonarr 1' }
|
||||
];
|
||||
const radarrInstances = [
|
||||
{ id: 'r1', url: 'http://radarr-1', apiKey: 'KEY_R1', name: 'Radarr 1' }
|
||||
];
|
||||
|
||||
describe('buildArrQueueCache', () => {
|
||||
it('returns empty array for empty / missing input', () => {
|
||||
expect(buildArrQueueCache([], sonarrInstances, 'series')).toEqual([]);
|
||||
expect(buildArrQueueCache(null, sonarrInstances, 'series')).toEqual([]);
|
||||
expect(buildArrQueueCache(undefined, sonarrInstances, 'series')).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns empty array for invalid mediaKey', () => {
|
||||
const queues = [{ instance: 's1', data: { records: [{ id: 1 }] } }];
|
||||
expect(buildArrQueueCache(queues, sonarrInstances, 'bogus')).toEqual([]);
|
||||
});
|
||||
|
||||
it('tags Sonarr records with _instanceUrl/_instanceKey and decorates embedded series', () => {
|
||||
const queues = [
|
||||
{
|
||||
instance: 's1',
|
||||
data: {
|
||||
records: [
|
||||
{ id: 1, downloadId: 'dl-1', series: { id: 100, title: 'X' } }
|
||||
]
|
||||
}
|
||||
}
|
||||
];
|
||||
const out = buildArrQueueCache(queues, sonarrInstances, 'series');
|
||||
expect(out).toHaveLength(1);
|
||||
expect(out[0]._instanceUrl).toBe('http://sonarr-1');
|
||||
expect(out[0]._instanceKey).toBe('KEY_S1');
|
||||
expect(out[0].series._instanceUrl).toBe('http://sonarr-1');
|
||||
});
|
||||
|
||||
it('tags Radarr records and decorates embedded movie', () => {
|
||||
const queues = [
|
||||
{
|
||||
instance: 'r1',
|
||||
data: {
|
||||
records: [
|
||||
{ id: 11, downloadId: 'dl-r1', movie: { id: 555, title: 'M' } }
|
||||
]
|
||||
}
|
||||
}
|
||||
];
|
||||
const out = buildArrQueueCache(queues, radarrInstances, 'movie');
|
||||
expect(out).toHaveLength(1);
|
||||
expect(out[0]._instanceUrl).toBe('http://radarr-1');
|
||||
expect(out[0]._instanceKey).toBe('KEY_R1');
|
||||
expect(out[0].movie._instanceUrl).toBe('http://radarr-1');
|
||||
});
|
||||
|
||||
it('annotates Sonarr season pack records (multiple entries sharing downloadId)', () => {
|
||||
const queues = [
|
||||
{
|
||||
instance: 's1',
|
||||
data: {
|
||||
records: [
|
||||
{ id: 1, downloadId: 'pack-A', episodeId: 101 },
|
||||
{ id: 2, downloadId: 'pack-A', episodeId: 102 },
|
||||
{ id: 3, downloadId: 'pack-A', episodeId: 103 },
|
||||
{ id: 4, downloadId: 'single-B', episodeId: 200 }
|
||||
]
|
||||
}
|
||||
}
|
||||
];
|
||||
const out = buildArrQueueCache(queues, sonarrInstances, 'series');
|
||||
expect(out).toHaveLength(4);
|
||||
const packMembers = out.filter(r => r.downloadId === 'pack-A');
|
||||
expect(packMembers).toHaveLength(3);
|
||||
for (const r of packMembers) {
|
||||
expect(r.isSeasonPack).toBe(true);
|
||||
expect(r.episodeCount).toBe(3);
|
||||
}
|
||||
const single = out.find(r => r.downloadId === 'single-B');
|
||||
expect(single.isSeasonPack).toBeUndefined();
|
||||
expect(single.episodeCount).toBeUndefined();
|
||||
});
|
||||
|
||||
it('does not annotate Radarr records as season packs even if downloadId repeats', () => {
|
||||
const queues = [
|
||||
{
|
||||
instance: 'r1',
|
||||
data: {
|
||||
records: [
|
||||
{ id: 1, downloadId: 'dup', movie: { id: 1 } },
|
||||
{ id: 2, downloadId: 'dup', movie: { id: 2 } }
|
||||
]
|
||||
}
|
||||
}
|
||||
];
|
||||
const out = buildArrQueueCache(queues, radarrInstances, 'movie');
|
||||
expect(out).toHaveLength(2);
|
||||
for (const r of out) {
|
||||
expect(r.isSeasonPack).toBeUndefined();
|
||||
expect(r.episodeCount).toBeUndefined();
|
||||
}
|
||||
});
|
||||
|
||||
it('skips malformed records and continues', () => {
|
||||
const queues = [
|
||||
{
|
||||
instance: 's1',
|
||||
data: {
|
||||
records: [
|
||||
null,
|
||||
{ id: 1, downloadId: 'ok', series: { id: 1 } }
|
||||
]
|
||||
}
|
||||
},
|
||||
null,
|
||||
{ instance: 's1' } // no data property
|
||||
];
|
||||
const out = buildArrQueueCache(queues, sonarrInstances, 'series');
|
||||
expect(out).toHaveLength(1);
|
||||
expect(out[0].id).toBe(1);
|
||||
});
|
||||
|
||||
it('handles unknown instance id gracefully (null url/key)', () => {
|
||||
const queues = [
|
||||
{
|
||||
instance: 'unknown-instance',
|
||||
data: { records: [{ id: 1, downloadId: 'x' }] }
|
||||
}
|
||||
];
|
||||
const out = buildArrQueueCache(queues, sonarrInstances, 'series');
|
||||
expect(out).toHaveLength(1);
|
||||
expect(out[0]._instanceUrl).toBeNull();
|
||||
expect(out[0]._instanceKey).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user