Skip to content

cmd/nntp-fakeserver: the fake server as a process, configured by JSON - #14

Merged
go-while merged 5 commits into
mainfrom
cmd-fakeserver
Nov 12, 2026
Merged

go-while merged 5 commits into
mainfrom
cmd-fakeserver

Conversation

@go-while

Copy link
Copy Markdown
Owner

Item 4 of survey-pynntp.md: the fake server as a program, so test suites in other languages can use the kit. It generalises pynntp's fault server (tests/faults/server/main.go in greenbender/pynntp#145, which drives 228 fault scenarios from Python) and leaves room for go-pugleaf's planned nntp-fakepeer (survey-go-pugleaf.md section 3): its peer mode is PeerOptions from JSON.

Usage

nntp-fakeserver [-listen host:port] config.json

  • When listening, it prints one JSON line, {"addr","host","port","ca"}. ca is the PEM of a fresh self-signed certificate (tlscert.GenerateSelfSigned, tlscert, fakeserver: twins without testing.TB #9), valid for localhost, 127.0.0.1 and ::1. Clients verify implicit TLS and STARTTLS against it.
  • It serves until stdin reaches EOF (or SIGINT/SIGTERM). Then it prints one summary line, {lines, mismatches, articles, notes, accepted, counts, tls_handshakes, tls_failed, server_names}, removes its temp dir and exits 0.
  • Exit codes: 2 for a bad config or flag, 1 for another failure.

The full description, with an example for each mode, is in the package doc. README is left for the release.

Config

  • Keys are the kit's Go field names (Options, StoreOpts, Faults, PeerOptions, Script, …). The decoder walks the kit types by reflection, so a new kit field, such as the Faults fields in the faults-bytes branch, works from JSON with no change here. TestEveryKitFieldDecodes fails if a new field has a shape it can't read.
  • Durations are milliseconds.
  • Errors: an unknown key is an error that names its path and lists the valid keys. So is a part the mode doesn't use.
  • Not settable from JSON: functions, channels and Options.Store.
  • TLS: Options.TLS: true means implicit TLS with the program's certificate. StartTLS: {} (plus the knobs Refuse, HideCapability, AuthNeedsTLS, CloseAfterHandshake) offers STARTTLS with it.
  • Modes:
    • store: Store, StoreOpts and Faults.
    • peer: PeerOptions.
    • script: Options.Script as fakeserver.Step.
    • raw: byte-exact scripts. Per step: an anchored regexp for the client line, an optional dot block, chunks as Text or B64 with Gap/Split/SplitGap, then close/rst/hang/starttls/inflate. starttls uses Conn.StartTLS. The kit's Script mode is text lines only, which is why raw stays a mode of its own.

Testing

  • main_test.go drives run() in-process:
    • store with faults, STARTTLS and implicit TLS verified against the printed CA file;
    • peer (IHAVE);
    • script;
    • raw: split chunks, starttls then a command over TLS, rst, pipelined plaintext after STARTTLS;
    • config errors (unknown key, wrong mode part, bad JSON);
    • the summary fields;
    • every kit field decoding.
  • On a test VM with Go 1.27.3: gofmt -l empty, go vet ./... clean, go test -race -count=1 ./... passes in all packages, and -count=5 passes for this package.
  • The built binary was also driven from Python 3.13 with ssl.create_default_context(cafile=ca) and a stdin pipe: TLS verified, summary with tls_handshakes: 1, temp dir gone after exit.

Next on the pynntp side: #145 switches from its own server to this program.

🤖 Generated with Claude Code

go-while and others added 5 commits November 12, 2026 13:21
A standalone program for test suites in other languages (Python, shell, C): it reads a JSON
config, prints {addr, host, port, ca} when it listens, serves until stdin reaches end of
file, then prints a summary {lines, mismatches, articles, notes, accepted, counts,
tls_handshakes, tls_failed, server_names}. Modes: store, peer, script (the kit's) and raw (a
byte-exact script with split writes, RST, STARTTLS and inflate, generalised from pynntp's
fault server).

The config keys are the Go field names of fakeserver.Options, StoreOptions, PeerOptions,
Faults and StartTLSOptions, durations in milliseconds; the decoder walks the types, so a field
added to the kit works from JSON at once, and an unknown key is an error. The certificate is
tlscert.GenerateSelfSigned, written to a temp dir that is removed on exit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ode, config checks)

Summary: lines_b64, mismatches_b64 and articles_raw (base64, lossless for bytes that are not
UTF-8), max_open and closed; ready line: ca_pem. Store articles: HeadersB64 and BodyB64.
Raw mode: pauses use Conn.Sleep (bounded by Deadline, ended by Close), reads of expected lines
and writes have the Deadline, lines over 1 MiB, blocks over 16 MiB and 64 MiB per connection
close the connection with a note.
Config: Faults command keys must be upper case; empty {} and [] sections are fine in any mode;
StartTLS "Config": false switches STARTTLS off; []byte is base64; check() guards a renamed kit
field. A second SIGINT or SIGTERM during shutdown is no longer swallowed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…byte must be a string

TestEveryKitFieldDecodes now builds nested samples (Split, Trailing); TestByteFaults checks
their values and a Split + Trailing reply end to end. A []byte field takes a base64 string
only (encoding/json would also take an array).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ames, usage keys)

- A raw Sleep, Gap or SplitGap longer than Options.Deadline is a config
  error: Conn.Sleep ends every pause at the Deadline, so it was cut short
  without a note. The package doc says a client that stays silent longer
  than the Deadline before an expected line is cut off.
- Base64 errors name their key (HeadersB64[0], BodyB64[0]), not Headers
  or Body.
- -h lists the current ready and summary keys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@go-while
go-while merged commit bbf25cd into main Nov 12, 2026
8 checks passed
go-while added a commit to go-while/pynntp that referenced this pull request Nov 13, 2026
kit_config() renames the scenarios' short keys to the Go field names
that nntp-testkit's cmd/nntp-fakeserver takes (an unknown key is an
error), so the suite can run against the kit's program instead of its
own server. With nntp-fakeserver (go-while/nntp-testkit#14): 219 passed,
9 xfailed, the same as with tests/faults/server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant