1
2
3
4
5 package trace
6
7 import (
8 "fmt"
9 "internal/diff"
10 "reflect"
11 "slices"
12 "testing"
13 "time"
14 )
15
16 func TestMakeEvent(t *testing.T) {
17 checkTime := func(t *testing.T, ev Event, want Time) {
18 t.Helper()
19 if ev.Time() != want {
20 t.Errorf("expected time to be %d, got %d", want, ev.Time())
21 }
22 }
23 checkValid := func(t *testing.T, err error, valid bool) bool {
24 t.Helper()
25 if valid && err == nil {
26 return true
27 }
28 if valid && err != nil {
29 t.Errorf("expected no error, got %v", err)
30 } else if !valid && err == nil {
31 t.Errorf("expected error, got %v", err)
32 }
33 return false
34 }
35 type stackType string
36 const (
37 schedStack stackType = "sched stack"
38 stStack stackType = "state transition stack"
39 )
40 checkStack := func(t *testing.T, got Stack, want Stack, which stackType) {
41 t.Helper()
42 diff := diff.Diff("want", []byte(want.String()), "got", []byte(got.String()))
43 if len(diff) > 0 {
44 t.Errorf("unexpected %s: %s", which, diff)
45 }
46 }
47 stk1 := MakeStack([]StackFrame{
48 {PC: 1, Func: "foo", File: "foo.go", Line: 10},
49 {PC: 2, Func: "bar", File: "bar.go", Line: 20},
50 })
51 stk2 := MakeStack([]StackFrame{
52 {PC: 1, Func: "foo", File: "foo.go", Line: 10},
53 {PC: 2, Func: "bar", File: "bar.go", Line: 20},
54 })
55
56 t.Run("Metric", func(t *testing.T) {
57 tests := []struct {
58 name string
59 metric string
60 val uint64
61 stack Stack
62 valid bool
63 }{
64 {name: "gomaxprocs", metric: "/sched/gomaxprocs:threads", valid: true, val: 1, stack: NoStack},
65 {name: "gomaxprocs with stack", metric: "/sched/gomaxprocs:threads", valid: true, val: 1, stack: stk1},
66 {name: "heap objects", metric: "/memory/classes/heap/objects:bytes", valid: true, val: 2, stack: NoStack},
67 {name: "heap goal", metric: "/gc/heap/goal:bytes", valid: true, val: 3, stack: NoStack},
68 {name: "invalid metric", metric: "/test", valid: false, val: 4, stack: NoStack},
69 }
70 for i, test := range tests {
71 t.Run(test.name, func(t *testing.T) {
72 ev, err := MakeEvent(EventConfig[Metric]{
73 Kind: EventMetric,
74 Time: Time(42 + i),
75 Details: Metric{Name: test.metric, Value: Uint64Value(test.val)},
76 Stack: test.stack,
77 })
78 if !checkValid(t, err, test.valid) {
79 return
80 }
81 checkTime(t, ev, Time(42+i))
82 checkStack(t, ev.Stack(), test.stack, schedStack)
83 got := ev.Metric()
84 if got.Name != test.metric {
85 t.Errorf("expected name to be %q, got %q", test.metric, got.Name)
86 }
87 if got.Value.Uint64() != test.val {
88 t.Errorf("expected value to be %d, got %d", test.val, got.Value.Uint64())
89 }
90 })
91 }
92 })
93
94 t.Run("Label", func(t *testing.T) {
95 ev, err := MakeEvent(EventConfig[Label]{
96 Kind: EventLabel,
97 Time: 42,
98 Details: Label{Label: "test", Resource: MakeResourceID(GoID(23))},
99 })
100 if !checkValid(t, err, true) {
101 return
102 }
103 label := ev.Label()
104 if label.Label != "test" {
105 t.Errorf("expected label to be test, got %q", label.Label)
106 }
107 if label.Resource.Kind != ResourceGoroutine {
108 t.Errorf("expected label resource to be goroutine, got %d", label.Resource.Kind)
109 }
110 if label.Resource.id != 23 {
111 t.Errorf("expected label resource to be 23, got %d", label.Resource.id)
112 }
113 checkTime(t, ev, 42)
114 })
115
116 t.Run("Range", func(t *testing.T) {
117 tests := []struct {
118 kind EventKind
119 name string
120 scope ResourceID
121 valid bool
122 }{
123 {kind: EventRangeBegin, name: "GC concurrent mark phase", scope: ResourceID{}, valid: true},
124 {kind: EventRangeActive, name: "GC concurrent mark phase", scope: ResourceID{}, valid: true},
125 {kind: EventRangeEnd, name: "GC concurrent mark phase", scope: ResourceID{}, valid: true},
126 {kind: EventMetric, name: "GC concurrent mark phase", scope: ResourceID{}, valid: false},
127 {kind: EventRangeBegin, name: "GC concurrent mark phase - INVALID", scope: ResourceID{}, valid: false},
128
129 {kind: EventRangeBegin, name: "GC incremental sweep", scope: MakeResourceID(ProcID(1)), valid: true},
130 {kind: EventRangeActive, name: "GC incremental sweep", scope: MakeResourceID(ProcID(2)), valid: true},
131 {kind: EventRangeEnd, name: "GC incremental sweep", scope: MakeResourceID(ProcID(3)), valid: true},
132 {kind: EventMetric, name: "GC incremental sweep", scope: MakeResourceID(ProcID(4)), valid: false},
133 {kind: EventRangeBegin, name: "GC incremental sweep - INVALID", scope: MakeResourceID(ProcID(5)), valid: false},
134
135 {kind: EventRangeBegin, name: "GC mark assist", scope: MakeResourceID(GoID(1)), valid: true},
136 {kind: EventRangeActive, name: "GC mark assist", scope: MakeResourceID(GoID(2)), valid: true},
137 {kind: EventRangeEnd, name: "GC mark assist", scope: MakeResourceID(GoID(3)), valid: true},
138 {kind: EventMetric, name: "GC mark assist", scope: MakeResourceID(GoID(4)), valid: false},
139 {kind: EventRangeBegin, name: "GC mark assist - INVALID", scope: MakeResourceID(GoID(5)), valid: false},
140
141 {kind: EventRangeBegin, name: "stop-the-world (for a good reason)", scope: MakeResourceID(GoID(1)), valid: true},
142 {kind: EventRangeActive, name: "stop-the-world (for a good reason)", scope: MakeResourceID(GoID(2)), valid: false},
143 {kind: EventRangeEnd, name: "stop-the-world (for a good reason)", scope: MakeResourceID(GoID(3)), valid: true},
144 {kind: EventMetric, name: "stop-the-world (for a good reason)", scope: MakeResourceID(GoID(4)), valid: false},
145 {kind: EventRangeBegin, name: "stop-the-world (for a good reason) - INVALID", scope: MakeResourceID(GoID(5)), valid: false},
146 }
147
148 for i, test := range tests {
149 name := fmt.Sprintf("%s/%s/%s", test.kind, test.name, test.scope)
150 t.Run(name, func(t *testing.T) {
151 ev, err := MakeEvent(EventConfig[Range]{
152 Time: Time(42 + i),
153 Kind: test.kind,
154 Details: Range{Name: test.name, Scope: test.scope},
155 })
156 if !checkValid(t, err, test.valid) {
157 return
158 }
159 got := ev.Range()
160 if got.Name != test.name {
161 t.Errorf("expected name to be %q, got %q", test.name, got.Name)
162 }
163 if ev.Kind() != test.kind {
164 t.Errorf("expected kind to be %s, got %s", test.kind, ev.Kind())
165 }
166 if got.Scope.String() != test.scope.String() {
167 t.Errorf("expected scope to be %s, got %s", test.scope.String(), got.Scope.String())
168 }
169 checkTime(t, ev, Time(42+i))
170 })
171 }
172 })
173
174 t.Run("GoroutineTransition", func(t *testing.T) {
175 const anotherG = 999
176 tests := []struct {
177 name string
178 g GoID
179 stack Stack
180 stG GoID
181 from GoState
182 to GoState
183 reason string
184 stStack Stack
185 valid bool
186 }{
187 {
188 name: "EvGoCreate",
189 g: anotherG,
190 stack: stk1,
191 stG: 1,
192 from: GoNotExist,
193 to: GoRunnable,
194 reason: "",
195 stStack: stk2,
196 valid: true,
197 },
198 {
199 name: "EvGoCreateBlocked",
200 g: anotherG,
201 stack: stk1,
202 stG: 2,
203 from: GoNotExist,
204 to: GoWaiting,
205 reason: "",
206 stStack: stk2,
207 valid: true,
208 },
209 {
210 name: "EvGoCreateSyscall",
211 g: anotherG,
212 stack: NoStack,
213 stG: 3,
214 from: GoNotExist,
215 to: GoSyscall,
216 reason: "",
217 stStack: NoStack,
218 valid: true,
219 },
220 {
221 name: "EvGoStart",
222 g: anotherG,
223 stack: NoStack,
224 stG: 4,
225 from: GoRunnable,
226 to: GoRunning,
227 reason: "",
228 stStack: NoStack,
229 valid: true,
230 },
231 {
232 name: "EvGoDestroy",
233 g: 5,
234 stack: NoStack,
235 stG: 5,
236 from: GoRunning,
237 to: GoNotExist,
238 reason: "",
239 stStack: NoStack,
240 valid: true,
241 },
242 {
243 name: "EvGoDestroySyscall",
244 g: 6,
245 stack: NoStack,
246 stG: 6,
247 from: GoSyscall,
248 to: GoNotExist,
249 reason: "",
250 stStack: NoStack,
251 valid: true,
252 },
253 {
254 name: "EvGoStop",
255 g: 7,
256 stack: stk1,
257 stG: 7,
258 from: GoRunning,
259 to: GoRunnable,
260 reason: "preempted",
261 stStack: stk1,
262 valid: true,
263 },
264 {
265 name: "EvGoBlock",
266 g: 8,
267 stack: stk1,
268 stG: 8,
269 from: GoRunning,
270 to: GoWaiting,
271 reason: "blocked",
272 stStack: stk1,
273 valid: true,
274 },
275 {
276 name: "EvGoUnblock",
277 g: 9,
278 stack: stk1,
279 stG: anotherG,
280 from: GoWaiting,
281 to: GoRunnable,
282 reason: "",
283 stStack: NoStack,
284 valid: true,
285 },
286
287
288
289 {
290 name: "EvGoSyscallBegin",
291 g: 10,
292 stack: stk1,
293 stG: 10,
294 from: GoRunning,
295 to: GoSyscall,
296 reason: "",
297 stStack: stk1,
298 valid: true,
299 },
300 {
301 name: "EvGoSyscallEnd",
302 g: 11,
303 stack: NoStack,
304 stG: 11,
305 from: GoSyscall,
306 to: GoRunning,
307 reason: "",
308 stStack: NoStack,
309 valid: true,
310 },
311 {
312 name: "EvGoSyscallEndBlocked",
313 g: 12,
314 stack: NoStack,
315 stG: 12,
316 from: GoSyscall,
317 to: GoRunnable,
318 reason: "",
319 stStack: NoStack,
320 valid: true,
321 },
322
323 {
324 name: "GoStatus Undetermined->Waiting",
325 g: anotherG,
326 stack: NoStack,
327 stG: 13,
328 from: GoUndetermined,
329 to: GoWaiting,
330 reason: "",
331 stStack: NoStack,
332 valid: true,
333 },
334 {
335 name: "GoStatus Undetermined->Running",
336 g: anotherG,
337 stack: NoStack,
338 stG: 14,
339 from: GoUndetermined,
340 to: GoRunning,
341 reason: "",
342 stStack: NoStack,
343 valid: true,
344 },
345 {
346 name: "GoStatusStack Undetermined->Waiting",
347 g: anotherG,
348 stack: stk1,
349 stG: 15,
350 from: GoUndetermined,
351 to: GoWaiting,
352 reason: "",
353 stStack: stk1,
354 valid: true,
355 },
356 {
357 name: "GoStatusStack Undetermined->Runnable",
358 g: anotherG,
359 stack: stk1,
360 stG: 16,
361 from: GoUndetermined,
362 to: GoRunnable,
363 reason: "",
364 stStack: stk1,
365 valid: true,
366 },
367 {
368 name: "GoStatus Runnable->Runnable",
369 g: anotherG,
370 stack: NoStack,
371 stG: 17,
372 from: GoRunnable,
373 to: GoRunnable,
374 reason: "",
375 stStack: NoStack,
376 valid: true,
377 },
378 {
379 name: "GoStatus Runnable->Running",
380 g: anotherG,
381 stack: NoStack,
382 stG: 18,
383 from: GoRunnable,
384 to: GoRunning,
385 reason: "",
386 stStack: NoStack,
387 valid: true,
388 },
389 {
390 name: "invalid NotExits->NotExists",
391 g: anotherG,
392 stack: stk1,
393 stG: 18,
394 from: GoNotExist,
395 to: GoNotExist,
396 reason: "",
397 stStack: NoStack,
398 valid: false,
399 },
400 {
401 name: "invalid Running->Undetermined",
402 g: anotherG,
403 stack: stk1,
404 stG: 19,
405 from: GoRunning,
406 to: GoUndetermined,
407 reason: "",
408 stStack: NoStack,
409 valid: false,
410 },
411 }
412
413 for i, test := range tests {
414 t.Run(test.name, func(t *testing.T) {
415 st := MakeGoStateTransition(test.stG, test.from, test.to)
416 st.Stack = test.stStack
417 st.Reason = test.reason
418 ev, err := MakeEvent(EventConfig[StateTransition]{
419 Kind: EventStateTransition,
420 Time: Time(42 + i),
421 Goroutine: test.g,
422 Stack: test.stack,
423 Details: st,
424 })
425 if !checkValid(t, err, test.valid) {
426 return
427 }
428 checkStack(t, ev.Stack(), test.stack, schedStack)
429 if ev.Goroutine() != test.g {
430 t.Errorf("expected goroutine to be %d, got %d", test.g, ev.Goroutine())
431 }
432 got := ev.StateTransition()
433 if got.Resource.Goroutine() != test.stG {
434 t.Errorf("expected resource to be %d, got %d", test.stG, got.Resource.Goroutine())
435 }
436 from, to := got.Goroutine()
437 if from != test.from {
438 t.Errorf("from got=%s want=%s", from, test.from)
439 }
440 if to != test.to {
441 t.Errorf("to got=%s want=%s", to, test.to)
442 }
443 if got.Reason != test.reason {
444 t.Errorf("expected reason to be %s, got %s", test.reason, got.Reason)
445 }
446 checkStack(t, got.Stack, test.stStack, stStack)
447 checkTime(t, ev, Time(42+i))
448 })
449 }
450 })
451
452 t.Run("ProcTransition", func(t *testing.T) {
453 tests := []struct {
454 name string
455 proc ProcID
456 schedProc ProcID
457 from ProcState
458 to ProcState
459 valid bool
460 }{
461 {name: "ProcStart", proc: 1, schedProc: 99, from: ProcIdle, to: ProcRunning, valid: true},
462 {name: "ProcStop", proc: 2, schedProc: 2, from: ProcRunning, to: ProcIdle, valid: true},
463 {name: "ProcSteal", proc: 3, schedProc: 99, from: ProcRunning, to: ProcIdle, valid: true},
464 {name: "ProcSteal lost info", proc: 4, schedProc: 99, from: ProcIdle, to: ProcIdle, valid: true},
465 {name: "ProcStatus", proc: 5, schedProc: 99, from: ProcUndetermined, to: ProcRunning, valid: true},
466 }
467 for i, test := range tests {
468 t.Run(test.name, func(t *testing.T) {
469 st := MakeProcStateTransition(test.proc, test.from, test.to)
470 ev, err := MakeEvent(EventConfig[StateTransition]{
471 Kind: EventStateTransition,
472 Time: Time(42 + i),
473 Proc: test.schedProc,
474 Details: st,
475 })
476 if !checkValid(t, err, test.valid) {
477 return
478 }
479 checkTime(t, ev, Time(42+i))
480 gotSt := ev.StateTransition()
481 from, to := gotSt.Proc()
482 if from != test.from {
483 t.Errorf("from got=%s want=%s", from, test.from)
484 }
485 if to != test.to {
486 t.Errorf("to got=%s want=%s", to, test.to)
487 }
488 if ev.Proc() != test.schedProc {
489 t.Errorf("expected proc to be %d, got %d", test.schedProc, ev.Proc())
490 }
491 if gotSt.Resource.Proc() != test.proc {
492 t.Errorf("expected resource to be %d, got %d", test.proc, gotSt.Resource.Proc())
493 }
494 })
495 }
496 })
497
498 t.Run("Sync", func(t *testing.T) {
499 tests := []struct {
500 name string
501 kind EventKind
502 n int
503 clock *ClockSnapshot
504 batches map[string][]ExperimentalBatch
505 valid bool
506 }{
507 {
508 name: "invalid kind",
509 n: 1,
510 valid: false,
511 },
512 {
513 name: "N",
514 kind: EventSync,
515 n: 1,
516 batches: map[string][]ExperimentalBatch{},
517 valid: true,
518 },
519 {
520 name: "N+ClockSnapshot",
521 kind: EventSync,
522 n: 1,
523 batches: map[string][]ExperimentalBatch{},
524 clock: &ClockSnapshot{
525 Trace: 1,
526 Wall: time.Unix(59, 123456789),
527 Mono: 2,
528 },
529 valid: true,
530 },
531 {
532 name: "N+Batches",
533 kind: EventSync,
534 n: 1,
535 batches: map[string][]ExperimentalBatch{
536 "AllocFree": {{Thread: 1, Data: []byte{1, 2, 3}}},
537 },
538 valid: true,
539 },
540 {
541 name: "unknown experiment",
542 kind: EventSync,
543 n: 1,
544 batches: map[string][]ExperimentalBatch{
545 "does-not-exist": {{Thread: 1, Data: []byte{1, 2, 3}}},
546 },
547 valid: false,
548 },
549 }
550 for i, test := range tests {
551 t.Run(test.name, func(t *testing.T) {
552 ev, err := MakeEvent(EventConfig[Sync]{
553 Kind: test.kind,
554 Time: Time(42 + i),
555 Details: Sync{N: test.n, ClockSnapshot: test.clock, ExperimentalBatches: test.batches},
556 })
557 if !checkValid(t, err, test.valid) {
558 return
559 }
560 got := ev.Sync()
561 checkTime(t, ev, Time(42+i))
562 if got.N != test.n {
563 t.Errorf("expected N to be %d, got %d", test.n, got.N)
564 }
565 if test.clock != nil && got.ClockSnapshot == nil {
566 t.Fatalf("expected ClockSnapshot to be non-nil")
567 } else if test.clock == nil && got.ClockSnapshot != nil {
568 t.Fatalf("expected ClockSnapshot to be nil")
569 } else if test.clock != nil && got.ClockSnapshot != nil {
570 if got.ClockSnapshot.Trace != test.clock.Trace {
571 t.Errorf("expected ClockSnapshot.Trace to be %d, got %d", test.clock.Trace, got.ClockSnapshot.Trace)
572 }
573 if !got.ClockSnapshot.Wall.Equal(test.clock.Wall) {
574 t.Errorf("expected ClockSnapshot.Wall to be %s, got %s", test.clock.Wall, got.ClockSnapshot.Wall)
575 }
576 if got.ClockSnapshot.Mono != test.clock.Mono {
577 t.Errorf("expected ClockSnapshot.Mono to be %d, got %d", test.clock.Mono, got.ClockSnapshot.Mono)
578 }
579 }
580 if !reflect.DeepEqual(got.ExperimentalBatches, test.batches) {
581 t.Errorf("expected ExperimentalBatches to be %#v, got %#v", test.batches, got.ExperimentalBatches)
582 }
583 })
584 }
585 })
586
587 t.Run("Task", func(t *testing.T) {
588 tests := []struct {
589 name string
590 kind EventKind
591 id TaskID
592 parent TaskID
593 typ string
594 valid bool
595 }{
596 {name: "no task", kind: EventTaskBegin, id: NoTask, parent: 1, typ: "type-0", valid: false},
597 {name: "invalid kind", kind: EventMetric, id: 1, parent: 2, typ: "type-1", valid: false},
598 {name: "EvUserTaskBegin", kind: EventTaskBegin, id: 2, parent: 3, typ: "type-2", valid: true},
599 {name: "EvUserTaskEnd", kind: EventTaskEnd, id: 3, parent: 4, typ: "type-3", valid: true},
600 {name: "no parent", kind: EventTaskBegin, id: 4, parent: NoTask, typ: "type-4", valid: true},
601 }
602
603 for i, test := range tests {
604 t.Run(test.name, func(t *testing.T) {
605 ev, err := MakeEvent(EventConfig[Task]{
606 Kind: test.kind,
607 Time: Time(42 + i),
608 Details: Task{ID: test.id, Parent: test.parent, Type: test.typ},
609 })
610 if !checkValid(t, err, test.valid) {
611 return
612 }
613 checkTime(t, ev, Time(42+i))
614 got := ev.Task()
615 if got.ID != test.id {
616 t.Errorf("expected ID to be %d, got %d", test.id, got.ID)
617 }
618 if got.Parent != test.parent {
619 t.Errorf("expected Parent to be %d, got %d", test.parent, got.Parent)
620 }
621 if got.Type != test.typ {
622 t.Errorf("expected Type to be %s, got %s", test.typ, got.Type)
623 }
624 })
625 }
626 })
627
628 t.Run("Region", func(t *testing.T) {
629 tests := []struct {
630 name string
631 kind EventKind
632 task TaskID
633 typ string
634 valid bool
635 }{
636 {name: "invalid kind", kind: EventMetric, task: 1, typ: "type-1", valid: false},
637 {name: "EvUserRegionBegin", kind: EventRegionBegin, task: 2, typ: "type-2", valid: true},
638 {name: "EvUserRegionEnd", kind: EventRegionEnd, task: 3, typ: "type-3", valid: true},
639 }
640
641 for i, test := range tests {
642 t.Run(test.name, func(t *testing.T) {
643 ev, err := MakeEvent(EventConfig[Region]{
644 Kind: test.kind,
645 Time: Time(42 + i),
646 Details: Region{Task: test.task, Type: test.typ},
647 })
648 if !checkValid(t, err, test.valid) {
649 return
650 }
651 checkTime(t, ev, Time(42+i))
652 got := ev.Region()
653 if got.Task != test.task {
654 t.Errorf("expected Task to be %d, got %d", test.task, got.Task)
655 }
656 if got.Type != test.typ {
657 t.Errorf("expected Type to be %s, got %s", test.typ, got.Type)
658 }
659 })
660 }
661 })
662
663 t.Run("Log", func(t *testing.T) {
664 tests := []struct {
665 name string
666 kind EventKind
667 task TaskID
668 category string
669 message string
670 valid bool
671 }{
672 {name: "invalid kind", kind: EventMetric, task: 1, category: "category-1", message: "message-1", valid: false},
673 {name: "basic", kind: EventLog, task: 2, category: "category-2", message: "message-2", valid: true},
674 }
675
676 for i, test := range tests {
677 t.Run(test.name, func(t *testing.T) {
678 ev, err := MakeEvent(EventConfig[Log]{
679 Kind: test.kind,
680 Time: Time(42 + i),
681 Details: Log{Task: test.task, Category: test.category, Message: test.message},
682 })
683 if !checkValid(t, err, test.valid) {
684 return
685 }
686 checkTime(t, ev, Time(42+i))
687 got := ev.Log()
688 if got.Task != test.task {
689 t.Errorf("expected Task to be %d, got %d", test.task, got.Task)
690 }
691 if got.Category != test.category {
692 t.Errorf("expected Category to be %s, got %s", test.category, got.Category)
693 }
694 if got.Message != test.message {
695 t.Errorf("expected Message to be %s, got %s", test.message, got.Message)
696 }
697 })
698 }
699
700 })
701
702 t.Run("StackSample", func(t *testing.T) {
703 tests := []struct {
704 name string
705 kind EventKind
706 stack Stack
707 valid bool
708 }{
709 {name: "invalid kind", kind: EventMetric, stack: stk1, valid: false},
710 {name: "basic", kind: EventStackSample, stack: stk1, valid: true},
711 }
712
713 for i, test := range tests {
714 t.Run(test.name, func(t *testing.T) {
715 ev, err := MakeEvent(EventConfig[StackSample]{
716 Kind: test.kind,
717 Time: Time(42 + i),
718 Stack: test.stack,
719
720
721 })
722 if !checkValid(t, err, test.valid) {
723 return
724 }
725 checkTime(t, ev, Time(42+i))
726 got := ev.Stack()
727 checkStack(t, got, test.stack, schedStack)
728 })
729 }
730
731 })
732 }
733
734 func TestMakeStack(t *testing.T) {
735 frames := []StackFrame{
736 {PC: 1, Func: "foo", File: "foo.go", Line: 10},
737 {PC: 2, Func: "bar", File: "bar.go", Line: 20},
738 }
739 got := slices.Collect(MakeStack(frames).Frames())
740 if len(got) != len(frames) {
741 t.Errorf("got=%d want=%d", len(got), len(frames))
742 }
743 for i := range got {
744 if got[i] != frames[i] {
745 t.Errorf("got=%v want=%v", got[i], frames[i])
746 }
747 }
748 }
749
750 func TestPanicEvent(t *testing.T) {
751
752 ev := syncEvent(nil, 0, 0)
753
754 mustPanic(t, func() {
755 _ = ev.Range()
756 })
757 mustPanic(t, func() {
758 _ = ev.Metric()
759 })
760 mustPanic(t, func() {
761 _ = ev.Log()
762 })
763 mustPanic(t, func() {
764 _ = ev.Task()
765 })
766 mustPanic(t, func() {
767 _ = ev.Region()
768 })
769 mustPanic(t, func() {
770 _ = ev.Label()
771 })
772 mustPanic(t, func() {
773 _ = ev.RangeAttributes()
774 })
775 }
776
777 func mustPanic(t *testing.T, f func()) {
778 defer func() {
779 if r := recover(); r == nil {
780 t.Fatal("failed to panic")
781 }
782 }()
783 f()
784 }
785
View as plain text