package dispatcher import ( "bytes" "context" "log/slog" "strings" "testing" "time" "git.ipao.vip/rogee/go-sip/internal/logging" ) func captureExecutionLogs(t *testing.T) *bytes.Buffer { t.Helper() previous := slog.Default() out := new(bytes.Buffer) logging.Configure("dispatcher", false, out) t.Cleanup(func() { slog.SetDefault(previous) }) return out } func TestWorkflowLogsExplainInvalidCalleeAndCapacityWait(t *testing.T) { out := captureExecutionLogs(t) c, originator, _, state := newExecuteFixture(t) snapshot, err := state.ReadSnapshot(c.DispatcherID, 1001, "task-asr") if err != nil { t.Fatal(err) } snapshot.Quota.MaxConcurrentCalls = 1 if err := state.SaveSnapshot(snapshot); err != nil { t.Fatal(err) } if err := c.ProcessExecute(context.Background(), executeBody(t, "invalid-log", "not-a-phone")); err != nil { t.Fatal(err) } if len(originator.calls) != 0 { t.Fatal("invalid callee dialed") } text := out.String() for _, part := range []string{"invalid-log", "task-asr", "callee_rejected", ErrCalleeRejected.Error()} { if !strings.Contains(text, part) { t.Fatalf("missing %s: %s", part, text) } } out.Reset() for _, id := range []string{"capacity-1", "capacity-2", "capacity-3"} { if err := c.ProcessExecute(context.Background(), executeBody(t, id, "15003164745")); err != nil { t.Fatal(err) } } text = out.String() if !strings.Contains(text, "reservation_wait") || !strings.Contains(text, "capacity") { t.Fatalf("silent capacity wait: %s", text) } } func TestWorkflowLogsExplainFutureIssuedAtAndPreDialCancellation(t *testing.T) { out := captureExecutionLogs(t) c, originator, _, _ := newExecuteFixture(t) body := executeBody(t, "future-log", "15003164745") body = []byte(strings.Replace(string(body), `"issued_at":"2026-09-21T01:00:00Z"`, `"issued_at":"2026-09-21T03:00:00Z"`, 1)) if err := c.ProcessExecute(context.Background(), body); err != nil { t.Fatal(err) } if len(originator.calls) != 0 || !strings.Contains(out.String(), "issued_at_wait") { t.Fatal(out.String()) } out.Reset() reads := 0 c.Now = func() time.Time { reads++ if reads == 1 { return monday(9, 30) } return monday(20, 0) } if err := c.ProcessExecute(context.Background(), executeBody(t, "cancel-log", "15003164745")); err != nil { t.Fatal(err) } if len(originator.calls) != 0 || !strings.Contains(out.String(), "reservation_cancelled") || !strings.Contains(out.String(), "cancel-log") { t.Fatal(out.String()) } } func TestWorkflowFailureIncludesIdentityStageAndActualReason(t *testing.T) { out := captureExecutionLogs(t) c, originator, _, _ := newExecuteFixture(t) originator.err = context.DeadlineExceeded if err := c.ProcessExecute(context.Background(), executeBody(t, "unknown-log", "15003164745")); err == nil { t.Fatal("error hidden") } for _, part := range []string{"unknown-log", "task-asr", "execution_outcome_unknown", "deadline exceeded", "occupancy_retained"} { if !strings.Contains(out.String(), part) { t.Fatalf("missing %s: %s", part, out.String()) } } }