mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-10-28 10:48:49 -04:00
added live e2e for seeker recent grabs
This commit is contained in:
1 parent
a3441376f4
commit
031fbaf1bf
3 files changed
+100
-1
No files matched your search
@@ -159,7 +159,15 @@ export async function arrangeInstance(
|
||||
|
||||
const instances = config.instances.map((i: { arrInstanceId: string }) =>
|
||||
i.arrInstanceId === instance.id
|
||||
? { ...i, enabled: true, monitoredOnly: true, minCycleTimeDays: 0, ...overrides.instance }
|
||||
? {
|
||||
...i,
|
||||
enabled: true,
|
||||
monitoredOnly: true,
|
||||
minCycleTimeDays: 0,
|
||||
// Grabs from earlier specs stay in the arr's history for the whole suite run.
|
||||
recentGrabWindowHours: 0,
|
||||
...overrides.instance,
|
||||
}
|
||||
: i,
|
||||
);
|
||||
|
||||
@@ -194,6 +202,23 @@ export async function arrangeInstance(
|
||||
return instance.id;
|
||||
}
|
||||
|
||||
/** Patches one already-arranged instance's settings and asserts the update stuck. */
|
||||
export async function updateInstance(
|
||||
api: CleanuparrApi,
|
||||
instanceId: string,
|
||||
patch: Record<string, unknown>,
|
||||
): Promise<void> {
|
||||
const config = await (await api.seeker.getConfig()).json();
|
||||
const instances = config.instances.map((i: { arrInstanceId: string }) =>
|
||||
i.arrInstanceId === instanceId ? { ...i, ...patch } : i,
|
||||
);
|
||||
|
||||
const updated = await api.seeker.updateConfig({ ...config, instances });
|
||||
if (!updated.ok) {
|
||||
throw new Error(`Seeker config update failed: ${await updated.text()}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes the instances and restores the settings the specs changed. */
|
||||
export async function teardownInstances(api: CleanuparrApi): Promise<void> {
|
||||
for (const instance of createdInstances.splice(0)) {
|
||||
|
||||
@@ -11,14 +11,17 @@ import {
|
||||
expectNoSearch,
|
||||
firstSearchEvent,
|
||||
listSearchEvents,
|
||||
resetDownloads,
|
||||
resetLiveArrState,
|
||||
restoreLibrary,
|
||||
snapshotLibrary,
|
||||
teardownInstances,
|
||||
teardownQueueCleaner,
|
||||
triggerSeeker,
|
||||
updateInstance,
|
||||
RUN_TAG,
|
||||
TRIGGERED_SEARCH_TIMEOUT,
|
||||
type SeededArr,
|
||||
} from '../helpers/seeker-live';
|
||||
import { grabbableRelease, grabbableReleases } from '../helpers/mocks/torznab-stubs';
|
||||
|
||||
@@ -107,6 +110,27 @@ test.describe('Seeker candidate filters', () => {
|
||||
throw new Error('the queue cleaner never struck the grabbed download');
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers one search and waits for the arr to record its grab.
|
||||
*
|
||||
* History, not the queue: the arr can refuse to track a release an earlier test grabbed.
|
||||
*/
|
||||
async function grabOnce(api: CleanuparrApi, instanceId: string, target: SeededArr): Promise<void> {
|
||||
const since = encodeURIComponent(new Date().toISOString());
|
||||
|
||||
await triggerSeeker(api);
|
||||
await expect
|
||||
.poll(async () => (await listSearchEvents(api, instanceId)).length, { timeout: SETTLE_MS })
|
||||
.toBe(1);
|
||||
|
||||
await expect
|
||||
.poll(
|
||||
async () => (await target.arr.get<unknown[]>(`/api/v3/history/since?date=${since}&eventType=1`)).length,
|
||||
{ timeout: TRIGGERED_SEARCH_TIMEOUT },
|
||||
)
|
||||
.toBeGreaterThan(0);
|
||||
}
|
||||
|
||||
/** Whether a strike landed within the window, without failing the test if none did. */
|
||||
function pollStrikeCount(api: CleanuparrApi): Promise<boolean> {
|
||||
return expect
|
||||
@@ -281,4 +305,49 @@ test.describe('Seeker candidate filters', () => {
|
||||
)
|
||||
.toBe(2);
|
||||
});
|
||||
|
||||
test('skips a movie grabbed within the recent grab window', async ({ api }) => {
|
||||
test.setTimeout(180_000);
|
||||
|
||||
const instanceId = await arrangeInstance(api, RADARR, { instance: { monitoredOnly: true } });
|
||||
await grabOnce(api, instanceId, RADARR);
|
||||
await resetDownloads();
|
||||
|
||||
await updateInstance(api, instanceId, { recentGrabWindowHours: 24 });
|
||||
await triggerSeeker(api);
|
||||
await new Promise((resolve) => setTimeout(resolve, SETTLE_MS));
|
||||
|
||||
// The grab stays in arr history after resetDownloads clears the queue, so it is still skipped.
|
||||
expect(await listSearchEvents(api, instanceId)).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('searches a grabbed movie again with the window off', async ({ api }) => {
|
||||
test.setTimeout(180_000);
|
||||
|
||||
const instanceId = await arrangeInstance(api, RADARR, { instance: { monitoredOnly: true } });
|
||||
await grabOnce(api, instanceId, RADARR);
|
||||
await resetDownloads();
|
||||
|
||||
await triggerSeeker(api);
|
||||
|
||||
await expect
|
||||
.poll(async () => (await listSearchEvents(api, instanceId)).length, { timeout: SETTLE_MS })
|
||||
.toBe(2);
|
||||
});
|
||||
|
||||
test('skips an episode grabbed within the recent grab window', async ({ api }) => {
|
||||
test.setTimeout(180_000);
|
||||
|
||||
await indexerMock.stubMany(grabbableRelease(SONARR.searchMode, SONARR.release, SONARR.category).mappings);
|
||||
|
||||
const instanceId = await arrangeInstance(api, SONARR, { instance: { monitoredOnly: true } });
|
||||
await grabOnce(api, instanceId, SONARR);
|
||||
await resetDownloads();
|
||||
|
||||
await updateInstance(api, instanceId, { recentGrabWindowHours: 24 });
|
||||
await triggerSeeker(api);
|
||||
await new Promise((resolve) => setTimeout(resolve, SETTLE_MS));
|
||||
|
||||
expect(await listSearchEvents(api, instanceId)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -43,6 +43,7 @@ test.describe('Seeker — per-instance config', () => {
|
||||
expect(instance).toHaveProperty('enabled');
|
||||
expect(instance).toHaveProperty('skipTags');
|
||||
expect(instance).toHaveProperty('includeTags');
|
||||
expect(instance).toHaveProperty('recentGrabWindowHours');
|
||||
expect(instance).toHaveProperty('activeDownloadLimit');
|
||||
expect(instance).toHaveProperty('ignoreStruckDownloads');
|
||||
expect(instance).toHaveProperty('minCycleTimeDays');
|
||||
@@ -59,6 +60,7 @@ test.describe('Seeker — per-instance config', () => {
|
||||
expect(radarr.useCustomFormatScore).toBe(false);
|
||||
expect(radarr.ignoreStruckDownloads).toBe(false);
|
||||
expect(radarr.includeTags).toEqual([]);
|
||||
expect(radarr.recentGrabWindowHours).toBe(24);
|
||||
});
|
||||
|
||||
test('updates per-instance settings independently', async ({ api }) => {
|
||||
@@ -75,6 +77,7 @@ test.describe('Seeker — per-instance config', () => {
|
||||
useCustomFormatScore: true,
|
||||
ignoreStruckDownloads: true,
|
||||
includeTags: ['wanted', '4k'],
|
||||
recentGrabWindowHours: 48,
|
||||
};
|
||||
}
|
||||
if (i.arrInstanceId === sonarrId) {
|
||||
@@ -95,7 +98,9 @@ test.describe('Seeker — per-instance config', () => {
|
||||
expect(radarr.useCustomFormatScore).toBe(true);
|
||||
expect(radarr.ignoreStruckDownloads).toBe(true);
|
||||
expect(radarr.includeTags).toEqual(['wanted', '4k']);
|
||||
expect(radarr.recentGrabWindowHours).toBe(48);
|
||||
expect(sonarr.includeTags).toEqual([]);
|
||||
expect(sonarr.recentGrabWindowHours).toBe(24);
|
||||
expect(sonarr.ignoreStruckDownloads).toBe(false);
|
||||
expect(sonarr.monitoredOnly).toBe(true);
|
||||
expect(sonarr.useCutoff).toBe(true);
|
||||
|
||||
Reference in new issue
Block a user