Add advanced filtering and test utilities for trap servers#1
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request adds advanced filtering and test utility features to both trap-webhook and trap-smtp servers to improve test automation and debugging capabilities.
Changes:
- Added
/api/awaitendpoint for polling-free synchronization in tests (blocks until conditions are met or timeout) - Added
/api/countendpoint for efficient entry counting without fetching full payloads - Added monotonic sequence numbers to all entries for gap detection after reconnection
- Added SHA-256 hashes for email attachments in trap-smtp for content integrity verification
- Added regex filter support (
path_regex,body_regex, etc.) for complex pattern matching
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| trap-webhook/store/store.go | Added Seq field and nextSeq counter to track entry sequence numbers |
| trap-webhook/store/store_test.go | Added comprehensive tests for sequence number behavior (monotonic, starts at 1, survives eviction) |
| trap-webhook/store/filter.go | Added regex filter fields and matching logic for path, query, body, content type, and host |
| trap-webhook/store/filter_test.go | Added test coverage for regex filters including combined filters |
| trap-webhook/handlers/api.go | Modified parseWebhookFilter to parse regex parameters and return errors for invalid regex |
| trap-webhook/handlers/handlers_test.go | Added tests for regex filter endpoint and invalid regex handling |
| trap-webhook/handlers/count.go | New handler returning entry count matching filter criteria |
| trap-webhook/handlers/count_test.go | Comprehensive tests for count endpoint with various filter scenarios |
| trap-webhook/handlers/await.go | New handler that blocks until entries match filter or timeout occurs |
| trap-webhook/handlers/await_test.go | Tests for await endpoint covering existing entries, waiting, timeout, and filtering |
| trap-webhook/handlers/doc/api.md | Updated documentation with new endpoints, regex filters, and sequence number field |
| trap-webhook/main.go | Registered new /await and /count routes |
| trap-smtp/store/store.go | Added Seq field to EmailEntry and Sha256 field to Attachment |
| trap-smtp/store/store_test.go | Added sequence number tests mirroring webhook implementation |
| trap-smtp/store/filter.go | Added regex filter fields and matching logic for from, to, subject, and body |
| trap-smtp/store/filter_test.go | Added test coverage for regex filters |
| trap-smtp/smtp/backend.go | Added SHA-256 hash computation for attachment data |
| trap-smtp/smtp/backend_test.go | Added tests verifying SHA-256 hash correctness for attachments and inline images |
| trap-smtp/handlers/api.go | Modified parseEmailFilter to parse regex parameters and return errors |
| trap-smtp/handlers/handlers_test.go | Added tests for regex filter endpoint and invalid regex handling |
| trap-smtp/handlers/count.go | New handler returning entry count matching filter criteria |
| trap-smtp/handlers/count_test.go | Comprehensive tests for count endpoint |
| trap-smtp/handlers/await.go | New handler that blocks until entries match filter or timeout |
| trap-smtp/handlers/await_test.go | Tests for await endpoint with various scenarios |
| trap-smtp/handlers/doc/api.md | Updated documentation with new endpoints, regex filters, sequence numbers, and attachment SHA-256 field |
| trap-smtp/main.go | Registered new /await and /count routes |
| README.md | Updated endpoint table to include new /api/count and /api/await endpoints |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Refactor parseAwaitFilter to call parseEmailFilter/parseWebhookFilter and clear pagination fields, eliminating code duplication - Replace json.Marshal + w.Write with json.NewEncoder for consistency across all handlers - Add explicit error handling for JSON encoding in count and await timeout responses Addresses 6 review comments from @copilot-pull-request-reviewer on PR #1.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 16 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Each entry now receives a monotonically increasing sequence number on Add(), starting at 1 and surviving eviction. This provides a stable ordering identifier independent of timestamps or UUIDs, useful for cursor-based pagination in the await endpoint.
Compute and store a hex-encoded SHA-256 digest for each attachment's binary data. This allows test assertions to verify attachment integrity without downloading the full binary content.
Extend the filter system with regex variants for text fields (e.g. from_regex, path_regex). Regex filters compile to Go regexp and return 400 Bad Request on invalid patterns. Combined with existing contains filters via AND logic.
Return the number of entries matching the filter criteria without transferring full entry data. Useful for quick test assertions like "exactly 3 emails arrived for this sender".
Block until the specified number of entries match the filter criteria or the timeout is reached. Returns 408 on timeout with matched/expected counts. This eliminates sleep-based polling in CI test pipelines.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The state-smtp binary (12MB) was committed by mistake and should be excluded from version control as a build artifact. Only source code should be tracked, not compiled binaries.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 31 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (2)
trap-webhook/store/store_test.go:286
- The TestStore_ConcurrentAccess test verifies that the correct count of entries is added, but it doesn't verify that sequence numbers remain unique and monotonically increasing under concurrent access. Consider adding assertions to check that all sequence numbers are unique and in the expected range (1 to numGoroutines*entriesPerGoroutine), which would better validate thread safety of the Seq field.
trap-smtp/store/store_test.go:286 - The TestStore_ConcurrentAccess test verifies that the correct count of entries is added, but it doesn't verify that sequence numbers remain unique and monotonically increasing under concurrent access. Consider adding assertions to check that all sequence numbers are unique and in the expected range (1 to numGoroutines*entriesPerGoroutine), which would better validate thread safety of the Seq field.
func TestStore_ConcurrentAccess(t *testing.T) {
t.Parallel()
s := store.New(1000, 0)
var wg sync.WaitGroup
numGoroutines := 100
entriesPerGoroutine := 10
// Concurrent adds
for i := 0; i < numGoroutines; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < entriesPerGoroutine; j++ {
s.Add(&store.EmailEntry{Subject: "Concurrent"})
}
}()
}
wg.Wait()
expected := numGoroutines * entriesPerGoroutine
if s.Count() != expected {
t.Errorf("Count() = %d, want %d", s.Count(), expected)
}
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Replace streaming json.NewEncoder(w).Encode() with json.Marshal() + w.Write() so that Content-Type and status headers are not implicitly sent before a marshal failure. Also properly handle w.Write() errors.
The count handler already used json.Marshal() but silently discarded the w.Write() return value. Check the error and return early on failure for consistency with the await handlers.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 31 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
/api/awaitendpoint for polling-free test synchronization/api/countendpoint for efficient entry countingWhy
These enhancements address common pain points in test automation:
Polling-free synchronization: Traditional tests use
sleep()or polling loops to wait for async events, leading to flaky tests (too short) or slow CI/CD (too long). The/api/awaitendpoint blocks until conditions are met or timeout occurs, eliminating timing races.Efficient assertions: Tests often only need to verify "N emails arrived" without fetching full payloads. The
/api/countendpoint reduces overhead by returning only the count.Gap detection: Sequence numbers enable clients to detect missed entries (e.g., after SSE reconnection) by checking for gaps in the monotonic counter, which persists across entry eviction.
Content integrity: SHA-256 hashes allow test assertions on binary attachments without storing full binary data in test expectations, and enable duplicate detection.
Advanced filtering: Regex filters complement existing substring filters for scenarios requiring domain validation (
^[a-z]+@example\.com$), URL patterns, or complex content matching.All features maintain backward compatibility and parallel test safety through stateless, filter-based isolation.
Test Plan