From 6c664e0df28f627cc9efc9796728767ff5ca5bf1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 09:20:53 +0000 Subject: [PATCH 1/2] test: cover uncovered branches in host-iptables-chain/validation Add host-iptables-chain-branches.test.ts targeting two remaining uncovered branches from the coverage report: 1. host-iptables-chain.ts line 20: checkPermissionsAndSetupChain DOCKER-USER list fails with ENOENT emits user-readable 'iptables is required but was not found'. 2. host-iptables-validation.ts line 34: isMissingIptablesError with non-Error thrown values takes the empty-string branch of the ternary. 7 new tests; all 166 host-iptables tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/host-iptables-chain-branches.test.ts | 96 ++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/host-iptables-chain-branches.test.ts diff --git a/src/host-iptables-chain-branches.test.ts b/src/host-iptables-chain-branches.test.ts new file mode 100644 index 00000000..f3dd244c --- /dev/null +++ b/src/host-iptables-chain-branches.test.ts @@ -0,0 +1,96 @@ +/** + * Branch coverage tests for host-iptables-chain.ts and host-iptables-validation.ts. + * + * These tests cover the two remaining uncovered branches identified by the + * coverage report: + * + * 1. host-iptables-chain.ts line 20: + * `throw new Error('iptables is required but was not found...')` inside the + * DOCKER-USER check catch block — triggered when the DOCKER-USER list command + * fails with an ENOENT / "not found" error. + * + * 2. host-iptables-validation.ts line 34: + * `error instanceof Error ? error.message : ''` — the `''` fallback branch + * exercised when `isMissingIptablesError` receives a non-Error thrown value + * (e.g. a plain object or string). + */ + +import { + execaResult, + execaMissingCommandError, + mockedExeca, + setupHostIptablesTestSuite, +} from './test-helpers/host-iptables-test-setup'; +import { checkPermissionsAndSetupChain } from './host-iptables-chain'; +import { isMissingIptablesError } from './host-iptables-validation'; +import { iptablesSharedTestHelpers } from './host-iptables-shared.test-utils'; + +describe('host-iptables-chain branch coverage', () => { + setupHostIptablesTestSuite(iptablesSharedTestHelpers.resetIpv6State); + + // ------------------------------------------------------------------------- + // chain.ts line 20 (branch): + // checkPermissionsAndSetupChain – the DOCKER-USER list check fails with an + // ENOENT / "not found" error. This path re-throws as a user-readable + // "iptables is required but was not found" message. + // ------------------------------------------------------------------------- + describe('checkPermissionsAndSetupChain – DOCKER-USER check fails with ENOENT', () => { + it('throws a user-readable message when DOCKER-USER list reports iptables not found', async () => { + mockedExeca + // iptables --version — succeeds (iptables binary IS present) + .mockResolvedValueOnce(execaResult({ exitCode: 0 })) + // iptables -L DOCKER-USER — fails with ENOENT (iptables binary absent on this call) + .mockRejectedValueOnce(execaMissingCommandError('iptables')); + + await expect(checkPermissionsAndSetupChain('FW_TEST')).rejects.toThrow( + 'iptables is required but was not found. Please install iptables and try again.', + ); + }); + + it('throws a user-readable message when DOCKER-USER list rejects with a "not found" message', async () => { + const notFoundError = new Error('iptables: not found'); + + mockedExeca + // iptables --version — succeeds + .mockResolvedValueOnce(execaResult({ exitCode: 0 })) + // iptables -L DOCKER-USER — fails with "not found" in message + .mockRejectedValueOnce(notFoundError); + + await expect(checkPermissionsAndSetupChain('FW_TEST')).rejects.toThrow( + 'iptables is required but was not found. Please install iptables and try again.', + ); + }); + }); +}); + +// ------------------------------------------------------------------------- +// validation.ts line 34 (branch): +// isMissingIptablesError – the `''` branch of the ternary: +// `const message = error instanceof Error ? error.message : ''` +// This branch fires when the caught value is NOT an Error instance. +// ------------------------------------------------------------------------- +describe('isMissingIptablesError – non-Error thrown values (validation.ts line 34)', () => { + it('returns false for a plain object with no code or message (takes the "" branch)', () => { + // Not an Error instance → message = '' → all three conditions false → returns false + expect(isMissingIptablesError({ someKey: 'someValue' })).toBe(false); + }); + + it('returns false for a thrown string (takes the "" branch)', () => { + // Strings are not Error instances; the '' branch produces no match + expect(isMissingIptablesError('something went wrong')).toBe(false); + }); + + it('returns false for null (takes the "" branch)', () => { + expect(isMissingIptablesError(null)).toBe(false); + }); + + it('returns true for a plain object with code ENOENT (takes the "" branch for message)', () => { + // code === 'ENOENT' is true even though message falls to '' — confirms short-circuit + expect(isMissingIptablesError({ code: 'ENOENT' })).toBe(true); + }); + + it('returns false for a plain object with non-ENOENT code (takes the "" branch)', () => { + // code !== 'ENOENT', message = '' → no match + expect(isMissingIptablesError({ code: 'EAGAIN', message: 'resource temporarily unavailable' })).toBe(false); + }); +}); From afa94f91125ace73b28de14b4fa5526a132363b7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:04:16 +0000 Subject: [PATCH 2/2] refactor(tests): remove line numbers from test comments/titles --- src/host-iptables-chain-branches.test.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/host-iptables-chain-branches.test.ts b/src/host-iptables-chain-branches.test.ts index f3dd244c..8c880dd4 100644 --- a/src/host-iptables-chain-branches.test.ts +++ b/src/host-iptables-chain-branches.test.ts @@ -4,12 +4,12 @@ * These tests cover the two remaining uncovered branches identified by the * coverage report: * - * 1. host-iptables-chain.ts line 20: + * 1. host-iptables-chain.ts — `checkPermissionsAndSetupChain`: * `throw new Error('iptables is required but was not found...')` inside the * DOCKER-USER check catch block — triggered when the DOCKER-USER list command * fails with an ENOENT / "not found" error. * - * 2. host-iptables-validation.ts line 34: + * 2. host-iptables-validation.ts — `isMissingIptablesError`: * `error instanceof Error ? error.message : ''` — the `''` fallback branch * exercised when `isMissingIptablesError` receives a non-Error thrown value * (e.g. a plain object or string). @@ -29,7 +29,6 @@ describe('host-iptables-chain branch coverage', () => { setupHostIptablesTestSuite(iptablesSharedTestHelpers.resetIpv6State); // ------------------------------------------------------------------------- - // chain.ts line 20 (branch): // checkPermissionsAndSetupChain – the DOCKER-USER list check fails with an // ENOENT / "not found" error. This path re-throws as a user-readable // "iptables is required but was not found" message. @@ -64,12 +63,11 @@ describe('host-iptables-chain branch coverage', () => { }); // ------------------------------------------------------------------------- -// validation.ts line 34 (branch): // isMissingIptablesError – the `''` branch of the ternary: // `const message = error instanceof Error ? error.message : ''` // This branch fires when the caught value is NOT an Error instance. // ------------------------------------------------------------------------- -describe('isMissingIptablesError – non-Error thrown values (validation.ts line 34)', () => { +describe('isMissingIptablesError – non-Error thrown values', () => { it('returns false for a plain object with no code or message (takes the "" branch)', () => { // Not an Error instance → message = '' → all three conditions false → returns false expect(isMissingIptablesError({ someKey: 'someValue' })).toBe(false);