Source file src/runtime/trace/subscribe_test.go

     1  // Copyright 2025 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package trace_test
     6  
     7  import (
     8  	"bytes"
     9  	inttrace "internal/trace"
    10  	"internal/trace/testtrace"
    11  	"io"
    12  	"runtime"
    13  	"runtime/trace"
    14  	"slices"
    15  	"testing"
    16  )
    17  
    18  func TestSubscribers(t *testing.T) {
    19  	validate := func(t *testing.T, source string, tr []byte) {
    20  		t.Log("validating", source)
    21  		defer func() {
    22  			if t.Failed() {
    23  				testtrace.Dump(t, "TestSubscribers."+source, tr, *dumpTraces)
    24  			}
    25  		}()
    26  
    27  		// Prepare to read the trace snapshot.
    28  		r, err := inttrace.NewReader(bytes.NewReader(tr))
    29  		if err != nil {
    30  			t.Errorf("unexpected error creating trace reader for %s: %v", source, err)
    31  			return
    32  		}
    33  
    34  		v := testtrace.NewValidator()
    35  		// These platforms can't guarantee a monotonically increasing clock reading in a short trace.
    36  		if runtime.GOOS == "windows" || runtime.GOARCH == "wasm" {
    37  			v.SkipClockSnapshotChecks()
    38  		}
    39  		// Make sure there are Sync events: at the start and end.
    40  		var syncs []int
    41  		evs := 0
    42  		for {
    43  			ev, err := r.ReadEvent()
    44  			if err == io.EOF {
    45  				break
    46  			}
    47  			if err != nil {
    48  				t.Errorf("unexpected error reading trace for %s: %v", source, err)
    49  				break
    50  			}
    51  			if err := v.Event(ev); err != nil {
    52  				t.Errorf("event validation failed: %s", err)
    53  				break
    54  			}
    55  			if ev.Kind() == inttrace.EventSync {
    56  				syncs = append(syncs, evs)
    57  			}
    58  			evs++
    59  		}
    60  		if !t.Failed() {
    61  			ends := []int{syncs[0], syncs[len(syncs)-1]}
    62  			if wantEnds := []int{0, evs - 1}; !slices.Equal(wantEnds, ends) {
    63  				t.Errorf("expected a sync event at each end of the trace, found sync events at %d instead of %d for %s",
    64  					ends, wantEnds, source)
    65  			}
    66  		}
    67  	}
    68  
    69  	validateTraces := func(t *testing.T, trace, frTrace *bytes.Buffer) {
    70  		validate(t, "tracer", trace.Bytes())
    71  		validate(t, "flightRecorder", frTrace.Bytes())
    72  	}
    73  	startFlightRecorder := func(t *testing.T) *trace.FlightRecorder {
    74  		fr := trace.NewFlightRecorder(trace.FlightRecorderConfig{})
    75  		if err := fr.Start(); err != nil {
    76  			t.Fatalf("unexpected error creating flight recorder: %v", err)
    77  		}
    78  		return fr
    79  	}
    80  	startTrace := func(t *testing.T, w io.Writer) {
    81  		if err := trace.Start(w); err != nil {
    82  			t.Fatalf("unexpected error starting flight recorder: %v", err)
    83  		}
    84  	}
    85  	stopFlightRecorder := func(t *testing.T, fr *trace.FlightRecorder, w io.Writer) {
    86  		if _, err := fr.WriteTo(w); err != nil {
    87  			t.Fatalf("unexpected error writing trace from flight recorder: %v", err)
    88  		}
    89  		fr.Stop()
    90  	}
    91  	stopTrace := func() {
    92  		trace.Stop()
    93  	}
    94  	t.Run("start(flight)_start(trace)_stop(trace)_stop(flight)", func(t *testing.T) {
    95  		if trace.IsEnabled() {
    96  			t.Skip("skipping because trace is already enabled")
    97  		}
    98  		frBuf := new(bytes.Buffer)
    99  		tBuf := new(bytes.Buffer)
   100  		fr := startFlightRecorder(t)
   101  		defer fr.Stop()
   102  		startTrace(t, tBuf)
   103  		defer trace.Stop()
   104  		stopTrace()
   105  		stopFlightRecorder(t, fr, frBuf)
   106  		validateTraces(t, tBuf, frBuf)
   107  	})
   108  	t.Run("start(trace)_start(flight)_stop(trace)_stop(flight)", func(t *testing.T) {
   109  		if trace.IsEnabled() {
   110  			t.Skip("skipping because trace is already enabled")
   111  		}
   112  		frBuf := new(bytes.Buffer)
   113  		tBuf := new(bytes.Buffer)
   114  		startTrace(t, tBuf)
   115  		defer trace.Stop()
   116  		fr := startFlightRecorder(t)
   117  		defer fr.Stop()
   118  		stopTrace()
   119  		stopFlightRecorder(t, fr, frBuf)
   120  		validateTraces(t, tBuf, frBuf)
   121  	})
   122  	t.Run("start(flight)_stop(flight)_start(trace)_stop(trace)", func(t *testing.T) {
   123  		if trace.IsEnabled() {
   124  			t.Skip("skipping because trace is already enabled")
   125  		}
   126  		frBuf := new(bytes.Buffer)
   127  		tBuf := new(bytes.Buffer)
   128  		fr := startFlightRecorder(t)
   129  		defer fr.Stop()
   130  		stopFlightRecorder(t, fr, frBuf)
   131  		startTrace(t, tBuf)
   132  		defer trace.Stop()
   133  		stopTrace()
   134  		validateTraces(t, tBuf, frBuf)
   135  	})
   136  	t.Run("start(flight)_stop(flight)_start(trace)_stop(trace)", func(t *testing.T) {
   137  		if trace.IsEnabled() {
   138  			t.Skip("skipping because trace is already enabled")
   139  		}
   140  		frBuf := new(bytes.Buffer)
   141  		tBuf := new(bytes.Buffer)
   142  		fr := startFlightRecorder(t)
   143  		defer fr.Stop()
   144  		stopFlightRecorder(t, fr, frBuf)
   145  		startTrace(t, tBuf)
   146  		defer trace.Stop()
   147  		stopTrace()
   148  		validateTraces(t, tBuf, frBuf)
   149  	})
   150  	t.Run("start(flight)_start(trace)_stop(flight)_stop(trace)", func(t *testing.T) {
   151  		if trace.IsEnabled() {
   152  			t.Skip("skipping because trace is already enabled")
   153  		}
   154  		frBuf := new(bytes.Buffer)
   155  		tBuf := new(bytes.Buffer)
   156  		fr := startFlightRecorder(t)
   157  		defer fr.Stop()
   158  		startTrace(t, tBuf)
   159  		defer trace.Stop()
   160  		stopFlightRecorder(t, fr, frBuf)
   161  		stopTrace()
   162  		validateTraces(t, tBuf, frBuf)
   163  	})
   164  }
   165  

View as plain text