@@ -162,6 +162,7 @@ func TestBigQueryToolEndpoints(t *testing.T) {
162162 tests .RunToolInvokeWithTemplateParameters (t , tableNameTemplateParam , templateParamTestConfig )
163163
164164 runBigQueryExecuteSqlToolInvokeTest (t , select1Want , invokeParamWant , tableNameParam , ddlWant )
165+ runBigQueryExecuteSqlToolInvokeDryRunTest (t , datasetName )
165166 runBigQueryDataTypeTests (t )
166167 runBigQueryListDatasetToolInvokeTest (t , datasetName )
167168 runBigQueryGetDatasetInfoToolInvokeTest (t , datasetName , datasetInfoWant )
@@ -556,6 +557,115 @@ func runBigQueryExecuteSqlToolInvokeTest(t *testing.T, select1Want, invokeParamW
556557 }
557558}
558559
560+ func runBigQueryExecuteSqlToolInvokeDryRunTest (t * testing.T , datasetName string ) {
561+ // Get ID token
562+ idToken , err := tests .GetGoogleIdToken (tests .ClientId )
563+ if err != nil {
564+ t .Fatalf ("error getting Google ID token: %s" , err )
565+ }
566+
567+ newTableName := fmt .Sprintf ("%s.new_dry_run_table_%s" , datasetName , strings .ReplaceAll (uuid .New ().String (), "-" , "" ))
568+
569+ // Test tool invoke endpoint
570+ invokeTcs := []struct {
571+ name string
572+ api string
573+ requestHeader map [string ]string
574+ requestBody io.Reader
575+ want string
576+ isErr bool
577+ }{
578+ {
579+ name : "invoke my-exec-sql-tool with dryRun" ,
580+ api : "http://127.0.0.1:5000/api/tool/my-exec-sql-tool/invoke" ,
581+ requestHeader : map [string ]string {},
582+ requestBody : bytes .NewBuffer ([]byte (`{"sql":"SELECT 1", "dry_run": true}` )),
583+ want : `\"statementType\": \"SELECT\"` ,
584+ isErr : false ,
585+ },
586+ {
587+ name : "invoke my-exec-sql-tool with dryRun create table" ,
588+ api : "http://127.0.0.1:5000/api/tool/my-exec-sql-tool/invoke" ,
589+ requestHeader : map [string ]string {},
590+ requestBody : bytes .NewBuffer ([]byte (fmt .Sprintf (`{"sql":"CREATE TABLE %s (id INT64, name STRING)", "dry_run": true}` , newTableName ))),
591+ want : `\"statementType\": \"CREATE_TABLE\"` ,
592+ isErr : false ,
593+ },
594+ {
595+ name : "invoke my-exec-sql-tool with dryRun execute immediate" ,
596+ api : "http://127.0.0.1:5000/api/tool/my-exec-sql-tool/invoke" ,
597+ requestHeader : map [string ]string {},
598+ requestBody : bytes .NewBuffer ([]byte (fmt .Sprintf (`{"sql":"EXECUTE IMMEDIATE \"CREATE TABLE %s (id INT64, name STRING)\"", "dry_run": true}` , newTableName ))),
599+ want : `\"statementType\": \"SCRIPT\"` ,
600+ isErr : false ,
601+ },
602+ {
603+ name : "Invoke my-auth-exec-sql-tool with dryRun and auth token" ,
604+ api : "http://127.0.0.1:5000/api/tool/my-auth-exec-sql-tool/invoke" ,
605+ requestHeader : map [string ]string {"my-google-auth_token" : idToken },
606+ requestBody : bytes .NewBuffer ([]byte (`{"sql":"SELECT 1", "dry_run": true}` )),
607+ isErr : false ,
608+ want : `\"statementType\": \"SELECT\"` ,
609+ },
610+ {
611+ name : "Invoke my-auth-exec-sql-tool with dryRun and invalid auth token" ,
612+ api : "http://127.0.0.1:5000/api/tool/my-auth-exec-sql-tool/invoke" ,
613+ requestHeader : map [string ]string {"my-google-auth_token" : "INVALID_TOKEN" },
614+ requestBody : bytes .NewBuffer ([]byte (`{"sql":"SELECT 1","dry_run": true}` )),
615+ isErr : true ,
616+ },
617+ {
618+ name : "Invoke my-auth-exec-sql-tool with dryRun and without auth token" ,
619+ api : "http://127.0.0.1:5000/api/tool/my-auth-exec-sql-tool/invoke" ,
620+ requestHeader : map [string ]string {},
621+ requestBody : bytes .NewBuffer ([]byte (`{"sql":"SELECT 1", "dry_run": true}` )),
622+ isErr : true ,
623+ },
624+ }
625+ for _ , tc := range invokeTcs {
626+ t .Run (tc .name , func (t * testing.T ) {
627+ // Send Tool invocation request
628+ req , err := http .NewRequest (http .MethodPost , tc .api , tc .requestBody )
629+ if err != nil {
630+ t .Fatalf ("unable to create request: %s" , err )
631+ }
632+ req .Header .Add ("Content-type" , "application/json" )
633+ for k , v := range tc .requestHeader {
634+ req .Header .Add (k , v )
635+ }
636+ resp , err := http .DefaultClient .Do (req )
637+ if err != nil {
638+ t .Fatalf ("unable to send request: %s" , err )
639+ }
640+ defer resp .Body .Close ()
641+
642+ if resp .StatusCode != http .StatusOK {
643+ if tc .isErr {
644+ return
645+ }
646+ bodyBytes , _ := io .ReadAll (resp .Body )
647+ t .Fatalf ("response status code is not 200, got %d: %s" , resp .StatusCode , string (bodyBytes ))
648+ }
649+
650+ // Check response body
651+ var body map [string ]interface {}
652+ err = json .NewDecoder (resp .Body ).Decode (& body )
653+ if err != nil {
654+ t .Fatalf ("error parsing response body" )
655+ }
656+
657+ got , ok := body ["result" ].(string )
658+ if ! ok {
659+ t .Fatalf ("unable to find result in response body" )
660+ }
661+
662+ if ! strings .Contains (got , tc .want ) {
663+ t .Fatalf ("expected %q to contain %q, but it did not" , got , tc .want )
664+ }
665+ })
666+ }
667+ }
668+
559669func runBigQueryDataTypeTests (t * testing.T ) {
560670 // Test tool invoke endpoint
561671 invokeTcs := []struct {
0 commit comments