golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_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/ioutil"
    20  	"net/http"
    21  	"net/url"
    22  	"os"
    23  	"path/filepath"
    24  	"reflect"
    25  	"regexp"
    26  	"runtime"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/google/pprof/internal/plugin"
    31  	"github.com/google/pprof/internal/proftest"
    32  	"github.com/google/pprof/profile"
    33  )
    34  
    35  func TestSymbolizationPath(t *testing.T) {
    36  	if runtime.GOOS == "windows" {
    37  		t.Skip("test assumes Unix paths")
    38  	}
    39  
    40  	// Save environment variables to restore after test
    41  	saveHome := os.Getenv(homeEnv())
    42  	savePath := os.Getenv("PPROF_BINARY_PATH")
    43  
    44  	tempdir, err := ioutil.TempDir("", "home")
    45  	if err != nil {
    46  		t.Fatal("creating temp dir: ", err)
    47  	}
    48  	defer os.RemoveAll(tempdir)
    49  	os.MkdirAll(filepath.Join(tempdir, "pprof", "binaries", "abcde10001"), 0700)
    50  	os.Create(filepath.Join(tempdir, "pprof", "binaries", "abcde10001", "binary"))
    51  
    52  	obj := testObj{tempdir}
    53  	os.Setenv(homeEnv(), tempdir)
    54  	for _, tc := range []struct {
    55  		env, file, buildID, want string
    56  		msgCount                 int
    57  	}{
    58  		{"", "/usr/bin/binary", "", "/usr/bin/binary", 0},
    59  		{"", "/usr/bin/binary", "fedcb10000", "/usr/bin/binary", 0},
    60  		{"/usr", "/bin/binary", "", "/usr/bin/binary", 0},
    61  		{"", "/prod/path/binary", "abcde10001", filepath.Join(tempdir, "pprof/binaries/abcde10001/binary"), 0},
    62  		{"/alternate/architecture", "/usr/bin/binary", "", "/alternate/architecture/binary", 0},
    63  		{"/alternate/architecture", "/usr/bin/binary", "abcde10001", "/alternate/architecture/binary", 0},
    64  		{"/nowhere:/alternate/architecture", "/usr/bin/binary", "fedcb10000", "/usr/bin/binary", 1},
    65  		{"/nowhere:/alternate/architecture", "/usr/bin/binary", "abcde10002", "/usr/bin/binary", 1},
    66  	} {
    67  		os.Setenv("PPROF_BINARY_PATH", tc.env)
    68  		p := &profile.Profile{
    69  			Mapping: []*profile.Mapping{
    70  				{
    71  					File:    tc.file,
    72  					BuildID: tc.buildID,
    73  				},
    74  			},
    75  		}
    76  		s := &source{}
    77  		locateBinaries(p, s, obj, &proftest.TestUI{T: t, Ignore: tc.msgCount})
    78  		if file := p.Mapping[0].File; file != tc.want {
    79  			t.Errorf("%s:%s:%s, want %s, got %s", tc.env, tc.file, tc.buildID, tc.want, file)
    80  		}
    81  	}
    82  	os.Setenv(homeEnv(), saveHome)
    83  	os.Setenv("PPROF_BINARY_PATH", savePath)
    84  }
    85  
    86  func TestCollectMappingSources(t *testing.T) {
    87  	const startAddress uint64 = 0x40000
    88  	const url = "http://example.com"
    89  	for _, tc := range []struct {
    90  		file, buildID string
    91  		want          plugin.MappingSources
    92  	}{
    93  		{"/usr/bin/binary", "buildId", mappingSources("buildId", url, startAddress)},
    94  		{"/usr/bin/binary", "", mappingSources("/usr/bin/binary", url, startAddress)},
    95  		{"", "", mappingSources(url, url, startAddress)},
    96  	} {
    97  		p := &profile.Profile{
    98  			Mapping: []*profile.Mapping{
    99  				{
   100  					File:    tc.file,
   101  					BuildID: tc.buildID,
   102  					Start:   startAddress,
   103  				},
   104  			},
   105  		}
   106  		got := collectMappingSources(p, url)
   107  		if !reflect.DeepEqual(got, tc.want) {
   108  			t.Errorf("%s:%s, want %v, got %v", tc.file, tc.buildID, tc.want, got)
   109  		}
   110  	}
   111  }
   112  
   113  func TestUnsourceMappings(t *testing.T) {
   114  	for _, tc := range []struct {
   115  		file, buildID, want string
   116  	}{
   117  		{"/usr/bin/binary", "buildId", "/usr/bin/binary"},
   118  		{"http://example.com", "", ""},
   119  	} {
   120  		p := &profile.Profile{
   121  			Mapping: []*profile.Mapping{
   122  				{
   123  					File:    tc.file,
   124  					BuildID: tc.buildID,
   125  				},
   126  			},
   127  		}
   128  		unsourceMappings(p)
   129  		if got := p.Mapping[0].File; got != tc.want {
   130  			t.Errorf("%s:%s, want %s, got %s", tc.file, tc.buildID, tc.want, got)
   131  		}
   132  	}
   133  }
   134  
   135  type testObj struct {
   136  	home string
   137  }
   138  
   139  func (o testObj) Open(file string, start, limit, offset uint64) (plugin.ObjFile, error) {
   140  	switch file {
   141  	case "/alternate/architecture/binary":
   142  		return testFile{file, "abcde10001"}, nil
   143  	case "/usr/bin/binary":
   144  		return testFile{file, "fedcb10000"}, nil
   145  	case filepath.Join(o.home, "pprof/binaries/abcde10001/binary"):
   146  		return testFile{file, "abcde10001"}, nil
   147  	}
   148  	return nil, fmt.Errorf("not found: %s", file)
   149  }
   150  func (testObj) Demangler(_ string) func(names []string) (map[string]string, error) {
   151  	return func(names []string) (map[string]string, error) { return nil, nil }
   152  }
   153  func (testObj) Disasm(file string, start, end uint64) ([]plugin.Inst, error) { return nil, nil }
   154  
   155  type testFile struct{ name, buildID string }
   156  
   157  func (f testFile) Name() string                                               { return f.name }
   158  func (testFile) Base() uint64                                                 { return 0 }
   159  func (f testFile) BuildID() string                                            { return f.buildID }
   160  func (testFile) SourceLine(addr uint64) ([]plugin.Frame, error)               { return nil, nil }
   161  func (testFile) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) { return nil, nil }
   162  func (testFile) Close() error                                                 { return nil }
   163  
   164  func TestFetch(t *testing.T) {
   165  	const path = "testdata/"
   166  
   167  	// Intercept http.Get calls from HTTPFetcher.
   168  	httpGet = stubHTTPGet
   169  
   170  	type testcase struct {
   171  		source, execName string
   172  	}
   173  
   174  	for _, tc := range []testcase{
   175  		{path + "go.crc32.cpu", ""},
   176  		{path + "go.nomappings.crash", "/bin/gotest.exe"},
   177  		{"http://localhost/profile?file=cppbench.cpu", ""},
   178  	} {
   179  		p, _, _, err := grabProfile(&source{ExecName: tc.execName}, tc.source, 0, nil, testObj{}, &proftest.TestUI{T: t})
   180  		if err != nil {
   181  			t.Fatalf("%s: %s", tc.source, err)
   182  		}
   183  		if len(p.Sample) == 0 {
   184  			t.Errorf("%s: want non-zero samples", tc.source)
   185  		}
   186  		if e := tc.execName; e != "" {
   187  			switch {
   188  			case len(p.Mapping) == 0 || p.Mapping[0] == nil:
   189  				t.Errorf("%s: want mapping[0].execName == %s, got no mappings", tc.source, e)
   190  			case p.Mapping[0].File != e:
   191  				t.Errorf("%s: want mapping[0].execName == %s, got %s", tc.source, e, p.Mapping[0].File)
   192  			}
   193  		}
   194  	}
   195  }
   196  
   197  // mappingSources creates MappingSources map with a single item.
   198  func mappingSources(key, source string, start uint64) plugin.MappingSources {
   199  	return plugin.MappingSources{
   200  		key: []struct {
   201  			Source string
   202  			Start  uint64
   203  		}{
   204  			{Source: source, Start: start},
   205  		},
   206  	}
   207  }
   208  
   209  // stubHTTPGet intercepts a call to http.Get and rewrites it to use
   210  // "file://" to get the profile directly from a file.
   211  func stubHTTPGet(source string, _ time.Duration) (*http.Response, error) {
   212  	url, err := url.Parse(source)
   213  	if err != nil {
   214  		return nil, err
   215  	}
   216  
   217  	values := url.Query()
   218  	file := values.Get("file")
   219  
   220  	if file == "" {
   221  		return nil, fmt.Errorf("want .../file?profile, got %s", source)
   222  	}
   223  
   224  	t := &http.Transport{}
   225  	t.RegisterProtocol("file", http.NewFileTransport(http.Dir("testdata/")))
   226  
   227  	c := &http.Client{Transport: t}
   228  	return c.Get("file:///" + file)
   229  }