15 type checkFn func(t *testing.T, stdout, stderr []byte, err error)
17 func TestProfile(t *testing.T) {
18 f, err := ioutil.TempFile("", "profile_test")
22 defer os.Remove(f.Name())
24 var profileTests = []struct {
29 name: "default profile (cpu)",
33 import "github.com/pkg/profile"
36 defer profile.Start().Stop()
41 Stderr("profile: cpu profiling enabled"),
45 name: "memory profile",
49 import "github.com/pkg/profile"
52 defer profile.Start(profile.MemProfile).Stop()
57 Stderr("profile: memory profiling enabled"),
61 name: "memory profile (rate 2048)",
65 import "github.com/pkg/profile"
68 defer profile.Start(profile.MemProfileRate(2048)).Stop()
73 Stderr("profile: memory profiling enabled (rate 2048)"),
81 import "github.com/pkg/profile"
90 Stderr("cpu profiling enabled", "profile: Start() already called"),
94 name: "block profile",
98 import "github.com/pkg/profile"
101 defer profile.Start(profile.BlockProfile).Stop()
106 Stderr("profile: block profiling enabled"),
110 name: "mutex profile",
114 import "github.com/pkg/profile"
117 defer profile.Start(profile.MutexProfile).Stop()
122 Stderr("profile: mutex profiling enabled"),
126 name: "profile path",
130 import "github.com/pkg/profile"
133 defer profile.Start(profile.ProfilePath(".")).Stop()
138 Stderr("profile: cpu profiling enabled, cpu.pprof"),
142 name: "profile path error",
146 import "github.com/pkg/profile"
149 defer profile.Start(profile.ProfilePath("` + f.Name() + `")).Stop()
154 Stderr("could not create initial output"),
158 name: "multiple profile sessions",
162 import "github.com/pkg/profile"
165 profile.Start(profile.CPUProfile).Stop()
166 profile.Start(profile.MemProfile).Stop()
167 profile.Start(profile.BlockProfile).Stop()
168 profile.Start(profile.CPUProfile).Stop()
169 profile.Start(profile.MutexProfile).Stop()
174 Stderr("profile: cpu profiling enabled",
175 "profile: cpu profiling disabled",
176 "profile: memory profiling enabled",
177 "profile: memory profiling disabled",
178 "profile: block profiling enabled",
179 "profile: block profiling disabled",
180 "profile: cpu profiling enabled",
181 "profile: cpu profiling disabled",
182 "profile: mutex profiling enabled",
183 "profile: mutex profiling disabled"),
187 name: "profile quiet",
191 import "github.com/pkg/profile"
194 defer profile.Start(profile.Quiet).Stop()
197 checks: []checkFn{NoStdout, NoStderr, NoErr},
199 for _, tt := range profileTests {
201 stdout, stderr, err := runTest(t, tt.code)
202 for _, f := range tt.checks {
203 f(t, stdout, stderr, err)
208 // NoStdout checks that stdout was blank.
209 func NoStdout(t *testing.T, stdout, _ []byte, _ error) {
210 if len := len(stdout); len > 0 {
211 t.Errorf("stdout: wanted 0 bytes, got %d", len)
215 // Stderr verifies that the given lines match the output from stderr
216 func Stderr(lines ...string) checkFn {
217 return func(t *testing.T, _, stderr []byte, _ error) {
218 r := bytes.NewReader(stderr)
219 if !validateOutput(r, lines) {
220 t.Errorf("stderr: wanted '%s', got '%s'", lines, stderr)
225 // NoStderr checks that stderr was blank.
226 func NoStderr(t *testing.T, _, stderr []byte, _ error) {
227 if len := len(stderr); len > 0 {
228 t.Errorf("stderr: wanted 0 bytes, got %d", len)
232 // Err checks that there was an error returned
233 func Err(t *testing.T, _, _ []byte, err error) {
235 t.Errorf("expected error")
239 // NoErr checks that err was nil
240 func NoErr(t *testing.T, _, _ []byte, err error) {
242 t.Errorf("error: expected nil, got %v", err)
246 // validatedOutput validates the given slice of lines against data from the given reader.
247 func validateOutput(r io.Reader, want []string) bool {
248 s := bufio.NewScanner(r)
249 for _, line := range want {
250 if !s.Scan() || !strings.Contains(s.Text(), line) {
257 var validateOutputTests = []struct {
271 lines: []string{"profile: yes"},
277 lines: []string{"profile: yes"},
283 lines: []string{"profile: yes", "profile: no"},
289 lines: []string{"profile: no"},
293 func TestValidateOutput(t *testing.T) {
294 for _, tt := range validateOutputTests {
295 r := strings.NewReader(tt.input)
296 got := validateOutput(r, tt.lines)
298 t.Errorf("validateOutput(%q, %q), want %v, got %v", tt.input, tt.lines, tt.want, got)
303 // runTest executes the go program supplied and returns the contents of stdout,
304 // stderr, and an error which may contain status information about the result
306 func runTest(t *testing.T, code string) ([]byte, []byte, error) {
307 chk := func(err error) {
312 gopath, err := ioutil.TempDir("", "profile-gopath")
314 defer os.RemoveAll(gopath)
316 srcdir := filepath.Join(gopath, "src")
317 err = os.Mkdir(srcdir, 0755)
319 src := filepath.Join(srcdir, "main.go")
320 err = ioutil.WriteFile(src, []byte(code), 0644)
323 cmd := exec.Command("go", "run", src)
325 var stdout, stderr bytes.Buffer
329 return stdout.Bytes(), stderr.Bytes(), err