Skip to content

Getting Started

go-while edited this page Oct 23, 2026 · 1 revision

Getting Started

Install

go get github.com/go-while/nntp-testkit@latest

The kit needs Go 1.26 or later and has no dependencies outside the standard library. To work on the kit and a project at the same time, point the project at a checkout:

replace github.com/go-while/nntp-testkit => ../nntp-testkit

A first test

A fake server with one group and one article, and the strict client:

package mypkg_test

import (
	"testing"

	"github.com/go-while/nntp-testkit/client"
	"github.com/go-while/nntp-testkit/fakeserver"
)

func TestGroup(t *testing.T) {
	st := fakeserver.NewStore()
	st.AddGroup("test.group", "a test group")
	st.AddArticle("test.group", fakeserver.Article{
		Headers: []string{"From: alice@example.invalid", "Subject: hello"},
		Body:    []string{"first article"},
	})
	s := fakeserver.New(t, fakeserver.Options{Store: st})

	c := client.Dial(t, s.Addr())
	if code, line := c.Cmd("GROUP test.group"); code != 211 {
		t.Fatalf("GROUP: %s", line)
	}
	c.Cmd("OVER 1-")
	if over := c.ReadDotLines(); len(over) != 1 {
		t.Fatalf("OVER: %q", over)
	}
	if n := s.Count("OVER"); n != 1 {
		t.Errorf("server saw %d OVER commands", n)
	}
}
  • fakeserver.New listens on 127.0.0.1:0 (a free port) and closes the server when the test ends.
  • client.Dial connects, reads the greeting and closes the connection when the test ends. Cmd sends one line and returns the status code and line; ReadDotLines reads a multi-line reply. Both fail the test on a read error or a wire mistake (see Strict Client).
  • A missing Message-ID is generated (<1.test.group@fakeserver.invalid>), and so are Date and Newsgroups.

Without testing (in a command-line tool, or an Example), use fakeserver.Start and client.TryDial and close both yourself. example_test.go has three runnable examples.

The hang guard

Every blocking step (dial, read, write, waits) has an upper bound, so a hung test fails instead of running until go test kills it. The bound is the Go duration in NNTP_TEST_DEADLINE, 60s when it is not set. A passing test never waits for it.

NNTP_TEST_DEADLINE=10s go test ./...

fakeserver.Options.Deadline, client.Conn.Deadline (or the deadline argument of DialWith and TryDial) and proc.Options.Deadline override it for one server, connection or process.

Testing a server binary

proc runs a server that isn't written in Go. This is how NewsCache tests its C++ server against a fake upstream:

func TestMyServer(t *testing.T) {
	up := fakeserver.New(t, fakeserver.Options{Store: fakeserver.NewStore()})
	p := proc.StartTCP(t, proc.Options{
		Path: "../../src/myserver",
		Args: []string{"-upstream", up.Addr(), "-listen", "127.0.0.1:11119"},
		Logs: []string{"myserver.log"},
	}, "127.0.0.1:11119")
	c := client.Dial(t, p.Addr())
	c.Cmd("QUIT")
}

StartTCP returns once a connection to the address gets a greeting line. For a server that speaks NNTP on stdin and stdout (inetd style), use StartStdio and wrap p.Conn() with client.New. See Running Server Binaries.

Next

Clone this wiki locally