test: fix impossible test scenarios
Some checks failed
Release Workflow / determine-release-type (push) Has been cancelled
Release Workflow / checks (push) Has been cancelled
Release Workflow / e2e-tests (push) Has been cancelled
Release Workflow / build-images (push) Has been cancelled
Release Workflow / publish-release (push) Has been cancelled
Some checks failed
Release Workflow / determine-release-type (push) Has been cancelled
Release Workflow / checks (push) Has been cancelled
Release Workflow / e2e-tests (push) Has been cancelled
Release Workflow / build-images (push) Has been cancelled
Release Workflow / publish-release (push) Has been cancelled
This commit is contained in:
parent
11efe87b2e
commit
7bcf380198
5 changed files with 43 additions and 11 deletions
|
|
@ -12,6 +12,7 @@ import * as context from "~/server/core/request-context";
|
||||||
import * as spawnModule from "~/server/utils/spawn";
|
import * as spawnModule from "~/server/utils/spawn";
|
||||||
import { restic } from "~/server/utils/restic";
|
import { restic } from "~/server/utils/restic";
|
||||||
import { NotFoundError, BadRequestError } from "http-errors-enhanced";
|
import { NotFoundError, BadRequestError } from "http-errors-enhanced";
|
||||||
|
import { scheduleQueries } from "../backups.queries";
|
||||||
|
|
||||||
const resticBackupMock = mock(() => Promise.resolve({ exitCode: 0, summary: generateBackupOutput(), error: "" }));
|
const resticBackupMock = mock(() => Promise.resolve({ exitCode: 0, summary: generateBackupOutput(), error: "" }));
|
||||||
const resticForgetMock = mock(() => Promise.resolve({ success: true, data: null }));
|
const resticForgetMock = mock(() => Promise.resolve({ success: true, data: null }));
|
||||||
|
|
@ -55,12 +56,21 @@ describe("backup execution - validation failures", () => {
|
||||||
|
|
||||||
test("should fail backup when volume does not exist", async () => {
|
test("should fail backup when volume does not exist", async () => {
|
||||||
// arrange
|
// arrange
|
||||||
|
const volume = await createTestVolume();
|
||||||
const repository = await createTestRepository();
|
const repository = await createTestRepository();
|
||||||
const schedule = await createTestBackupSchedule({
|
const schedule = await createTestBackupSchedule({
|
||||||
volumeId: 99999,
|
volumeId: volume.id,
|
||||||
repositoryId: repository.id,
|
repositoryId: repository.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const hydratedSchedule = await scheduleQueries.findById(schedule.id, TEST_ORG_ID);
|
||||||
|
expect(hydratedSchedule).toBeDefined();
|
||||||
|
const scheduleWithoutVolume = {
|
||||||
|
...hydratedSchedule!,
|
||||||
|
volume: null,
|
||||||
|
} as unknown as NonNullable<Awaited<ReturnType<typeof scheduleQueries.findById>>>;
|
||||||
|
spyOn(scheduleQueries, "findById").mockResolvedValueOnce(scheduleWithoutVolume);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
const result = await backupsExecutionService.validateBackupExecution(schedule.id);
|
const result = await backupsExecutionService.validateBackupExecution(schedule.id);
|
||||||
|
|
||||||
|
|
@ -76,11 +86,20 @@ describe("backup execution - validation failures", () => {
|
||||||
test("should fail backup when repository does not exist", async () => {
|
test("should fail backup when repository does not exist", async () => {
|
||||||
// arrange
|
// arrange
|
||||||
const volume = await createTestVolume();
|
const volume = await createTestVolume();
|
||||||
|
const repository = await createTestRepository();
|
||||||
const schedule = await createTestBackupSchedule({
|
const schedule = await createTestBackupSchedule({
|
||||||
volumeId: volume.id,
|
volumeId: volume.id,
|
||||||
repositoryId: "non-existent-repo",
|
repositoryId: repository.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const hydratedSchedule = await scheduleQueries.findById(schedule.id, TEST_ORG_ID);
|
||||||
|
expect(hydratedSchedule).toBeDefined();
|
||||||
|
const scheduleWithoutRepository = {
|
||||||
|
...hydratedSchedule!,
|
||||||
|
repository: null,
|
||||||
|
} as unknown as NonNullable<Awaited<ReturnType<typeof scheduleQueries.findById>>>;
|
||||||
|
spyOn(scheduleQueries, "findById").mockResolvedValueOnce(scheduleWithoutRepository);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
const result = await backupsExecutionService.validateBackupExecution(schedule.id);
|
const result = await backupsExecutionService.validateBackupExecution(schedule.id);
|
||||||
|
|
||||||
|
|
@ -216,14 +235,13 @@ describe("retention policy - runForget", () => {
|
||||||
test("should throw NotFoundError when repository does not exist", async () => {
|
test("should throw NotFoundError when repository does not exist", async () => {
|
||||||
// arrange
|
// arrange
|
||||||
const schedule = await createTestBackupSchedule({
|
const schedule = await createTestBackupSchedule({
|
||||||
repositoryId: "non-existent-repo",
|
|
||||||
retentionPolicy: {
|
retentionPolicy: {
|
||||||
keepHourly: 24,
|
keepHourly: 24,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// act & assert
|
// act & assert
|
||||||
expect(backupsExecutionService.runForget(schedule.id)).rejects.toThrow("Repository not found");
|
expect(backupsExecutionService.runForget(schedule.id, "non-existent-repo")).rejects.toThrow("Repository not found");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { scheduleQueries } from "../backups.queries";
|
||||||
import { createTestBackupSchedule } from "~/test/helpers/backup";
|
import { createTestBackupSchedule } from "~/test/helpers/backup";
|
||||||
import { createTestVolume } from "~/test/helpers/volume";
|
import { createTestVolume } from "~/test/helpers/volume";
|
||||||
import { createTestRepository } from "~/test/helpers/repository";
|
import { createTestRepository } from "~/test/helpers/repository";
|
||||||
|
import { createTestOrganization } from "~/test/helpers/organization";
|
||||||
import { TEST_ORG_ID } from "~/test/helpers/organization";
|
import { TEST_ORG_ID } from "~/test/helpers/organization";
|
||||||
import { faker } from "@faker-js/faker";
|
import { faker } from "@faker-js/faker";
|
||||||
|
|
||||||
|
|
@ -140,6 +141,7 @@ describe("scheduleQueries.findExecutable", () => {
|
||||||
test("should not return schedules from other organizations", async () => {
|
test("should not return schedules from other organizations", async () => {
|
||||||
// arrange
|
// arrange
|
||||||
const otherOrgId = faker.string.uuid();
|
const otherOrgId = faker.string.uuid();
|
||||||
|
await createTestOrganization({ id: otherOrgId });
|
||||||
const schedule = await createTestBackupSchedule({
|
const schedule = await createTestBackupSchedule({
|
||||||
volumeId: volume.id,
|
volumeId: volume.id,
|
||||||
repositoryId: repository.id,
|
repositoryId: repository.id,
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@ describe("listSchedules", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("cleanupOrphanedSchedules", () => {
|
describe("cleanupOrphanedSchedules", () => {
|
||||||
test("should delete orphaned schedules and their mirror assignments", async () => {
|
test("should return zero when cascades already removed orphaned schedules", async () => {
|
||||||
const healthyVolume = await createTestVolume();
|
const healthyVolume = await createTestVolume();
|
||||||
const healthyRepository = await createTestRepository();
|
const healthyRepository = await createTestRepository();
|
||||||
const healthySchedule = await createTestBackupSchedule({
|
const healthySchedule = await createTestBackupSchedule({
|
||||||
|
|
@ -262,7 +262,7 @@ describe("cleanupOrphanedSchedules", () => {
|
||||||
|
|
||||||
const cleanupResult = await backupsService.cleanupOrphanedSchedules();
|
const cleanupResult = await backupsService.cleanupOrphanedSchedules();
|
||||||
|
|
||||||
expect(cleanupResult.deletedSchedules).toBeGreaterThanOrEqual(1);
|
expect(cleanupResult.deletedSchedules).toBe(0);
|
||||||
|
|
||||||
const deletedSchedule = await db.query.backupSchedulesTable.findFirst({
|
const deletedSchedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: { id: orphanSchedule.id },
|
where: { id: orphanSchedule.id },
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,29 @@
|
||||||
import { db } from "~/server/db/db";
|
import { db } from "~/server/db/db";
|
||||||
import { faker } from "@faker-js/faker";
|
import { faker } from "@faker-js/faker";
|
||||||
import { backupSchedulesTable, type BackupScheduleInsert } from "~/server/db/schema";
|
import { backupSchedulesTable, type BackupScheduleInsert } from "~/server/db/schema";
|
||||||
import { ensureTestOrganization, TEST_ORG_ID } from "./organization";
|
import { createTestOrganization, ensureTestOrganization, TEST_ORG_ID } from "./organization";
|
||||||
|
import { createTestVolume } from "./volume";
|
||||||
|
import { createTestRepository } from "./repository";
|
||||||
|
|
||||||
export const createTestBackupSchedule = async (overrides: Partial<BackupScheduleInsert> = {}) => {
|
export const createTestBackupSchedule = async (overrides: Partial<BackupScheduleInsert> = {}) => {
|
||||||
await ensureTestOrganization();
|
const organizationId = overrides.organizationId ?? TEST_ORG_ID;
|
||||||
|
|
||||||
|
if (organizationId === TEST_ORG_ID) {
|
||||||
|
await ensureTestOrganization();
|
||||||
|
} else {
|
||||||
|
await createTestOrganization({ id: organizationId });
|
||||||
|
}
|
||||||
|
|
||||||
|
const volumeId = overrides.volumeId ?? (await createTestVolume({ organizationId })).id;
|
||||||
|
const repositoryId = overrides.repositoryId ?? (await createTestRepository({ organizationId })).id;
|
||||||
|
|
||||||
const backup: BackupScheduleInsert = {
|
const backup: BackupScheduleInsert = {
|
||||||
name: faker.system.fileName(),
|
name: faker.system.fileName(),
|
||||||
cronExpression: "0 0 * * *",
|
cronExpression: "0 0 * * *",
|
||||||
repositoryId: "repo_123",
|
repositoryId,
|
||||||
volumeId: 1,
|
volumeId,
|
||||||
shortId: faker.string.uuid(),
|
shortId: faker.string.uuid(),
|
||||||
organizationId: TEST_ORG_ID,
|
organizationId,
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,4 +25,5 @@ void mock.module("~/server/utils/crypto", () => ({
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const migrationsFolder = path.join(cwd(), "app", "drizzle");
|
const migrationsFolder = path.join(cwd(), "app", "drizzle");
|
||||||
migrate(db, { migrationsFolder });
|
migrate(db, { migrationsFolder });
|
||||||
|
db.run("PRAGMA foreign_keys = ON;");
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue