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
5package runtime_test
6
7import (
8	"bytes"
9	"encoding/binary"
10	"errors"
11	"internal/testenv"
12	"os/exec"
13	"reflect"
14	"runtime"
15	"testing"
16)
17
18func TestFakeTime(t *testing.T) {
19	if runtime.GOOS == "windows" {
20		t.Skip("faketime not supported on windows")
21	}
22	if runtime.Compiler == "gccgo" {
23		t.Skip("faketime not supported for gccgo")
24	}
25
26	t.Parallel()
27
28	exe, err := buildTestProg(t, "testfaketime", "-tags=faketime")
29	if err != nil {
30		t.Fatal(err)
31	}
32
33	var stdout, stderr bytes.Buffer
34	cmd := exec.Command(exe)
35	cmd.Stdout = &stdout
36	cmd.Stderr = &stderr
37
38	err = testenv.CleanCmdEnv(cmd).Run()
39	if err != nil {
40		t.Fatalf("exit status: %v\n%s", err, stderr.String())
41	}
42
43	t.Logf("raw stdout: %q", stdout.String())
44	t.Logf("raw stderr: %q", stdout.String())
45
46	f1, err1 := parseFakeTime(stdout.Bytes())
47	if err1 != nil {
48		t.Fatal(err1)
49	}
50	f2, err2 := parseFakeTime(stderr.Bytes())
51	if err2 != nil {
52		t.Fatal(err2)
53	}
54
55	const time0 = 1257894000000000000
56	got := [][]fakeTimeFrame{f1, f2}
57	var want = [][]fakeTimeFrame{{
58		{time0 + 1, "line 2\n"},
59		{time0 + 1, "line 3\n"},
60		{time0 + 1e9, "line 5\n"},
61		{time0 + 1e9, "2009-11-10T23:00:01Z"},
62	}, {
63		{time0, "line 1\n"},
64		{time0 + 2, "line 4\n"},
65	}}
66	if !reflect.DeepEqual(want, got) {
67		t.Fatalf("want %v, got %v", want, got)
68	}
69}
70
71type fakeTimeFrame struct {
72	time uint64
73	data string
74}
75
76func parseFakeTime(x []byte) ([]fakeTimeFrame, error) {
77	var frames []fakeTimeFrame
78	for len(x) != 0 {
79		if len(x) < 4+8+4 {
80			return nil, errors.New("truncated header")
81		}
82		const magic = "\x00\x00PB"
83		if string(x[:len(magic)]) != magic {
84			return nil, errors.New("bad magic")
85		}
86		x = x[len(magic):]
87		time := binary.BigEndian.Uint64(x)
88		x = x[8:]
89		dlen := binary.BigEndian.Uint32(x)
90		x = x[4:]
91		data := string(x[:dlen])
92		x = x[dlen:]
93		frames = append(frames, fakeTimeFrame{time, data})
94	}
95	return frames, nil
96}
97