mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-26 20:59:13 +01:00
- Extract pure backup logic to /src/jobs/logic/createBackup.ts
- Update job definition to use extracted logic
- Fix absolute path parsing for tar command
- Add 7 tests: success cases, filename format, file extraction,
error handling (non-existent dir, file instead of dir), empty dir
- Uses BaseTest framework with temp directories and tar extraction
303 lines
9.7 KiB
TypeScript
303 lines
9.7 KiB
TypeScript
/**
|
|
* Tests for createBackup job
|
|
* Tests the creation of compressed backups
|
|
*/
|
|
|
|
import { BaseTest } from "../base/BaseTest.ts";
|
|
import { createBackup } from "../../src/jobs/logic/createBackup.ts";
|
|
import { assertEquals } from "@std/assert";
|
|
|
|
class CreateBackupTest extends BaseTest {
|
|
/**
|
|
* Test 1: Basic successful backup
|
|
*/
|
|
testBasicSuccessfulBackup(): void {
|
|
this.test("basic successful backup", async (context) => {
|
|
// Setup: Create source directory with test files
|
|
const sourceDir = `${context.tempDir}/source`;
|
|
await Deno.mkdir(sourceDir, { recursive: true });
|
|
|
|
// Create some test files
|
|
await Deno.writeTextFile(`${sourceDir}/file1.txt`, "test content 1\n");
|
|
await Deno.writeTextFile(`${sourceDir}/file2.txt`, "test content 2\n");
|
|
await Deno.writeTextFile(
|
|
`${sourceDir}/file3.json`,
|
|
JSON.stringify({ test: "data" }) + "\n",
|
|
);
|
|
|
|
// Create backup directory
|
|
const backupDir = `${context.tempDir}/backups`;
|
|
|
|
// Run backup
|
|
const result = await createBackup(sourceDir, backupDir);
|
|
|
|
// Assert success
|
|
assertEquals(result.success, true);
|
|
assertEquals(typeof result.filename, "string");
|
|
assertEquals(typeof result.sizeBytes, "number");
|
|
|
|
// Assert size is greater than 0
|
|
if (result.sizeBytes) {
|
|
assertEquals(result.sizeBytes > 0, true);
|
|
}
|
|
|
|
// Assert no error
|
|
assertEquals(result.error, undefined);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test 2: Backup filename format
|
|
*/
|
|
testBackupFilenameFormat(): void {
|
|
this.test("backup filename format", async (context) => {
|
|
// Setup: Create source directory with test files
|
|
const sourceDir = `${context.tempDir}/source`;
|
|
await Deno.mkdir(sourceDir, { recursive: true });
|
|
await Deno.writeTextFile(`${sourceDir}/test.txt`, "content\n");
|
|
|
|
const backupDir = `${context.tempDir}/backups`;
|
|
|
|
// Use a custom timestamp for predictable filename
|
|
const customTimestamp = new Date("2025-01-15T14:30:45.000Z");
|
|
|
|
// Run backup with custom timestamp
|
|
const result = await createBackup(sourceDir, backupDir, customTimestamp);
|
|
|
|
// Assert success
|
|
assertEquals(result.success, true);
|
|
|
|
// Assert filename matches expected format: backup-2025-01-15-143045.tar.gz
|
|
assertEquals(result.filename, "backup-2025-01-15-143045.tar.gz");
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test 3: Backup file exists and is valid
|
|
*/
|
|
testBackupFileExistsAndValid(): void {
|
|
this.test("backup file exists and is valid", async (context) => {
|
|
// Setup: Create source directory with test files
|
|
const sourceDir = `${context.tempDir}/source`;
|
|
await Deno.mkdir(sourceDir, { recursive: true });
|
|
await Deno.writeTextFile(`${sourceDir}/file1.txt`, "test content\n");
|
|
await Deno.writeTextFile(`${sourceDir}/file2.txt`, "more content\n");
|
|
|
|
const backupDir = `${context.tempDir}/backups`;
|
|
|
|
// Run backup
|
|
const result = await createBackup(sourceDir, backupDir);
|
|
|
|
// Assert success
|
|
assertEquals(result.success, true);
|
|
|
|
// Construct backup file path
|
|
const backupFilePath = `${backupDir}/${result.filename}`;
|
|
|
|
// Assert backup file exists
|
|
await this.assertFileExists(backupFilePath);
|
|
|
|
// Get file stats and verify size
|
|
const stat = await Deno.stat(backupFilePath);
|
|
assertEquals(stat.size > 0, true);
|
|
|
|
// Verify returned sizeBytes matches actual file size
|
|
assertEquals(result.sizeBytes, stat.size);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test 4: Backup contains expected files
|
|
*/
|
|
testBackupContainsExpectedFiles(): void {
|
|
this.test("backup contains expected files", async (context) => {
|
|
// Setup: Create source directory with specific test files
|
|
const sourceDir = `${context.tempDir}/source`;
|
|
await Deno.mkdir(sourceDir, { recursive: true });
|
|
|
|
const testContent1 = "This is test file 1\n";
|
|
const testContent2 = "This is test file 2\n";
|
|
const testContent3 = JSON.stringify({ key: "value", data: [1, 2, 3] });
|
|
|
|
await Deno.writeTextFile(`${sourceDir}/file1.txt`, testContent1);
|
|
await Deno.writeTextFile(`${sourceDir}/file2.txt`, testContent2);
|
|
await Deno.writeTextFile(`${sourceDir}/data.json`, testContent3);
|
|
|
|
const backupDir = `${context.tempDir}/backups`;
|
|
|
|
// Run backup
|
|
const result = await createBackup(sourceDir, backupDir);
|
|
|
|
// Assert success
|
|
assertEquals(result.success, true);
|
|
|
|
// Extract backup to verify contents
|
|
const extractDir = `${context.tempDir}/extract`;
|
|
await Deno.mkdir(extractDir, { recursive: true });
|
|
|
|
const backupFilePath = `${backupDir}/${result.filename}`;
|
|
|
|
// Extract tar.gz
|
|
const extractCommand = new Deno.Command("tar", {
|
|
args: ["-xzf", backupFilePath, "-C", extractDir],
|
|
stdout: "piped",
|
|
stderr: "piped",
|
|
});
|
|
|
|
const { code } = await extractCommand.output();
|
|
assertEquals(code, 0);
|
|
|
|
// Verify extracted files exist and have correct content
|
|
const extractedSourceDir = `${extractDir}/source`;
|
|
await this.assertFileExists(`${extractedSourceDir}/file1.txt`);
|
|
await this.assertFileExists(`${extractedSourceDir}/file2.txt`);
|
|
await this.assertFileExists(`${extractedSourceDir}/data.json`);
|
|
|
|
// Verify file contents
|
|
const extractedContent1 = await Deno.readTextFile(
|
|
`${extractedSourceDir}/file1.txt`,
|
|
);
|
|
const extractedContent2 = await Deno.readTextFile(
|
|
`${extractedSourceDir}/file2.txt`,
|
|
);
|
|
const extractedContent3 = await Deno.readTextFile(
|
|
`${extractedSourceDir}/data.json`,
|
|
);
|
|
|
|
assertEquals(extractedContent1, testContent1);
|
|
assertEquals(extractedContent2, testContent2);
|
|
assertEquals(extractedContent3, testContent3);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test 5: Non-existent source directory
|
|
*/
|
|
testNonExistentSourceDirectory(): void {
|
|
this.test("non-existent source directory", async (context) => {
|
|
// Setup: Create path to non-existent directory
|
|
const sourceDir = `${context.tempDir}/does-not-exist`;
|
|
const backupDir = `${context.tempDir}/backups`;
|
|
|
|
// Run backup on non-existent directory
|
|
const result = await createBackup(sourceDir, backupDir);
|
|
|
|
// Assert failure
|
|
assertEquals(result.success, false);
|
|
|
|
// Assert error message mentions source directory
|
|
assertEquals(typeof result.error, "string");
|
|
if (result.error) {
|
|
assertEquals(
|
|
result.error.includes("Source directory does not exist"),
|
|
true,
|
|
);
|
|
}
|
|
|
|
// Assert no filename or size returned
|
|
assertEquals(result.filename, undefined);
|
|
assertEquals(result.sizeBytes, undefined);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test 6: Source path is a file, not directory
|
|
*/
|
|
testSourcePathIsFile(): void {
|
|
this.test("source path is a file, not directory", async (context) => {
|
|
// Setup: Create a file instead of a directory
|
|
const sourcePath = `${context.tempDir}/somefile.txt`;
|
|
await Deno.writeTextFile(sourcePath, "this is a file\n");
|
|
|
|
const backupDir = `${context.tempDir}/backups`;
|
|
|
|
// Run backup on file path
|
|
const result = await createBackup(sourcePath, backupDir);
|
|
|
|
// Assert failure
|
|
assertEquals(result.success, false);
|
|
|
|
// Assert error message mentions not a directory
|
|
assertEquals(typeof result.error, "string");
|
|
if (result.error) {
|
|
assertEquals(
|
|
result.error.includes("Source path is not a directory"),
|
|
true,
|
|
);
|
|
}
|
|
|
|
// Assert no filename or size returned
|
|
assertEquals(result.filename, undefined);
|
|
assertEquals(result.sizeBytes, undefined);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test 7: Empty source directory
|
|
*/
|
|
testEmptySourceDirectory(): void {
|
|
this.test("empty source directory", async (context) => {
|
|
// Setup: Create an empty source directory
|
|
const sourceDir = `${context.tempDir}/empty-source`;
|
|
await Deno.mkdir(sourceDir, { recursive: true });
|
|
|
|
const backupDir = `${context.tempDir}/backups`;
|
|
|
|
// Run backup on empty directory
|
|
const result = await createBackup(sourceDir, backupDir);
|
|
|
|
// Assert success
|
|
assertEquals(result.success, true);
|
|
assertEquals(typeof result.filename, "string");
|
|
assertEquals(typeof result.sizeBytes, "number");
|
|
|
|
// Assert backup file exists
|
|
const backupFilePath = `${backupDir}/${result.filename}`;
|
|
await this.assertFileExists(backupFilePath);
|
|
|
|
// Assert file has size > 0 (even empty tar.gz has some size for headers)
|
|
if (result.sizeBytes) {
|
|
assertEquals(result.sizeBytes > 0, true);
|
|
}
|
|
|
|
// Extract and verify empty directory structure is preserved
|
|
const extractDir = `${context.tempDir}/extract`;
|
|
await Deno.mkdir(extractDir, { recursive: true });
|
|
|
|
const extractCommand = new Deno.Command("tar", {
|
|
args: ["-xzf", backupFilePath, "-C", extractDir],
|
|
stdout: "piped",
|
|
stderr: "piped",
|
|
});
|
|
|
|
const { code } = await extractCommand.output();
|
|
assertEquals(code, 0);
|
|
|
|
// Verify extracted directory exists and is empty
|
|
const extractedSourceDir = `${extractDir}/empty-source`;
|
|
await this.assertFileExists(extractedSourceDir);
|
|
|
|
// Read directory to verify it's empty
|
|
const entries = [];
|
|
for await (const entry of Deno.readDir(extractedSourceDir)) {
|
|
entries.push(entry);
|
|
}
|
|
assertEquals(entries.length, 0);
|
|
});
|
|
}
|
|
|
|
runTests(): void {
|
|
this.testBasicSuccessfulBackup();
|
|
this.testBackupFilenameFormat();
|
|
this.testBackupFileExistsAndValid();
|
|
this.testBackupContainsExpectedFiles();
|
|
this.testNonExistentSourceDirectory();
|
|
this.testSourcePathIsFile();
|
|
this.testEmptySourceDirectory();
|
|
}
|
|
}
|
|
|
|
// Run tests
|
|
const test = new CreateBackupTest();
|
|
await test.runTests();
|