Skip to content

Server behaviour tests, running on every platform (incl. Windows)#305

Draft
hhugo wants to merge 9 commits into
more-cifrom
server-behavior-tests
Draft

Server behaviour tests, running on every platform (incl. Windows)#305
hhugo wants to merge 9 commits into
more-cifrom
server-behavior-tests

Conversation

@hhugo

@hhugo hhugo commented Jun 28, 2026

Copy link
Copy Markdown
Member

Adds a suite of behaviour tests for the server and makes the whole suite — including the serve-mode HTTP tests — pass on every platform, including Windows in bytecode. Builds on the Windows-CI work in #253.

Tests

  • http-semantics — methods (GET/HEAD), status codes, content-type/length
  • static-files — index resolution, nested paths, directory listing, protection against escaping the served directory
  • range-requests — documents that byte ranges are currently ignored (TODO where Ocsigen_range used to be in ocsigen_cohttp.ml)
  • serve / serve-listing / serve-cli — end-to-end serve-mode binary: directory listing on/off + CLI error handling
  • extensions — redirectmod, accesscontrol, authbasic, cors, rewritemod, outputfilter (one focused test each)

Harness / CI

  • dune runtest is now wired into CI (it was never run before)
  • server-test-helpers.sh rewritten in POSIX sh (was bash-only, failed under dash); server logs go to a file to avoid non-deterministic interleaving
  • serve-mode servers are stopped gracefully (ocsigenserver --command shutdown) so they exit on their own — nothing is left for dune's cram cleanup to hang on, which lets the serve-mode tests run on Windows too
  • programmatic (unix-socket) tests are skipped on Windows via (enabled_if (<> %{os_type} Win32))
  • fixed bitrotted tests: deflatemod test.ml used pre-modernisation module names; serve.t had a spurious (no-eol)

Windows portability fixes (needed to run the suite there)

  • secure RNG (Cryptokit.Random.secure_rng) instead of opening /dev/urandom
  • tolerate signals (e.g. SIGPIPE) that don't exist on Windows
  • Content-Length from stat instead of Lwt_io.length, which seeks and fails on Windows
  • local_files: fix a Filename.dirname infinite loop at drive roots (e.g. D:\) that wedged the Lwt main thread on directory requests — this was the real cause of the directory-listing hang
  • trim the trailing CR from ocamlfind output when computing builtin packages

Command channel

  • a new --command CMD --command-pipe NAME client mode lets a running server be controlled (notably stopped) without a signal
  • the command pipe is a FIFO on Unix and a polled regular file on Windows (where mkfifo is unavailable), so graceful shutdown works everywhere with no platform-specific C code

A named-pipe variant of the command channel (plus a couple of changes that turned out unnecessary) is preserved on the windows-serve-support branch.

🤖 Generated with Claude Code

@hhugo hhugo force-pushed the server-behavior-tests branch from 8e4e356 to 33bd231 Compare June 30, 2026 15:34
hhugo and others added 4 commits June 30, 2026 17:53
Cryptokit.Random.device_rng "/dev/urandom" fails at startup on Windows, which has no /dev/urandom. Use Cryptokit.Random.secure_rng, the platform's own CSPRNG.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ocamlfind output carries a trailing CR on Windows, so package names did not match and base64 was reported as 'already loaded'. Trim each line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Some signals (e.g. SIGPIPE) do not exist on Windows, where Sys.set_signal raises Invalid_argument. Wrap it so the server still starts there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lwt_io.length seeks the channel, which fails on Windows ('Lwt_io.length: seek failed'). Use Lwt_unix.LargeFile.stat for the Content-Length instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hhugo hhugo force-pushed the server-behavior-tests branch 2 times, most recently from 0a163d9 to 0b3c816 Compare June 30, 2026 16:14
hhugo and others added 2 commits June 30, 2026 22:06
When resolving a directory request whose filename ends with the platform separator (from Filename.concat dir ""): the trailing '\\' was not recognised, causing a spurious redirect; and check_symlinks_parent_directories walked up with Filename.dirname stopping only at '/', '.', or no_check_for, so on Windows it skipped no_check_for and looped forever at a drive root like 'D:\\' (where Filename.dirname is a fixed point), wedging the Lwt main thread. Accept the platform separator and stop at a dirname fixed point.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Serve mode needs a way to stop a running server gracefully -- on Windows killing the background process is unreliable. Keep the Unix command pipe (a FIFO), and on Windows (where mkfifo is unavailable) use an ordinary file that the server polls for commands; stop polling once a shutdown is requested. Add a client side: 'ocsigenserver --command CMD --command-pipe NAME' writes CMD to the pipe (FIFO) or appends it to the polled file, so a server can be controlled without a signal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hhugo hhugo force-pushed the server-behavior-tests branch from 0b3c816 to f1b53e2 Compare June 30, 2026 20:07
@hhugo hhugo changed the title Server behaviour tests Server behaviour tests, running on every platform (incl. Windows) Jun 30, 2026
@hhugo hhugo force-pushed the server-behavior-tests branch 3 times, most recently from 28ff5b5 to e3363f7 Compare June 30, 2026 21:54
hhugo and others added 3 commits July 1, 2026 12:19
conduit-lwt-unix sets SO_REUSEADDR on every listening socket, including AF_UNIX ones. That is a harmless no-op on Unix, but on Windows it makes the following bind fail with EOPNOTSUPP, so a server on a Unix-domain socket cannot start. Pin (via pin-depends) a conduit fork that skips SO_REUSEADDR for ADDR_UNIX, until the fix is released upstream.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add cram tests for core HTTP semantics, static-file and range-request serving, and several extensions (accesscontrol, authbasic, cors, outputfilter, redirectmod, rewritemod), plus serve-mode tests. The shared cram harness starts the server detached with logs to a file and stops it gracefully through its command pipe ('ocsigenserver --command shutdown'), so the server exits on its own -- this lets the tests run on every platform, including Windows, without leaving a process for dune's cram cleanup to hang on. The per-test servers are built by the project and passed to the cram tests as dependencies, so the test directories need no nested dune-project.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Run 'dune runtest' (with a timeout) on every job so the new tests are exercised on all platforms.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hhugo hhugo force-pushed the server-behavior-tests branch from e3363f7 to dba829b Compare July 1, 2026 10:20
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