1// Copyright 2015 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 trace
6
7import (
8	"bytes"
9	"io/ioutil"
10	"path/filepath"
11	"strings"
12	"testing"
13)
14
15func TestCorruptedInputs(t *testing.T) {
16	// These inputs crashed parser previously.
17	tests := []string{
18		"gotrace\x00\x020",
19		"gotrace\x00Q00\x020",
20		"gotrace\x00T00\x020",
21		"gotrace\x00\xc3\x0200",
22		"go 1.5 trace\x00\x00\x00\x00\x020",
23		"go 1.5 trace\x00\x00\x00\x00Q00\x020",
24		"go 1.5 trace\x00\x00\x00\x00T00\x020",
25		"go 1.5 trace\x00\x00\x00\x00\xc3\x0200",
26	}
27	for _, data := range tests {
28		res, err := Parse(strings.NewReader(data), "")
29		if err == nil || res.Events != nil || res.Stacks != nil {
30			t.Fatalf("no error on input: %q", data)
31		}
32	}
33}
34
35func TestParseCanned(t *testing.T) {
36	files, err := ioutil.ReadDir("./testdata")
37	if err != nil {
38		t.Fatalf("failed to read ./testdata: %v", err)
39	}
40	for _, f := range files {
41		data, err := ioutil.ReadFile(filepath.Join("./testdata", f.Name()))
42		if err != nil {
43			t.Fatalf("failed to read input file: %v", err)
44		}
45		// Instead of Parse that requires a proper binary name for old traces,
46		// we use 'parse' that omits symbol lookup if an empty string is given.
47		_, _, err = parse(bytes.NewReader(data), "")
48		switch {
49		case strings.HasSuffix(f.Name(), "_good"):
50			if err != nil {
51				t.Errorf("failed to parse good trace %v: %v", f.Name(), err)
52			}
53		case strings.HasSuffix(f.Name(), "_unordered"):
54			if err != ErrTimeOrder {
55				t.Errorf("unordered trace is not detected %v: %v", f.Name(), err)
56			}
57		default:
58			t.Errorf("unknown input file suffix: %v", f.Name())
59		}
60	}
61}
62
63func TestParseVersion(t *testing.T) {
64	tests := map[string]int{
65		"go 1.5 trace\x00\x00\x00\x00": 1005,
66		"go 1.7 trace\x00\x00\x00\x00": 1007,
67		"go 1.10 trace\x00\x00\x00":    1010,
68		"go 1.25 trace\x00\x00\x00":    1025,
69		"go 1.234 trace\x00\x00":       1234,
70		"go 1.2345 trace\x00":          -1,
71		"go 0.0 trace\x00\x00\x00\x00": -1,
72		"go a.b trace\x00\x00\x00\x00": -1,
73	}
74	for header, ver := range tests {
75		ver1, err := parseHeader([]byte(header))
76		if ver == -1 {
77			if err == nil {
78				t.Fatalf("no error on input: %q, version %v", header, ver1)
79			}
80		} else {
81			if err != nil {
82				t.Fatalf("failed to parse: %q (%v)", header, err)
83			}
84			if ver != ver1 {
85				t.Fatalf("wrong version: %v, want %v, input: %q", ver1, ver, header)
86			}
87		}
88	}
89}
90
91func TestTimestampOverflow(t *testing.T) {
92	// Test that parser correctly handles large timestamps (long tracing).
93	w := NewWriter()
94	w.Emit(EvBatch, 0, 0)
95	w.Emit(EvFrequency, 1e9)
96	for ts := uint64(1); ts < 1e16; ts *= 2 {
97		w.Emit(EvGoCreate, ts, ts, 0, 0)
98	}
99	if _, err := Parse(w, ""); err != nil {
100		t.Fatalf("failed to parse: %v", err)
101	}
102}
103