golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive_test.go (about)

     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  
    15  package driver
    16  
    17  import (
    18  	"fmt"
    19  	"io"
    20  	"math/rand"
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/google/pprof/internal/plugin"
    25  	"github.com/google/pprof/internal/report"
    26  	"github.com/google/pprof/profile"
    27  )
    28  
    29  func TestShell(t *testing.T) {
    30  	p := &profile.Profile{}
    31  	generateReportWrapper = checkValue
    32  	defer func() { generateReportWrapper = generateReport }()
    33  
    34  	// Use test commands and variables to exercise interactive processing
    35  	var savedCommands commands
    36  	savedCommands, pprofCommands = pprofCommands, testCommands
    37  	defer func() { pprofCommands = savedCommands }()
    38  
    39  	savedVariables := pprofVariables
    40  	defer func() { pprofVariables = savedVariables }()
    41  
    42  	// Random interleave of independent scripts
    43  	pprofVariables = testVariables(savedVariables)
    44  	o := setDefaults(nil)
    45  	o.UI = newUI(t, interleave(script, 0))
    46  	if err := interactive(p, o); err != nil {
    47  		t.Error("first attempt:", err)
    48  	}
    49  	// Random interleave of independent scripts
    50  	pprofVariables = testVariables(savedVariables)
    51  	o.UI = newUI(t, interleave(script, 1))
    52  	if err := interactive(p, o); err != nil {
    53  		t.Error("second attempt:", err)
    54  	}
    55  
    56  	// Random interleave of independent scripts with shortcuts
    57  	pprofVariables = testVariables(savedVariables)
    58  	var scScript []string
    59  	pprofShortcuts, scScript = makeShortcuts(interleave(script, 2), 1)
    60  	o.UI = newUI(t, scScript)
    61  	if err := interactive(p, o); err != nil {
    62  		t.Error("first shortcut attempt:", err)
    63  	}
    64  
    65  	// Random interleave of independent scripts with shortcuts
    66  	pprofVariables = testVariables(savedVariables)
    67  	pprofShortcuts, scScript = makeShortcuts(interleave(script, 1), 2)
    68  	o.UI = newUI(t, scScript)
    69  	if err := interactive(p, o); err != nil {
    70  		t.Error("second shortcut attempt:", err)
    71  	}
    72  
    73  	// Verify propagation of IO errors
    74  	pprofVariables = testVariables(savedVariables)
    75  	o.UI = newUI(t, []string{"**error**"})
    76  	if err := interactive(p, o); err == nil {
    77  		t.Error("expected IO error, got nil")
    78  	}
    79  
    80  }
    81  
    82  var testCommands = commands{
    83  	"check": &command{report.Raw, nil, nil, true, "", ""},
    84  }
    85  
    86  func testVariables(base variables) variables {
    87  	v := base.makeCopy()
    88  
    89  	v["b"] = &variable{boolKind, "f", "", ""}
    90  	v["bb"] = &variable{boolKind, "f", "", ""}
    91  	v["i"] = &variable{intKind, "0", "", ""}
    92  	v["ii"] = &variable{intKind, "0", "", ""}
    93  	v["f"] = &variable{floatKind, "0", "", ""}
    94  	v["ff"] = &variable{floatKind, "0", "", ""}
    95  	v["s"] = &variable{stringKind, "", "", ""}
    96  	v["ss"] = &variable{stringKind, "", "", ""}
    97  
    98  	v["ta"] = &variable{boolKind, "f", "radio", ""}
    99  	v["tb"] = &variable{boolKind, "f", "radio", ""}
   100  	v["tc"] = &variable{boolKind, "t", "radio", ""}
   101  
   102  	return v
   103  }
   104  
   105  // script contains sequences of commands to be executed for testing. Commands
   106  // are split by semicolon and interleaved randomly, so they must be
   107  // independent from each other.
   108  var script = []string{
   109  	"bb=true;bb=false;check bb=false;bb=yes;check bb=true",
   110  	"b=1;check b=true;b=n;check b=false",
   111  	"i=-1;i=-2;check i=-2;i=999999;check i=999999",
   112  	"check ii=0;ii=-1;check ii=-1;ii=100;check ii=100",
   113  	"f=-1;f=-2.5;check f=-2.5;f=0.0001;check f=0.0001",
   114  	"check ff=0;ff=-1.01;check ff=-1.01;ff=100;check ff=100",
   115  	"s=one;s=two;check s=two",
   116  	"ss=tree;check ss=tree;ss=;check ss;ss=forest;check ss=forest",
   117  	"ta=true;check ta=true;check tb=false;check tc=false;tb=1;check tb=true;check ta=false;check tc=false;tc=yes;check tb=false;check ta=false;check tc=true",
   118  }
   119  
   120  func makeShortcuts(input []string, seed int) (shortcuts, []string) {
   121  	rand.Seed(int64(seed))
   122  
   123  	s := shortcuts{}
   124  	var output, chunk []string
   125  	for _, l := range input {
   126  		chunk = append(chunk, l)
   127  		switch rand.Intn(3) {
   128  		case 0:
   129  			// Create a macro for commands in 'chunk'.
   130  			macro := fmt.Sprintf("alias%d", len(s))
   131  			s[macro] = chunk
   132  			output = append(output, macro)
   133  			chunk = nil
   134  		case 1:
   135  			// Append commands in 'chunk' by themselves.
   136  			output = append(output, chunk...)
   137  			chunk = nil
   138  		case 2:
   139  			// Accumulate commands into 'chunk'
   140  		}
   141  	}
   142  	output = append(output, chunk...)
   143  	return s, output
   144  }
   145  
   146  func newUI(t *testing.T, input []string) plugin.UI {
   147  	return &testUI{
   148  		t:     t,
   149  		input: input,
   150  	}
   151  }
   152  
   153  type testUI struct {
   154  	t     *testing.T
   155  	input []string
   156  	index int
   157  }
   158  
   159  func (ui *testUI) ReadLine(_ string) (string, error) {
   160  	if ui.index >= len(ui.input) {
   161  		return "", io.EOF
   162  	}
   163  	input := ui.input[ui.index]
   164  	if input == "**error**" {
   165  		return "", fmt.Errorf("Error: %s", input)
   166  	}
   167  	ui.index++
   168  	return input, nil
   169  }
   170  
   171  func (ui *testUI) Print(args ...interface{}) {
   172  }
   173  
   174  func (ui *testUI) PrintErr(args ...interface{}) {
   175  	output := fmt.Sprint(args)
   176  	if output != "" {
   177  		ui.t.Error(output)
   178  	}
   179  }
   180  
   181  func (ui *testUI) IsTerminal() bool {
   182  	return false
   183  }
   184  
   185  func (ui *testUI) SetAutoComplete(func(string) string) {
   186  }
   187  
   188  func checkValue(p *profile.Profile, cmd []string, vars variables, o *plugin.Options) error {
   189  	if len(cmd) != 2 {
   190  		return fmt.Errorf("expected len(cmd)==2, got %v", cmd)
   191  	}
   192  
   193  	input := cmd[1]
   194  	args := strings.SplitN(input, "=", 2)
   195  	if len(args) == 0 {
   196  		return fmt.Errorf("unexpected empty input")
   197  	}
   198  	name, value := args[0], ""
   199  	if len(args) == 2 {
   200  		value = args[1]
   201  	}
   202  
   203  	gotv := vars[name]
   204  	if gotv == nil {
   205  		return fmt.Errorf("Could not find variable named %s", name)
   206  	}
   207  
   208  	if got := gotv.stringValue(); got != value {
   209  		return fmt.Errorf("Variable %s, want %s, got %s", name, value, got)
   210  	}
   211  	return nil
   212  }
   213  
   214  func interleave(input []string, seed int) []string {
   215  	var inputs [][]string
   216  	for _, s := range input {
   217  		inputs = append(inputs, strings.Split(s, ";"))
   218  	}
   219  	rand.Seed(int64(seed))
   220  	var output []string
   221  	for len(inputs) > 0 {
   222  		next := rand.Intn(len(inputs))
   223  		output = append(output, inputs[next][0])
   224  		if tail := inputs[next][1:]; len(tail) > 0 {
   225  			inputs[next] = tail
   226  		} else {
   227  			inputs = append(inputs[:next], inputs[next+1:]...)
   228  		}
   229  	}
   230  	return output
   231  }
   232  
   233  func TestInteractiveCommands(t *testing.T) {
   234  	type interactiveTestcase struct {
   235  		input string
   236  		want  map[string]string
   237  	}
   238  
   239  	testcases := []interactiveTestcase{
   240  		{
   241  			"top 10 --cum focus1 -ignore focus2",
   242  			map[string]string{
   243  				"functions": "true",
   244  				"nodecount": "10",
   245  				"cum":       "true",
   246  				"focus":     "focus1|focus2",
   247  				"ignore":    "ignore",
   248  			},
   249  		},
   250  		{
   251  			"top10 --cum focus1 -ignore focus2",
   252  			map[string]string{
   253  				"functions": "true",
   254  				"nodecount": "10",
   255  				"cum":       "true",
   256  				"focus":     "focus1|focus2",
   257  				"ignore":    "ignore",
   258  			},
   259  		},
   260  		{
   261  			"dot",
   262  			map[string]string{
   263  				"functions": "true",
   264  				"nodecount": "80",
   265  				"cum":       "false",
   266  			},
   267  		},
   268  		{
   269  			"tags   -ignore1 -ignore2 focus1 >out",
   270  			map[string]string{
   271  				"functions": "true",
   272  				"nodecount": "80",
   273  				"cum":       "false",
   274  				"output":    "out",
   275  				"tagfocus":  "focus1",
   276  				"tagignore": "ignore1|ignore2",
   277  			},
   278  		},
   279  		{
   280  			"weblist  find -test",
   281  			map[string]string{
   282  				"functions":        "false",
   283  				"addressnoinlines": "true",
   284  				"nodecount":        "0",
   285  				"cum":              "false",
   286  				"flat":             "true",
   287  				"ignore":           "test",
   288  			},
   289  		},
   290  		{
   291  			"callgrind   fun -ignore  >out",
   292  			map[string]string{
   293  				"functions": "false",
   294  				"addresses": "true",
   295  				"nodecount": "0",
   296  				"cum":       "false",
   297  				"flat":      "true",
   298  				"output":    "out",
   299  			},
   300  		},
   301  		{
   302  			"999",
   303  			nil, // Error
   304  		},
   305  	}
   306  
   307  	for _, tc := range testcases {
   308  		cmd, vars, err := parseCommandLine(strings.Fields(tc.input))
   309  		if tc.want == nil && err != nil {
   310  			// Error expected
   311  			continue
   312  		}
   313  		if err != nil {
   314  			t.Errorf("failed on %q: %v", tc.input, err)
   315  			continue
   316  		}
   317  		vars = applyCommandOverrides(cmd, vars)
   318  
   319  		for n, want := range tc.want {
   320  			if got := vars[n].stringValue(); got != want {
   321  				t.Errorf("failed on %q, cmd=%q, %s got %s, want %s", tc.input, cmd, n, got, want)
   322  			}
   323  		}
   324  	}
   325  }