github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/structs/flamebearer/convert/convert_test.go (about)

     1  package convert
     2  
     3  import (
     4  	"io/ioutil"
     5  	"reflect"
     6  
     7  	. "github.com/onsi/ginkgo/v2"
     8  	. "github.com/onsi/gomega"
     9  
    10  	"github.com/pyroscope-io/pyroscope/pkg/structs/flamebearer"
    11  )
    12  
    13  var _ = Describe("Server", func() {
    14  	Describe("Detecting format", func() {
    15  		Context("with a valid pprof type", func() {
    16  			When("there's only type", func() {
    17  				var m ProfileFile
    18  
    19  				BeforeEach(func() {
    20  					m = ProfileFile{
    21  						Type: "pprof",
    22  					}
    23  				})
    24  				It("should return pprof as type is be enough to detect the type", func() {
    25  					// We want to compare functions, which is not ideal.
    26  					expected := reflect.ValueOf(PprofToProfile).Pointer()
    27  					f, err := converter(m)
    28  					Expect(err).To(BeNil())
    29  					Expect(f).ToNot(BeNil())
    30  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
    31  				})
    32  			})
    33  			When("there's pprof type and json filename", func() {
    34  				var m ProfileFile
    35  
    36  				BeforeEach(func() {
    37  					m = ProfileFile{
    38  						Name: "profile.json",
    39  						Type: "pprof",
    40  					}
    41  				})
    42  				It("should return pprof as type takes precedence over filename", func() {
    43  					// We want to compare functions, which is not ideal.
    44  					expected := reflect.ValueOf(PprofToProfile).Pointer()
    45  					f, err := converter(m)
    46  					Expect(err).To(BeNil())
    47  					Expect(f).ToNot(BeNil())
    48  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
    49  				})
    50  			})
    51  
    52  			When("there's pprof type and json profile contents", func() {
    53  				var m ProfileFile
    54  
    55  				BeforeEach(func() {
    56  					m = ProfileFile{
    57  						Data: []byte(`{"flamebearer":""}`),
    58  						Type: "pprof",
    59  					}
    60  				})
    61  				It("should return pprof as type takes precedence over profile contents", func() {
    62  					// We want to compare functions, which is not ideal.
    63  					expected := reflect.ValueOf(PprofToProfile).Pointer()
    64  					f, err := converter(m)
    65  					Expect(err).To(BeNil())
    66  					Expect(f).ToNot(BeNil())
    67  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
    68  				})
    69  			})
    70  		})
    71  
    72  		Context("with no (valid) type and a valid pprof filename", func() {
    73  			When("there's pprof filename and json profile contents", func() {
    74  				var m ProfileFile
    75  				BeforeEach(func() {
    76  					m = ProfileFile{
    77  						Name: "profile.pprof",
    78  						Data: []byte(`{"flamebearer":""}`),
    79  					}
    80  				})
    81  
    82  				It("should return pprof as filename takes precedence over profile contents", func() {
    83  					// We want to compare functions, which is not ideal.
    84  					expected := reflect.ValueOf(PprofToProfile).Pointer()
    85  					f, err := converter(m)
    86  					Expect(err).To(BeNil())
    87  					Expect(f).ToNot(BeNil())
    88  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
    89  				})
    90  			})
    91  			When("there's pprof filename and an unsupported type", func() {
    92  				var m ProfileFile
    93  				BeforeEach(func() {
    94  					m = ProfileFile{
    95  						Name: "profile.pprof",
    96  						Type: "unsupported",
    97  					}
    98  				})
    99  
   100  				It("should return pprof as unsupported type is ignored", func() {
   101  					// We want to compare functions, which is not ideal.
   102  					expected := reflect.ValueOf(PprofToProfile).Pointer()
   103  					f, err := converter(m)
   104  					Expect(err).To(BeNil())
   105  					Expect(f).ToNot(BeNil())
   106  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   107  				})
   108  			})
   109  		})
   110  
   111  		Context("with no (valid) type and filename, a valid pprof profile", func() {
   112  			When("there's a profile with uncompressed pprof content", func() {
   113  				var m ProfileFile
   114  
   115  				BeforeEach(func() {
   116  					m = ProfileFile{
   117  						Data: []byte{0x0a, 0x04},
   118  					}
   119  				})
   120  
   121  				It("should return pprof", func() {
   122  					// We want to compare functions, which is not ideal.
   123  					expected := reflect.ValueOf(PprofToProfile).Pointer()
   124  					f, err := converter(m)
   125  					Expect(err).To(BeNil())
   126  					Expect(f).ToNot(BeNil())
   127  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   128  				})
   129  			})
   130  
   131  			When("there's a profile with compressed pprof content", func() {
   132  				var m ProfileFile
   133  
   134  				BeforeEach(func() {
   135  					m = ProfileFile{
   136  						Data: []byte{0x1f, 0x8b},
   137  					}
   138  				})
   139  
   140  				It("should return pprof", func() {
   141  					// We want to compare functions, which is not ideal.
   142  					expected := reflect.ValueOf(PprofToProfile).Pointer()
   143  					f, err := converter(m)
   144  					Expect(err).To(BeNil())
   145  					Expect(f).ToNot(BeNil())
   146  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   147  				})
   148  			})
   149  
   150  			When("there's a profile with compressed pprof content and an unsupported type", func() {
   151  				var m ProfileFile
   152  
   153  				BeforeEach(func() {
   154  					m = ProfileFile{
   155  						Data: []byte{0x1f, 0x8b},
   156  						Type: "unsupported",
   157  					}
   158  				})
   159  
   160  				It("should return pprof as unsupported types are ignored", func() {
   161  					// We want to compare functions, which is not ideal.
   162  					expected := reflect.ValueOf(PprofToProfile).Pointer()
   163  					f, err := converter(m)
   164  					Expect(err).To(BeNil())
   165  					Expect(f).ToNot(BeNil())
   166  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   167  				})
   168  			})
   169  
   170  			When("there's a profile with compressed pprof content and unsupported filename", func() {
   171  				var m ProfileFile
   172  
   173  				BeforeEach(func() {
   174  					m = ProfileFile{
   175  						Name: "profile.unsupported",
   176  						Data: []byte{0x1f, 0x8b},
   177  					}
   178  				})
   179  
   180  				It("should return pprof as unsupported filenames are ignored", func() {
   181  					// We want to compare functions, which is not ideal.
   182  					expected := reflect.ValueOf(PprofToProfile).Pointer()
   183  					f, err := converter(m)
   184  					Expect(err).To(BeNil())
   185  					Expect(f).ToNot(BeNil())
   186  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   187  				})
   188  			})
   189  		})
   190  
   191  		Context("with a valid json type", func() {
   192  			When("there's only type", func() {
   193  				var m ProfileFile
   194  
   195  				BeforeEach(func() {
   196  					m = ProfileFile{
   197  						Type: "json",
   198  					}
   199  				})
   200  				It("should return json as type is be enough to detect the type", func() {
   201  					// We want to compare functions, which is not ideal.
   202  					expected := reflect.ValueOf(JSONToProfile).Pointer()
   203  					f, err := converter(m)
   204  					Expect(err).To(BeNil())
   205  					Expect(f).ToNot(BeNil())
   206  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   207  				})
   208  			})
   209  			When("there's json type and pprof filename", func() {
   210  				var m ProfileFile
   211  
   212  				BeforeEach(func() {
   213  					m = ProfileFile{
   214  						Name: "profile.pprof",
   215  						Type: "json",
   216  					}
   217  				})
   218  				It("should return json as type takes precedence over filename", func() {
   219  					// We want to compare functions, which is not ideal.
   220  					expected := reflect.ValueOf(JSONToProfile).Pointer()
   221  					f, err := converter(m)
   222  					Expect(err).To(BeNil())
   223  					Expect(f).ToNot(BeNil())
   224  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   225  				})
   226  			})
   227  
   228  			When("there's json type and pprof profile contents", func() {
   229  				var m ProfileFile
   230  
   231  				BeforeEach(func() {
   232  					m = ProfileFile{
   233  						Data: []byte{0x1f, 0x8b},
   234  						Type: "json",
   235  					}
   236  				})
   237  				It("should return json as type takes precedence over profile contents", func() {
   238  					// We want to compare functions, which is not ideal.
   239  					expected := reflect.ValueOf(JSONToProfile).Pointer()
   240  					f, err := converter(m)
   241  					Expect(err).To(BeNil())
   242  					Expect(f).ToNot(BeNil())
   243  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   244  				})
   245  			})
   246  		})
   247  
   248  		Context("with no (valid) type and a valid json filename", func() {
   249  			When("there's json filename and pprof profile contents", func() {
   250  				var m ProfileFile
   251  				BeforeEach(func() {
   252  					m = ProfileFile{
   253  						Name: "profile.json",
   254  						Data: []byte{0x1f, 0x8b},
   255  					}
   256  				})
   257  
   258  				It("should return json as filename takes precedence over profile contents", func() {
   259  					// We want to compare functions, which is not ideal.
   260  					expected := reflect.ValueOf(JSONToProfile).Pointer()
   261  					f, err := converter(m)
   262  					Expect(err).To(BeNil())
   263  					Expect(f).ToNot(BeNil())
   264  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   265  				})
   266  			})
   267  			When("there's json filename and an unsupported type", func() {
   268  				var m ProfileFile
   269  				BeforeEach(func() {
   270  					m = ProfileFile{
   271  						Name: "profile.json",
   272  						Type: "unsupported",
   273  					}
   274  				})
   275  
   276  				It("should return json as unsupported type is ignored", func() {
   277  					// We want to compare functions, which is not ideal.
   278  					expected := reflect.ValueOf(JSONToProfile).Pointer()
   279  					f, err := converter(m)
   280  					Expect(err).To(BeNil())
   281  					Expect(f).ToNot(BeNil())
   282  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   283  				})
   284  			})
   285  		})
   286  
   287  		Context("with no (valid) type and filename, a valid json profile", func() {
   288  			When("there's a profile with json content", func() {
   289  				var m ProfileFile
   290  
   291  				BeforeEach(func() {
   292  					m = ProfileFile{
   293  						Data: []byte(`{"flamebearer":""}`),
   294  					}
   295  				})
   296  
   297  				It("should return json", func() {
   298  					// We want to compare functions, which is not ideal.
   299  					expected := reflect.ValueOf(JSONToProfile).Pointer()
   300  					f, err := converter(m)
   301  					Expect(err).To(BeNil())
   302  					Expect(f).ToNot(BeNil())
   303  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   304  				})
   305  			})
   306  
   307  			When("there's a profile with json content and an unsupported type", func() {
   308  				var m ProfileFile
   309  
   310  				BeforeEach(func() {
   311  					m = ProfileFile{
   312  						Data: []byte(`{"flamebearer":""}`),
   313  						Type: "unsupported",
   314  					}
   315  				})
   316  
   317  				It("should return json as unsupported types are ignored", func() {
   318  					// We want to compare functions, which is not ideal.
   319  					expected := reflect.ValueOf(JSONToProfile).Pointer()
   320  					f, err := converter(m)
   321  					Expect(err).To(BeNil())
   322  					Expect(f).ToNot(BeNil())
   323  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   324  				})
   325  			})
   326  
   327  			When("there's a profile with json content and unsupported filename", func() {
   328  				var m ProfileFile
   329  
   330  				BeforeEach(func() {
   331  					m = ProfileFile{
   332  						Name: "profile.unsupported",
   333  						Data: []byte(`{"flamebearer":""}`),
   334  					}
   335  				})
   336  
   337  				It("should return json as unsupported filenames are ignored", func() {
   338  					// We want to compare functions, which is not ideal.
   339  					expected := reflect.ValueOf(JSONToProfile).Pointer()
   340  					f, err := converter(m)
   341  					Expect(err).To(BeNil())
   342  					Expect(f).ToNot(BeNil())
   343  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   344  				})
   345  			})
   346  		})
   347  
   348  		Context("with a valid collapsed type", func() {
   349  			When("there's only type", func() {
   350  				var m ProfileFile
   351  
   352  				BeforeEach(func() {
   353  					m = ProfileFile{
   354  						Type: "collapsed",
   355  					}
   356  				})
   357  				It("should return collapsed as type is be enough to detect the type", func() {
   358  					// We want to compare functions, which is not ideal.
   359  					expected := reflect.ValueOf(CollapsedToProfile).Pointer()
   360  					f, err := converter(m)
   361  					Expect(err).To(BeNil())
   362  					Expect(f).ToNot(BeNil())
   363  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   364  				})
   365  			})
   366  			When("there's collapsed type and pprof filename", func() {
   367  				var m ProfileFile
   368  
   369  				BeforeEach(func() {
   370  					m = ProfileFile{
   371  						Name: "profile.pprof",
   372  						Type: "collapsed",
   373  					}
   374  				})
   375  				It("should return collapsed as type takes precedence over filename", func() {
   376  					// We want to compare functions, which is not ideal.
   377  					expected := reflect.ValueOf(CollapsedToProfile).Pointer()
   378  					f, err := converter(m)
   379  					Expect(err).To(BeNil())
   380  					Expect(f).ToNot(BeNil())
   381  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   382  				})
   383  			})
   384  
   385  			When("there's json type and pprof profile contents", func() {
   386  				var m ProfileFile
   387  
   388  				BeforeEach(func() {
   389  					m = ProfileFile{
   390  						Data: []byte{0x1f, 0x8b},
   391  						Type: "collapsed",
   392  					}
   393  				})
   394  				It("should return collapsed as type takes precedence over profile contents", func() {
   395  					// We want to compare functions, which is not ideal.
   396  					expected := reflect.ValueOf(CollapsedToProfile).Pointer()
   397  					f, err := converter(m)
   398  					Expect(err).To(BeNil())
   399  					Expect(f).ToNot(BeNil())
   400  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   401  				})
   402  			})
   403  		})
   404  
   405  		Context("with no (valid) type and a valid collapsed filename", func() {
   406  			When("there's collapsed filename and pprof profile contents", func() {
   407  				var m ProfileFile
   408  				BeforeEach(func() {
   409  					m = ProfileFile{
   410  						Name: "profile.collapsed",
   411  						Data: []byte{0x1f, 0x8b},
   412  					}
   413  				})
   414  
   415  				It("should return collapsed as filename takes precedence over profile contents", func() {
   416  					// We want to compare functions, which is not ideal.
   417  					expected := reflect.ValueOf(CollapsedToProfile).Pointer()
   418  					f, err := converter(m)
   419  					Expect(err).To(BeNil())
   420  					Expect(f).ToNot(BeNil())
   421  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   422  				})
   423  			})
   424  			When("there's collapsed filename and an unsupported type", func() {
   425  				var m ProfileFile
   426  				BeforeEach(func() {
   427  					m = ProfileFile{
   428  						Name: "profile.collapsed",
   429  						Type: "unsupported",
   430  					}
   431  				})
   432  
   433  				It("should return collapsed as unsupported type is ignored", func() {
   434  					// We want to compare functions, which is not ideal.
   435  					expected := reflect.ValueOf(CollapsedToProfile).Pointer()
   436  					f, err := converter(m)
   437  					Expect(err).To(BeNil())
   438  					Expect(f).ToNot(BeNil())
   439  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   440  				})
   441  			})
   442  
   443  			When("there's collapsed text filename and an unsupported type", func() {
   444  				var m ProfileFile
   445  				BeforeEach(func() {
   446  					m = ProfileFile{
   447  						Name: "profile.collapsed.txt",
   448  						Type: "unsupported",
   449  					}
   450  				})
   451  
   452  				It("should return collapsed as unsupported type is ignored", func() {
   453  					// We want to compare functions, which is not ideal.
   454  					expected := reflect.ValueOf(CollapsedToProfile).Pointer()
   455  					f, err := converter(m)
   456  					Expect(err).To(BeNil())
   457  					Expect(f).ToNot(BeNil())
   458  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   459  				})
   460  			})
   461  		})
   462  
   463  		Context("with no (valid) type and filename, a valid collapsed profile", func() {
   464  			When("there's a profile with collapsed content", func() {
   465  				var m ProfileFile
   466  
   467  				BeforeEach(func() {
   468  					m = ProfileFile{
   469  						Data: []byte("fn1 1\nfn2 2"),
   470  					}
   471  				})
   472  
   473  				It("should return collapsed", func() {
   474  					// We want to compare functions, which is not ideal.
   475  					expected := reflect.ValueOf(CollapsedToProfile).Pointer()
   476  					f, err := converter(m)
   477  					Expect(err).To(BeNil())
   478  					Expect(f).ToNot(BeNil())
   479  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   480  				})
   481  			})
   482  
   483  			When("there's a profile with collapsed content and an unsupported type", func() {
   484  				var m ProfileFile
   485  
   486  				BeforeEach(func() {
   487  					m = ProfileFile{
   488  						Data: []byte("fn1 1\nfn2 2"),
   489  						Type: "unsupported",
   490  					}
   491  				})
   492  
   493  				It("should return collapsed as unsupported types are ignored", func() {
   494  					// We want to compare functions, which is not ideal.
   495  					expected := reflect.ValueOf(CollapsedToProfile).Pointer()
   496  					f, err := converter(m)
   497  					Expect(err).To(BeNil())
   498  					Expect(f).ToNot(BeNil())
   499  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   500  				})
   501  			})
   502  
   503  			When("there's a profile with collapsed content and unsupported filename", func() {
   504  				var m ProfileFile
   505  
   506  				BeforeEach(func() {
   507  					m = ProfileFile{
   508  						Name: "profile.unsupported",
   509  						Data: []byte("fn1 1\nfn2 2"),
   510  					}
   511  				})
   512  
   513  				It("should return collapsed as unsupported filenames are ignored", func() {
   514  					// We want to compare functions, which is not ideal.
   515  					expected := reflect.ValueOf(CollapsedToProfile).Pointer()
   516  					f, err := converter(m)
   517  					Expect(err).To(BeNil())
   518  					Expect(f).ToNot(BeNil())
   519  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   520  				})
   521  			})
   522  		})
   523  
   524  		Context("perf script", func() {
   525  			When("detect by content", func() {
   526  				var m ProfileFile
   527  
   528  				BeforeEach(func() {
   529  					m = ProfileFile{
   530  						Data: []byte("java 12688 [002] 6544038.708352: cpu-clock:\n\n"),
   531  					}
   532  				})
   533  
   534  				It("should return perf_script", func() {
   535  					// We want to compare functions, which is not ideal.
   536  					expected := reflect.ValueOf(PerfScriptToProfile).Pointer()
   537  					f, err := converter(m)
   538  					Expect(err).To(BeNil())
   539  					Expect(f).ToNot(BeNil())
   540  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   541  				})
   542  			})
   543  			When("detect by .txt extension and content", func() {
   544  				var m ProfileFile
   545  
   546  				BeforeEach(func() {
   547  					m = ProfileFile{
   548  						Name: "foo.txt",
   549  						Data: []byte("java 12688 [002] 6544038.708352: cpu-clock:\n\n"),
   550  					}
   551  				})
   552  
   553  				It("should return perf_script", func() {
   554  					// We want to compare functions, which is not ideal.
   555  					expected := reflect.ValueOf(PerfScriptToProfile).Pointer()
   556  					f, err := converter(m)
   557  					Expect(err).To(BeNil())
   558  					Expect(f).ToNot(BeNil())
   559  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   560  				})
   561  			})
   562  			When("detect by .perf_script extension", func() {
   563  				var m ProfileFile
   564  
   565  				BeforeEach(func() {
   566  					m = ProfileFile{
   567  						Name: "foo.perf_script",
   568  						Data: []byte("foo;bar 239"),
   569  					}
   570  				})
   571  
   572  				It("should return perf_script", func() {
   573  					// We want to compare functions, which is not ideal.
   574  					expected := reflect.ValueOf(PerfScriptToProfile).Pointer()
   575  					f, err := converter(m)
   576  					Expect(err).To(BeNil())
   577  					Expect(f).ToNot(BeNil())
   578  					Expect(reflect.ValueOf(f).Pointer()).To(Equal(expected))
   579  				})
   580  			})
   581  		})
   582  
   583  		Context("with an empty ProfileFile", func() {
   584  			var m ProfileFile
   585  			It("should return an error", func() {
   586  				_, err := converter(m)
   587  				Expect(err).ToNot(Succeed())
   588  			})
   589  		})
   590  	})
   591  
   592  	Describe("Calling DiffV1", func() {
   593  		Context("with v1 profiles", func() {
   594  			var base, diff *flamebearer.FlamebearerProfile
   595  
   596  			When("Diff is called with valid and equal base and diff profiles", func() {
   597  				BeforeEach(func() {
   598  					base = &flamebearer.FlamebearerProfile{
   599  						Version: 1,
   600  						FlamebearerProfileV1: flamebearer.FlamebearerProfileV1{
   601  							Metadata: flamebearer.FlamebearerMetadataV1{
   602  								Format: "single",
   603  							},
   604  							// Taken from flamebearer test
   605  							Flamebearer: flamebearer.FlamebearerV1{
   606  								Names: []string{"total", "a", "c", "b"},
   607  								Levels: [][]int{
   608  									{0, 3, 0, 0},
   609  									{0, 3, 0, 1},
   610  									{0, 1, 1, 3, 0, 2, 2, 2},
   611  								},
   612  								NumTicks: 3,
   613  								MaxSelf:  2,
   614  							},
   615  						},
   616  					}
   617  
   618  					diff = &flamebearer.FlamebearerProfile{
   619  						Version: 1,
   620  						FlamebearerProfileV1: flamebearer.FlamebearerProfileV1{
   621  							Metadata: flamebearer.FlamebearerMetadataV1{
   622  								Format: "single",
   623  							},
   624  							// Taken from flamebearer test
   625  							Flamebearer: flamebearer.FlamebearerV1{
   626  								Names: []string{"total", "a", "c", "b"},
   627  								Levels: [][]int{
   628  									{0, 3, 0, 0},
   629  									{0, 3, 0, 1},
   630  									{0, 1, 1, 3, 0, 2, 2, 2},
   631  								},
   632  								NumTicks: 3,
   633  								MaxSelf:  2,
   634  							},
   635  						},
   636  					}
   637  				})
   638  
   639  				It("returns the diff profile", func() {
   640  					fb, err := flamebearer.Diff("name", base, diff, 1024)
   641  					Expect(err).To(Succeed())
   642  					Expect(fb.Version).To(Equal(uint(1)))
   643  					Expect(fb.Metadata.Name).To(Equal("name"))
   644  					Expect(fb.Metadata.Format).To(Equal("double"))
   645  					Expect(fb.Flamebearer.Names).To(Equal([]string{"total", "a", "c", "b"}))
   646  					Expect(fb.Flamebearer.Levels).To(Equal([][]int{
   647  						{0, 3, 0, 0, 3, 0, 0},
   648  						{0, 3, 0, 0, 3, 0, 1},
   649  						{0, 1, 1, 0, 1, 1, 3, 0, 2, 2, 0, 2, 2, 2},
   650  					}))
   651  					Expect(fb.Flamebearer.NumTicks).To(Equal(6))
   652  					Expect(fb.Flamebearer.MaxSelf).To(Equal(2))
   653  					Expect(fb.LeftTicks).To(Equal(uint64(3)))
   654  					Expect(fb.RightTicks).To(Equal(uint64(3)))
   655  				})
   656  			})
   657  		})
   658  	})
   659  })
   660  
   661  var _ = Describe("Convert", func() {
   662  	It("converts malformed pprof", func() {
   663  		m := ProfileFile{
   664  			Type: "pprof",
   665  			Data: readFile("./testdata/cpu-unknown.pb.gz"),
   666  		}
   667  
   668  		f, err := converter(m)
   669  		Expect(err).To(BeNil())
   670  		Expect(f).ToNot(BeNil())
   671  
   672  		b, err := f(m.Data, "appname", 1024)
   673  		Expect(err).To(BeNil())
   674  		Expect(b).ToNot(BeNil())
   675  	})
   676  
   677  	Describe("JSON", func() {
   678  		It("prunes tree", func() {
   679  			m := ProfileFile{
   680  				Type: "json",
   681  				Data: readFile("./testdata/profile.json"),
   682  			}
   683  
   684  			f, err := converter(m)
   685  			Expect(err).To(BeNil())
   686  			Expect(f).ToNot(BeNil())
   687  
   688  			b, err := f(m.Data, "appname", 1)
   689  			Expect(err).To(BeNil())
   690  			Expect(b).ToNot(BeNil())
   691  
   692  			// 1 + total
   693  			Expect(len(b.FlamebearerProfileV1.Flamebearer.Levels)).To(Equal(2))
   694  		})
   695  	})
   696  })
   697  
   698  func readFile(path string) []byte {
   699  	f, err := ioutil.ReadFile(path)
   700  	if err != nil {
   701  		panic(err)
   702  	}
   703  	return f
   704  }