mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-09 07:25:44 +02:00
GitHub backup can now optionally include spool inventory (with usage history) and print archive metadata as JSON. Both toggles are off by default. No binary files (gcode/3MF) are included.
318 lines
9.0 KiB
TypeScript
318 lines
9.0 KiB
TypeScript
/**
|
|
* Tests for the GitHub Backup API client functions.
|
|
*/
|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
import { http, HttpResponse } from 'msw';
|
|
import { setupServer } from 'msw/node';
|
|
import type {
|
|
GitHubBackupConfig,
|
|
GitHubBackupStatus,
|
|
GitHubBackupLog,
|
|
} from '../../api/client';
|
|
|
|
// Mock API base URL
|
|
const API_BASE = 'http://localhost:5000/api/v1';
|
|
|
|
// Create MSW server
|
|
const server = setupServer();
|
|
|
|
beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' }));
|
|
afterEach(() => server.resetHandlers());
|
|
afterAll(() => server.close());
|
|
|
|
describe('GitHub Backup API Types', () => {
|
|
it('GitHubBackupConfig has correct shape', () => {
|
|
const config: GitHubBackupConfig = {
|
|
id: 1,
|
|
repository_url: 'https://github.com/test/repo',
|
|
has_token: true,
|
|
branch: 'main',
|
|
schedule_enabled: true,
|
|
schedule_type: 'daily',
|
|
backup_kprofiles: true,
|
|
backup_cloud_profiles: true,
|
|
backup_settings: false,
|
|
backup_spools: false,
|
|
backup_archives: false,
|
|
enabled: true,
|
|
last_backup_at: '2026-01-27T10:00:00Z',
|
|
last_backup_status: 'success',
|
|
last_backup_message: null,
|
|
last_backup_commit_sha: 'abc123',
|
|
next_scheduled_run: '2026-01-28T00:00:00Z',
|
|
created_at: '2026-01-01T00:00:00Z',
|
|
updated_at: '2026-01-27T10:00:00Z',
|
|
};
|
|
|
|
expect(config.id).toBe(1);
|
|
expect(config.has_token).toBe(true);
|
|
expect(config.schedule_type).toBe('daily');
|
|
expect(config.backup_spools).toBe(false);
|
|
expect(config.backup_archives).toBe(false);
|
|
});
|
|
|
|
it('GitHubBackupStatus has correct shape', () => {
|
|
const status: GitHubBackupStatus = {
|
|
configured: true,
|
|
enabled: true,
|
|
is_running: false,
|
|
progress: null,
|
|
last_backup_at: '2026-01-27T10:00:00Z',
|
|
last_backup_status: 'success',
|
|
next_scheduled_run: '2026-01-28T00:00:00Z',
|
|
};
|
|
|
|
expect(status.configured).toBe(true);
|
|
expect(status.is_running).toBe(false);
|
|
});
|
|
|
|
it('GitHubBackupStatus can have progress', () => {
|
|
const status: GitHubBackupStatus = {
|
|
configured: true,
|
|
enabled: true,
|
|
is_running: true,
|
|
progress: 'Pushing to GitHub...',
|
|
last_backup_at: null,
|
|
last_backup_status: null,
|
|
next_scheduled_run: null,
|
|
};
|
|
|
|
expect(status.is_running).toBe(true);
|
|
expect(status.progress).toBe('Pushing to GitHub...');
|
|
});
|
|
|
|
it('GitHubBackupLog has correct shape', () => {
|
|
const log: GitHubBackupLog = {
|
|
id: 1,
|
|
config_id: 1,
|
|
started_at: '2026-01-27T10:00:00Z',
|
|
completed_at: '2026-01-27T10:01:00Z',
|
|
status: 'success',
|
|
trigger: 'manual',
|
|
commit_sha: 'abc123',
|
|
files_changed: 5,
|
|
error_message: null,
|
|
};
|
|
|
|
expect(log.status).toBe('success');
|
|
expect(log.trigger).toBe('manual');
|
|
expect(log.files_changed).toBe(5);
|
|
});
|
|
|
|
it('GitHubBackupConfig supports spool and archive backup toggles', () => {
|
|
const config: GitHubBackupConfig = {
|
|
id: 2,
|
|
repository_url: 'https://github.com/test/full-backup',
|
|
has_token: true,
|
|
branch: 'main',
|
|
schedule_enabled: false,
|
|
schedule_type: 'daily',
|
|
backup_kprofiles: true,
|
|
backup_cloud_profiles: false,
|
|
backup_settings: false,
|
|
backup_spools: true,
|
|
backup_archives: true,
|
|
enabled: true,
|
|
last_backup_at: null,
|
|
last_backup_status: null,
|
|
last_backup_message: null,
|
|
last_backup_commit_sha: null,
|
|
next_scheduled_run: null,
|
|
created_at: '2026-04-01T00:00:00Z',
|
|
updated_at: '2026-04-01T00:00:00Z',
|
|
};
|
|
|
|
expect(config.backup_spools).toBe(true);
|
|
expect(config.backup_archives).toBe(true);
|
|
expect(config.backup_cloud_profiles).toBe(false);
|
|
});
|
|
|
|
it('GitHubBackupLog can have error', () => {
|
|
const log: GitHubBackupLog = {
|
|
id: 2,
|
|
config_id: 1,
|
|
started_at: '2026-01-27T10:00:00Z',
|
|
completed_at: '2026-01-27T10:00:30Z',
|
|
status: 'failed',
|
|
trigger: 'scheduled',
|
|
commit_sha: null,
|
|
files_changed: 0,
|
|
error_message: 'Authentication failed',
|
|
};
|
|
|
|
expect(log.status).toBe('failed');
|
|
expect(log.error_message).toBe('Authentication failed');
|
|
expect(log.commit_sha).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('GitHub Backup API Endpoints', () => {
|
|
it('GET /github-backup/config returns null when not configured', async () => {
|
|
server.use(
|
|
http.get(`${API_BASE}/github-backup/config`, () => {
|
|
return HttpResponse.json(null);
|
|
})
|
|
);
|
|
|
|
const response = await fetch(`${API_BASE}/github-backup/config`);
|
|
const data = await response.json();
|
|
expect(data).toBeNull();
|
|
});
|
|
|
|
it('GET /github-backup/config returns config when exists', async () => {
|
|
const mockConfig: GitHubBackupConfig = {
|
|
id: 1,
|
|
repository_url: 'https://github.com/test/repo',
|
|
has_token: true,
|
|
branch: 'main',
|
|
schedule_enabled: false,
|
|
schedule_type: 'daily',
|
|
backup_kprofiles: true,
|
|
backup_cloud_profiles: true,
|
|
backup_settings: false,
|
|
backup_spools: true,
|
|
backup_archives: true,
|
|
enabled: true,
|
|
last_backup_at: null,
|
|
last_backup_status: null,
|
|
last_backup_message: null,
|
|
last_backup_commit_sha: null,
|
|
next_scheduled_run: null,
|
|
created_at: '2026-01-01T00:00:00Z',
|
|
updated_at: '2026-01-01T00:00:00Z',
|
|
};
|
|
|
|
server.use(
|
|
http.get(`${API_BASE}/github-backup/config`, () => {
|
|
return HttpResponse.json(mockConfig);
|
|
})
|
|
);
|
|
|
|
const response = await fetch(`${API_BASE}/github-backup/config`);
|
|
const data = await response.json();
|
|
expect(data.repository_url).toBe('https://github.com/test/repo');
|
|
expect(data.has_token).toBe(true);
|
|
});
|
|
|
|
it('GET /github-backup/status returns not configured status', async () => {
|
|
const mockStatus: GitHubBackupStatus = {
|
|
configured: false,
|
|
enabled: false,
|
|
is_running: false,
|
|
progress: null,
|
|
last_backup_at: null,
|
|
last_backup_status: null,
|
|
next_scheduled_run: null,
|
|
};
|
|
|
|
server.use(
|
|
http.get(`${API_BASE}/github-backup/status`, () => {
|
|
return HttpResponse.json(mockStatus);
|
|
})
|
|
);
|
|
|
|
const response = await fetch(`${API_BASE}/github-backup/status`);
|
|
const data = await response.json();
|
|
expect(data.configured).toBe(false);
|
|
expect(data.enabled).toBe(false);
|
|
});
|
|
|
|
it('GET /github-backup/logs returns empty list when no logs', async () => {
|
|
server.use(
|
|
http.get(`${API_BASE}/github-backup/logs`, () => {
|
|
return HttpResponse.json([]);
|
|
})
|
|
);
|
|
|
|
const response = await fetch(`${API_BASE}/github-backup/logs`);
|
|
const data = await response.json();
|
|
expect(data).toEqual([]);
|
|
});
|
|
|
|
it('GET /github-backup/logs returns log entries', async () => {
|
|
const mockLogs: GitHubBackupLog[] = [
|
|
{
|
|
id: 1,
|
|
config_id: 1,
|
|
started_at: '2026-01-27T10:00:00Z',
|
|
completed_at: '2026-01-27T10:01:00Z',
|
|
status: 'success',
|
|
trigger: 'manual',
|
|
commit_sha: 'abc123',
|
|
files_changed: 5,
|
|
error_message: null,
|
|
},
|
|
];
|
|
|
|
server.use(
|
|
http.get(`${API_BASE}/github-backup/logs`, () => {
|
|
return HttpResponse.json(mockLogs);
|
|
})
|
|
);
|
|
|
|
const response = await fetch(`${API_BASE}/github-backup/logs`);
|
|
const data = await response.json();
|
|
expect(data.length).toBe(1);
|
|
expect(data[0].status).toBe('success');
|
|
});
|
|
|
|
it('POST /github-backup/run returns 404 when not configured', async () => {
|
|
server.use(
|
|
http.post(`${API_BASE}/github-backup/run`, () => {
|
|
return HttpResponse.json(
|
|
{ detail: 'No configuration found' },
|
|
{ status: 404 }
|
|
);
|
|
})
|
|
);
|
|
|
|
const response = await fetch(`${API_BASE}/github-backup/run`, {
|
|
method: 'POST',
|
|
});
|
|
expect(response.status).toBe(404);
|
|
});
|
|
|
|
it('POST /github-backup/test returns success on valid credentials', async () => {
|
|
server.use(
|
|
http.post(`${API_BASE}/github-backup/test`, () => {
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Connection successful',
|
|
repo_name: 'test/repo',
|
|
default_branch: 'main',
|
|
});
|
|
})
|
|
);
|
|
|
|
const response = await fetch(
|
|
`${API_BASE}/github-backup/test?repo_url=https://github.com/test/repo&token=ghp_test`,
|
|
{ method: 'POST' }
|
|
);
|
|
const data = await response.json();
|
|
expect(data.success).toBe(true);
|
|
expect(data.repo_name).toBe('test/repo');
|
|
});
|
|
|
|
it('POST /github-backup/test returns failure on invalid credentials', async () => {
|
|
server.use(
|
|
http.post(`${API_BASE}/github-backup/test`, () => {
|
|
return HttpResponse.json({
|
|
success: false,
|
|
message: 'Authentication failed',
|
|
repo_name: null,
|
|
default_branch: null,
|
|
});
|
|
})
|
|
);
|
|
|
|
const response = await fetch(
|
|
`${API_BASE}/github-backup/test?repo_url=https://github.com/test/repo&token=invalid`,
|
|
{ method: 'POST' }
|
|
);
|
|
const data = await response.json();
|
|
expect(data.success).toBe(false);
|
|
expect(data.message).toBe('Authentication failed');
|
|
});
|
|
});
|