Files
portainer/app/react/docker/containers/ItemView/ContainerDetailsSection/AutoHealRow.test.tsx
T
claude code agent b233f75ab7 fix(automation): retry-state retention + running-only heal + per-restart ctx (#8 F1-F6)
F1: prune retry-state by elapsed window since lastRestart instead of "not
seen this tick", so a container flapping through "starting" keeps its
cooldown/max-retries accounting (storm guard no longer defeated). Recovered
containers quiet for > window are still cleaned up.
F2: list running containers only (All:false) so stopped-unhealthy containers
are never revived.
F3: each ContainerRestart gets its own context (stop-timeout + buffer),
separate from the per-endpoint list context, so a slow/hung restart cannot
starve the others or exhaust a single shared deadline.
F4: start() is idempotent (no-op when a job is already scheduled); Reload
still stops first so it always reschedules.
F5: frontend parseBool mirrors Go strconv.ParseBool (case-insensitive
1/t/true; present-but-invalid counts as present & false).
F6: tests TestPruneRetries and TestRetryStateSurvivesStartingTick lock in
the F1 behavior; added AutoHealRow parse cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 08:39:17 +03:00

61 lines
1.8 KiB
TypeScript

import { render, screen } from '@testing-library/react';
import { AutoHealRow } from './AutoHealRow';
function renderRow(labels?: Record<string, string>) {
return render(
<table>
<tbody>
<AutoHealRow labels={labels} />
</tbody>
</table>
);
}
describe('AutoHealRow', () => {
it('shows enabled when the primary label is true', () => {
renderRow({ 'io.portainer.autoheal.enable': 'true' });
expect(screen.getByText('Enabled')).toBeInTheDocument();
});
it('shows enabled via the community alias', () => {
renderRow({ autoheal: 'true' });
expect(screen.getByText('Enabled')).toBeInTheDocument();
});
it.each(['TRUE', 'True', 'T', 't', '1'])(
'parses the truthy value %s like strconv.ParseBool',
(value) => {
renderRow({ 'io.portainer.autoheal.enable': value });
expect(screen.getByText('Enabled')).toBeInTheDocument();
}
);
it('treats a present-but-invalid value as opted out', () => {
renderRow({ 'io.portainer.autoheal.enable': 'yepp' });
expect(screen.getByText('Disabled (opted out)')).toBeInTheDocument();
});
it('shows opted out when the label is false', () => {
renderRow({ 'io.portainer.autoheal.enable': 'false' });
expect(screen.getByText('Disabled (opted out)')).toBeInTheDocument();
});
it('shows the global-scope fallback when no label is set', () => {
renderRow({});
expect(
screen.getByText('Not labeled (follows global scope)')
).toBeInTheDocument();
});
it('renders stop timeout and retries when present', () => {
renderRow({
'io.portainer.autoheal.enable': 'true',
'io.portainer.autoheal.stop-timeout': '20',
'io.portainer.autoheal.retries': '5',
});
expect(screen.getByText('Stop timeout: 20s')).toBeInTheDocument();
expect(screen.getByText('Max retries: 5')).toBeInTheDocument();
});
});