Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherror_test.go
More file actions
Latest commit
117 lines (102 loc) · 3.28 KB
/
Copy patherror_test.go
File metadata and controls
117 lines (102 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package stack_test
import (
"context"
"errors"
"fmt"
"slices"
"strings"
"testing"
"github.com/themakers/stack"
"github.com/themakers/stack/stack_backend"
)
typestackTraceProviderinterface {
error
StackTrace() stack_backend.StackTrace
}
typetracedTestErrorstruct{}
func (*tracedTestError) Error() string {
return"boom"
}
funccaptureErrorAtOrigin(ctx context.Context, errerror) error {
returnstack.Error(ctx, "origin failed", err)
}
funclogErrorAtBoundary(ctx context.Context, errerror) error {
returnstack.Error(ctx, "boundary failed", err)
}
funcTestErrorPreservesFirstStackTrace(t*testing.T) {
cap:=&capture{}
ctx:=newCtx(cap)
target:=&tracedTestError{}
originCtx, originDone:=stack.Span(ctx)
originErr:=captureErrorAtOrigin(originCtx, target)
originDone()
iforiginErr==target {
t.Fatal("Error returned the original error without a stack trace wrapper")
}
if!errors.Is(originErr, target) {
t.Fatal("wrapped error does not preserve errors.Is")
}
iftyped, ok:= errors.AsType[*tracedTestError](originErr); !ok||typed!=target {
t.Fatal("wrapped error does not preserve errors.AsType")
}
traceProvider, ok:= errors.AsType[stackTraceProvider](originErr)
if!ok {
t.Fatal("wrapped error does not expose its stack trace")
}
outerErr:=fmt.Errorf("outer: %w", originErr)
joinedErr:=errors.Join(errors.New("unrelated"), outerErr)
boundaryCtx, boundaryDone:=stack.Span(ctx)
ifgot:=logErrorAtBoundary(boundaryCtx, joinedErr); got!=joinedErr {
t.Fatal("Error rewrapped an error whose tree already contains a stack trace")
}
boundaryDone()
vartraces []stack_backend.StackTrace
for_, event:=rangecap.events {
ifevent.Kind&stack_backend.KindError!=0 {
traces=append(traces, event.LogEvent.StackTrace)
}
}
iflen(traces) !=2 {
t.Fatalf("expected 2 error events, got %d", len(traces))
}
if!slices.Equal(traces[0], traces[1]) {
t.Fatal("boundary error event did not reuse the origin stack trace")
}
if!slices.Equal(traceProvider.StackTrace(), traces[0]) {
t.Fatal("error wrapper exposes a different stack trace than the origin event")
}
spanEnds:=cap.spanEnds()
iflen(spanEnds) !=2 {
t.Fatalf("expected 2 span-end events, got %d", len(spanEnds))
}
if!slices.Equal(spanEnds[1].State.Span.ErrorStackTrace, traces[0]) {
t.Fatal("boundary span did not reuse the origin stack trace")
}
trace:=traces[1].String()
if!strings.Contains(trace, "captureErrorAtOrigin") {
t.Fatalf("origin frame missing from preserved stack trace:\n%s", trace)
}
ifstrings.Contains(trace, "logErrorAtBoundary") {
t.Fatalf("boundary frame replaced the origin stack trace:\n%s", trace)
}
}
funcTestErrorWithNilPreservesReturnContract(t*testing.T) {
cap:=&capture{}
ctx:=newCtx(cap)
iferr:=stack.Error(ctx, "failed without an error", nil); err!=nil {
t.Fatalf("expected nil, got %v", err)
}
iflen(cap.events) !=1 {
t.Fatalf("expected 1 event, got %d", len(cap.events))
}
event:=cap.events[0]
ifevent.Kind&stack_backend.KindError==0 {
t.Fatalf("expected an error event, got kind %v", event.Kind)
}
ifevent.LogEvent.Error==nil {
t.Fatal("nil error event does not contain a synthesized error")
}
iflen(event.LogEvent.StackTrace) ==0 {
t.Fatal("nil error event does not contain a stack trace")
}
}