Dev/test setup: sample capture generators, portable Makefile - #340
Merged
Merged
Conversation
The runtime, regression and integration tests read eleven captures out of sample/, which .gitignore excludes, so a fresh clone fails 28 tests and CI has to skip those suites entirely. util/make_samples.py rebuilds the whole set: the .pcap fixtures are constructed with scapy from the traffic each test pins, and the .pcapng ones are either fetched from Wireshark's test/captures with a pinned SHA-256 or synthesised block by block, with an offline fallback so generation never depends on the network. The Makefile could not run anywhere but a Homebrew macOS box, since SHELL was hardcoded to /opt/homebrew/bin/bash; bash now comes from PATH and the libxml2/libxslt prefixes from brew --prefix. Added samples, test, test-all and coverage targets, and fixed the isort and vermin targets, which referenced an untracked scratch file and a missing temp/ directory. Full suite: 334 passed, 70 subtests passed.
The captures and the scripts that build them now live under examples/, next to the legacy_smoke demonstrations that read them as ../sample/ and were therefore pointing at nothing. Generators moved from util/ to examples/samples/, fixtures to examples/sample/. Tests no longer spell that directory out: tests/_support.sample_path() resolves a capture name against the repository root, so the suite no longer depends on pytest being invoked from the top of the tree, and a fresh clone gets an error naming the command that rebuilds the fixture. Added examples/samples/legacy.py for the two captures only the smoke scripts read - test.pcap, whose out-of-order and retransmitted segments give TCP reassembly something to reassemble, and http6.cap, HTTP/1.1 over IPv6 including a 304 with no body. setup.py read README.rst by bare relative name, which failed whenever setup.py was loaded from elsewhere; it now resolves against its own directory. Full suite: 334 passed, 70 subtests passed, from the repository root and from an unrelated working directory.
The runtime, regression and integration tiers were ignored in CI because their captures are not in the repository. They can be rebuilt now, so both the pull-request matrix and the reusable gate generate the fixtures and then run the suite with no --ignore flags. Python 3.10 through 3.14 block, 3.15 stays experimental, matching the unit job. Generation is a step of its own, and a failure there annotates the run as a fixture-generation failure so it cannot be misread as a test failure. When the upstream Wireshark captures are unreachable the generators fall back to synthesised stand-ins, which parse and pass; the step now says which of the two happened, since a silent fallback would halve that tier's coverage without turning the build red. Installs the Scapy extra, which the .pcap generators need.
The Test Cases proposal predates the unit suite: there are now 84 test modules under tests/, bundled with the distribution and running in CI across Python 3.10 through 3.14, so the section records what remains wanted - coverage of the protocols that are still unimplemented - rather than asking for a suite that exists. The New Engines proposal still describes adding handler methods to Extractor. That stopped being true when engines became Engine subclasses with two abstract methods and automatic registration; the note points at that and at the worked example in ext.rst. The candidate engines themselves are still open. Dropped the PCAP-NG todo from pcapkit.foundation.engines, whose docstring asked for support that engines/pcapng.py already provides.
JarryShaw
marked this pull request as ready for review
September 14, 2026 02:32
This was referenced Sep 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft, accumulating — further commits will land on this branch as each subtask finishes.
Why
A fresh clone cannot run the whole test suite. The runtime, regression and integration suites read eleven captures out of
sample/, and.gitignorekeeps them out of the repository, so those 28 tests fail locally and CI has to--ignorethem. This branch reconstructs the fixtures from source instead, sopytestwith no ignore flags passes on any machine.What changed
util/make_samples.py(plusutil/samples_pcap.py,util/samples_pcapng.py) — regenerates every fixture; also wired asmake samples..pcapfixtures (arp,ipv4,ipv6,tcp,stream,http) are built with scapy from the traffic each test pins. Checksums are computed by scapy from the finished packets, sequence/acknowledgement continuity holds across all 114 connections, and regeneration is byte-identical..pcapngfixtures are either downloaded from Wireshark'stest/captureswith the source URL and SHA-256 pinned in the script (dhcp_big_endian.pcapng,many_interfaces.pcapng), or synthesised block by block (dhcp_little_endian.pcapng,test.pcapng,profile.pcapng). A digest mismatch is a hard error; losing the network degrades to a synthesised stand-in and says so. Nothing downloaded is redistributed —sample/stays gitignored.Makefile— could not run outside a Homebrew macOS box:SHELLwas hardcoded to/opt/homebrew/bin/bash, so every target died withCommand not foundon Linux.bashnow comes fromPATHand the libxml2/libxslt prefixes frombrew --prefix, leaving macOS behaviour unchanged. Addedsamples,test(the CI-equivalent selection),test-allandcoverage; fixedisort(referenced an untrackedtemp/sort.py) andvermin(wrote into a missingtemp/, and hard-required VS Code).README.rst— a Testing section covering the three commands and why CI runs the narrower selection.Test result
pytest -q→ 334 passed, 70 subtests passed (was 28 failed, 309 passed).make test(CI selection) → 284 passed.Defects found on the way, not fixed here
Building the pcapng fixtures surfaced parser bugs, all documented in
util/samples_pcapng.pyand left for their own change:pcapkit/protocols/schema/misc/pcapng.py:1591— Custom Block padding is(4 - pkt['data'] % 4) % 4onbytes; every custom block raisesTypeError.:1335— ISBoptionssizedlength - 20, but the fixed prefix is 24 bytes. Fires on Wireshark's ownmany_interfaces.pcapng.:1102/:1177— NRB IPv6 records sized as if the address were 4 bytes, and NRB options over-run whenns_*options are present.:1657/:1659— obsolete Packet Block declaresinterface_id/drop_countas 32-bit; the spec makes both 16-bit, and the options arithmetic assumes the 16-bit layout, so neither parses.pcapkit/corekit/fields/ipaddress.py—if_IPv6addrparses the prefix-length octet as an ASCII decimal string;/64raises,/56silently decodes as/8.pcapkit/foundation/engines/pcapng.py:218— rejects a Simple Packet Block in any section with more than one interface. Per spec §4.4 that is legal; the check should be for zero interfaces.pcapkit/protocols/internet/ipv6.py:342— the extension-header loopbreaks before advancing past the last header, so a fragmented datagram hands the fragment header to the next layer as if it were the UDP header.tests/protocols/internet/test_ipv6_extension_runtime.pycurrently pins this behaviour.