mirror of https://github.com/restic/restic.git
255 lines
6.8 KiB
Go
255 lines
6.8 KiB
Go
// 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)
|
|
}
|
|
}
|