|
- // Copyright 2016 Google LLC
- //
- // 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 (
- "testing"
-
- "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug"
- "cloud.google.com/go/internal/testutil"
- 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 !testutil.Equal(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); !testutil.Equal(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
- }
|