hub v0.137.0 source + burn-down round 2 in felhom.eu: R-277 R-581 R-600 R-544 R-855 R-134 R-92 R-292 R-599 R-725 R-728 (hub), R-819 R-857 R-555 R-364 R-587 (gates/tools), R-571 R-129 R-124-runbook (docs); 28 rows closed incl. catalog + agent v0.147.0 rows, R-350 merged into R-132, R-888 opened, R-887 mechanism (249 -> 222)
gates / gates (push) Successful in 2m3s

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-05 19:43:37 +02:00
parent e0d884565f
commit 557629d2bf
65 changed files with 2680 additions and 122 deletions
+78
View File
@@ -0,0 +1,78 @@
package web
import (
"log"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"sync"
"testing"
"time"
)
func postCreate(s *Server, id string) *httptest.ResponseRecorder {
form := url.Values{"customer_id": {id}, "customer_name": {"Tester"}, "email": {"t@felhom.example"}}
req := httptest.NewRequest(http.MethodPost, "/configs/new", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
rr := httptest.NewRecorder()
s.handleConfigCreate(rr, req)
return rr
}
// R-728: a second submit for the same customer ID while the first is still between its duplicate check
// and its save must NOT create (and mint) a second time. The first create is held at the save by the
// test seam while the second runs to completion.
func TestConfigCreate_ConcurrentSubmitCreatesOnce(t *testing.T) {
s, _ := newTestServer(t)
var logBuf syncBuf
s.logger = log.New(&logBuf, "", 0)
started, release := make(chan struct{}), make(chan struct{})
var once sync.Once
s.beforeCreateSave = func(string) {
first := false
once.Do(func() { first = true })
if first {
close(started)
<-release
}
}
done := make(chan *httptest.ResponseRecorder)
go func() { done <- postCreate(s, "tester-2") }()
select {
case <-started:
case <-time.After(5 * time.Second):
t.Fatal("the first create never reached the save")
}
second := postCreate(s, "tester-2")
close(release)
first := <-done
if first.Code != http.StatusSeeOther {
t.Fatalf("first create = %d, want 303", first.Code)
}
if n := strings.Count(logBuf.String(), "Customer config created: tester-2"); n != 1 {
t.Fatalf("customer created %d times for one press, want exactly 1:\n%s", n, logBuf.String())
}
if !strings.Contains(second.Body.String(), "already being created") {
t.Errorf("the second submit must be told a create is in progress; got %d", second.Code)
}
// The guard is released: a later create of the SAME id is refused by the ordinary duplicate check,
// not stuck behind the in-flight guard.
s.beforeCreateSave = nil
if body := postCreate(s, "tester-2").Body.String(); !strings.Contains(body, "already exists") {
t.Error("after the first create returned, a re-submit must meet the ordinary 'already exists' check")
}
}
// syncBuf is a goroutine-safe log sink.
type syncBuf struct {
mu sync.Mutex
b strings.Builder
}
func (w *syncBuf) Write(p []byte) (int, error) { w.mu.Lock(); defer w.mu.Unlock(); return w.b.Write(p) }
func (w *syncBuf) String() string { w.mu.Lock(); defer w.mu.Unlock(); return w.b.String() }