The black-box monitor tests showed socketv1_controller.go and
socketv2_controller.go were near-identical: same constants (identical
values), upgrader, read/write pumps, Close, and handler bodies, differing
only in the event payload shape and v1 dropping deletions.
Extract the shared machinery into socket_controller.go:
- msgListener[T] generic listener with toStored/toDeleted payload
transforms; a nil toDeleted preserves the socketv1 behavior of ignoring
deletions
- socketReadPump / socketWritePump free functions (WriteJSON is
payload-type agnostic)
- serveMonitor shared handler body (upgrade, gauge tracking, listener
registration, pump wiring)
The version files shrink to their listener constructors and the four
exported handlers, whose signatures are unchanged. v1 payloads are now
shaped at enqueue time rather than write time; the JSON on the wire is
identical, pinned by the commit-1 tests, which pass unmodified.
Adds direct unit tests for the extracted listener logic: watches()
filtering, Receive/Delete filtering + payload shaping, nil-toDeleted
deletion dropping, and sequential Close idempotency.
Cover the REST WebSocket monitor endpoints (v1 + v2), previously at 0%
for all 18 functions in socketv1_controller.go and socketv2_controller.go;
pkg/rest coverage goes from 20.9% to 73.2%.
The harness dials a real gorilla/websocket client into an httptest server
wired to a running msghub.Hub, and relies on the hub's history replay for
deterministic ordering: dispatching before dialing seeds the replay, and
events are relayed in dispatch order, so receiving event N next proves
filtered events were skipped rather than delayed.
Covered for both API versions:
- monitor-all and per-mailbox endpoints, including history replay and live
delivery, and mailbox filtering of both message-stored and (v2)
message-deleted events
- address-form mailbox names via Manager.MailboxForAddress (user%40example.com)
- invalid mailbox names rejected with 500 before the upgrade, and plain GET
requests failing the handshake with 400
- client data messages discarded by the read pump
- clean client shutdown: listener deregistration, empty close frame from
the writer racing the read pump's close-code echo, and the
WebSocketConnectsCurrent expvar gauge increment/decrement
Tests only; no production changes. Notes for follow-up commits:
- v1 monitors ignore deletions while v2 reports them (pinned as current
behavior in TestMonitorMailboxMessagesV1)
- httptest.Server.Close does not wait for hijacked connections, so
dialMonitor's cleanup awaits the handler goroutine via the connections
gauge before the hub is stopped; the read/write pumps calling
msgListener.Close concurrently can still double-close its channel
(check-then-act race in Close's select) and deserves a fix
- deadline-set error paths, the 54s ping/pong cycle, and write-failure
paths remain uncovered, consistent with the POP3 send-error paths
- RETR and TOP now respond "-ERR You deleted message N" for messages
marked deleted, as RFC 1939 sections 5 (RETR) and 7 (TOP) require;
previously the message content was still sent.
- STLS: a failed TLS handshake previously continued the session with
the dead TLS connection installed as s.conn and a bogus tlsState,
producing confusing follow-on errors. RFC 2595 section 4 requires
the negotiation to complete before further commands, so a failure
is now fatal: log it and terminate the session.
Updates the scripted tests that previously pinned the old behavior,
and adds a STLS handshake failure regression test.
Signed-off-by: James Hillyerd <james@hillyerd.com>
- validateMsgNum parses and range-checks message-number arguments,
replacing five copies of the parse/check/respond sequence in the
LIST, UIDL, DELE, RETR and TOP arms (wire responses unchanged).
- listMessages implements LIST and UIDL, which differ only in the
per-message value reported.
- sendMessageLines unifies sendMessage/sendMessageTop via a body line
limit, negative meaning unlimited.
Adds a direct unit test for validateMsgNum and an equivalence test
asserting TOP with a large line limit matches RETR output. All
scripted session tests from the previous commit pass unchanged.
Signed-off-by: James Hillyerd <james@hillyerd.com>
Covers the POP3 TRANSACTION state machine via scripted sessions over
net.Pipe, mirroring the SMTP handler test harness: STAT/LIST/UIDL/DELE/
RETR/TOP/NOOP/RSET/QUIT including argument error paths, deleted-message
behavior, dot-stuffing, RETR/TOP source error paths, mailbox load
errors, session read error handling (idle timeout vs other), and the
TCP listener lifecycle (Start/serve/Notify/Drain).
No production code changes; current behavior is pinned as-is. Two
known RFC deviations are documented in tests (RETR/TOP of messages
marked deleted) for follow-up fixes. Package coverage: 24.4% -> 93.2%.
Signed-off-by: James Hillyerd <james@hillyerd.com>
* fix: POP3 server now uses TLS HandshakeContext
Signed-off-by: James Hillyerd <james@hillyerd.com>
* fix: Web server now uses Listen with context
Signed-off-by: James Hillyerd <james@hillyerd.com>
* fix: replace interface{} with any
Signed-off-by: James Hillyerd <james@hillyerd.com>
---------
Signed-off-by: James Hillyerd <james@hillyerd.com>
* Update to golangci lint 2.0.x
Signed-off-by: James Hillyerd <james@hillyerd.com>
* Fix new lint warnings
Signed-off-by: James Hillyerd <james@hillyerd.com>
---------
Signed-off-by: James Hillyerd <james@hillyerd.com>
* chore: Update Go deps
Signed-off-by: James Hillyerd <james@hillyerd.com>
* Fix lint warnings for loopvars
Signed-off-by: James Hillyerd <james@hillyerd.com>
---------
Signed-off-by: James Hillyerd <james@hillyerd.com>
* chore: rename BeforeMailAccepted to BeforeMailFromAccepted
Signed-off-by: James Hillyerd <james@hillyerd.com>
* chore: update BeforeMailAccepted to use SMTPSession
Signed-off-by: James Hillyerd <james@hillyerd.com>
---------
Signed-off-by: James Hillyerd <james@hillyerd.com>
* chore: faster hash to string conv
Signed-off-by: James Hillyerd <james@hillyerd.com>
* chore: require NoError in integration test setup
Signed-off-by: James Hillyerd <james@hillyerd.com>
---------
Signed-off-by: James Hillyerd <james@hillyerd.com>
* chore: convert smtp/handler if-else chain to switch-case
Signed-off-by: James Hillyerd <james@hillyerd.com>
* chore: extract long case into parseMailCmd func
Signed-off-by: James Hillyerd <james@hillyerd.com>
* chore: remove extraneous braces in cases
Signed-off-by: James Hillyerd <james@hillyerd.com>
---------
Signed-off-by: James Hillyerd <james@hillyerd.com>
* chore: colocate SMTP session WaitGroup incr/decr
Signed-off-by: James Hillyerd <james@hillyerd.com>
* fix: smtp tests that hang on panic/t.Fatal
Signed-off-by: James Hillyerd <james@hillyerd.com>
* chore: reorder smtp/handler test helpers
Signed-off-by: James Hillyerd <james@hillyerd.com>
---------
Signed-off-by: James Hillyerd <james@hillyerd.com>
* fix whitespace warnings
Signed-off-by: James Hillyerd <james@hillyerd.com>
* fix a number of typos
Signed-off-by: James Hillyerd <james@hillyerd.com>
* fix many cosmetic linter warnings
Signed-off-by: James Hillyerd <james@hillyerd.com>
---------
Signed-off-by: James Hillyerd <james@hillyerd.com>
* event: Use pointers for InboundMessage addresses
To ease conversions to/from MessageMetadata
Signed-off-by: James Hillyerd <james@hillyerd.com>
* message: test StoreManager.MailboxForAddress()
Signed-off-by: James Hillyerd <james@hillyerd.com>
---------
Signed-off-by: James Hillyerd <james@hillyerd.com>