Source file src/runtime/time_test.go

     1  // Copyright 2019 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 runtime_test
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/binary"
    10  	"errors"
    11  	"internal/testenv"
    12  	"os/exec"
    13  	"reflect"
    14  	"runtime"
    15  	"testing"
    16  	"time"
    17  )
    18  
    19  func TestFakeTime(t *testing.T) {
    20  	if runtime.GOOS == "windows" {
    21  		t.Skip("faketime not supported on windows")
    22  	}
    23  
    24  	// Faketime is advanced in checkdead. External linking brings in cgo,
    25  	// causing checkdead not working.
    26  	testenv.MustInternalLink(t, false)
    27  
    28  	t.Parallel()
    29  
    30  	exe, err := buildTestProg(t, "testfaketime", "-tags=faketime")
    31  	if err != nil {
    32  		t.Fatal(err)
    33  	}
    34  
    35  	var stdout, stderr bytes.Buffer
    36  	cmd := exec.Command(exe)
    37  	cmd.Stdout = &stdout
    38  	cmd.Stderr = &stderr
    39  
    40  	err = testenv.CleanCmdEnv(cmd).Run()
    41  	if err != nil {
    42  		t.Fatalf("exit status: %v\n%s", err, stderr.String())
    43  	}
    44  
    45  	t.Logf("raw stdout: %q", stdout.String())
    46  	t.Logf("raw stderr: %q", stderr.String())
    47  
    48  	f1, err1 := parseFakeTime(stdout.Bytes())
    49  	if err1 != nil {
    50  		t.Fatal(err1)
    51  	}
    52  	f2, err2 := parseFakeTime(stderr.Bytes())
    53  	if err2 != nil {
    54  		t.Fatal(err2)
    55  	}
    56  
    57  	const time0 = 1257894000000000000
    58  	got := [][]fakeTimeFrame{f1, f2}
    59  	var want = [][]fakeTimeFrame{{
    60  		{time0 + 1, "line 2\n"},
    61  		{time0 + 1, "line 3\n"},
    62  		{time0 + 1e9, "line 5\n"},
    63  		{time0 + 1e9, "2009-11-10T23:00:01Z"},
    64  	}, {
    65  		{time0, "line 1\n"},
    66  		{time0 + 2, "line 4\n"},
    67  	}}
    68  	if !reflect.DeepEqual(want, got) {
    69  		t.Fatalf("want %v, got %v", want, got)
    70  	}
    71  }
    72  
    73  type fakeTimeFrame struct {
    74  	time uint64
    75  	data string
    76  }
    77  
    78  func parseFakeTime(x []byte) ([]fakeTimeFrame, error) {
    79  	var frames []fakeTimeFrame
    80  	for len(x) != 0 {
    81  		if len(x) < 4+8+4 {
    82  			return nil, errors.New("truncated header")
    83  		}
    84  		const magic = "\x00\x00PB"
    85  		if string(x[:len(magic)]) != magic {
    86  			return nil, errors.New("bad magic")
    87  		}
    88  		x = x[len(magic):]
    89  		time := binary.BigEndian.Uint64(x)
    90  		x = x[8:]
    91  		dlen := binary.BigEndian.Uint32(x)
    92  		x = x[4:]
    93  		data := string(x[:dlen])
    94  		x = x[dlen:]
    95  		frames = append(frames, fakeTimeFrame{time, data})
    96  	}
    97  	return frames, nil
    98  }
    99  
   100  func TestTimeTimerType(t *testing.T) {
   101  	// runtime.timeTimer (exported for testing as TimeTimer)
   102  	// must have time.Timer and time.Ticker as a prefix
   103  	// (meaning those two must have the same layout).
   104  	runtimeTimeTimer := reflect.TypeOf(runtime.TimeTimer{})
   105  
   106  	check := func(name string, typ reflect.Type) {
   107  		n1 := runtimeTimeTimer.NumField()
   108  		n2 := typ.NumField()
   109  		if n1 != n2+1 {
   110  			t.Errorf("runtime.TimeTimer has %d fields, want %d (%s has %d fields)", n1, n2+1, name, n2)
   111  			return
   112  		}
   113  		for i := 0; i < n2; i++ {
   114  			f1 := runtimeTimeTimer.Field(i)
   115  			f2 := typ.Field(i)
   116  			t1 := f1.Type
   117  			t2 := f2.Type
   118  			if t1 != t2 && !(t1.Kind() == reflect.UnsafePointer && t2.Kind() == reflect.Chan) {
   119  				t.Errorf("runtime.Timer field %s %v incompatible with %s field %s %v", f1.Name, t1, name, f2.Name, t2)
   120  			}
   121  			if f1.Offset != f2.Offset {
   122  				t.Errorf("runtime.Timer field %s offset %d incompatible with %s field %s offset %d", f1.Name, f1.Offset, name, f2.Name, f2.Offset)
   123  			}
   124  		}
   125  	}
   126  
   127  	check("time.Timer", reflect.TypeOf(time.Timer{}))
   128  	check("time.Ticker", reflect.TypeOf(time.Ticker{}))
   129  }
   130  

View as plain text