1 Commits
Author SHA1 Message Date
sneak 1a7966b97a main() is one call into internal/cli (closes #160)
check / check (push) Canceled after 0s
cmd/netwatch-server/main.go parsed the command line, ran the check-cidr
and prepare-data-dir subcommands and built the fx application itself;
the Go style guide puts all of that in internal/ or pkg/. The new
package internal/cli does it, with the same arguments, messages and
exit codes, and main() is now os.Exit(cli.Main(Appname, Version,
os.Args[1:])). Appname and Version stay in main, where the build sets
Version. Each subcommand writes its error to a writer it is given, and
prepare-data-dir also takes the volume and the user's name, so the new
unit tests give it a temporary directory and the user they run as.

Model: opus-5-5
2026-10-19 04:19:31 +00:00
6 changed files with 12 additions and 66 deletions
+1 -1
View File
@@ -207,7 +207,7 @@ stops. Its routes:
It is an `fx`-wired Go application: `cmd/netwatch-server/` starts it, and its
packages are in `internal/`:
- **`cli`**: Runs `netwatch-server` from its command line: the `check-cidr` and
- **`cli`**: Runs netwatch-server from its command line: the `check-cidr` and
`prepare-data-dir` subcommands, which `bin/entrypoint.sh` runs before it
starts the server, and otherwise the server, with the `fx` wiring.
- **`config`**: Loads configuration from environment variables and config files
+3 -7
View File
@@ -26,13 +26,9 @@ Run `make frontend-viewport-test` in CI as its own step; it is not part of
([#160](https://git.eeqj.de/sneak/netwatch/issues/160)). `internal/cli` runs
the `check-cidr` and `prepare-data-dir` subcommands, with the same arguments,
messages and exit codes, and otherwise the server, with the `fx` wiring.
`Appname` and `Version` stay in `main`, where the build sets `Version`, and
`main` gives `cli.Main` the function that runs the server, which the tests
replace with one that fails them. Unit tests call `cli.Main` with `check-cidr`
and a CIDR it takes and one it refuses, and with `prepare-data-dir` and a path
outside `/data`, and check the exit code. Others give each subcommand input it
takes and input it refuses, and check the exit code and what it writes to
stderr
`Appname` and `Version` stay in `main`, where the build sets `Version`. Unit
tests give each subcommand input it takes and input it refuses, and check the
exit code and what it writes to stderr
- 2026-10-19: report file writes no longer overlap
([#150](https://git.eeqj.de/sneak/netwatch/issues/150)), so the reports of
failed writes are written in the order they arrived. Two writes that failed at
+1 -1
View File
@@ -15,5 +15,5 @@ var (
)
func main() {
os.Exit(cli.Main(Appname, Version, os.Args[1:], cli.RunServer))
os.Exit(cli.Main(Appname, Version, os.Args[1:]))
}
+6 -17
View File
@@ -24,19 +24,9 @@ import (
)
// Main runs netwatch-server with args, its command line after the
// program's name, and returns the exit code. Unless args are
// "check-cidr CIDR" or "prepare-data-dir DATA_DIR", Main runs the
// server by calling serve with appname and version, the name and
// version the server logs and reports. main passes RunServer; the
// tests pass a function that fails them, so that no test starts the
// server. When serve is RunServer and the server fails to start or to
// stop, fx's Run exits the process with status 1 and Main never
// returns.
func Main(
appname, version string,
args []string,
serve func(appname, version string),
) int {
// program's name, and returns the exit code. appname and version are
// the name and version the server logs and reports.
func Main(appname, version string, args []string) int {
// "netwatch-server check-cidr CIDR" exits 1, with the error, if
// this server would refuse CIDR in its TRUSTED_PROXIES.
// bin/entrypoint.sh runs it on each entry it gives nginx.
@@ -52,7 +42,7 @@ func Main(
return prepareDataDir(os.Stderr, "/data", args[1], "netwatch")
}
serve(appname, version)
runServer(appname, version)
return 0
}
@@ -93,11 +83,10 @@ func prepareDataDir(stderr io.Writer, volume, dataDir, username string) int {
return 0
}
// RunServer runs the server until it is told to stop, with appname and
// version as the name and version it logs and reports. If the server
// runServer runs the server until it is told to stop. If the server
// fails to start or to stop, fx's Run exits the process with status 1
// itself.
func RunServer(appname, version string) {
func runServer(appname, version string) {
globals.Appname = appname
globals.Version = version
-39
View File
@@ -13,35 +13,6 @@ import (
"sneak.berlin/go/netwatch/internal/reportbuf"
)
// TestMainRunsCheckCIDR: Main given check-cidr returns 0 for a CIDR the
// server takes in its TRUSTED_PROXIES and 1 for one it refuses, and
// does not start the server.
func TestMainRunsCheckCIDR(t *testing.T) {
t.Parallel()
for cidr, want := range map[string]int{"10.0.0.0/8": 0, "1.2.3/32": 1} {
code := cli.Main("netwatch", "test", []string{"check-cidr", cidr},
failIfServerStarts(t))
if code != want {
t.Errorf("check-cidr %q: exit %d, want %d", cidr, code, want)
}
}
}
// TestMainRunsPrepareDataDir: Main given prepare-data-dir returns 1 for
// a DATA_DIR outside /data, and does not start the server. The test
// image has no netwatch user, so there the 1 comes from looking that
// user up; TestPrepareDataDirRefusesPathOutsideVolume checks the path.
func TestMainRunsPrepareDataDir(t *testing.T) {
t.Parallel()
code := cli.Main("netwatch", "test", []string{"prepare-data-dir", "/etc"},
failIfServerStarts(t))
if code != 1 {
t.Errorf("prepare-data-dir /etc: exit %d, want 1", code)
}
}
// TestCheckCIDRTakesCIDR: check-cidr exits 0, writing nothing, for a
// CIDR the server takes in its TRUSTED_PROXIES.
func TestCheckCIDRTakesCIDR(t *testing.T) {
@@ -133,13 +104,3 @@ func currentUsername(t *testing.T) string {
return current.Username
}
// failIfServerStarts is what the tests give Main in place of
// cli.RunServer: it fails the test instead of starting the server.
func failIfServerStarts(t *testing.T) func(appname, version string) {
t.Helper()
return func(string, string) {
t.Error("Main started the server")
}
}
+1 -1
View File
@@ -4,7 +4,7 @@ package globals
import "go.uber.org/fx"
//nolint:gochecknoglobals // set by cli.RunServer before fx starts
//nolint:gochecknoglobals // set by cli.Main before fx starts
var (
// Appname is the application name.
Appname string