mirror of
https://github.com/dutchcoders/transfer.sh.git
synced 2020-11-18 19:53:40 -08:00
336 lines
7.1 KiB
Go
336 lines
7.1 KiB
Go
// Copyright 2014 Google Inc. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package graph
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/google/pprof/internal/proftest"
|
|
)
|
|
|
|
var updateFlag = flag.Bool("update", false, "Update the golden files")
|
|
|
|
func TestComposeWithStandardGraph(t *testing.T) {
|
|
g := baseGraph()
|
|
a, c := baseAttrsAndConfig()
|
|
|
|
var buf bytes.Buffer
|
|
ComposeDot(&buf, g, a, c)
|
|
|
|
compareGraphs(t, buf.Bytes(), "compose1.dot")
|
|
}
|
|
|
|
func TestComposeWithNodeAttributesAndZeroFlat(t *testing.T) {
|
|
g := baseGraph()
|
|
a, c := baseAttrsAndConfig()
|
|
|
|
// Set NodeAttributes for Node 1.
|
|
a.Nodes[g.Nodes[0]] = &DotNodeAttributes{
|
|
Shape: "folder",
|
|
Bold: true,
|
|
Peripheries: 2,
|
|
URL: "www.google.com",
|
|
Formatter: func(ni *NodeInfo) string {
|
|
return strings.ToUpper(ni.Name)
|
|
},
|
|
}
|
|
|
|
// Set Flat value to zero on Node 2.
|
|
g.Nodes[1].Flat = 0
|
|
|
|
var buf bytes.Buffer
|
|
ComposeDot(&buf, g, a, c)
|
|
|
|
compareGraphs(t, buf.Bytes(), "compose2.dot")
|
|
}
|
|
|
|
func TestComposeWithTagsAndResidualEdge(t *testing.T) {
|
|
g := baseGraph()
|
|
a, c := baseAttrsAndConfig()
|
|
|
|
// Add tags to Node 1.
|
|
g.Nodes[0].LabelTags["a"] = &Tag{
|
|
Name: "tag1",
|
|
Cum: 10,
|
|
Flat: 10,
|
|
}
|
|
g.Nodes[0].NumericTags[""] = TagMap{
|
|
"b": &Tag{
|
|
Name: "tag2",
|
|
Cum: 20,
|
|
Flat: 20,
|
|
Unit: "ms",
|
|
},
|
|
}
|
|
|
|
// Set edge to be Residual.
|
|
g.Nodes[0].Out[g.Nodes[1]].Residual = true
|
|
|
|
var buf bytes.Buffer
|
|
ComposeDot(&buf, g, a, c)
|
|
|
|
compareGraphs(t, buf.Bytes(), "compose3.dot")
|
|
}
|
|
|
|
func TestComposeWithNestedTags(t *testing.T) {
|
|
g := baseGraph()
|
|
a, c := baseAttrsAndConfig()
|
|
|
|
// Add tags to Node 1.
|
|
g.Nodes[0].LabelTags["tag1"] = &Tag{
|
|
Name: "tag1",
|
|
Cum: 10,
|
|
Flat: 10,
|
|
}
|
|
g.Nodes[0].NumericTags["tag1"] = TagMap{
|
|
"tag2": &Tag{
|
|
Name: "tag2",
|
|
Cum: 20,
|
|
Flat: 20,
|
|
Unit: "ms",
|
|
},
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
ComposeDot(&buf, g, a, c)
|
|
|
|
compareGraphs(t, buf.Bytes(), "compose5.dot")
|
|
}
|
|
|
|
func TestComposeWithEmptyGraph(t *testing.T) {
|
|
g := &Graph{}
|
|
a, c := baseAttrsAndConfig()
|
|
|
|
var buf bytes.Buffer
|
|
ComposeDot(&buf, g, a, c)
|
|
|
|
compareGraphs(t, buf.Bytes(), "compose4.dot")
|
|
}
|
|
|
|
func TestComposeWithStandardGraphAndURL(t *testing.T) {
|
|
g := baseGraph()
|
|
a, c := baseAttrsAndConfig()
|
|
c.LegendURL = "http://example.com"
|
|
|
|
var buf bytes.Buffer
|
|
ComposeDot(&buf, g, a, c)
|
|
|
|
compareGraphs(t, buf.Bytes(), "compose6.dot")
|
|
}
|
|
|
|
func baseGraph() *Graph {
|
|
src := &Node{
|
|
Info: NodeInfo{Name: "src"},
|
|
Flat: 10,
|
|
Cum: 25,
|
|
In: make(EdgeMap),
|
|
Out: make(EdgeMap),
|
|
LabelTags: make(TagMap),
|
|
NumericTags: make(map[string]TagMap),
|
|
}
|
|
dest := &Node{
|
|
Info: NodeInfo{Name: "dest"},
|
|
Flat: 15,
|
|
Cum: 25,
|
|
In: make(EdgeMap),
|
|
Out: make(EdgeMap),
|
|
LabelTags: make(TagMap),
|
|
NumericTags: make(map[string]TagMap),
|
|
}
|
|
edge := &Edge{
|
|
Src: src,
|
|
Dest: dest,
|
|
Weight: 10,
|
|
}
|
|
src.Out[dest] = edge
|
|
src.In[src] = edge
|
|
return &Graph{
|
|
Nodes: Nodes{
|
|
src,
|
|
dest,
|
|
},
|
|
}
|
|
}
|
|
|
|
func baseAttrsAndConfig() (*DotAttributes, *DotConfig) {
|
|
a := &DotAttributes{
|
|
Nodes: make(map[*Node]*DotNodeAttributes),
|
|
}
|
|
c := &DotConfig{
|
|
Title: "testtitle",
|
|
Labels: []string{"label1", "label2"},
|
|
Total: 100,
|
|
FormatValue: func(v int64) string {
|
|
return strconv.FormatInt(v, 10)
|
|
},
|
|
}
|
|
return a, c
|
|
}
|
|
|
|
func compareGraphs(t *testing.T, got []byte, wantFile string) {
|
|
wantFile = filepath.Join("testdata", wantFile)
|
|
want, err := ioutil.ReadFile(wantFile)
|
|
if err != nil {
|
|
t.Fatalf("error reading test file %s: %v", wantFile, err)
|
|
}
|
|
|
|
if string(got) != string(want) {
|
|
d, err := proftest.Diff(got, want)
|
|
if err != nil {
|
|
t.Fatalf("error finding diff: %v", err)
|
|
}
|
|
t.Errorf("Compose incorrectly wrote %s", string(d))
|
|
if *updateFlag {
|
|
err := ioutil.WriteFile(wantFile, got, 0644)
|
|
if err != nil {
|
|
t.Errorf("failed to update the golden file %q: %v", wantFile, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNodeletCountCapping(t *testing.T) {
|
|
labelTags := make(TagMap)
|
|
for i := 0; i < 10; i++ {
|
|
name := fmt.Sprintf("tag-%d", i)
|
|
labelTags[name] = &Tag{
|
|
Name: name,
|
|
Flat: 10,
|
|
Cum: 10,
|
|
}
|
|
}
|
|
numTags := make(TagMap)
|
|
for i := 0; i < 10; i++ {
|
|
name := fmt.Sprintf("num-tag-%d", i)
|
|
numTags[name] = &Tag{
|
|
Name: name,
|
|
Unit: "mb",
|
|
Value: 16,
|
|
Flat: 10,
|
|
Cum: 10,
|
|
}
|
|
}
|
|
node1 := &Node{
|
|
Info: NodeInfo{Name: "node1-with-tags"},
|
|
Flat: 10,
|
|
Cum: 10,
|
|
NumericTags: map[string]TagMap{"": numTags},
|
|
LabelTags: labelTags,
|
|
}
|
|
node2 := &Node{
|
|
Info: NodeInfo{Name: "node2"},
|
|
Flat: 15,
|
|
Cum: 15,
|
|
}
|
|
node3 := &Node{
|
|
Info: NodeInfo{Name: "node3"},
|
|
Flat: 15,
|
|
Cum: 15,
|
|
}
|
|
g := &Graph{
|
|
Nodes: Nodes{
|
|
node1,
|
|
node2,
|
|
node3,
|
|
},
|
|
}
|
|
for n := 1; n <= 3; n++ {
|
|
input := maxNodelets + n
|
|
if got, want := len(g.SelectTopNodes(input, true)), n; got != want {
|
|
t.Errorf("SelectTopNodes(%d): got %d nodes, want %d", input, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMultilinePrintableName(t *testing.T) {
|
|
ni := &NodeInfo{
|
|
Name: "test1.test2::test3",
|
|
File: "src/file.cc",
|
|
Address: 123,
|
|
Lineno: 999,
|
|
}
|
|
|
|
want := fmt.Sprintf(`%016x\ntest1\ntest2\ntest3\nfile.cc:999\n`, 123)
|
|
if got := multilinePrintableName(ni); got != want {
|
|
t.Errorf("multilinePrintableName(%#v) == %q, want %q", ni, got, want)
|
|
}
|
|
}
|
|
|
|
func TestTagCollapse(t *testing.T) {
|
|
|
|
makeTag := func(name, unit string, value, flat, cum int64) *Tag {
|
|
return &Tag{name, unit, value, flat, 0, cum, 0}
|
|
}
|
|
|
|
tagSource := []*Tag{
|
|
makeTag("12mb", "mb", 12, 100, 100),
|
|
makeTag("1kb", "kb", 1, 1, 1),
|
|
makeTag("1mb", "mb", 1, 1000, 1000),
|
|
makeTag("2048mb", "mb", 2048, 1000, 1000),
|
|
makeTag("1b", "b", 1, 100, 100),
|
|
makeTag("2b", "b", 2, 100, 100),
|
|
makeTag("7b", "b", 7, 100, 100),
|
|
}
|
|
|
|
tagWant := [][]*Tag{
|
|
{
|
|
makeTag("1B..2GB", "", 0, 2401, 2401),
|
|
},
|
|
{
|
|
makeTag("2GB", "", 0, 1000, 1000),
|
|
makeTag("1B..12MB", "", 0, 1401, 1401),
|
|
},
|
|
{
|
|
makeTag("2GB", "", 0, 1000, 1000),
|
|
makeTag("12MB", "", 0, 100, 100),
|
|
makeTag("1B..1MB", "", 0, 1301, 1301),
|
|
},
|
|
{
|
|
makeTag("2GB", "", 0, 1000, 1000),
|
|
makeTag("1MB", "", 0, 1000, 1000),
|
|
makeTag("2B..1kB", "", 0, 201, 201),
|
|
makeTag("1B", "", 0, 100, 100),
|
|
makeTag("12MB", "", 0, 100, 100),
|
|
},
|
|
}
|
|
|
|
for _, tc := range tagWant {
|
|
var got, want []*Tag
|
|
b := builder{nil, &DotAttributes{}, &DotConfig{}}
|
|
got = b.collapsedTags(tagSource, len(tc), true)
|
|
want = SortTags(tc, true)
|
|
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Errorf("collapse to %d, got:\n%v\nwant:\n%v", len(tc), tagString(got), tagString(want))
|
|
}
|
|
}
|
|
}
|
|
|
|
func tagString(t []*Tag) string {
|
|
var ret []string
|
|
for _, s := range t {
|
|
ret = append(ret, fmt.Sprintln(s))
|
|
}
|
|
return strings.Join(ret, ":")
|
|
}
|