test: stabilize distributed load verification
This commit is contained in:
@@ -39,6 +39,7 @@ type coordinatorState struct {
|
||||
armed map[string]bool
|
||||
ledgers map[string][]AcceptedMessage
|
||||
observed map[string][]AcceptedMessage
|
||||
history map[string][]string
|
||||
summaries map[string]AgentSummary
|
||||
complete chan struct{}
|
||||
completeOnce sync.Once
|
||||
@@ -58,14 +59,15 @@ func runCoordinator(ctx context.Context, listen, runID, scenario, output string,
|
||||
start: StartInfo{RunID: runID, Scenario: scenario}, startDelay: startDelay, commitDelay: 5 * time.Second,
|
||||
expectedAgents: expectedAgents,
|
||||
ready: make(map[string]AgentReady), ledgers: make(map[string][]AcceptedMessage),
|
||||
observed: make(map[string][]AcceptedMessage),
|
||||
armed: make(map[string]bool), summaries: make(map[string]AgentSummary), complete: make(chan struct{}),
|
||||
observed: make(map[string][]AcceptedMessage), history: make(map[string][]string),
|
||||
armed: make(map[string]bool), summaries: make(map[string]AgentSummary), complete: make(chan struct{}),
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/v1/ready", state.handleReady)
|
||||
mux.HandleFunc("/v1/start", state.handleStart)
|
||||
mux.HandleFunc("/v1/ledger", state.handleLedger)
|
||||
mux.HandleFunc("/v1/observed", state.handleObserved)
|
||||
mux.HandleFunc("/v1/history", state.handleHistory)
|
||||
mux.HandleFunc("/v1/summary", state.handleSummary)
|
||||
mux.HandleFunc("/v1/status", state.handleStatus)
|
||||
server := &http.Server{Addr: listen, Handler: mux, ReadHeaderTimeout: 5 * time.Second}
|
||||
@@ -94,6 +96,52 @@ func runCoordinator(ctx context.Context, listen, runID, scenario, output string,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *coordinatorState) handleHistory(w http.ResponseWriter, r *http.Request) {
|
||||
machine := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("machine")))
|
||||
switch r.Method {
|
||||
case http.MethodPost:
|
||||
if machine != "a" && machine != "b" {
|
||||
http.Error(w, "invalid machine", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
var messageIDs []string
|
||||
if !decodeLimitedJSON(w, r, &messageIDs) {
|
||||
return
|
||||
}
|
||||
s.mu.Lock()
|
||||
if s.history == nil {
|
||||
s.history = make(map[string][]string)
|
||||
}
|
||||
s.history[machine] = messageIDs
|
||||
count := len(s.history)
|
||||
s.mu.Unlock()
|
||||
writeJSON(w, http.StatusOK, map[string]int{"submitted_agents": count})
|
||||
case http.MethodGet:
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if len(s.history) < s.expectedAgents {
|
||||
writeJSON(w, http.StatusAccepted, map[string]int{"submitted_agents": len(s.history), "expected_agents": s.expectedAgents})
|
||||
return
|
||||
}
|
||||
unique := make(map[string]bool)
|
||||
for _, messageIDs := range s.history {
|
||||
for _, mid := range messageIDs {
|
||||
if mid != "" {
|
||||
unique[mid] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
merged := make([]string, 0, len(unique))
|
||||
for mid := range unique {
|
||||
merged = append(merged, mid)
|
||||
}
|
||||
sort.Strings(merged)
|
||||
writeJSON(w, http.StatusOK, merged)
|
||||
default:
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *coordinatorState) handleObserved(w http.ResponseWriter, r *http.Request) {
|
||||
machine := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("machine")))
|
||||
switch r.Method {
|
||||
@@ -264,7 +312,8 @@ func (s *coordinatorState) handleStatus(w http.ResponseWriter, _ *http.Request)
|
||||
defer s.mu.Unlock()
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"start": s.start, "ready": s.ready, "armed": s.armed,
|
||||
"ledger_agents": len(s.ledgers), "observed_agents": len(s.observed), "summary_agents": len(s.summaries),
|
||||
"ledger_agents": len(s.ledgers), "observed_agents": len(s.observed),
|
||||
"history_agents": len(s.history), "summary_agents": len(s.summaries),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -275,8 +324,12 @@ func (s *coordinatorState) writeOutput(path string) error {
|
||||
Ready map[string]AgentReady `json:"ready"`
|
||||
Ledgers map[string][]AcceptedMessage `json:"ledgers"`
|
||||
Observed map[string][]AcceptedMessage `json:"observed"`
|
||||
History map[string][]string `json:"history"`
|
||||
Summaries map[string]AgentSummary `json:"summaries"`
|
||||
}{s.start, s.ready, s.ledgers, s.observed, s.summaries}
|
||||
}{
|
||||
Start: s.start, Ready: s.ready, Ledgers: s.ledgers, Observed: s.observed,
|
||||
History: s.history, Summaries: s.summaries,
|
||||
}
|
||||
s.mu.Unlock()
|
||||
raw, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
@@ -387,6 +440,27 @@ func (c *coordinatorClient) observed(ctx context.Context) ([]AcceptedMessage, er
|
||||
}
|
||||
}
|
||||
|
||||
func (c *coordinatorClient) submitHistory(ctx context.Context, machine string, messageIDs []string) error {
|
||||
_, err := c.request(ctx, http.MethodPost, "/v1/history?machine="+machine, messageIDs, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *coordinatorClient) history(ctx context.Context) ([]string, error) {
|
||||
for {
|
||||
var messageIDs []string
|
||||
status, err := c.request(ctx, http.MethodGet, "/v1/history", nil, &messageIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status == http.StatusOK {
|
||||
return messageIDs, nil
|
||||
}
|
||||
if err = waitContext(ctx, time.Second); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *coordinatorClient) submitSummary(ctx context.Context, summary AgentSummary) error {
|
||||
_, err := c.request(ctx, http.MethodPost, "/v1/summary", summary, nil)
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user