e04ed9c211
CF: Deploy Dev Docs / deploy (push) Waiting to run
Sync Labels / build (push) Waiting to run
tests / unit tests (macos-latest) (push) Waiting to run
tests / unit tests (ubuntu-latest) (push) Waiting to run
tests / unit tests (windows-latest) (push) Waiting to run
99 lines
4.6 KiB
Go
99 lines
4.6 KiB
Go
// Copyright 2026 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 cloudstoragecommon_test
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"testing"
|
|
|
|
"cloud.google.com/go/storage"
|
|
"github.com/googleapis/mcp-toolbox/internal/tools/cloudstorage/cloudstoragecommon"
|
|
"github.com/googleapis/mcp-toolbox/internal/util"
|
|
"google.golang.org/api/googleapi"
|
|
)
|
|
|
|
func gcpErr(code int) error {
|
|
return &googleapi.Error{Code: code, Message: fmt.Sprintf("synthetic %d", code)}
|
|
}
|
|
|
|
func TestProcessGCSError_NilPassthrough(t *testing.T) {
|
|
if got := cloudstoragecommon.ProcessGCSError(nil); got != nil {
|
|
t.Fatalf("expected nil, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestProcessGCSError_Categorization(t *testing.T) {
|
|
tcs := []struct {
|
|
desc string
|
|
in error
|
|
category util.ErrorCategory
|
|
// code is checked only for server errors.
|
|
code int
|
|
}{
|
|
{desc: "bucket not exist sentinel", in: storage.ErrBucketNotExist, category: util.CategoryAgent},
|
|
{desc: "object not exist sentinel", in: storage.ErrObjectNotExist, category: util.CategoryAgent},
|
|
{desc: "wrapped object not exist", in: fmt.Errorf("wrapped: %w", storage.ErrObjectNotExist), category: util.CategoryAgent},
|
|
{desc: "read size limit exceeded", in: fmt.Errorf("big: %w", cloudstoragecommon.ErrReadSizeLimitExceeded), category: util.CategoryAgent},
|
|
{desc: "binary (non-UTF-8) content", in: fmt.Errorf("obj: %w", cloudstoragecommon.ErrBinaryContent), category: util.CategoryAgent},
|
|
{desc: "download destination exists", in: fmt.Errorf("dest: %w", cloudstoragecommon.ErrDestinationExists), category: util.CategoryAgent},
|
|
{desc: "local path not exist", in: fmt.Errorf("src: %w", os.ErrNotExist), category: util.CategoryAgent},
|
|
{desc: "400 bad request", in: gcpErr(http.StatusBadRequest), category: util.CategoryAgent},
|
|
{desc: "401 unauthorized", in: gcpErr(http.StatusUnauthorized), category: util.CategoryServer, code: http.StatusUnauthorized},
|
|
{desc: "403 forbidden", in: gcpErr(http.StatusForbidden), category: util.CategoryServer, code: http.StatusForbidden},
|
|
{desc: "404 not found", in: gcpErr(http.StatusNotFound), category: util.CategoryAgent},
|
|
{desc: "409 conflict", in: gcpErr(http.StatusConflict), category: util.CategoryAgent},
|
|
{desc: "412 precondition failed", in: gcpErr(http.StatusPreconditionFailed), category: util.CategoryAgent},
|
|
{desc: "416 range not satisfiable", in: gcpErr(http.StatusRequestedRangeNotSatisfiable), category: util.CategoryAgent},
|
|
{desc: "429 rate limited", in: gcpErr(http.StatusTooManyRequests), category: util.CategoryServer, code: http.StatusTooManyRequests},
|
|
{desc: "500 internal", in: gcpErr(http.StatusInternalServerError), category: util.CategoryServer, code: http.StatusBadGateway},
|
|
{desc: "503 unavailable", in: gcpErr(http.StatusServiceUnavailable), category: util.CategoryServer, code: http.StatusBadGateway},
|
|
{desc: "418 teapot (unmapped 4xx)", in: gcpErr(http.StatusTeapot), category: util.CategoryServer, code: http.StatusInternalServerError},
|
|
{desc: "context cancelled", in: context.Canceled, category: util.CategoryServer, code: http.StatusGatewayTimeout},
|
|
{desc: "context deadline exceeded", in: context.DeadlineExceeded, category: util.CategoryServer, code: http.StatusGatewayTimeout},
|
|
{desc: "unrecognized error", in: errors.New("kaboom"), category: util.CategoryServer, code: http.StatusInternalServerError},
|
|
}
|
|
for _, tc := range tcs {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
got := cloudstoragecommon.ProcessGCSError(tc.in)
|
|
if got == nil {
|
|
t.Fatalf("expected non-nil ToolboxError, got nil")
|
|
}
|
|
if got.Category() != tc.category {
|
|
t.Errorf("category = %v, want %v", got.Category(), tc.category)
|
|
}
|
|
if tc.category == util.CategoryServer {
|
|
cse, ok := got.(*util.ClientServerError)
|
|
if !ok {
|
|
t.Fatalf("expected *ClientServerError, got %T", got)
|
|
}
|
|
if cse.Code != tc.code {
|
|
t.Errorf("code = %d, want %d", cse.Code, tc.code)
|
|
}
|
|
} else {
|
|
if _, ok := got.(*util.AgentError); !ok {
|
|
t.Fatalf("expected *AgentError, got %T", got)
|
|
}
|
|
}
|
|
if !errors.Is(got, tc.in) {
|
|
t.Errorf("errors.Is chain broken: got %v not wrapping original %v", got, tc.in)
|
|
}
|
|
})
|
|
}
|
|
}
|