Atlas › Test

panic_propagates

Exact test identity: go.temporal.io/server/common/testing/await/TestRequire_FailureScenarios/panic_propagates

Package
go.temporal.io/server/common/testing/await
Suite / test hierarchy
TestRequire_FailureScenarios/panic_propagates
Test
panic_propagates
Introduced at
require_ctx.go ×2 Frontier kind: Joint frontier
Covered ranges
23
Covered lines
80
Covered files
3

Covered source

Expand a file to inspect source; the > gutter marks covered lines.

go.temporal.io/server/common/testing/await/require_ctx.go 60 covered LOC · 19 ranges

Open complete file

20 const defaultSoftDeadlockTimeout = 30 * time.Second
21
22 > func softDeadlockTimeout() time.Duration { require_ctx.go
23 > if s := os.Getenv(softDeadlockTimeoutEnvVar); s != "" {
24 if d, err := time.ParseDuration(s); err == nil {
25 return d
26 }
27 }
28 > return defaultSoftDeadlockTimeout require_ctx.go
29 }
30
54 // Pass the *await.T to require.*/assert.* — failures cause a retry, not a
55 // test failure. Use t.Context() inside the callback to honor the timeout.
56 > func Require(ctx context.Context, tb testing.TB, condition func(*T), timeout, pollInterval time.Duration) { require_ctx.go
57 > tb.Helper()
58 > run(ctx, tb, condition, legacyConfig(timeout, pollInterval, ""), "Require", requireMisuseHint, true)
59 > }
60
61 // Requiref is like [Require] but adds a formatted message to the timeout
74 misuseHint string,
75 cancellable bool,
76 > ) { require_ctx.go
77 > tb.Helper()
78 >
79 > // Skip if the test already failed — no point polling.
80 > if tb.Failed() {
81 tb.Logf("%s: skipping (test already failed)", funcName)
82 return
83 }
84 // Guard: context.WithDeadline panics on a nil parent.
85 > if parentCtx == nil { require_ctx.go
86 tb.Fatalf("%s: nil context", funcName)
87 return
88 }
89
90 > deadline := time.Now().Add(cfg.totalTimeout) require_ctx.go
91 >
92 > // Cap at the parent context's deadline if it's earlier than our timeout.
93 > if parentDeadline, hasDeadline := parentCtx.Deadline(); hasDeadline && parentDeadline.Before(deadline) {
94 deadline = parentDeadline
95 }
97 // Cap at the test's deadline if it's earlier than our deadline.
98 // Ideally, the parent context already accounts for the test's deadline - but we are being defensive.
99 > if d, ok := tb.(interface{ Deadline() (time.Time, bool) }); ok { require_ctx.go
100 > if testDeadline, hasDeadline := d.Deadline(); hasDeadline && testDeadline.Before(deadline) { require_ctx.go
101 deadline = testDeadline
102 }
103 }
104
105 > effectiveTimeout := max(0, time.Until(deadline)) require_ctx.go
106 > awaitCtx, awaitCancel := context.WithDeadline(parentCtx, deadline)
107 > defer awaitCancel()
108 >
109 > report := timeoutReport{effectiveTimeout: effectiveTimeout}
110 >
111 > for {
112 > // Parent context was canceled while we were sleeping (not our deadline).
113 > if err := awaitCtx.Err(); err != nil && !deadlineReached(deadline) {
114 report.reportAttemptErrors(tb)
115 tb.Fatalf("%s: context canceled before condition was satisfied: %v", funcName, err)
117 }
118
119 > report.nextPoll() require_ctx.go
120 >
121 > // Per-attempt context: bounded by the configured attempt timeout and
122 > // further capped by the overall awaitCtx.
123 > attemptCtx, attemptCancel := context.WithTimeout(awaitCtx, cfg.attemptTimeout)
124 > t := &T{tb: tb, ctx: attemptCtx}
125 >
126 > // Run attempt.
127 > res := runAttempt(t, condition, attemptCancel, funcName, cancellable)
128 > attemptCancel()
129 > if res.panicVal != nil {
130 > panic(res.panicVal) // propagate to caller require_ctx.go
131 }
132 if res.deadlocked {
211 funcName string,
212 cancellable bool,
213 > ) attemptResult { require_ctx.go
214 > done := make(chan attemptResult, 1)
215 >
216 > go func() {
217 > completed := false
218 > defer func() {
219 > if r := recover(); r != nil { require_ctx.go
220 > if _, ok := r.(attemptFailed); ok { require_ctx.go
221 done <- attemptResult{stopped: true}
222 return
223 }
224 > done <- attemptResult{panicVal: r} require_ctx.go
225 > return
226 }
227 // recover returned nil: either normal return (completed=true) or
229 done <- attemptResult{stopped: !completed}
230 }()
231 > condition(t) require_ctx.go
232 > completed = true
233 }()
234
235 > if cancellable { require_ctx.go
236 > // Soft phase: wait for the condition, our soft timer, or parent cancel. require_ctx.go
237 > softTimer := time.NewTimer(softDeadlockTimeout())
238 > defer softTimer.Stop()
239 >
240 > select {
241 > case r := <-done: require_ctx.go
242 > return r
243 case <-softTimer.C:
244 // Soft deadlock: log a warning.
go.temporal.io/server/common/testing/await/config.go 17 covered LOC · 3 ranges

Open complete file

17 }
18
19 > func newConfig() config { config.go
20 > return config{
21 > attemptTimeout: envDuration(attemptTimeoutEnvVar, 10*time.Second) * debug.TimeoutMultiplier,
22 > }
23 > }
24
25 > func legacyConfig(timeout, pollInterval time.Duration, timeoutMsg string) config { config.go
26 > cfg := newConfig()
27 > cfg.totalTimeout = timeout
28 > cfg.pollInterval = pollInterval
29 > cfg.timeoutMsg = timeoutMsg
30 > return cfg
31 > }
32
33 > func envDuration(name string, fallback time.Duration) time.Duration { config.go
34 > if s := os.Getenv(name); s != "" {
35 > if d, err := time.ParseDuration(s); err == nil && d > 0 {
36 > return d
37 > }
38 }
39 return fallback
go.temporal.io/server/common/testing/await/report.go 3 covered LOC · 1 range

Open complete file

28 }
29
30 > func (r *timeoutReport) nextPoll() { report.go
31 > r.attempts++
32 > }
33
34 func (r *timeoutReport) recordErrors(errors []string) {