aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/cloud.google.com/go/cmd
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-06-13 20:23:21 +0200
committerDmitry Vyukov <dvyukov@google.com>2017-06-13 20:23:21 +0200
commitb41e96b421acda1761e9ba2ee17da16efad436cd (patch)
treeb6200bf1c3665161b6d76453bb56f7bd5ce32f42 /vendor/cloud.google.com/go/cmd
parentf58147fb5ea43427d38c2a4437f35647138fbf9d (diff)
vendor: switch from dep to godep
dep tool vendored too much code (100MB) including tests and unused packages. godep vendored significantly less (12MB) without tests and unused packages. The main advantage is that pre-Go1.9 toolchain does not run tests of all vendor packages now.
Diffstat (limited to 'vendor/cloud.google.com/go/cmd')
-rw-r--r--vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/debuglet.go450
-rw-r--r--vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints.go174
-rw-r--r--vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints_test.go168
-rw-r--r--vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client.go291
-rw-r--r--vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client_test.go254
-rw-r--r--vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector.go460
-rw-r--r--vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector_test.go418
7 files changed, 0 insertions, 2215 deletions
diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/debuglet.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/debuglet.go
deleted file mode 100644
index 6a8702c77..000000000
--- a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/debuglet.go
+++ /dev/null
@@ -1,450 +0,0 @@
-// Copyright 2016 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.
-
-// +build linux
-
-package main
-
-import (
- "encoding/json"
- "flag"
- "fmt"
- "io/ioutil"
- "log"
- "math/rand"
- "os"
- "sync"
- "time"
-
- "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints"
- debuglet "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller"
- "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector"
- "cloud.google.com/go/compute/metadata"
- "golang.org/x/debug"
- "golang.org/x/debug/local"
- "golang.org/x/net/context"
- "golang.org/x/oauth2"
- "golang.org/x/oauth2/google"
- cd "google.golang.org/api/clouddebugger/v2"
-)
-
-var (
- appModule = flag.String("appmodule", "", "Optional application module name.")
- appVersion = flag.String("appversion", "", "Optional application module version name.")
- sourceContextFile = flag.String("sourcecontext", "", "File containing JSON-encoded source context.")
- verbose = flag.Bool("v", false, "Output verbose log messages.")
- projectNumber = flag.String("projectnumber", "", "Project number."+
- " If this is not set, it is read from the GCP metadata server.")
- projectID = flag.String("projectid", "", "Project ID."+
- " If this is not set, it is read from the GCP metadata server.")
- serviceAccountFile = flag.String("serviceaccountfile", "", "File containing JSON service account credentials.")
-)
-
-const (
- maxCapturedStackFrames = 50
- maxCapturedVariables = 1000
-)
-
-func main() {
- flag.Usage = usage
- flag.Parse()
- args := flag.Args()
- if len(args) == 0 {
- // The user needs to supply the name of the executable to run.
- flag.Usage()
- return
- }
- if *projectNumber == "" {
- var err error
- *projectNumber, err = metadata.NumericProjectID()
- if err != nil {
- log.Print("Debuglet initialization: ", err)
- }
- }
- if *projectID == "" {
- var err error
- *projectID, err = metadata.ProjectID()
- if err != nil {
- log.Print("Debuglet initialization: ", err)
- }
- }
- sourceContexts, err := readSourceContextFile(*sourceContextFile)
- if err != nil {
- log.Print("Reading source context file: ", err)
- }
- var ts oauth2.TokenSource
- ctx := context.Background()
- if *serviceAccountFile != "" {
- if ts, err = serviceAcctTokenSource(ctx, *serviceAccountFile, cd.CloudDebuggerScope); err != nil {
- log.Fatalf("Error getting credentials from file %s: %v", *serviceAccountFile, err)
- }
- } else if ts, err = google.DefaultTokenSource(ctx, cd.CloudDebuggerScope); err != nil {
- log.Print("Error getting application default credentials for Cloud Debugger:", err)
- os.Exit(103)
- }
- c, err := debuglet.NewController(ctx, debuglet.Options{
- ProjectNumber: *projectNumber,
- ProjectID: *projectID,
- AppModule: *appModule,
- AppVersion: *appVersion,
- SourceContexts: sourceContexts,
- Verbose: *verbose,
- TokenSource: ts,
- })
- if err != nil {
- log.Fatal("Error connecting to Cloud Debugger: ", err)
- }
- prog, err := local.New(args[0])
- if err != nil {
- log.Fatal("Error loading program: ", err)
- }
- // Load the program, but don't actually start it running yet.
- if _, err = prog.Run(args[1:]...); err != nil {
- log.Fatal("Error loading program: ", err)
- }
- bs := breakpoints.NewBreakpointStore(prog)
-
- // Seed the random number generator.
- rand.Seed(time.Now().UnixNano())
-
- // Now we want to do two things: run the user's program, and start sending
- // List requests periodically to the Debuglet Controller to get breakpoints
- // to set.
- //
- // We want to give the Debuglet Controller a chance to give us breakpoints
- // before we start the program, otherwise we would miss any breakpoint
- // triggers that occur during program startup -- for example, a breakpoint on
- // the first line of main. But if the Debuglet Controller is not responding or
- // is returning errors, we don't want to delay starting the program
- // indefinitely.
- //
- // We pass a channel to breakpointListLoop, which will close it when the first
- // List call finishes. Then we wait until either the channel is closed or a
- // 5-second timer has finished before starting the program.
- ch := make(chan bool)
- // Start a goroutine that sends List requests to the Debuglet Controller, and
- // sets any breakpoints it gets back.
- go breakpointListLoop(ctx, c, bs, ch)
- // Wait until 5 seconds have passed or breakpointListLoop has closed ch.
- select {
- case <-time.After(5 * time.Second):
- case <-ch:
- }
- // Run the debuggee.
- programLoop(ctx, c, bs, prog)
-}
-
-// usage prints a usage message to stderr and exits.
-func usage() {
- me := "a.out"
- if len(os.Args) >= 1 {
- me = os.Args[0]
- }
- fmt.Fprintf(os.Stderr, "Usage of %s:\n", me)
- fmt.Fprintf(os.Stderr, "\t%s [flags...] -- <program name> args...\n", me)
- fmt.Fprintf(os.Stderr, "Flags:\n")
- flag.PrintDefaults()
- fmt.Fprintf(os.Stderr,
- "See https://cloud.google.com/tools/cloud-debugger/setting-up-on-compute-engine for more information.\n")
- os.Exit(2)
-}
-
-// readSourceContextFile reads a JSON-encoded source context from the given file.
-// It returns a non-empty slice on success.
-func readSourceContextFile(filename string) ([]*cd.SourceContext, error) {
- if filename == "" {
- return nil, nil
- }
- scJSON, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, fmt.Errorf("reading file %q: %v", filename, err)
- }
- var sc cd.SourceContext
- if err = json.Unmarshal(scJSON, &sc); err != nil {
- return nil, fmt.Errorf("parsing file %q: %v", filename, err)
- }
- return []*cd.SourceContext{&sc}, nil
-}
-
-// breakpointListLoop repeatedly calls the Debuglet Controller's List RPC, and
-// passes the results to the BreakpointStore so it can set and unset breakpoints
-// in the program.
-//
-// After the first List call finishes, ch is closed.
-func breakpointListLoop(ctx context.Context, c *debuglet.Controller, bs *breakpoints.BreakpointStore, first chan bool) {
- const (
- avgTimeBetweenCalls = time.Second
- errorDelay = 5 * time.Second
- )
-
- // randomDuration returns a random duration with expected value avg.
- randomDuration := func(avg time.Duration) time.Duration {
- return time.Duration(rand.Int63n(int64(2*avg + 1)))
- }
-
- var consecutiveFailures uint
-
- for {
- callStart := time.Now()
- resp, err := c.List(ctx)
- if err != nil && err != debuglet.ErrListUnchanged {
- log.Printf("Debuglet controller server error: %v", err)
- }
- if err == nil {
- bs.ProcessBreakpointList(resp.Breakpoints)
- }
-
- if first != nil {
- // We've finished one call to List and set any breakpoints we received.
- close(first)
- first = nil
- }
-
- // Asynchronously send updates for any breakpoints that caused an error when
- // the BreakpointStore tried to process them. We don't wait for the update
- // to finish before the program can exit, as we do for normal updates.
- errorBps := bs.ErrorBreakpoints()
- for _, bp := range errorBps {
- go func(bp *cd.Breakpoint) {
- if err := c.Update(ctx, bp.Id, bp); err != nil {
- log.Printf("Failed to send breakpoint update for %s: %s", bp.Id, err)
- }
- }(bp)
- }
-
- // Make the next call not too soon after the one we just did.
- delay := randomDuration(avgTimeBetweenCalls)
-
- // If the call returned an error other than ErrListUnchanged, wait longer.
- if err != nil && err != debuglet.ErrListUnchanged {
- // Wait twice as long after each consecutive failure, to a maximum of 16x.
- delay += randomDuration(errorDelay * (1 << consecutiveFailures))
- if consecutiveFailures < 4 {
- consecutiveFailures++
- }
- } else {
- consecutiveFailures = 0
- }
-
- // Sleep until we reach time callStart+delay. If we've already passed that
- // time, time.Sleep will return immediately -- this should be the common
- // case, since the server will delay responding to List for a while when
- // there are no changes to report.
- time.Sleep(callStart.Add(delay).Sub(time.Now()))
- }
-}
-
-// programLoop runs the program being debugged to completion. When a breakpoint's
-// conditions are satisfied, it sends an Update RPC to the Debuglet Controller.
-// The function returns when the program exits and all Update RPCs have finished.
-func programLoop(ctx context.Context, c *debuglet.Controller, bs *breakpoints.BreakpointStore, prog debug.Program) {
- var wg sync.WaitGroup
- for {
- // Run the program until it hits a breakpoint or exits.
- status, err := prog.Resume()
- if err != nil {
- break
- }
-
- // Get the breakpoints at this address whose conditions were satisfied,
- // and remove the ones that aren't logpoints.
- bps := bs.BreakpointsAtPC(status.PC)
- bps = bpsWithConditionSatisfied(bps, prog)
- for _, bp := range bps {
- if bp.Action != "LOG" {
- bs.RemoveBreakpoint(bp)
- }
- }
-
- if len(bps) == 0 {
- continue
- }
-
- // Evaluate expressions and get the stack.
- vc := valuecollector.NewCollector(prog, maxCapturedVariables)
- needStackFrames := false
- for _, bp := range bps {
- // If evaluating bp's condition didn't return an error, evaluate bp's
- // expressions, and later get the stack frames.
- if bp.Status == nil {
- bp.EvaluatedExpressions = expressionValues(bp.Expressions, prog, vc)
- needStackFrames = true
- }
- }
- var (
- stack []*cd.StackFrame
- stackFramesStatusMessage *cd.StatusMessage
- )
- if needStackFrames {
- stack, stackFramesStatusMessage = stackFrames(prog, vc)
- }
-
- // Read variable values from the program.
- variableTable := vc.ReadValues()
-
- // Start a goroutine to send updates to the Debuglet Controller or write
- // to logs, concurrently with resuming the program.
- // TODO: retry Update on failure.
- for _, bp := range bps {
- wg.Add(1)
- switch bp.Action {
- case "LOG":
- go func(format string, evaluatedExpressions []*cd.Variable) {
- s := valuecollector.LogString(format, evaluatedExpressions, variableTable)
- log.Print(s)
- wg.Done()
- }(bp.LogMessageFormat, bp.EvaluatedExpressions)
- bp.Status = nil
- bp.EvaluatedExpressions = nil
- default:
- go func(bp *cd.Breakpoint) {
- defer wg.Done()
- bp.IsFinalState = true
- if bp.Status == nil {
- // If evaluating bp's condition didn't return an error, include the
- // stack frames, variable table, and any status message produced when
- // getting the stack frames.
- bp.StackFrames = stack
- bp.VariableTable = variableTable
- bp.Status = stackFramesStatusMessage
- }
- if err := c.Update(ctx, bp.Id, bp); err != nil {
- log.Printf("Failed to send breakpoint update for %s: %s", bp.Id, err)
- }
- }(bp)
- }
- }
- }
-
- // Wait for all updates to finish before returning.
- wg.Wait()
-}
-
-// bpsWithConditionSatisfied returns the breakpoints whose conditions are true
-// (or that do not have a condition.)
-func bpsWithConditionSatisfied(bpsIn []*cd.Breakpoint, prog debug.Program) []*cd.Breakpoint {
- var bpsOut []*cd.Breakpoint
- for _, bp := range bpsIn {
- cond, err := condTruth(bp.Condition, prog)
- if err != nil {
- bp.Status = errorStatusMessage(err.Error(), refersToBreakpointCondition)
- // Include bp in the list to be updated when there's an error, so that
- // the user gets a response.
- bpsOut = append(bpsOut, bp)
- } else if cond {
- bpsOut = append(bpsOut, bp)
- }
- }
- return bpsOut
-}
-
-// condTruth evaluates a condition.
-func condTruth(condition string, prog debug.Program) (bool, error) {
- if condition == "" {
- // A condition wasn't set.
- return true, nil
- }
- val, err := prog.Evaluate(condition)
- if err != nil {
- return false, err
- }
- if v, ok := val.(bool); !ok {
- return false, fmt.Errorf("condition expression has type %T, should be bool", val)
- } else {
- return v, nil
- }
-}
-
-// expressionValues evaluates a slice of expressions and returns a []*cd.Variable
-// containing the results.
-// If the result of an expression evaluation refers to values from the program's
-// memory (e.g., the expression evaluates to a slice) a corresponding variable is
-// added to the value collector, to be read later.
-func expressionValues(expressions []string, prog debug.Program, vc *valuecollector.Collector) []*cd.Variable {
- evaluatedExpressions := make([]*cd.Variable, len(expressions))
- for i, exp := range expressions {
- ee := &cd.Variable{Name: exp}
- evaluatedExpressions[i] = ee
- if val, err := prog.Evaluate(exp); err != nil {
- ee.Status = errorStatusMessage(err.Error(), refersToBreakpointExpression)
- } else {
- vc.FillValue(val, ee)
- }
- }
- return evaluatedExpressions
-}
-
-// stackFrames returns a stack trace for the program. It passes references to
-// function parameters and local variables to the value collector, so it can read
-// their values later.
-func stackFrames(prog debug.Program, vc *valuecollector.Collector) ([]*cd.StackFrame, *cd.StatusMessage) {
- frames, err := prog.Frames(maxCapturedStackFrames)
- if err != nil {
- return nil, errorStatusMessage("Error getting stack: "+err.Error(), refersToUnspecified)
- }
- stackFrames := make([]*cd.StackFrame, len(frames))
- for i, f := range frames {
- frame := &cd.StackFrame{}
- frame.Function = f.Function
- for _, v := range f.Params {
- frame.Arguments = append(frame.Arguments, vc.AddVariable(debug.LocalVar(v)))
- }
- for _, v := range f.Vars {
- frame.Locals = append(frame.Locals, vc.AddVariable(v))
- }
- frame.Location = &cd.SourceLocation{
- Path: f.File,
- Line: int64(f.Line),
- }
- stackFrames[i] = frame
- }
- return stackFrames, nil
-}
-
-// errorStatusMessage returns a *cd.StatusMessage indicating an error,
-// with the given message and refersTo field.
-func errorStatusMessage(msg string, refersTo int) *cd.StatusMessage {
- return &cd.StatusMessage{
- Description: &cd.FormatMessage{Format: "$0", Parameters: []string{msg}},
- IsError: true,
- RefersTo: refersToString[refersTo],
- }
-}
-
-const (
- // RefersTo values for cd.StatusMessage.
- refersToUnspecified = iota
- refersToBreakpointCondition
- refersToBreakpointExpression
-)
-
-// refersToString contains the strings for each refersTo value.
-// See the definition of StatusMessage in the v2/clouddebugger package.
-var refersToString = map[int]string{
- refersToUnspecified: "UNSPECIFIED",
- refersToBreakpointCondition: "BREAKPOINT_CONDITION",
- refersToBreakpointExpression: "BREAKPOINT_EXPRESSION",
-}
-
-func serviceAcctTokenSource(ctx context.Context, filename string, scope ...string) (oauth2.TokenSource, error) {
- data, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, fmt.Errorf("cannot read service account file: %v", err)
- }
- cfg, err := google.JWTConfigFromJSON(data, scope...)
- if err != nil {
- return nil, fmt.Errorf("google.JWTConfigFromJSON: %v", err)
- }
- return cfg.TokenSource(ctx), nil
-}
diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints.go
deleted file mode 100644
index afe07cbfb..000000000
--- a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints.go
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright 2016 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 breakpoints handles breakpoint requests we get from the user through
-// the Debuglet Controller, and manages corresponding breakpoints set in the code.
-package breakpoints
-
-import (
- "log"
- "sync"
-
- "golang.org/x/debug"
- cd "google.golang.org/api/clouddebugger/v2"
-)
-
-// BreakpointStore stores the set of breakpoints for a program.
-type BreakpointStore struct {
- mu sync.Mutex
- // prog is the program being debugged.
- prog debug.Program
- // idToBreakpoint is a map from breakpoint identifier to *cd.Breakpoint. The
- // map value is nil if the breakpoint is inactive. A breakpoint is active if:
- // - We received it from the Debuglet Controller, and it was active at the time;
- // - We were able to set code breakpoints for it;
- // - We have not reached any of those code breakpoints while satisfying the
- // breakpoint's conditions, or the breakpoint has action LOG; and
- // - The Debuglet Controller hasn't informed us the breakpoint has become inactive.
- idToBreakpoint map[string]*cd.Breakpoint
- // pcToBps and bpToPCs store the many-to-many relationship between breakpoints we
- // received from the Debuglet Controller and the code breakpoints we set for them.
- pcToBps map[uint64][]*cd.Breakpoint
- bpToPCs map[*cd.Breakpoint][]uint64
- // errors contains any breakpoints which couldn't be set because they caused an
- // error. These are retrieved with ErrorBreakpoints, and the caller is
- // expected to handle sending updates for them.
- errors []*cd.Breakpoint
-}
-
-// NewBreakpointStore returns a BreakpointStore for the given program.
-func NewBreakpointStore(prog debug.Program) *BreakpointStore {
- return &BreakpointStore{
- idToBreakpoint: make(map[string]*cd.Breakpoint),
- pcToBps: make(map[uint64][]*cd.Breakpoint),
- bpToPCs: make(map[*cd.Breakpoint][]uint64),
- prog: prog,
- }
-}
-
-// ProcessBreakpointList applies updates received from the Debuglet Controller through a List call.
-func (bs *BreakpointStore) ProcessBreakpointList(bps []*cd.Breakpoint) {
- bs.mu.Lock()
- defer bs.mu.Unlock()
- for _, bp := range bps {
- if storedBp, ok := bs.idToBreakpoint[bp.Id]; ok {
- if storedBp != nil && bp.IsFinalState {
- // IsFinalState indicates that the breakpoint has been made inactive.
- bs.removeBreakpointLocked(storedBp)
- }
- } else {
- if bp.IsFinalState {
- // The controller is notifying us that the breakpoint is no longer active,
- // but we didn't know about it anyway.
- continue
- }
- if bp.Action != "" && bp.Action != "CAPTURE" && bp.Action != "LOG" {
- bp.IsFinalState = true
- bp.Status = &cd.StatusMessage{
- Description: &cd.FormatMessage{Format: "Action is not supported"},
- IsError: true,
- }
- bs.errors = append(bs.errors, bp)
- // Note in idToBreakpoint that we've already seen this breakpoint, so that we
- // don't try to report it as an error multiple times.
- bs.idToBreakpoint[bp.Id] = nil
- continue
- }
- pcs, err := bs.prog.BreakpointAtLine(bp.Location.Path, uint64(bp.Location.Line))
- if err != nil {
- log.Printf("error setting breakpoint at %s:%d: %v", bp.Location.Path, bp.Location.Line, err)
- }
- if len(pcs) == 0 {
- // We can't find a PC for this breakpoint's source line, so don't make it active.
- // TODO: we could snap the line to a location where we can break, or report an error to the user.
- bs.idToBreakpoint[bp.Id] = nil
- } else {
- bs.idToBreakpoint[bp.Id] = bp
- for _, pc := range pcs {
- bs.pcToBps[pc] = append(bs.pcToBps[pc], bp)
- }
- bs.bpToPCs[bp] = pcs
- }
- }
- }
-}
-
-// ErrorBreakpoints returns a slice of Breakpoints that caused errors when the
-// BreakpointStore tried to process them, and resets the list of such
-// breakpoints.
-// The caller is expected to send updates to the server to indicate the errors.
-func (bs *BreakpointStore) ErrorBreakpoints() []*cd.Breakpoint {
- bs.mu.Lock()
- defer bs.mu.Unlock()
- bps := bs.errors
- bs.errors = nil
- return bps
-}
-
-// BreakpointsAtPC returns all the breakpoints for which we set a code
-// breakpoint at the given address.
-func (bs *BreakpointStore) BreakpointsAtPC(pc uint64) []*cd.Breakpoint {
- bs.mu.Lock()
- defer bs.mu.Unlock()
- return bs.pcToBps[pc]
-}
-
-// RemoveBreakpoint makes the given breakpoint inactive.
-// This is called when either the debugged program hits the breakpoint, or the Debuglet
-// Controller informs us that the breakpoint is now inactive.
-func (bs *BreakpointStore) RemoveBreakpoint(bp *cd.Breakpoint) {
- bs.mu.Lock()
- bs.removeBreakpointLocked(bp)
- bs.mu.Unlock()
-}
-
-func (bs *BreakpointStore) removeBreakpointLocked(bp *cd.Breakpoint) {
- // Set the ID's corresponding breakpoint to nil, so that we won't activate it
- // if we see it again.
- // TODO: we could delete it after a few seconds.
- bs.idToBreakpoint[bp.Id] = nil
-
- // Delete bp from the list of cd breakpoints at each of its corresponding
- // code breakpoint locations, and delete any code breakpoints which no longer
- // have a corresponding cd breakpoint.
- var codeBreakpointsToDelete []uint64
- for _, pc := range bs.bpToPCs[bp] {
- bps := remove(bs.pcToBps[pc], bp)
- if len(bps) == 0 {
- // bp was the last breakpoint set at this PC, so delete the code breakpoint.
- codeBreakpointsToDelete = append(codeBreakpointsToDelete, pc)
- delete(bs.pcToBps, pc)
- } else {
- bs.pcToBps[pc] = bps
- }
- }
- if len(codeBreakpointsToDelete) > 0 {
- bs.prog.DeleteBreakpoints(codeBreakpointsToDelete)
- }
- delete(bs.bpToPCs, bp)
-}
-
-// remove updates rs by removing r, then returns rs.
-// The mutex in the BreakpointStore which contains rs should be held.
-func remove(rs []*cd.Breakpoint, r *cd.Breakpoint) []*cd.Breakpoint {
- for i := range rs {
- if rs[i] == r {
- rs[i] = rs[len(rs)-1]
- rs = rs[0 : len(rs)-1]
- return rs
- }
- }
- // We shouldn't reach here.
- return rs
-}
diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints_test.go
deleted file mode 100644
index 089a3ba61..000000000
--- a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints_test.go
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2016 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 breakpoints
-
-import (
- "reflect"
- "testing"
-
- "golang.org/x/debug"
- cd "google.golang.org/api/clouddebugger/v2"
-)
-
-var (
- testPC1 uint64 = 0x1234
- testPC2 uint64 = 0x5678
- testPC3 uint64 = 0x3333
- testFile = "foo.go"
- testLine uint64 = 42
- testLine2 uint64 = 99
- testLogPC uint64 = 0x9abc
- testLogLine uint64 = 43
- testBadPC uint64 = 0xdef0
- testBadLine uint64 = 44
- testBP = &cd.Breakpoint{
- Action: "CAPTURE",
- Id: "TestBreakpoint",
- IsFinalState: false,
- Location: &cd.SourceLocation{Path: testFile, Line: int64(testLine)},
- }
- testBP2 = &cd.Breakpoint{
- Action: "CAPTURE",
- Id: "TestBreakpoint2",
- IsFinalState: false,
- Location: &cd.SourceLocation{Path: testFile, Line: int64(testLine2)},
- }
- testLogBP = &cd.Breakpoint{
- Action: "LOG",
- Id: "TestLogBreakpoint",
- IsFinalState: false,
- Location: &cd.SourceLocation{Path: testFile, Line: int64(testLogLine)},
- }
- testBadBP = &cd.Breakpoint{
- Action: "BEEP",
- Id: "TestBadBreakpoint",
- IsFinalState: false,
- Location: &cd.SourceLocation{Path: testFile, Line: int64(testBadLine)},
- }
-)
-
-func TestBreakpointStore(t *testing.T) {
- p := &Program{breakpointPCs: make(map[uint64]bool)}
- bs := NewBreakpointStore(p)
- checkPCs := func(expected map[uint64]bool) {
- if !reflect.DeepEqual(p.breakpointPCs, expected) {
- t.Errorf("got breakpoint map %v want %v", p.breakpointPCs, expected)
- }
- }
- bs.ProcessBreakpointList([]*cd.Breakpoint{testBP, testBP2, testLogBP, testBadBP})
- checkPCs(map[uint64]bool{
- testPC1: true,
- testPC2: true,
- testPC3: true,
- testLogPC: true,
- })
- for _, test := range []struct {
- pc uint64
- expected []*cd.Breakpoint
- }{
- {testPC1, []*cd.Breakpoint{testBP}},
- {testPC2, []*cd.Breakpoint{testBP}},
- {testPC3, []*cd.Breakpoint{testBP2}},
- {testLogPC, []*cd.Breakpoint{testLogBP}},
- } {
- if bps := bs.BreakpointsAtPC(test.pc); !reflect.DeepEqual(bps, test.expected) {
- t.Errorf("BreakpointsAtPC(%x): got %v want %v", test.pc, bps, test.expected)
- }
- }
- testBP2.IsFinalState = true
- bs.ProcessBreakpointList([]*cd.Breakpoint{testBP, testBP2, testLogBP, testBadBP})
- checkPCs(map[uint64]bool{
- testPC1: true,
- testPC2: true,
- testPC3: false,
- testLogPC: true,
- })
- bs.RemoveBreakpoint(testBP)
- checkPCs(map[uint64]bool{
- testPC1: false,
- testPC2: false,
- testPC3: false,
- testLogPC: true,
- })
- for _, pc := range []uint64{testPC1, testPC2, testPC3} {
- if bps := bs.BreakpointsAtPC(pc); len(bps) != 0 {
- t.Errorf("BreakpointsAtPC(%x): got %v want []", pc, bps)
- }
- }
- // bs.ErrorBreakpoints should return testBadBP.
- errorBps := bs.ErrorBreakpoints()
- if len(errorBps) != 1 {
- t.Errorf("ErrorBreakpoints: got %d want 1", len(errorBps))
- } else {
- bp := errorBps[0]
- if bp.Id != testBadBP.Id {
- t.Errorf("ErrorBreakpoints: got id %q want 1", bp.Id)
- }
- if bp.Status == nil || !bp.Status.IsError {
- t.Errorf("ErrorBreakpoints: got %v, want error", bp.Status)
- }
- }
- // The error should have been removed by the last call to bs.ErrorBreakpoints.
- errorBps = bs.ErrorBreakpoints()
- if len(errorBps) != 0 {
- t.Errorf("ErrorBreakpoints: got %d want 0", len(errorBps))
- }
- // Even if testBadBP is sent in a new list, it should not be returned again.
- bs.ProcessBreakpointList([]*cd.Breakpoint{testBadBP})
- errorBps = bs.ErrorBreakpoints()
- if len(errorBps) != 0 {
- t.Errorf("ErrorBreakpoints: got %d want 0", len(errorBps))
- }
-}
-
-// Program implements the similarly-named interface in x/debug.
-// ValueCollector should only call its BreakpointAtLine and DeleteBreakpoints methods.
-type Program struct {
- debug.Program
- // breakpointPCs contains the state of code breakpoints -- true if the
- // breakpoint is currently set, false if it has been deleted.
- breakpointPCs map[uint64]bool
-}
-
-func (p *Program) BreakpointAtLine(file string, line uint64) ([]uint64, error) {
- var pcs []uint64
- switch {
- case file == testFile && line == testLine:
- pcs = []uint64{testPC1, testPC2}
- case file == testFile && line == testLine2:
- pcs = []uint64{testPC3}
- case file == testFile && line == testLogLine:
- pcs = []uint64{testLogPC}
- default:
- pcs = []uint64{0xbad}
- }
- for _, pc := range pcs {
- p.breakpointPCs[pc] = true
- }
- return pcs, nil
-}
-
-func (p *Program) DeleteBreakpoints(pcs []uint64) error {
- for _, pc := range pcs {
- p.breakpointPCs[pc] = false
- }
- return nil
-}
diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client.go
deleted file mode 100644
index 87d283546..000000000
--- a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client.go
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright 2016 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 controller is a library for interacting with the Google Cloud Debugger's Debuglet Controller service.
-package controller
-
-import (
- "crypto/sha256"
- "encoding/json"
- "errors"
- "fmt"
- "log"
- "sync"
-
- "golang.org/x/net/context"
- "golang.org/x/oauth2"
- cd "google.golang.org/api/clouddebugger/v2"
- "google.golang.org/api/googleapi"
- "google.golang.org/api/option"
- "google.golang.org/api/transport"
-)
-
-const (
- // agentVersionString identifies the agent to the service.
- agentVersionString = "google.com/go-gcp/v0.2"
- // initWaitToken is the wait token sent in the first Update request to a server.
- initWaitToken = "init"
-)
-
-var (
- // ErrListUnchanged is returned by List if the server time limit is reached
- // before the list of breakpoints changes.
- ErrListUnchanged = errors.New("breakpoint list unchanged")
- // ErrDebuggeeDisabled is returned by List or Update if the server has disabled
- // this Debuggee. The caller can retry later.
- ErrDebuggeeDisabled = errors.New("debuglet disabled by server")
-)
-
-// Controller manages a connection to the Debuglet Controller service.
-type Controller struct {
- s serviceInterface
- // waitToken is sent with List requests so the server knows which set of
- // breakpoints this client has already seen. Each successful List request
- // returns a new waitToken to send in the next request.
- waitToken string
- // verbose determines whether to do some logging
- verbose bool
- // options, uniquifier and description are used in register.
- options Options
- uniquifier string
- description string
- // labels are included when registering the debuggee. They should contain
- // the module name, version and minorversion, and are used by the debug UI
- // to label the correct version active for debugging.
- labels map[string]string
- // mu protects debuggeeID
- mu sync.Mutex
- // debuggeeID is returned from the server on registration, and is passed back
- // to the server in List and Update requests.
- debuggeeID string
-}
-
-// Options controls how the Debuglet Controller client identifies itself to the server.
-// See https://cloud.google.com/storage/docs/projects and
-// https://cloud.google.com/tools/cloud-debugger/setting-up-on-compute-engine
-// for further documentation of these parameters.
-type Options struct {
- ProjectNumber string // GCP Project Number.
- ProjectID string // GCP Project ID.
- AppModule string // Module name for the debugged program.
- AppVersion string // Version number for this module.
- SourceContexts []*cd.SourceContext // Description of source.
- Verbose bool
- TokenSource oauth2.TokenSource // Source of Credentials used for Stackdriver Debugger.
-}
-
-type serviceInterface interface {
- Register(ctx context.Context, req *cd.RegisterDebuggeeRequest) (*cd.RegisterDebuggeeResponse, error)
- Update(ctx context.Context, debuggeeID, breakpointID string, req *cd.UpdateActiveBreakpointRequest) (*cd.UpdateActiveBreakpointResponse, error)
- List(ctx context.Context, debuggeeID, waitToken string) (*cd.ListActiveBreakpointsResponse, error)
-}
-
-var newService = func(ctx context.Context, tokenSource oauth2.TokenSource) (serviceInterface, error) {
- httpClient, endpoint, err := transport.NewHTTPClient(ctx, option.WithTokenSource(tokenSource))
- if err != nil {
- return nil, err
- }
- s, err := cd.New(httpClient)
- if err != nil {
- return nil, err
- }
- if endpoint != "" {
- s.BasePath = endpoint
- }
- return &service{s: s}, nil
-}
-
-type service struct {
- s *cd.Service
-}
-
-func (s service) Register(ctx context.Context, req *cd.RegisterDebuggeeRequest) (*cd.RegisterDebuggeeResponse, error) {
- call := cd.NewControllerDebuggeesService(s.s).Register(req)
- return call.Context(ctx).Do()
-}
-
-func (s service) Update(ctx context.Context, debuggeeID, breakpointID string, req *cd.UpdateActiveBreakpointRequest) (*cd.UpdateActiveBreakpointResponse, error) {
- call := cd.NewControllerDebuggeesBreakpointsService(s.s).Update(debuggeeID, breakpointID, req)
- return call.Context(ctx).Do()
-}
-
-func (s service) List(ctx context.Context, debuggeeID, waitToken string) (*cd.ListActiveBreakpointsResponse, error) {
- call := cd.NewControllerDebuggeesBreakpointsService(s.s).List(debuggeeID)
- call.WaitToken(waitToken)
- return call.Context(ctx).Do()
-}
-
-// NewController connects to the Debuglet Controller server using the given options,
-// and returns a Controller for that connection.
-// Google Application Default Credentials are used to connect to the Debuglet Controller;
-// see https://developers.google.com/identity/protocols/application-default-credentials
-func NewController(ctx context.Context, o Options) (*Controller, error) {
- // We build a JSON encoding of o.SourceContexts so we can hash it.
- scJSON, err := json.Marshal(o.SourceContexts)
- if err != nil {
- scJSON = nil
- o.SourceContexts = nil
- }
- const minorversion = "107157" // any arbitrary numeric string
-
- // Compute a uniquifier string by hashing the project number, app module name,
- // app module version, debuglet version, and source context.
- // The choice of hash function is arbitrary.
- h := sha256.Sum256([]byte(fmt.Sprintf("%d %s %d %s %d %s %d %s %d %s %d %s",
- len(o.ProjectNumber), o.ProjectNumber,
- len(o.AppModule), o.AppModule,
- len(o.AppVersion), o.AppVersion,
- len(agentVersionString), agentVersionString,
- len(scJSON), scJSON,
- len(minorversion), minorversion)))
- uniquifier := fmt.Sprintf("%X", h[0:16]) // 32 hex characters
-
- description := o.ProjectID
- if o.AppModule != "" {
- description += "-" + o.AppModule
- }
- if o.AppVersion != "" {
- description += "-" + o.AppVersion
- }
-
- s, err := newService(ctx, o.TokenSource)
- if err != nil {
- return nil, err
- }
-
- // Construct client.
- c := &Controller{
- s: s,
- waitToken: initWaitToken,
- verbose: o.Verbose,
- options: o,
- uniquifier: uniquifier,
- description: description,
- labels: map[string]string{
- "module": o.AppModule,
- "version": o.AppVersion,
- "minorversion": minorversion,
- },
- }
-
- return c, nil
-}
-
-func (c *Controller) getDebuggeeID(ctx context.Context) (string, error) {
- c.mu.Lock()
- defer c.mu.Unlock()
- if c.debuggeeID != "" {
- return c.debuggeeID, nil
- }
- // The debuglet hasn't been registered yet, or it is disabled and we should try registering again.
- if err := c.register(ctx); err != nil {
- return "", err
- }
- return c.debuggeeID, nil
-}
-
-// List retrieves the current list of breakpoints from the server.
-// If the set of breakpoints on the server is the same as the one returned in
-// the previous call to List, the server can delay responding until it changes,
-// and return an error instead if no change occurs before a time limit the
-// server sets. List can't be called concurrently with itself.
-func (c *Controller) List(ctx context.Context) (*cd.ListActiveBreakpointsResponse, error) {
- id, err := c.getDebuggeeID(ctx)
- if err != nil {
- return nil, err
- }
- resp, err := c.s.List(ctx, id, c.waitToken)
- if err != nil {
- if isAbortedError(err) {
- return nil, ErrListUnchanged
- }
- // For other errors, the protocol requires that we attempt to re-register.
- c.mu.Lock()
- defer c.mu.Unlock()
- if regError := c.register(ctx); regError != nil {
- return nil, regError
- }
- return nil, err
- }
- if resp == nil {
- return nil, errors.New("no response")
- }
- if c.verbose {
- log.Printf("List response: %v", resp)
- }
- c.waitToken = resp.NextWaitToken
- return resp, nil
-}
-
-// isAbortedError tests if err is a *googleapi.Error, that it contains one error
-// in Errors, and that that error's Reason is "aborted".
-func isAbortedError(err error) bool {
- e, _ := err.(*googleapi.Error)
- if e == nil {
- return false
- }
- if len(e.Errors) != 1 {
- return false
- }
- return e.Errors[0].Reason == "aborted"
-}
-
-// Update reports information to the server about a breakpoint that was hit.
-// Update can be called concurrently with List and Update.
-func (c *Controller) Update(ctx context.Context, breakpointID string, bp *cd.Breakpoint) error {
- req := &cd.UpdateActiveBreakpointRequest{Breakpoint: bp}
- if c.verbose {
- log.Printf("sending update for %s: %v", breakpointID, req)
- }
- id, err := c.getDebuggeeID(ctx)
- if err != nil {
- return err
- }
- _, err = c.s.Update(ctx, id, breakpointID, req)
- return err
-}
-
-// register calls the Debuglet Controller Register method, and sets c.debuggeeID.
-// c.mu should be locked while calling this function. List and Update can't
-// make progress until it returns.
-func (c *Controller) register(ctx context.Context) error {
- req := cd.RegisterDebuggeeRequest{
- Debuggee: &cd.Debuggee{
- AgentVersion: agentVersionString,
- Description: c.description,
- Project: c.options.ProjectNumber,
- SourceContexts: c.options.SourceContexts,
- Uniquifier: c.uniquifier,
- Labels: c.labels,
- },
- }
- resp, err := c.s.Register(ctx, &req)
- if err != nil {
- return err
- }
- if resp == nil {
- return errors.New("register: no response")
- }
- if resp.Debuggee.IsDisabled {
- // Setting c.debuggeeID to empty makes sure future List and Update calls
- // will call register first.
- c.debuggeeID = ""
- } else {
- c.debuggeeID = resp.Debuggee.Id
- }
- if c.debuggeeID == "" {
- return ErrDebuggeeDisabled
- }
- return nil
-}
diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client_test.go
deleted file mode 100644
index fa0634706..000000000
--- a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client_test.go
+++ /dev/null
@@ -1,254 +0,0 @@
-// Copyright 2016 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 controller
-
-import (
- "bytes"
- "errors"
- "fmt"
- "strconv"
- "testing"
-
- "golang.org/x/net/context"
- "golang.org/x/oauth2"
-
- cd "google.golang.org/api/clouddebugger/v2"
- "google.golang.org/api/googleapi"
-)
-
-const (
- testDebuggeeID = "d12345"
- testBreakpointID = "bp12345"
-)
-
-var (
- // The sequence of wait tokens in List requests and responses.
- expectedWaitToken = []string{"init", "token1", "token2", "token1", "token1"}
- // The set of breakpoints returned from each List call.
- expectedBreakpoints = [][]*cd.Breakpoint{
- nil,
- {
- &cd.Breakpoint{
- Id: testBreakpointID,
- IsFinalState: false,
- Location: &cd.SourceLocation{Line: 42, Path: "foo.go"},
- },
- },
- nil,
- }
- abortedError error = &googleapi.Error{
- Code: 409,
- Message: "Conflict",
- Body: `{
- "error": {
- "errors": [
- {
- "domain": "global",
- "reason": "aborted",
- "message": "Conflict"
- }
- ],
- "code": 409,
- "message": "Conflict"
- }
- }`,
- Errors: []googleapi.ErrorItem{
- {Reason: "aborted", Message: "Conflict"},
- },
- }
- backendError error = &googleapi.Error{
- Code: 503,
- Message: "Backend Error",
- Body: `{
- "error": {
- "errors": [
- {
- "domain": "global",
- "reason": "backendError",
- "message": "Backend Error"
- }
- ],
- "code": 503,
- "message": "Backend Error"
- }
- }`,
- Errors: []googleapi.ErrorItem{
- {Reason: "backendError", Message: "Backend Error"},
- },
- }
-)
-
-type mockService struct {
- t *testing.T
- listCallsSeen int
- registerCallsSeen int
-}
-
-func (s *mockService) Register(ctx context.Context, req *cd.RegisterDebuggeeRequest) (*cd.RegisterDebuggeeResponse, error) {
- s.registerCallsSeen++
- if req.Debuggee == nil {
- s.t.Errorf("missing debuggee")
- return nil, nil
- }
- if req.Debuggee.AgentVersion == "" {
- s.t.Errorf("missing agent version")
- }
- if req.Debuggee.Description == "" {
- s.t.Errorf("missing debuglet description")
- }
- if req.Debuggee.Project == "" {
- s.t.Errorf("missing project id")
- }
- if req.Debuggee.Uniquifier == "" {
- s.t.Errorf("missing uniquifier")
- }
- return &cd.RegisterDebuggeeResponse{
- Debuggee: &cd.Debuggee{Id: testDebuggeeID},
- }, nil
-}
-
-func (s *mockService) Update(ctx context.Context, id, breakpointID string, req *cd.UpdateActiveBreakpointRequest) (*cd.UpdateActiveBreakpointResponse, error) {
- if id != testDebuggeeID {
- s.t.Errorf("got debuggee ID %s want %s", id, testDebuggeeID)
- }
- if breakpointID != testBreakpointID {
- s.t.Errorf("got breakpoint ID %s want %s", breakpointID, testBreakpointID)
- }
- if !req.Breakpoint.IsFinalState {
- s.t.Errorf("got IsFinalState = false, want true")
- }
- return nil, nil
-}
-
-func (s *mockService) List(ctx context.Context, id, waitToken string) (*cd.ListActiveBreakpointsResponse, error) {
- if id != testDebuggeeID {
- s.t.Errorf("got debuggee ID %s want %s", id, testDebuggeeID)
- }
- if waitToken != expectedWaitToken[s.listCallsSeen] {
- s.t.Errorf("got wait token %s want %s", waitToken, expectedWaitToken[s.listCallsSeen])
- }
- s.listCallsSeen++
- if s.listCallsSeen == 4 {
- return nil, backendError
- }
- if s.listCallsSeen == 5 {
- return nil, abortedError
- }
- resp := &cd.ListActiveBreakpointsResponse{
- Breakpoints: expectedBreakpoints[s.listCallsSeen-1],
- NextWaitToken: expectedWaitToken[s.listCallsSeen],
- }
- return resp, nil
-}
-
-func TestDebugletControllerClientLibrary(t *testing.T) {
- var (
- m *mockService
- c *Controller
- list *cd.ListActiveBreakpointsResponse
- err error
- )
- m = &mockService{t: t}
- newService = func(context.Context, oauth2.TokenSource) (serviceInterface, error) { return m, nil }
- opts := Options{
- ProjectNumber: "5",
- ProjectID: "p1",
- AppModule: "mod1",
- AppVersion: "v1",
- }
- ctx := context.Background()
- if c, err = NewController(ctx, opts); err != nil {
- t.Fatal("Initializing Controller client:", err)
- }
- if err := validateLabels(c, opts); err != nil {
- t.Fatalf("Invalid labels:\n%v", err)
- }
- if list, err = c.List(ctx); err != nil {
- t.Fatal("List:", err)
- }
- if m.registerCallsSeen != 1 {
- t.Errorf("saw %d Register calls, want 1", m.registerCallsSeen)
- }
- if list, err = c.List(ctx); err != nil {
- t.Fatal("List:", err)
- }
- if len(list.Breakpoints) != 1 {
- t.Fatalf("got %d breakpoints, want 1", len(list.Breakpoints))
- }
- if err = c.Update(ctx, list.Breakpoints[0].Id, &cd.Breakpoint{Id: testBreakpointID, IsFinalState: true}); err != nil {
- t.Fatal("Update:", err)
- }
- if list, err = c.List(ctx); err != nil {
- t.Fatal("List:", err)
- }
- if m.registerCallsSeen != 1 {
- t.Errorf("saw %d Register calls, want 1", m.registerCallsSeen)
- }
- // The next List call produces an error that should cause a Register call.
- if list, err = c.List(ctx); err == nil {
- t.Fatal("List should have returned an error")
- }
- if m.registerCallsSeen != 2 {
- t.Errorf("saw %d Register calls, want 2", m.registerCallsSeen)
- }
- // The next List call produces an error that should not cause a Register call.
- if list, err = c.List(ctx); err == nil {
- t.Fatal("List should have returned an error")
- }
- if m.registerCallsSeen != 2 {
- t.Errorf("saw %d Register calls, want 2", m.registerCallsSeen)
- }
- if m.listCallsSeen != 5 {
- t.Errorf("saw %d list calls, want 5", m.listCallsSeen)
- }
-}
-
-func validateLabels(c *Controller, o Options) error {
- errMsg := new(bytes.Buffer)
- if m, ok := c.labels["module"]; ok {
- if m != o.AppModule {
- errMsg.WriteString(fmt.Sprintf("label module: want %s, got %s\n", o.AppModule, m))
- }
- } else {
- errMsg.WriteString("Missing \"module\" label\n")
- }
- if v, ok := c.labels["version"]; ok {
- if v != o.AppVersion {
- errMsg.WriteString(fmt.Sprintf("label version: want %s, got %s\n", o.AppVersion, v))
- }
- } else {
- errMsg.WriteString("Missing \"version\" label\n")
- }
- if mv, ok := c.labels["minorversion"]; ok {
- if _, err := strconv.Atoi(mv); err != nil {
- errMsg.WriteString(fmt.Sprintln("label minorversion: not a numeric string:", mv))
- }
- } else {
- errMsg.WriteString("Missing \"minorversion\" label\n")
- }
- if errMsg.Len() != 0 {
- return errors.New(errMsg.String())
- }
- return nil
-}
-
-func TestIsAbortedError(t *testing.T) {
- if !isAbortedError(abortedError) {
- t.Errorf("isAborted(%+v): got false, want true", abortedError)
- }
- if isAbortedError(backendError) {
- t.Errorf("isAborted(%+v): got true, want false", backendError)
- }
-}
diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector.go
deleted file mode 100644
index 8dadc2f63..000000000
--- a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector.go
+++ /dev/null
@@ -1,460 +0,0 @@
-// Copyright 2016 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 valuecollector is used to collect the values of variables in a program.
-package valuecollector
-
-import (
- "bytes"
- "fmt"
- "strconv"
- "strings"
-
- "golang.org/x/debug"
- cd "google.golang.org/api/clouddebugger/v2"
-)
-
-const (
- maxArrayLength = 50
- maxMapLength = 20
-)
-
-// Collector is given references to variables from a program being debugged
-// using AddVariable. Then when ReadValues is called, the Collector will fetch
-// the values of those variables. Any variables referred to by those values
-// will also be fetched; e.g. the targets of pointers, members of structs,
-// elements of slices, etc. This continues iteratively, building a graph of
-// values, until all the reachable values are fetched, or a size limit is
-// reached.
-//
-// Variables are passed to the Collector as debug.Var, which is used by x/debug
-// to represent references to variables. Values are returned as cd.Variable,
-// which is used by the Debuglet Controller to represent the graph of values.
-//
-// For example, if the program has a struct variable:
-//
-// foo := SomeStruct{a:42, b:"xyz"}
-//
-// and we call AddVariable with a reference to foo, we will get back a result
-// like:
-//
-// cd.Variable{Name:"foo", VarTableIndex:10}
-//
-// which denotes a variable named "foo" which will have its value stored in
-// element 10 of the table that will later be returned by ReadValues. That
-// element might be:
-//
-// out[10] = &cd.Variable{Members:{{Name:"a", VarTableIndex:11},{Name:"b", VarTableIndex:12}}}
-//
-// which denotes a struct with two members a and b, whose values are in elements
-// 11 and 12 of the output table:
-//
-// out[11] = &cd.Variable{Value:"42"}
-// out[12] = &cd.Variable{Value:"xyz"}
-type Collector struct {
- // prog is the program being debugged.
- prog debug.Program
- // limit is the maximum size of the output slice of values.
- limit int
- // index is a map from references (variables and map elements) to their
- // locations in the table.
- index map[reference]int
- // table contains the references, including those given to the
- // Collector directly and those the Collector itself found.
- // If VarTableIndex is set to 0 in a cd.Variable, it is ignored, so the first entry
- // of table can't be used. On initialization we put a dummy value there.
- table []reference
-}
-
-// reference represents a value which is in the queue to be read by the
-// collector. It is either a debug.Var, or a mapElement.
-type reference interface{}
-
-// mapElement represents an element of a map in the debugged program's memory.
-type mapElement struct {
- debug.Map
- index uint64
-}
-
-// NewCollector returns a Collector for the given program and size limit.
-// The limit is the maximum size of the slice of values returned by ReadValues.
-func NewCollector(prog debug.Program, limit int) *Collector {
- return &Collector{
- prog: prog,
- limit: limit,
- index: make(map[reference]int),
- table: []reference{debug.Var{}},
- }
-}
-
-// AddVariable adds another variable to be collected.
-// The Collector doesn't get the value immediately; it returns a cd.Variable
-// that contains an index into the table which will later be returned by
-// ReadValues.
-func (c *Collector) AddVariable(lv debug.LocalVar) *cd.Variable {
- ret := &cd.Variable{Name: lv.Name}
- if index, ok := c.add(lv.Var); !ok {
- // If the add call failed, it's because we reached the size limit.
- // The Debuglet Controller's convention is to pass it a "Not Captured" error
- // in this case.
- ret.Status = statusMessage(messageNotCaptured, true, refersToVariableName)
- } else {
- ret.VarTableIndex = int64(index)
- }
- return ret
-}
-
-// add adds a reference to the set of values to be read from the
-// program. It returns the index in the output table that will contain the
-// corresponding value. It fails if the table has reached the size limit.
-// It deduplicates references, so the index may be the same as one that was
-// returned from an earlier add call.
-func (c *Collector) add(r reference) (outputIndex int, ok bool) {
- if i, ok := c.index[r]; ok {
- return i, true
- }
- i := len(c.table)
- if i >= c.limit {
- return 0, false
- }
- c.index[r] = i
- c.table = append(c.table, r)
- return i, true
-}
-
-func addMember(v *cd.Variable, name string) *cd.Variable {
- v2 := &cd.Variable{Name: name}
- v.Members = append(v.Members, v2)
- return v2
-}
-
-// ReadValues fetches values of the variables that were passed to the Collector
-// with AddVariable. The values of any new variables found are also fetched,
-// e.g. the targets of pointers or the members of structs, until we reach the
-// size limit or we run out of values to fetch.
-// The results are output as a []*cd.Variable, which is the type we need to send
-// to the Debuglet Controller after we trigger a breakpoint.
-func (c *Collector) ReadValues() (out []*cd.Variable) {
- for i := 0; i < len(c.table); i++ {
- // Create a new cd.Variable for this value, and append it to the output.
- dcv := new(cd.Variable)
- out = append(out, dcv)
- if i == 0 {
- // The first element is unused.
- continue
- }
- switch x := c.table[i].(type) {
- case mapElement:
- key, value, err := c.prog.MapElement(x.Map, x.index)
- if err != nil {
- dcv.Status = statusMessage(err.Error(), true, refersToVariableValue)
- continue
- }
- // Add a member for the key.
- member := addMember(dcv, "key")
- if index, ok := c.add(key); !ok {
- // The table is full.
- member.Status = statusMessage(messageNotCaptured, true, refersToVariableName)
- continue
- } else {
- member.VarTableIndex = int64(index)
- }
- // Add a member for the value.
- member = addMember(dcv, "value")
- if index, ok := c.add(value); !ok {
- // The table is full.
- member.Status = statusMessage(messageNotCaptured, true, refersToVariableName)
- } else {
- member.VarTableIndex = int64(index)
- }
- case debug.Var:
- if v, err := c.prog.Value(x); err != nil {
- dcv.Status = statusMessage(err.Error(), true, refersToVariableValue)
- } else {
- c.FillValue(v, dcv)
- }
- }
- }
- return out
-}
-
-// indexable is an interface for arrays, slices and channels.
-type indexable interface {
- Len() uint64
- Element(uint64) debug.Var
-}
-
-// channel implements indexable.
-type channel struct {
- debug.Channel
-}
-
-func (c channel) Len() uint64 {
- return c.Length
-}
-
-var (
- _ indexable = debug.Array{}
- _ indexable = debug.Slice{}
- _ indexable = channel{}
-)
-
-// FillValue copies a value into a cd.Variable. Any variables referred to by
-// that value, e.g. struct members and pointer targets, are added to the
-// collector's queue, to be fetched later by ReadValues.
-func (c *Collector) FillValue(v debug.Value, dcv *cd.Variable) {
- if c, ok := v.(debug.Channel); ok {
- // Convert to channel, which implements indexable.
- v = channel{c}
- }
- // Fill in dcv in a manner depending on the type of the value we got.
- switch val := v.(type) {
- case int8, int16, int32, int64, bool, uint8, uint16, uint32, uint64, float32, float64, complex64, complex128:
- // For simple types, we just print the value to dcv.Value.
- dcv.Value = fmt.Sprint(val)
- case string:
- // Put double quotes around strings.
- dcv.Value = strconv.Quote(val)
- case debug.String:
- if uint64(len(val.String)) < val.Length {
- // This string value was truncated.
- dcv.Value = strconv.Quote(val.String + "...")
- } else {
- dcv.Value = strconv.Quote(val.String)
- }
- case debug.Struct:
- // For structs, we add an entry to dcv.Members for each field in the
- // struct.
- // Each member will contain the name of the field, and the index in the
- // output table which will contain the value of that field.
- for _, f := range val.Fields {
- member := addMember(dcv, f.Name)
- if index, ok := c.add(f.Var); !ok {
- // The table is full.
- member.Status = statusMessage(messageNotCaptured, true, refersToVariableName)
- } else {
- member.VarTableIndex = int64(index)
- }
- }
- case debug.Map:
- dcv.Value = fmt.Sprintf("len = %d", val.Length)
- for i := uint64(0); i < val.Length; i++ {
- field := addMember(dcv, `⚫`)
- if i == maxMapLength {
- field.Name = "..."
- field.Status = statusMessage(messageTruncated, true, refersToVariableName)
- break
- }
- if index, ok := c.add(mapElement{val, i}); !ok {
- // The value table is full; add a member to contain the error message.
- field.Name = "..."
- field.Status = statusMessage(messageNotCaptured, true, refersToVariableName)
- break
- } else {
- field.VarTableIndex = int64(index)
- }
- }
- case debug.Pointer:
- if val.Address == 0 {
- dcv.Value = "<nil>"
- } else if val.TypeID == 0 {
- // We don't know the type of the pointer, so just output the address as
- // the value.
- dcv.Value = fmt.Sprintf("0x%X", val.Address)
- dcv.Status = statusMessage(messageUnknownPointerType, false, refersToVariableName)
- } else {
- // Adds the pointed-to variable to the table, and links this value to
- // that table entry through VarTableIndex.
- dcv.Value = fmt.Sprintf("0x%X", val.Address)
- target := addMember(dcv, "")
- if index, ok := c.add(debug.Var(val)); !ok {
- target.Status = statusMessage(messageNotCaptured, true, refersToVariableName)
- } else {
- target.VarTableIndex = int64(index)
- }
- }
- case indexable:
- // Arrays, slices and channels.
- dcv.Value = "len = " + fmt.Sprint(val.Len())
- for j := uint64(0); j < val.Len(); j++ {
- field := addMember(dcv, fmt.Sprint(`[`, j, `]`))
- if j == maxArrayLength {
- field.Name = "..."
- field.Status = statusMessage(messageTruncated, true, refersToVariableName)
- break
- }
- vr := val.Element(j)
- if index, ok := c.add(vr); !ok {
- // The value table is full; add a member to contain the error message.
- field.Name = "..."
- field.Status = statusMessage(messageNotCaptured, true, refersToVariableName)
- break
- } else {
- // Add a member with the index as the name.
- field.VarTableIndex = int64(index)
- }
- }
- default:
- dcv.Status = statusMessage(messageUnknownType, false, refersToVariableName)
- }
-}
-
-// statusMessage returns a *cd.StatusMessage with the given message, IsError
-// field and refersTo field.
-func statusMessage(msg string, isError bool, refersTo int) *cd.StatusMessage {
- return &cd.StatusMessage{
- Description: &cd.FormatMessage{Format: "$0", Parameters: []string{msg}},
- IsError: isError,
- RefersTo: refersToString[refersTo],
- }
-}
-
-// LogString produces a string for a logpoint, substituting in variable values
-// using evaluatedExpressions and varTable.
-func LogString(s string, evaluatedExpressions []*cd.Variable, varTable []*cd.Variable) string {
- var buf bytes.Buffer
- fmt.Fprintf(&buf, "LOGPOINT: ")
- seen := make(map[*cd.Variable]bool)
- for i := 0; i < len(s); {
- if s[i] == '$' {
- i++
- if num, n, ok := parseToken(s[i:], len(evaluatedExpressions)-1); ok {
- // This token is one of $0, $1, etc. Write the corresponding expression.
- writeExpression(&buf, evaluatedExpressions[num], false, varTable, seen)
- i += n
- } else {
- // Something else, like $$.
- buf.WriteByte(s[i])
- i++
- }
- } else {
- buf.WriteByte(s[i])
- i++
- }
- }
- return buf.String()
-}
-
-func parseToken(s string, max int) (num int, bytesRead int, ok bool) {
- var i int
- for i < len(s) && s[i] >= '0' && s[i] <= '9' {
- i++
- }
- num, err := strconv.Atoi(s[:i])
- return num, i, err == nil && num <= max
-}
-
-// writeExpression recursively writes variables to buf, in a format suitable
-// for logging. If printName is true, writes the name of the variable.
-func writeExpression(buf *bytes.Buffer, v *cd.Variable, printName bool, varTable []*cd.Variable, seen map[*cd.Variable]bool) {
- if v == nil {
- // Shouldn't happen.
- return
- }
- name, value, status, members := v.Name, v.Value, v.Status, v.Members
-
- // If v.VarTableIndex is not zero, it refers to an element of varTable.
- // We merge its fields with the fields we got from v.
- var other *cd.Variable
- if idx := int(v.VarTableIndex); idx > 0 && idx < len(varTable) {
- other = varTable[idx]
- }
- if other != nil {
- if name == "" {
- name = other.Name
- }
- if value == "" {
- value = other.Value
- }
- if status == nil {
- status = other.Status
- }
- if len(members) == 0 {
- members = other.Members
- }
- }
- if printName && name != "" {
- buf.WriteString(name)
- buf.WriteByte(':')
- }
-
- // If we have seen this value before, write "..." rather than repeating it.
- if seen[v] {
- buf.WriteString("...")
- return
- }
- seen[v] = true
- if other != nil {
- if seen[other] {
- buf.WriteString("...")
- return
- }
- seen[other] = true
- }
-
- if value != "" && !strings.HasPrefix(value, "len = ") {
- // A plain value.
- buf.WriteString(value)
- } else if status != nil && status.Description != nil {
- // An error.
- for _, p := range status.Description.Parameters {
- buf.WriteByte('(')
- buf.WriteString(p)
- buf.WriteByte(')')
- }
- } else if name == `⚫` {
- // A map element.
- first := true
- for _, member := range members {
- if first {
- first = false
- } else {
- buf.WriteByte(':')
- }
- writeExpression(buf, member, false, varTable, seen)
- }
- } else {
- // A map, array, slice, channel, or struct.
- isStruct := value == ""
- first := true
- buf.WriteByte('{')
- for _, member := range members {
- if first {
- first = false
- } else {
- buf.WriteString(", ")
- }
- writeExpression(buf, member, isStruct, varTable, seen)
- }
- buf.WriteByte('}')
- }
-}
-
-const (
- // Error messages for cd.StatusMessage
- messageNotCaptured = "Not captured"
- messageTruncated = "Truncated"
- messageUnknownPointerType = "Unknown pointer type"
- messageUnknownType = "Unknown type"
- // RefersTo values for cd.StatusMessage.
- refersToVariableName = iota
- refersToVariableValue
-)
-
-// refersToString contains the strings for each refersTo value.
-// See the definition of StatusMessage in the v2/clouddebugger package.
-var refersToString = map[int]string{
- refersToVariableName: "VARIABLE_NAME",
- refersToVariableValue: "VARIABLE_VALUE",
-}
diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector_test.go
deleted file mode 100644
index 2bc97dcfa..000000000
--- a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector_test.go
+++ /dev/null
@@ -1,418 +0,0 @@
-// Copyright 2016 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 valuecollector
-
-import (
- "fmt"
- "reflect"
- "testing"
-
- "golang.org/x/debug"
- cd "google.golang.org/api/clouddebugger/v2"
-)
-
-const (
- // Some arbitrary type IDs for the test, for use in debug.Var's TypeID field.
- // A TypeID of 0 means the type is unknown, so we start at 1.
- int16Type = iota + 1
- stringType
- structType
- pointerType
- arrayType
- int32Type
- debugStringType
- mapType
- channelType
- sliceType
-)
-
-func TestValueCollector(t *testing.T) {
- // Construct the collector.
- c := NewCollector(&Program{}, 26)
- // Add some variables of various types, whose values we want the collector to read.
- variablesToAdd := []debug.LocalVar{
- {Name: "a", Var: debug.Var{int16Type, 0x1}},
- {Name: "b", Var: debug.Var{stringType, 0x2}},
- {Name: "c", Var: debug.Var{structType, 0x3}},
- {Name: "d", Var: debug.Var{pointerType, 0x4}},
- {Name: "e", Var: debug.Var{arrayType, 0x5}},
- {Name: "f", Var: debug.Var{debugStringType, 0x6}},
- {Name: "g", Var: debug.Var{mapType, 0x7}},
- {Name: "h", Var: debug.Var{channelType, 0x8}},
- {Name: "i", Var: debug.Var{sliceType, 0x9}},
- }
- expectedResults := []*cd.Variable{
- &cd.Variable{Name: "a", VarTableIndex: 1},
- &cd.Variable{Name: "b", VarTableIndex: 2},
- &cd.Variable{Name: "c", VarTableIndex: 3},
- &cd.Variable{Name: "d", VarTableIndex: 4},
- &cd.Variable{Name: "e", VarTableIndex: 5},
- &cd.Variable{Name: "f", VarTableIndex: 6},
- &cd.Variable{Name: "g", VarTableIndex: 7},
- &cd.Variable{Name: "h", VarTableIndex: 8},
- &cd.Variable{Name: "i", VarTableIndex: 9},
- }
- for i, v := range variablesToAdd {
- added := c.AddVariable(v)
- if !reflect.DeepEqual(added, expectedResults[i]) {
- t.Errorf("AddVariable: got %+v want %+v", *added, *expectedResults[i])
- }
- }
- // Read the values, compare the output to what we expect.
- v := c.ReadValues()
- expectedValues := []*cd.Variable{
- &cd.Variable{},
- &cd.Variable{Value: "1"},
- &cd.Variable{Value: `"hello"`},
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "x", VarTableIndex: 1},
- &cd.Variable{Name: "y", VarTableIndex: 2},
- },
- },
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{VarTableIndex: 1},
- },
- Value: "0x1",
- },
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "[0]", VarTableIndex: 10},
- &cd.Variable{Name: "[1]", VarTableIndex: 11},
- &cd.Variable{Name: "[2]", VarTableIndex: 12},
- &cd.Variable{Name: "[3]", VarTableIndex: 13},
- },
- Value: "len = 4",
- },
- &cd.Variable{Value: `"world"`},
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "⚫", VarTableIndex: 14},
- &cd.Variable{Name: "⚫", VarTableIndex: 15},
- &cd.Variable{Name: "⚫", VarTableIndex: 16},
- },
- Value: "len = 3",
- },
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "[0]", VarTableIndex: 17},
- &cd.Variable{Name: "[1]", VarTableIndex: 18},
- },
- Value: "len = 2",
- },
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "[0]", VarTableIndex: 19},
- &cd.Variable{Name: "[1]", VarTableIndex: 20},
- },
- Value: "len = 2",
- },
- &cd.Variable{Value: "100"},
- &cd.Variable{Value: "104"},
- &cd.Variable{Value: "108"},
- &cd.Variable{Value: "112"},
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "key", VarTableIndex: 21},
- &cd.Variable{Name: "value", VarTableIndex: 22},
- },
- },
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "key", VarTableIndex: 23},
- &cd.Variable{Name: "value", VarTableIndex: 24},
- },
- },
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "key", VarTableIndex: 25},
- &cd.Variable{
- Name: "value",
- Status: &cd.StatusMessage{
- Description: &cd.FormatMessage{
- Format: "$0",
- Parameters: []string{"Not captured"},
- },
- IsError: true,
- RefersTo: "VARIABLE_NAME",
- },
- },
- },
- },
- &cd.Variable{Value: "246"},
- &cd.Variable{Value: "210"},
- &cd.Variable{Value: "300"},
- &cd.Variable{Value: "304"},
- &cd.Variable{Value: "400"},
- &cd.Variable{Value: "404"},
- &cd.Variable{Value: "1400"},
- &cd.Variable{Value: "1404"},
- &cd.Variable{Value: "2400"},
- }
- if !reflect.DeepEqual(v, expectedValues) {
- t.Errorf("ReadValues: got %v want %v", v, expectedValues)
- // Do element-by-element comparisons, for more useful error messages.
- for i := range v {
- if i < len(expectedValues) && !reflect.DeepEqual(v[i], expectedValues[i]) {
- t.Errorf("element %d: got %+v want %+v", i, *v[i], *expectedValues[i])
- }
- }
- }
-}
-
-// Program implements the similarly-named interface in x/debug.
-// ValueCollector should only call its Value and MapElement methods.
-type Program struct {
- debug.Program
-}
-
-func (p *Program) Value(v debug.Var) (debug.Value, error) {
- // We determine what to return using v.TypeID.
- switch v.TypeID {
- case int16Type:
- // We use the address as the value, so that we're testing whether the right
- // address was calculated.
- return int16(v.Address), nil
- case stringType:
- // A string.
- return "hello", nil
- case structType:
- // A struct with two elements.
- return debug.Struct{
- Fields: []debug.StructField{
- {
- Name: "x",
- Var: debug.Var{int16Type, 0x1},
- },
- {
- Name: "y",
- Var: debug.Var{stringType, 0x2},
- },
- },
- }, nil
- case pointerType:
- // A pointer to the first variable above.
- return debug.Pointer{int16Type, 0x1}, nil
- case arrayType:
- // An array of 4 32-bit-wide elements.
- return debug.Array{
- ElementTypeID: int32Type,
- Address: 0x64,
- Length: 4,
- StrideBits: 32,
- }, nil
- case debugStringType:
- return debug.String{
- Length: 5,
- String: "world",
- }, nil
- case mapType:
- return debug.Map{
- TypeID: 99,
- Address: 0x100,
- Length: 3,
- }, nil
- case channelType:
- return debug.Channel{
- ElementTypeID: int32Type,
- Address: 200,
- Buffer: 210,
- Length: 2,
- Capacity: 10,
- Stride: 4,
- BufferStart: 9,
- }, nil
- case sliceType:
- // A slice of 2 32-bit-wide elements.
- return debug.Slice{
- Array: debug.Array{
- ElementTypeID: int32Type,
- Address: 300,
- Length: 2,
- StrideBits: 32,
- },
- Capacity: 50,
- }, nil
- case int32Type:
- // We use the address as the value, so that we're testing whether the right
- // address was calculated.
- return int32(v.Address), nil
- }
- return nil, fmt.Errorf("unexpected Value request")
-}
-
-func (p *Program) MapElement(m debug.Map, index uint64) (debug.Var, debug.Var, error) {
- return debug.Var{TypeID: int16Type, Address: 1000*index + 400},
- debug.Var{TypeID: int32Type, Address: 1000*index + 404},
- nil
-}
-
-func TestLogString(t *testing.T) {
- bp := cd.Breakpoint{
- Action: "LOG",
- LogMessageFormat: "$0 hello, $$7world! $1 $2 $3 $4 $5$6 $7 $8",
- EvaluatedExpressions: []*cd.Variable{
- &cd.Variable{Name: "a", VarTableIndex: 1},
- &cd.Variable{Name: "b", VarTableIndex: 2},
- &cd.Variable{Name: "c", VarTableIndex: 3},
- &cd.Variable{Name: "d", VarTableIndex: 4},
- &cd.Variable{Name: "e", VarTableIndex: 5},
- &cd.Variable{Name: "f", VarTableIndex: 6},
- &cd.Variable{Name: "g", VarTableIndex: 7},
- &cd.Variable{Name: "h", VarTableIndex: 8},
- &cd.Variable{Name: "i", VarTableIndex: 9},
- },
- }
- varTable := []*cd.Variable{
- &cd.Variable{},
- &cd.Variable{Value: "1"},
- &cd.Variable{Value: `"hello"`},
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "x", Value: "1"},
- &cd.Variable{Name: "y", Value: `"hello"`},
- &cd.Variable{Name: "z", VarTableIndex: 3},
- },
- },
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{VarTableIndex: 1},
- },
- Value: "0x1",
- },
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "[0]", VarTableIndex: 10},
- &cd.Variable{Name: "[1]", VarTableIndex: 11},
- &cd.Variable{Name: "[2]", VarTableIndex: 12},
- &cd.Variable{Name: "[3]", VarTableIndex: 13},
- },
- Value: "len = 4",
- },
- &cd.Variable{Value: `"world"`},
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "⚫", VarTableIndex: 14},
- &cd.Variable{Name: "⚫", VarTableIndex: 15},
- &cd.Variable{Name: "⚫", VarTableIndex: 16},
- },
- Value: "len = 3",
- },
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "[0]", VarTableIndex: 17},
- &cd.Variable{Name: "[1]", VarTableIndex: 18},
- },
- Value: "len = 2",
- },
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "[0]", VarTableIndex: 19},
- &cd.Variable{Name: "[1]", VarTableIndex: 20},
- },
- Value: "len = 2",
- },
- &cd.Variable{Value: "100"},
- &cd.Variable{Value: "104"},
- &cd.Variable{Value: "108"},
- &cd.Variable{Value: "112"},
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "key", VarTableIndex: 21},
- &cd.Variable{Name: "value", VarTableIndex: 22},
- },
- },
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "key", VarTableIndex: 23},
- &cd.Variable{Name: "value", VarTableIndex: 24},
- },
- },
- &cd.Variable{
- Members: []*cd.Variable{
- &cd.Variable{Name: "key", VarTableIndex: 25},
- &cd.Variable{
- Name: "value",
- Status: &cd.StatusMessage{
- Description: &cd.FormatMessage{
- Format: "$0",
- Parameters: []string{"Not captured"},
- },
- IsError: true,
- RefersTo: "VARIABLE_NAME",
- },
- },
- },
- },
- &cd.Variable{Value: "246"},
- &cd.Variable{Value: "210"},
- &cd.Variable{Value: "300"},
- &cd.Variable{Value: "304"},
- &cd.Variable{Value: "400"},
- &cd.Variable{Value: "404"},
- &cd.Variable{Value: "1400"},
- &cd.Variable{Value: "1404"},
- &cd.Variable{Value: "2400"},
- }
- s := LogString(bp.LogMessageFormat, bp.EvaluatedExpressions, varTable)
- expected := `LOGPOINT: 1 hello, $7world! "hello" {x:1, y:"hello", z:...} ` +
- `0x1 {100, 104, 108, 112} "world"{400:404, 1400:1404, 2400:(Not captured)} ` +
- `{246, 210} {300, 304}`
- if s != expected {
- t.Errorf("LogString: got %q want %q", s, expected)
- }
-}
-
-func TestParseToken(t *testing.T) {
- for _, c := range []struct {
- s string
- max int
- num int
- n int
- ok bool
- }{
- {"", 0, 0, 0, false},
- {".", 0, 0, 0, false},
- {"0", 0, 0, 1, true},
- {"0", 1, 0, 1, true},
- {"00", 0, 0, 2, true},
- {"1.", 1, 1, 1, true},
- {"1.", 0, 0, 0, false},
- {"10", 10, 10, 2, true},
- {"10..", 10, 10, 2, true},
- {"10", 11, 10, 2, true},
- {"10..", 11, 10, 2, true},
- {"10", 9, 0, 0, false},
- {"10..", 9, 0, 0, false},
- {" 10", 10, 0, 0, false},
- {"010", 10, 10, 3, true},
- {"123456789", 123456789, 123456789, 9, true},
- {"123456789", 123456788, 0, 0, false},
- {"123456789123456789123456789", 999999999, 0, 0, false},
- } {
- num, n, ok := parseToken(c.s, c.max)
- if ok != c.ok {
- t.Errorf("parseToken(%q, %d): got ok=%t want ok=%t", c.s, c.max, ok, c.ok)
- continue
- }
- if !ok {
- continue
- }
- if num != c.num || n != c.n {
- t.Errorf("parseToken(%q, %d): got %d,%d,%t want %d,%d,%t", c.s, c.max, num, n, ok, c.num, c.n, c.ok)
- }
- }
-}