Source file src/internal/godebug/godebug_test.go

     1  // Copyright 2021 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 godebug_test
     6  
     7  import (
     8  	"fmt"
     9  	. "internal/godebug"
    10  	"internal/race"
    11  	"internal/testenv"
    12  	"os"
    13  	"os/exec"
    14  	"runtime/metrics"
    15  	"slices"
    16  	"strings"
    17  	"testing"
    18  )
    19  
    20  func TestGet(t *testing.T) {
    21  	foo := New("#foo")
    22  	tests := []struct {
    23  		godebug string
    24  		setting *Setting
    25  		want    string
    26  	}{
    27  		{"", New("#"), ""},
    28  		{"", foo, ""},
    29  		{"foo=bar", foo, "bar"},
    30  		{"foo=bar,after=x", foo, "bar"},
    31  		{"before=x,foo=bar,after=x", foo, "bar"},
    32  		{"before=x,foo=bar", foo, "bar"},
    33  		{",,,foo=bar,,,", foo, "bar"},
    34  		{"foodecoy=wrong,foo=bar", foo, "bar"},
    35  		{"foo=", foo, ""},
    36  		{"foo", foo, ""},
    37  		{",foo", foo, ""},
    38  		{"foo=bar,baz", New("#loooooooong"), ""},
    39  	}
    40  	for _, tt := range tests {
    41  		t.Setenv("GODEBUG", tt.godebug)
    42  		got := tt.setting.Value()
    43  		if got != tt.want {
    44  			t.Errorf("get(%q, %q) = %q; want %q", tt.godebug, tt.setting.Name(), got, tt.want)
    45  		}
    46  	}
    47  }
    48  
    49  func TestMetrics(t *testing.T) {
    50  	const name = "http2client" // must be a real name so runtime will accept it
    51  
    52  	var m [1]metrics.Sample
    53  	m[0].Name = "/godebug/non-default-behavior/" + name + ":events"
    54  	metrics.Read(m[:])
    55  	if kind := m[0].Value.Kind(); kind != metrics.KindUint64 {
    56  		t.Fatalf("NonDefault kind = %v, want uint64", kind)
    57  	}
    58  
    59  	s := New(name)
    60  	s.Value()
    61  	s.IncNonDefault()
    62  	s.IncNonDefault()
    63  	s.IncNonDefault()
    64  	metrics.Read(m[:])
    65  	if kind := m[0].Value.Kind(); kind != metrics.KindUint64 {
    66  		t.Fatalf("NonDefault kind = %v, want uint64", kind)
    67  	}
    68  	if count := m[0].Value.Uint64(); count != 3 {
    69  		t.Fatalf("NonDefault value = %d, want 3", count)
    70  	}
    71  }
    72  
    73  // TestPanicNilRace checks for a race in the runtime caused by use of runtime
    74  // atomics (not visible to usual race detection) to install the counter for
    75  // non-default panic(nil) semantics.  For #64649.
    76  func TestPanicNilRace(t *testing.T) {
    77  	if !race.Enabled {
    78  		t.Skip("Skipping test intended for use with -race.")
    79  	}
    80  	if os.Getenv("GODEBUG") != "panicnil=1" {
    81  		cmd := testenv.CleanCmdEnv(testenv.Command(t, os.Args[0], "-test.run=^TestPanicNilRace$", "-test.v", "-test.parallel=2", "-test.count=1"))
    82  		cmd.Env = append(cmd.Env, "GODEBUG=panicnil=1")
    83  		out, err := cmd.CombinedOutput()
    84  		t.Logf("output:\n%s", out)
    85  
    86  		if err != nil {
    87  			t.Errorf("Was not expecting a crash")
    88  		}
    89  		return
    90  	}
    91  
    92  	test := func(t *testing.T) {
    93  		t.Parallel()
    94  		defer func() {
    95  			recover()
    96  		}()
    97  		panic(nil)
    98  	}
    99  	t.Run("One", test)
   100  	t.Run("Two", test)
   101  }
   102  
   103  func TestCmdBisect(t *testing.T) {
   104  	testenv.MustHaveGoBuild(t)
   105  	out, err := exec.Command("go", "run", "cmd/vendor/golang.org/x/tools/cmd/bisect", "GODEBUG=buggy=1#PATTERN", os.Args[0], "-test.run=^TestBisectTestCase$").CombinedOutput()
   106  	if err != nil {
   107  		t.Fatalf("exec bisect: %v\n%s", err, out)
   108  	}
   109  
   110  	var want []string
   111  	src, err := os.ReadFile("godebug_test.go")
   112  	for i, line := range strings.Split(string(src), "\n") {
   113  		if strings.Contains(line, "BISECT"+" "+"BUG") {
   114  			want = append(want, fmt.Sprintf("godebug_test.go:%d", i+1))
   115  		}
   116  	}
   117  	slices.Sort(want)
   118  
   119  	var have []string
   120  	for _, line := range strings.Split(string(out), "\n") {
   121  		if strings.Contains(line, "godebug_test.go:") {
   122  			have = append(have, line[strings.LastIndex(line, "godebug_test.go:"):])
   123  		}
   124  	}
   125  	slices.Sort(have)
   126  
   127  	if !slices.Equal(have, want) {
   128  		t.Errorf("bad bisect output:\nhave %v\nwant %v\ncomplete output:\n%s", have, want, string(out))
   129  	}
   130  }
   131  
   132  // This test does nothing by itself, but you can run
   133  //
   134  //	bisect 'GODEBUG=buggy=1#PATTERN' go test -run='^TestBisectTestCase$'
   135  //
   136  // to see that the GODEBUG bisect support is working.
   137  // TestCmdBisect above does exactly that.
   138  func TestBisectTestCase(t *testing.T) {
   139  	s := New("#buggy")
   140  	for i := 0; i < 10; i++ {
   141  		a := s.Value() == "1"
   142  		b := s.Value() == "1"
   143  		c := s.Value() == "1" // BISECT BUG
   144  		d := s.Value() == "1" // BISECT BUG
   145  		e := s.Value() == "1" // BISECT BUG
   146  
   147  		if a {
   148  			t.Log("ok")
   149  		}
   150  		if b {
   151  			t.Log("ok")
   152  		}
   153  		if c {
   154  			t.Error("bug")
   155  		}
   156  		if d &&
   157  			e {
   158  			t.Error("bug")
   159  		}
   160  	}
   161  }
   162  

View as plain text