Нет описания

report_test.go 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. // Copyright 2014 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package report
  15. import (
  16. "bytes"
  17. "io/ioutil"
  18. "regexp"
  19. "runtime"
  20. "testing"
  21. "github.com/google/pprof/internal/binutils"
  22. "github.com/google/pprof/internal/graph"
  23. "github.com/google/pprof/internal/proftest"
  24. "github.com/google/pprof/profile"
  25. )
  26. type testcase struct {
  27. rpt *Report
  28. want string
  29. }
  30. func TestSource(t *testing.T) {
  31. const path = "testdata/"
  32. sampleValue1 := func(v []int64) int64 {
  33. return v[1]
  34. }
  35. for _, tc := range []testcase{
  36. {
  37. rpt: New(
  38. testProfile.Copy(),
  39. &Options{
  40. OutputFormat: List,
  41. Symbol: regexp.MustCompile(`.`),
  42. SampleValue: sampleValue1,
  43. SampleUnit: testProfile.SampleType[1].Unit,
  44. },
  45. ),
  46. want: path + "source.rpt",
  47. },
  48. {
  49. rpt: New(
  50. testProfile.Copy(),
  51. &Options{
  52. OutputFormat: Dot,
  53. CallTree: true,
  54. Symbol: regexp.MustCompile(`.`),
  55. SampleValue: sampleValue1,
  56. SampleUnit: testProfile.SampleType[1].Unit,
  57. },
  58. ),
  59. want: path + "source.dot",
  60. },
  61. } {
  62. b := bytes.NewBuffer(nil)
  63. if err := Generate(b, tc.rpt, &binutils.Binutils{}); err != nil {
  64. t.Fatalf("%s: %v", tc.want, err)
  65. }
  66. gold, err := ioutil.ReadFile(tc.want)
  67. if err != nil {
  68. t.Fatalf("%s: %v", tc.want, err)
  69. }
  70. if runtime.GOOS == "windows" {
  71. gold = bytes.Replace(gold, []byte("testdata/"), []byte("testdata\\"), -1)
  72. }
  73. if string(b.String()) != string(gold) {
  74. d, err := proftest.Diff(gold, b.Bytes())
  75. if err != nil {
  76. t.Fatalf("%s: %v", "source", err)
  77. }
  78. t.Error("source" + "\n" + string(d) + "\n" + "gold:\n" + tc.want)
  79. }
  80. }
  81. }
  82. var testM = []*profile.Mapping{
  83. {
  84. ID: 1,
  85. HasFunctions: true,
  86. HasFilenames: true,
  87. HasLineNumbers: true,
  88. HasInlineFrames: true,
  89. },
  90. }
  91. var testF = []*profile.Function{
  92. {
  93. ID: 1,
  94. Name: "main",
  95. Filename: "testdata/source1",
  96. },
  97. {
  98. ID: 2,
  99. Name: "foo",
  100. Filename: "testdata/source1",
  101. },
  102. {
  103. ID: 3,
  104. Name: "bar",
  105. Filename: "testdata/source1",
  106. },
  107. {
  108. ID: 4,
  109. Name: "tee",
  110. Filename: "testdata/source2",
  111. },
  112. }
  113. var testL = []*profile.Location{
  114. {
  115. ID: 1,
  116. Mapping: testM[0],
  117. Line: []profile.Line{
  118. {
  119. Function: testF[0],
  120. Line: 2,
  121. },
  122. },
  123. },
  124. {
  125. ID: 2,
  126. Mapping: testM[0],
  127. Line: []profile.Line{
  128. {
  129. Function: testF[1],
  130. Line: 4,
  131. },
  132. },
  133. },
  134. {
  135. ID: 3,
  136. Mapping: testM[0],
  137. Line: []profile.Line{
  138. {
  139. Function: testF[2],
  140. Line: 10,
  141. },
  142. },
  143. },
  144. {
  145. ID: 4,
  146. Mapping: testM[0],
  147. Line: []profile.Line{
  148. {
  149. Function: testF[3],
  150. Line: 2,
  151. },
  152. },
  153. },
  154. {
  155. ID: 5,
  156. Mapping: testM[0],
  157. Line: []profile.Line{
  158. {
  159. Function: testF[3],
  160. Line: 8,
  161. },
  162. },
  163. },
  164. }
  165. var testProfile = &profile.Profile{
  166. PeriodType: &profile.ValueType{Type: "cpu", Unit: "millisecond"},
  167. Period: 10,
  168. DurationNanos: 10e9,
  169. SampleType: []*profile.ValueType{
  170. {Type: "samples", Unit: "count"},
  171. {Type: "cpu", Unit: "cycles"},
  172. },
  173. Sample: []*profile.Sample{
  174. {
  175. Location: []*profile.Location{testL[0]},
  176. Value: []int64{1, 1},
  177. },
  178. {
  179. Location: []*profile.Location{testL[2], testL[1], testL[0]},
  180. Value: []int64{1, 10},
  181. },
  182. {
  183. Location: []*profile.Location{testL[4], testL[2], testL[0]},
  184. Value: []int64{1, 100},
  185. },
  186. {
  187. Location: []*profile.Location{testL[3], testL[0]},
  188. Value: []int64{1, 1000},
  189. },
  190. {
  191. Location: []*profile.Location{testL[4], testL[3], testL[0]},
  192. Value: []int64{1, 10000},
  193. },
  194. },
  195. Location: testL,
  196. Function: testF,
  197. Mapping: testM,
  198. }
  199. func TestDisambiguation(t *testing.T) {
  200. parent1 := &graph.Node{Info: graph.NodeInfo{Name: "parent1"}}
  201. parent2 := &graph.Node{Info: graph.NodeInfo{Name: "parent2"}}
  202. child1 := &graph.Node{Info: graph.NodeInfo{Name: "child"}, Function: parent1}
  203. child2 := &graph.Node{Info: graph.NodeInfo{Name: "child"}, Function: parent2}
  204. child3 := &graph.Node{Info: graph.NodeInfo{Name: "child"}, Function: parent1}
  205. sibling := &graph.Node{Info: graph.NodeInfo{Name: "sibling"}, Function: parent1}
  206. n := []*graph.Node{parent1, parent2, child1, child2, child3, sibling}
  207. wanted := map[*graph.Node]string{
  208. parent1: "parent1",
  209. parent2: "parent2",
  210. child1: "child [1/2]",
  211. child2: "child [2/2]",
  212. child3: "child [1/2]",
  213. sibling: "sibling",
  214. }
  215. g := &graph.Graph{Nodes: n}
  216. names := getDisambiguatedNames(g)
  217. for node, want := range wanted {
  218. if got := names[node]; got != want {
  219. t.Errorf("name %s, got %s, want %s", node.Info.Name, got, want)
  220. }
  221. }
  222. }
  223. func TestFunctionMap(t *testing.T) {
  224. fm := make(functionMap)
  225. nodes := []graph.NodeInfo{
  226. {Name: "fun1"},
  227. {Name: "fun2", File: "filename"},
  228. {Name: "fun1"},
  229. {Name: "fun2", File: "filename2"},
  230. }
  231. want := []profile.Function{
  232. {ID: 1, Name: "fun1"},
  233. {ID: 2, Name: "fun2", Filename: "filename"},
  234. {ID: 1, Name: "fun1"},
  235. {ID: 3, Name: "fun2", Filename: "filename2"},
  236. }
  237. for i, tc := range nodes {
  238. if got, want := fm.FindOrAdd(tc), want[i]; *got != want {
  239. t.Errorf("%d: want %v, got %v", i, want, got)
  240. }
  241. }
  242. }
  243. func TestLegendActiveFilters(t *testing.T) {
  244. activeFilterInput := []string{
  245. "focus=123|456|789|101112|131415|161718|192021|222324|252627|282930|313233|343536|363738|acbdefghijklmnop",
  246. "show=short filter",
  247. }
  248. expectedLegendActiveFilter := []string{
  249. "Active filters:",
  250. " focus=123|456|789|101112|131415|161718|192021|222324|252627|282930|313233|343536…",
  251. " show=short filter",
  252. }
  253. legendActiveFilter := legendActiveFilters(activeFilterInput)
  254. if len(legendActiveFilter) != len(expectedLegendActiveFilter) {
  255. t.Errorf("wanted length %v got length %v", len(expectedLegendActiveFilter), len(legendActiveFilter))
  256. }
  257. for i := range legendActiveFilter {
  258. if legendActiveFilter[i] != expectedLegendActiveFilter[i] {
  259. t.Errorf("%d: want \"%v\", got \"%v\"", i, expectedLegendActiveFilter[i], legendActiveFilter[i])
  260. }
  261. }
  262. }