mesh-mail: tighten tests that proved less than their criterion — attempt 5 and no mail received (1198/AC4), mail_health actually turning unhealthy (1199/AC2), and the words mail_send_status gives, not only its status (1199/AC4) (review round 1 finding 6)

This commit is contained in:
jochen
2026-10-19 10:53:12 +02:00
parent 95089762ef
commit 7397051771
3 changed files with 52 additions and 3 deletions
@@ -273,8 +273,14 @@ func TestMailSenderAcceptanceARefusedSignInFailsAfterItsAttemptsAndNothingIsRece
<-done
kept, _, ok, err := getSend(store, id)
if err != nil || !ok || kept.Decided == nil || kept.Decided.Outcome == "sent" {
t.Fatalf("the kept send ended as sent, or could not be read: %v %v %+v", err, ok, kept.Decided)
if err != nil || !ok || kept.Decided == nil || !strings.HasPrefix(kept.Decided.Outcome, "failed: ") {
t.Fatalf("the kept send did not end failed: %v %v %+v", err, ok, kept.Decided)
}
if kept.Decided.Attempt != MostAttempts {
t.Fatalf("failed after %d attempt(s), want all %d", kept.Decided.Attempt, MostAttempts)
}
if n := s.receivedCount(); n != 0 {
t.Fatalf("the scripted server received %d message(s), want none: a refused sign-in never reaches DATA", n)
}
}
@@ -114,3 +114,39 @@ func TestTheWatchJudgesFromTheFilesAndTheIndex(t *testing.T) {
t.Fatalf("the status file's shape: %s", raw)
}
}
// 1199/AC2: mail_health (the tool, not only Overdue or WithOverdue in isolation) turns unhealthy naming an
// overdue send, even while the watch's own verdict is healthy (novox/hq review round 1 finding 6).
func TestMailHealthToolTurnsUnhealthyNamingAnOverdueSend(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "health.json")
if err := writeStatus(path, Status{Answer: health.Healthy("1 account(s) watched"), At: judgedAt}); err != nil {
t.Fatal(err)
}
sends := newMemSends()
overdueID := "send-overdue1"
req := SendRequest{ID: overdueID, Account: "mesh", At: judgedAt}
req.Decided = &SendDecision{At: judgedAt.Add(-20 * time.Minute), Outcome: "queued"}
if _, err := sends.Create(req.ID, req); err != nil {
t.Fatal(err)
}
if err := addSenderPending(sends, req.ID); err != nil {
t.Fatal(err)
}
b := &Bundle{Env: Env{Status: path}, Sends: sends, Now: func() time.Time { return judgedAt }}
out, err := b.healthTool(nil)
if err != nil {
t.Fatalf("mail_health: %v", err)
}
a, ok := out.(health.Answer)
if !ok {
t.Fatalf("mail_health answered %T, want health.Answer", out)
}
if a.State != health.StateUnhealthy {
t.Fatalf("mail_health: %+v, want unhealthy", a)
}
if !strings.Contains(a.Why, overdueID) {
t.Fatalf("mail_health's why does not name the overdue send: %q", a.Why)
}
}
@@ -12,6 +12,7 @@ import (
"net"
"net/smtp"
"strings"
"sync/atomic"
"testing"
)
@@ -31,6 +32,7 @@ func drop() step { return step{drop: true} }
type scriptedSMTPServer struct {
ln net.Listener
ehlo, auth, mail, rcpt, dataOpen, dataEnd step
received int32 // atomic: how many full DATA bodies this server has read
}
func newScriptedSMTPServer(t *testing.T) *scriptedSMTPServer {
@@ -48,6 +50,10 @@ func newScriptedSMTPServer(t *testing.T) *scriptedSMTPServer {
func (s *scriptedSMTPServer) addr() string { return s.ln.Addr().String() }
// receivedCount is how many full DATA bodies this server has read, for a test to prove nothing was
// received at all (novox/hq review round 1 finding 6).
func (s *scriptedSMTPServer) receivedCount() int { return int(atomic.LoadInt32(&s.received)) }
func (s *scriptedSMTPServer) dialer() SMTPDialer {
addr := s.addr()
return func(Server) (*smtp.Client, error) { return smtp.Dial(addr) }
@@ -115,7 +121,8 @@ func (s *scriptedSMTPServer) handle(conn net.Conn) {
break
}
}
s.send(conn, s.dataEnd) // a drop here is "the connection lost after the data was written"
atomic.AddInt32(&s.received, 1) // a full message body was read, whatever dataEnd then says
s.send(conn, s.dataEnd) // a drop here is "the connection lost after the data was written"
return
case upper == "QUIT":
fmt.Fprintf(conn, "221 bye\r\n")