mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-12-24 13:48:04 +08:00
271 lines
7.7 KiB
Go
271 lines
7.7 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 driver
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"strings"
|
|
"testing"
|
|
|
|
"m7s.live/v5/plugin/debug/pkg/internal/plugin"
|
|
"m7s.live/v5/plugin/debug/pkg/internal/proftest"
|
|
"m7s.live/v5/plugin/debug/pkg/internal/report"
|
|
"m7s.live/v5/plugin/debug/pkg/internal/transport"
|
|
"m7s.live/v5/plugin/debug/pkg/profile"
|
|
)
|
|
|
|
func TestShell(t *testing.T) {
|
|
p := &profile.Profile{}
|
|
generateReportWrapper = checkValue
|
|
defer func() { generateReportWrapper = generateReport }()
|
|
|
|
// Use test commands and variables to exercise interactive processing
|
|
var savedCommands commands
|
|
savedCommands, pprofCommands = pprofCommands, testCommands
|
|
defer func() { pprofCommands = savedCommands }()
|
|
|
|
savedConfig := currentConfig()
|
|
defer setCurrentConfig(savedConfig)
|
|
|
|
shortcuts1, scScript1 := makeShortcuts(interleave(script, 2), 1)
|
|
shortcuts2, scScript2 := makeShortcuts(interleave(script, 1), 2)
|
|
|
|
var testcases = []struct {
|
|
name string
|
|
input []string
|
|
shortcuts shortcuts
|
|
allowRx string
|
|
numAllowRxMatches int
|
|
propagateError bool
|
|
}{
|
|
{"Random interleave of independent scripts 1", interleave(script, 0), pprofShortcuts, "", 0, false},
|
|
{"Random interleave of independent scripts 2", interleave(script, 1), pprofShortcuts, "", 0, false},
|
|
{"Random interleave of independent scripts with shortcuts 1", scScript1, shortcuts1, "", 0, false},
|
|
{"Random interleave of independent scripts with shortcuts 2", scScript2, shortcuts2, "", 0, false},
|
|
{"Group with invalid value", []string{"sort=this"}, pprofShortcuts, `invalid "sort" value`, 1, false},
|
|
{"No special value provided for the option", []string{"sample_index"}, pprofShortcuts, `please specify a value, e.g. sample_index=<val>`, 1, false},
|
|
{"No string value provided for the option", []string{"focus"}, pprofShortcuts, `please specify a value, e.g. focus=<val>`, 1, false},
|
|
{"No float value provided for the option", []string{"divide_by"}, pprofShortcuts, `please specify a value, e.g. divide_by=<val>`, 1, false},
|
|
{"Helpful input format reminder", []string{"sample_index 0"}, pprofShortcuts, `did you mean: sample_index=0`, 1, false},
|
|
{"Verify propagation of IO errors", []string{"**error**"}, pprofShortcuts, "", 0, true},
|
|
}
|
|
|
|
o := setDefaults(&plugin.Options{HTTPTransport: transport.New(nil)})
|
|
for _, tc := range testcases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
setCurrentConfig(savedConfig)
|
|
pprofShortcuts = tc.shortcuts
|
|
ui := &proftest.TestUI{
|
|
T: t,
|
|
Input: tc.input,
|
|
AllowRx: tc.allowRx,
|
|
}
|
|
o.UI = ui
|
|
|
|
err := interactive(p, o)
|
|
if (tc.propagateError && err == nil) || (!tc.propagateError && err != nil) {
|
|
t.Errorf("%s: %v", tc.name, err)
|
|
}
|
|
|
|
// Confirm error message written out once.
|
|
if tc.numAllowRxMatches != ui.NumAllowRxMatches {
|
|
t.Errorf("want error message to be printed %d time(s), got %d",
|
|
tc.numAllowRxMatches, ui.NumAllowRxMatches)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
var testCommands = commands{
|
|
"check": &command{report.Raw, nil, nil, true, "", ""},
|
|
}
|
|
|
|
// script contains sequences of commands to be executed for testing. Commands
|
|
// are split by semicolon and interleaved randomly, so they must be
|
|
// independent from each other.
|
|
var script = []string{
|
|
"call_tree=true;call_tree=false;check call_tree=false;call_tree=yes;check call_tree=true",
|
|
"mean=1;check mean=true;mean=n;check mean=false",
|
|
"nodecount=-1;nodecount=-2;check nodecount=-2;nodecount=999999;check nodecount=999999",
|
|
"nodefraction=-1;nodefraction=-2.5;check nodefraction=-2.5;nodefraction=0.0001;check nodefraction=0.0001",
|
|
"focus=one;focus=two;check focus=two",
|
|
"flat=true;check sort=flat;cum=1;check sort=cum",
|
|
}
|
|
|
|
func makeShortcuts(input []string, seed int64) (shortcuts, []string) {
|
|
rand := rand.New(rand.NewSource(seed))
|
|
|
|
s := shortcuts{}
|
|
var output, chunk []string
|
|
for _, l := range input {
|
|
chunk = append(chunk, l)
|
|
switch rand.Intn(3) {
|
|
case 0:
|
|
// Create a macro for commands in 'chunk'.
|
|
macro := fmt.Sprintf("alias%d", len(s))
|
|
s[macro] = chunk
|
|
output = append(output, macro)
|
|
chunk = nil
|
|
case 1:
|
|
// Append commands in 'chunk' by themselves.
|
|
output = append(output, chunk...)
|
|
chunk = nil
|
|
case 2:
|
|
// Accumulate commands into 'chunk'
|
|
}
|
|
}
|
|
output = append(output, chunk...)
|
|
return s, output
|
|
}
|
|
|
|
func checkValue(p *profile.Profile, cmd []string, cfg config, o *plugin.Options) error {
|
|
if len(cmd) != 2 {
|
|
return fmt.Errorf("expected len(cmd)==2, got %v", cmd)
|
|
}
|
|
|
|
input := cmd[1]
|
|
args := strings.SplitN(input, "=", 2)
|
|
if len(args) == 0 {
|
|
return fmt.Errorf("unexpected empty input")
|
|
}
|
|
name, value := args[0], ""
|
|
if len(args) == 2 {
|
|
value = args[1]
|
|
}
|
|
|
|
f, ok := configFieldMap[name]
|
|
if !ok {
|
|
return fmt.Errorf("Could not find variable named %s", name)
|
|
}
|
|
|
|
if got := cfg.get(f); got != value {
|
|
return fmt.Errorf("Variable %s, want %s, got %s", name, value, got)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func interleave(input []string, seed int64) []string {
|
|
var inputs [][]string
|
|
for _, s := range input {
|
|
inputs = append(inputs, strings.Split(s, ";"))
|
|
}
|
|
rand := rand.New(rand.NewSource(seed))
|
|
var output []string
|
|
for len(inputs) > 0 {
|
|
next := rand.Intn(len(inputs))
|
|
output = append(output, inputs[next][0])
|
|
if tail := inputs[next][1:]; len(tail) > 0 {
|
|
inputs[next] = tail
|
|
} else {
|
|
inputs = append(inputs[:next], inputs[next+1:]...)
|
|
}
|
|
}
|
|
return output
|
|
}
|
|
|
|
func TestInteractiveCommands(t *testing.T) {
|
|
type interactiveTestcase struct {
|
|
input string
|
|
want map[string]string
|
|
}
|
|
|
|
testcases := []interactiveTestcase{
|
|
{
|
|
"top 10 --cum focus1 -ignore focus2",
|
|
map[string]string{
|
|
"nodecount": "10",
|
|
"sort": "cum",
|
|
"focus": "focus1|focus2",
|
|
"ignore": "ignore",
|
|
},
|
|
},
|
|
{
|
|
"top10 --cum focus1 -ignore focus2",
|
|
map[string]string{
|
|
"nodecount": "10",
|
|
"sort": "cum",
|
|
"focus": "focus1|focus2",
|
|
"ignore": "ignore",
|
|
},
|
|
},
|
|
{
|
|
"dot",
|
|
map[string]string{
|
|
"nodecount": "80",
|
|
"sort": "flat",
|
|
},
|
|
},
|
|
{
|
|
"tags -ignore1 -ignore2 focus1 >out",
|
|
map[string]string{
|
|
"nodecount": "80",
|
|
"sort": "flat",
|
|
"output": "out",
|
|
"tagfocus": "focus1",
|
|
"tagignore": "ignore1|ignore2",
|
|
},
|
|
},
|
|
{
|
|
"weblist find -test",
|
|
map[string]string{
|
|
"granularity": "addresses",
|
|
"noinlines": "false",
|
|
"nodecount": "0",
|
|
"sort": "flat",
|
|
"ignore": "test",
|
|
},
|
|
},
|
|
{
|
|
"callgrind fun -ignore >out",
|
|
map[string]string{
|
|
"granularity": "addresses",
|
|
"nodecount": "0",
|
|
"sort": "flat",
|
|
"output": "out",
|
|
},
|
|
},
|
|
{
|
|
"999",
|
|
nil, // Error
|
|
},
|
|
}
|
|
|
|
for _, tc := range testcases {
|
|
cmd, cfg, err := parseCommandLine(strings.Fields(tc.input))
|
|
if tc.want == nil && err != nil {
|
|
// Error expected
|
|
continue
|
|
}
|
|
if err != nil {
|
|
t.Errorf("failed on %q: %v", tc.input, err)
|
|
continue
|
|
}
|
|
|
|
// Get report output format
|
|
c := pprofCommands[cmd[0]]
|
|
if c == nil {
|
|
t.Fatalf("unexpected nil command")
|
|
}
|
|
cfg = applyCommandOverrides(cmd[0], c.format, cfg)
|
|
|
|
for n, want := range tc.want {
|
|
if got := cfg.get(configFieldMap[n]); got != want {
|
|
t.Errorf("failed on %q, cmd=%q, %s got %s, want %s", tc.input, cmd, n, got, want)
|
|
}
|
|
}
|
|
}
|
|
}
|