mirror of
https://github.com/googleapis/genai-toolbox.git
synced 2026-02-11 23:55:07 -05:00
sbenp.prettier-vscode
This commit is contained in:
@@ -361,7 +361,11 @@ func (s *Source) GetOperations(ctx context.Context, project, location, operation
|
||||
}
|
||||
}
|
||||
|
||||
return string(opBytes), nil
|
||||
var result any
|
||||
if err := json.Unmarshal(opBytes, &result); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal operation bytes: %w", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
logger.DebugContext(ctx, fmt.Sprintf("Operation not complete, retrying in %v\n", delay))
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
||||
|
||||
op, err := source.GetOperations(ctx, project, location, operation, alloyDBConnectionMessageTemplate, delay, string(accessToken))
|
||||
if err != nil {
|
||||
return nil, util.ProcessGcpError(err)
|
||||
return nil, util.ProcessGeneralError(err)
|
||||
}
|
||||
if op != nil {
|
||||
return op, nil
|
||||
|
||||
@@ -1239,8 +1239,8 @@ func TestAlloyDBCreateInstance(t *testing.T) {
|
||||
{
|
||||
name: "api failure",
|
||||
body: `{"project": "p1", "location": "l1", "cluster": "c1", "instance": "i2-api-failure", "instanceType": "PRIMARY", "displayName": "i1-success"}`,
|
||||
want: "internal api error",
|
||||
wantStatusCode: http.StatusBadRequest,
|
||||
want: `{"error":"error processing GCP request: error creating AlloyDB instance: googleapi: Error 500: internal api error"}`,
|
||||
wantStatusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "missing project",
|
||||
@@ -1269,8 +1269,8 @@ func TestAlloyDBCreateInstance(t *testing.T) {
|
||||
{
|
||||
name: "invalid instanceType",
|
||||
body: `{"project": "p1", "location": "l1", "cluster": "c1", "instance": "i1", "instanceType": "INVALID", "displayName": "invalid"}`,
|
||||
want: `invalid 'instanceType' parameter; expected 'PRIMARY' or 'READ_POOL'`,
|
||||
wantStatusCode: http.StatusBadRequest,
|
||||
want: `{"error":"invalid 'instanceType' parameter; expected 'PRIMARY' or 'READ_POOL'"}`,
|
||||
wantStatusCode: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -165,13 +164,13 @@ func TestWaitToolEndpoints(t *testing.T) {
|
||||
name: "successful operation",
|
||||
toolName: "wait-for-op1",
|
||||
body: `{"project": "p1", "location": "l1", "operation": "op1"}`,
|
||||
want: `{"name":"op1","done":true,"response":"success"}`,
|
||||
want: `{"done":true,"name":"op1","response":"success"}`,
|
||||
},
|
||||
{
|
||||
name: "failed operation",
|
||||
toolName: "wait-for-op2",
|
||||
body: `{"project": "p1", "location": "l1", "operation": "op2"}`,
|
||||
expectError: true,
|
||||
name: "failed operation",
|
||||
toolName: "wait-for-op2",
|
||||
body: `{"project": "p1", "location": "l1", "operation": "op2"}`,
|
||||
want: `{"error":"error processing request: operation finished with error: {\"code\":1,\"message\":\"failed\"}"}`,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -189,48 +188,42 @@ func TestWaitToolEndpoints(t *testing.T) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if tc.expectError {
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
t.Fatal("expected error but got status 200")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||
t.Fatalf("response status code is not 200, got %d: %s", resp.StatusCode, string(bodyBytes))
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Result string `json:"result"`
|
||||
var response struct {
|
||||
Result any `json:"result"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
|
||||
t.Fatalf("failed to decode response: %v", err)
|
||||
}
|
||||
|
||||
var got string
|
||||
// Check if the result is a string (which contains JSON)
|
||||
if s, ok := response.Result.(string); ok {
|
||||
got = s
|
||||
} else {
|
||||
b, err := json.Marshal(response.Result)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal result object: %v", err)
|
||||
}
|
||||
got = string(b)
|
||||
}
|
||||
|
||||
// Clean up both strings to ignore whitespace differences
|
||||
got = strings.ReplaceAll(strings.ReplaceAll(got, " ", ""), "\n", "")
|
||||
want := strings.ReplaceAll(strings.ReplaceAll(tc.want, " ", ""), "\n", "")
|
||||
|
||||
if tc.wantSubstring {
|
||||
if !bytes.Contains([]byte(result.Result), []byte(tc.want)) {
|
||||
t.Fatalf("unexpected result: got %q, want substring %q", result.Result, tc.want)
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("unexpected result: got %q, want substring %q", got, want)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// The result is a JSON-encoded string, so we need to unmarshal it twice.
|
||||
var tempString string
|
||||
if err := json.Unmarshal([]byte(result.Result), &tempString); err != nil {
|
||||
t.Fatalf("failed to unmarshal result string: %v", err)
|
||||
}
|
||||
|
||||
var got, want map[string]any
|
||||
if err := json.Unmarshal([]byte(tempString), &got); err != nil {
|
||||
t.Fatalf("failed to unmarshal result: %v", err)
|
||||
}
|
||||
if err := json.Unmarshal([]byte(tc.want), &want); err != nil {
|
||||
t.Fatalf("failed to unmarshal want: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Fatalf("unexpected result: got %+v, want %+v", got, want)
|
||||
if got != want {
|
||||
t.Fatalf("unexpected result: \ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -354,6 +354,7 @@ func runToolUpdateInvokeTest(t *testing.T, update1Want, updateManyWant string) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func runToolAggregateInvokeTest(t *testing.T, aggregate1Want string, aggregateManyWant string) {
|
||||
// Test tool invoke endpoint
|
||||
invokeTcs := []struct {
|
||||
@@ -385,8 +386,8 @@ func runToolAggregateInvokeTest(t *testing.T, aggregate1Want string, aggregateMa
|
||||
api: "http://127.0.0.1:5000/api/tool/my-read-only-aggregate-tool/invoke",
|
||||
requestHeader: map[string]string{},
|
||||
requestBody: bytes.NewBuffer([]byte(`{ "name" : "ToBeAggregated" }`)),
|
||||
want: "",
|
||||
isErr: true,
|
||||
want: `{"error":"error processing request: this is not a read-only pipeline: {\"$out\":\"target_collection\"}"}`,
|
||||
isErr: false,
|
||||
},
|
||||
{
|
||||
name: "invoke my-read-write-aggregate-tool",
|
||||
|
||||
@@ -287,25 +287,37 @@ func TestNeo4jToolEndpoints(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invoke my-simple-execute-cypher-tool with dry_run and invalid syntax",
|
||||
api: "http://127.0.0.1:5000/api/tool/my-simple-execute-cypher-tool/invoke",
|
||||
requestBody: bytes.NewBuffer([]byte(`{"cypher": "RTN 1", "dry_run": true}`)),
|
||||
wantStatus: http.StatusBadRequest,
|
||||
wantErrorSubstring: "unable to execute query",
|
||||
name: "invoke my-simple-execute-cypher-tool with dry_run and invalid syntax",
|
||||
api: "http://127.0.0.1:5000/api/tool/my-simple-execute-cypher-tool/invoke",
|
||||
requestBody: bytes.NewBuffer([]byte(`{"cypher": "RTN 1", "dry_run": true}`)),
|
||||
wantStatus: http.StatusOK,
|
||||
validateFunc: func(t *testing.T, body string) {
|
||||
if !strings.Contains(body, "unable to execute query") {
|
||||
t.Errorf("expected error message not found in body: %s", body)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invoke readonly tool with write query",
|
||||
api: "http://127.0.0.1:5000/api/tool/my-readonly-execute-cypher-tool/invoke",
|
||||
requestBody: bytes.NewBuffer([]byte(`{"cypher": "CREATE (n:TestNode)"}`)),
|
||||
wantStatus: http.StatusBadRequest,
|
||||
wantErrorSubstring: "this tool is read-only and cannot execute write queries",
|
||||
name: "invoke readonly tool with write query",
|
||||
api: "http://127.0.0.1:5000/api/tool/my-readonly-execute-cypher-tool/invoke",
|
||||
requestBody: bytes.NewBuffer([]byte(`{"cypher": "CREATE (n:TestNode)"}`)),
|
||||
wantStatus: http.StatusOK,
|
||||
validateFunc: func(t *testing.T, body string) {
|
||||
if !strings.Contains(body, "this tool is read-only and cannot execute write queries") {
|
||||
t.Errorf("expected error message not found in body: %s", body)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invoke readonly tool with write query and dry_run",
|
||||
api: "http://127.0.0.1:5000/api/tool/my-readonly-execute-cypher-tool/invoke",
|
||||
requestBody: bytes.NewBuffer([]byte(`{"cypher": "CREATE (n:TestNode)", "dry_run": true}`)),
|
||||
wantStatus: http.StatusBadRequest,
|
||||
wantErrorSubstring: "this tool is read-only and cannot execute write queries",
|
||||
name: "invoke readonly tool with write query and dry_run",
|
||||
api: "http://127.0.0.1:5000/api/tool/my-readonly-execute-cypher-tool/invoke",
|
||||
requestBody: bytes.NewBuffer([]byte(`{"cypher": "CREATE (n:TestNode)", "dry_run": true}`)),
|
||||
wantStatus: http.StatusOK,
|
||||
validateFunc: func(t *testing.T, body string) {
|
||||
if !strings.Contains(body, "this tool is read-only and cannot execute write queries") {
|
||||
t.Errorf("expected error message not found in body: %s", body)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invoke my-schema-tool",
|
||||
|
||||
Reference in New Issue
Block a user