Files
Homarr/packages/integrations/test/nzbget.spec.ts
2024-12-16 15:06:31 +01:00

198 lines
6.7 KiB
TypeScript

import { join } from "path";
import type { StartedTestContainer } from "testcontainers";
import { GenericContainer, getContainerRuntimeClient, ImageName, Wait } from "testcontainers";
import { beforeAll, describe, expect, test } from "vitest";
import { NzbGetIntegration } from "../src";
const username = "nzbget";
const password = "tegbzn6789";
const IMAGE_NAME = "linuxserver/nzbget:latest";
describe("Nzbget integration", () => {
beforeAll(async () => {
const containerRuntimeClient = await getContainerRuntimeClient();
await containerRuntimeClient.image.pull(ImageName.fromString(IMAGE_NAME));
}, 100_000);
test("Test connection should work", async () => {
// Arrange
const startedContainer = await createNzbGetContainer().start();
const nzbGetIntegration = createNzbGetIntegration(startedContainer, username, password);
// Act
const actAsync = async () => await nzbGetIntegration.testConnectionAsync();
// Assert
await expect(actAsync()).resolves.not.toThrow();
// Cleanup
await startedContainer.stop();
}, 30_000);
test("Test connection should fail with wrong credentials", async () => {
// Arrange
const startedContainer = await createNzbGetContainer().start();
const nzbGetIntegration = createNzbGetIntegration(startedContainer, "wrong-user", "wrong-password");
// Act
const actAsync = async () => await nzbGetIntegration.testConnectionAsync();
// Assert
await expect(actAsync()).rejects.toThrow();
// Cleanup
await startedContainer.stop();
}, 30_000); // Timeout of 30 seconds
test("pauseQueueAsync should work", async () => {
// Arrange
const startedContainer = await createNzbGetContainer().start();
const nzbGetIntegration = createNzbGetIntegration(startedContainer, username, password);
// Acts
const actAsync = async () => await nzbGetIntegration.pauseQueueAsync();
const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync();
// Assert
await expect(actAsync()).resolves.not.toThrow();
await expect(getAsync()).resolves.toMatchObject({ status: { paused: true } });
// Cleanup
await startedContainer.stop();
}, 30_000); // Timeout of 30 seconds
test("resumeQueueAsync should work", async () => {
// Arrange
const startedContainer = await createNzbGetContainer().start();
const nzbGetIntegration = createNzbGetIntegration(startedContainer, username, password);
await nzbGetIntegration.pauseQueueAsync();
// Acts
const actAsync = async () => await nzbGetIntegration.resumeQueueAsync();
const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync();
// Assert
await expect(actAsync()).resolves.not.toThrow();
await expect(getAsync()).resolves.toMatchObject({
status: { paused: false },
});
// Cleanup
await startedContainer.stop();
}, 30_000); // Timeout of 30 seconds
test("Items should be empty", async () => {
// Arrange
const startedContainer = await createNzbGetContainer().start();
const nzbGetIntegration = createNzbGetIntegration(startedContainer, username, password);
// Act
const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync();
// Assert
await expect(getAsync()).resolves.not.toThrow();
await expect(getAsync()).resolves.toMatchObject({
items: [],
});
// Cleanup
await startedContainer.stop();
}, 30_000); // Timeout of 30 seconds
test("1 Items should exist after adding one", async () => {
// Arrange
const startedContainer = await createNzbGetContainer().start();
const nzbGetIntegration = createNzbGetIntegration(startedContainer, username, password);
await nzbGetAddItemAsync(startedContainer, username, password, nzbGetIntegration);
// Act
const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync();
// Assert
await expect(getAsync()).resolves.not.toThrow();
expect((await getAsync()).items).toHaveLength(1);
// Cleanup
await startedContainer.stop();
}, 30_000); // Timeout of 30 seconds
test("Delete item should result in empty items", async () => {
// Arrange
const startedContainer = await createNzbGetContainer().start();
const nzbGetIntegration = createNzbGetIntegration(startedContainer, username, password);
const item = await nzbGetAddItemAsync(startedContainer, username, password, nzbGetIntegration);
// Act
const actAsync = async () => await nzbGetIntegration.deleteItemAsync(item, true);
// Assert
await expect(actAsync()).resolves.not.toThrow();
// NzbGet is slow and we wait for a second before querying the items. Test was flaky without this.
await new Promise((resolve) => setTimeout(resolve, 1000));
const result = await nzbGetIntegration.getClientJobsAndStatusAsync();
expect(result.items).toHaveLength(0);
// Cleanup
await startedContainer.stop();
}, 30_000); // Timeout of 30 seconds
});
const createNzbGetContainer = () => {
return new GenericContainer(IMAGE_NAME)
.withExposedPorts(6789)
.withEnvironment({ PUID: "0", PGID: "0" })
.withWaitStrategy(Wait.forLogMessage("[ls.io-init] done."));
};
const createNzbGetIntegration = (container: StartedTestContainer, username: string, password: string) => {
return new NzbGetIntegration({
id: "1",
decryptedSecrets: [
{
kind: "username",
value: username,
},
{
kind: "password",
value: password,
},
],
name: "NzbGet",
url: `http://${container.getHost()}:${container.getMappedPort(6789)}`,
});
};
const nzbGetAddItemAsync = async (
container: StartedTestContainer,
username: string,
password: string,
integration: NzbGetIntegration,
) => {
// Add nzb file in the watch folder
await container.copyFilesToContainer([
{
source: join(__dirname, "/volumes/usenet/test_download_100MB.nzb"),
target: "/downloads/nzb/test_download_100MB.nzb",
},
]);
// Trigger scanning of the watch folder (Only available way to add an item except "append" which is too complex and unnecessary)
await fetch(`http://${container.getHost()}:${container.getMappedPort(6789)}/${username}:${password}/jsonrpc`, {
method: "POST",
body: JSON.stringify({ method: "scan" }),
});
// Retries up to 10000 times to let NzbGet scan and process the nzb (1 retry should suffice tbh but NzbGet is slow)
for (let i = 0; i < 10000; i++) {
const {
items: [item],
} = await integration.getClientJobsAndStatusAsync();
if (item) {
// Remove the added time because NzbGet doesn't return it properly in this specific case
const { added: _, ...itemRest } = item;
return itemRest;
}
}
// Throws if it can't find the item
throw new Error("No item found");
};