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

View as plain text