• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2022 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 pods_test
6
7import (
8	"crypto/md5"
9	"fmt"
10	"internal/coverage"
11	"internal/coverage/pods"
12	"os"
13	"path/filepath"
14	"runtime"
15	"testing"
16)
17
18func TestPodCollection(t *testing.T) {
19	//testenv.MustHaveGoBuild(t)
20
21	mkdir := func(d string, perm os.FileMode) string {
22		dp := filepath.Join(t.TempDir(), d)
23		if err := os.Mkdir(dp, perm); err != nil {
24			t.Fatal(err)
25		}
26		return dp
27	}
28
29	mkfile := func(d string, fn string) string {
30		fp := filepath.Join(d, fn)
31		if err := os.WriteFile(fp, []byte("foo"), 0666); err != nil {
32			t.Fatal(err)
33		}
34		return fp
35	}
36
37	mkmeta := func(dir string, tag string) string {
38		hash := md5.Sum([]byte(tag))
39		fn := fmt.Sprintf("%s.%x", coverage.MetaFilePref, hash)
40		return mkfile(dir, fn)
41	}
42
43	mkcounter := func(dir string, tag string, nt int, pid int) string {
44		hash := md5.Sum([]byte(tag))
45		fn := fmt.Sprintf(coverage.CounterFileTempl, coverage.CounterFilePref, hash, pid, nt)
46		return mkfile(dir, fn)
47	}
48
49	trim := func(path string) string {
50		b := filepath.Base(path)
51		d := filepath.Dir(path)
52		db := filepath.Base(d)
53		return db + "/" + b
54	}
55
56	podToString := func(p pods.Pod) string {
57		rv := trim(p.MetaFile) + " [\n"
58		for k, df := range p.CounterDataFiles {
59			rv += trim(df)
60			if p.Origins != nil {
61				rv += fmt.Sprintf(" o:%d", p.Origins[k])
62			}
63			rv += "\n"
64		}
65		return rv + "]"
66	}
67
68	// Create a couple of directories.
69	o1 := mkdir("o1", 0777)
70	o2 := mkdir("o2", 0777)
71
72	// Add some random files (not coverage related)
73	mkfile(o1, "blah.txt")
74	mkfile(o1, "something.exe")
75
76	// Add a meta-data file with two counter files to first dir.
77	mkmeta(o1, "m1")
78	mkcounter(o1, "m1", 1, 42)
79	mkcounter(o1, "m1", 2, 41)
80	mkcounter(o1, "m1", 2, 40)
81
82	// Add a counter file with no associated meta file.
83	mkcounter(o1, "orphan", 9, 39)
84
85	// Add a meta-data file with three counter files to second dir.
86	mkmeta(o2, "m2")
87	mkcounter(o2, "m2", 1, 38)
88	mkcounter(o2, "m2", 2, 37)
89	mkcounter(o2, "m2", 3, 36)
90
91	// Add a duplicate of the first meta-file and a corresponding
92	// counter file to the second dir. This is intended to capture
93	// the scenario where we have two different runs of the same
94	// coverage-instrumented binary, but with the output files
95	// sent to separate directories.
96	mkmeta(o2, "m1")
97	mkcounter(o2, "m1", 11, 35)
98
99	// Collect pods.
100	podlist, err := pods.CollectPods([]string{o1, o2}, true)
101	if err != nil {
102		t.Fatal(err)
103	}
104
105	// Verify pods
106	if len(podlist) != 2 {
107		t.Fatalf("expected 2 pods got %d pods", len(podlist))
108	}
109
110	for k, p := range podlist {
111		t.Logf("%d: mf=%s\n", k, p.MetaFile)
112	}
113
114	expected := []string{
115		`o1/covmeta.ae7be26cdaa742ca148068d5ac90eaca [
116o1/covcounters.ae7be26cdaa742ca148068d5ac90eaca.40.2 o:0
117o1/covcounters.ae7be26cdaa742ca148068d5ac90eaca.41.2 o:0
118o1/covcounters.ae7be26cdaa742ca148068d5ac90eaca.42.1 o:0
119o2/covcounters.ae7be26cdaa742ca148068d5ac90eaca.35.11 o:1
120]`,
121		`o2/covmeta.aaf2f89992379705dac844c0a2a1d45f [
122o2/covcounters.aaf2f89992379705dac844c0a2a1d45f.36.3 o:1
123o2/covcounters.aaf2f89992379705dac844c0a2a1d45f.37.2 o:1
124o2/covcounters.aaf2f89992379705dac844c0a2a1d45f.38.1 o:1
125]`,
126	}
127	for k, exp := range expected {
128		got := podToString(podlist[k])
129		if exp != got {
130			t.Errorf("pod %d: expected:\n%s\ngot:\n%s", k, exp, got)
131		}
132	}
133
134	// Check handling of bad/unreadable dir.
135	if runtime.GOOS == "linux" {
136		dbad := "/dev/null"
137		_, err = pods.CollectPods([]string{dbad}, true)
138		if err == nil {
139			t.Errorf("executed error due to unreadable dir")
140		}
141	}
142}
143