Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions GEMINI.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,4 @@ Any pull request modifying or extending the driver's features must include:
- **Mock Server Tests**: Located in files such as `driver_with_mockserver_test.go`, `conn_with_mockserver_test.go`, and `stmt_with_mockserver_test.go`. Use these (or add new test files) to mock Spanner gRPC API responses (e.g. BeginTransaction, Commit, ExecuteSql) and verify that the driver translates options, tags, and states correctly.
- **Emulator Tests**: Validate integration behavior against the Cloud Spanner Emulator (`integration_test.go` and examples). Make sure the test configurations can run locally with `auto_config_emulator=true`.
- **Wrapper Tests**: If you modified `spannerlib`, ensure you trigger or run unit/integration tests for the respective wrappers (`python-spanner-lib-wrapper-unit-tests.yml`, `ruby-wrapper-tests.yml`, etc.).
- **Subtests & Early Failure**: Prefer using Go subtests (`t.Run`) to isolate distinct test cases. When an intermediate setup step fails (e.g., helper function error, unexpected nil, client initialization failure), use `t.Fatalf` or `t.Fatal` to fail and abort that specific test/subtest immediately. Avoid using `t.Errorf` or `t.Error` if subsequent assertions rely on values or state from the failed step, as this results in redundant and confusing secondary error outputs.
37 changes: 37 additions & 0 deletions stmt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,46 @@ package spannerdriver
import (
"database/sql/driver"
"reflect"
"strings"
"testing"

"cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
"github.com/googleapis/go-sql-spanner/connectionstate"
"github.com/googleapis/go-sql-spanner/parser"
)

func TestPrepareSpannerStmt(t *testing.T) {
state := createInitialConnectionState(connectionstate.TypeNonTransactional, nil)
p, err := parser.NewStatementParser(databasepb.DatabaseDialect_GOOGLE_STANDARD_SQL, 1000)
if err != nil {
t.Fatal(err)
}

t.Run("QueryParameterNameMatchesExactly", func(t *testing.T) {
stmt, err := prepareSpannerStmt(state, p, "SELECT * FROM Singers WHERE SingerId = @id", []driver.NamedValue{
{Name: "id", Value: int64(1)},
})
if err != nil {
t.Fatalf("Unexpected error for matching parameter name: %v", err)
}
Comment thread
olavloite marked this conversation as resolved.
if got, want := stmt.Params["id"], int64(1); got != want {
t.Errorf("Params[\"id\"] = %v, want %v", got, want)
}
})

t.Run("QueryParameterNameMismatch", func(t *testing.T) {
_, err := prepareSpannerStmt(state, p, "SELECT * FROM Singers WHERE SingerId = @singer_id", []driver.NamedValue{
{Name: "id", Value: int64(1)},
})
if err == nil {
t.Fatal("Expected error for mismatched parameter name, got nil")
}
if !strings.Contains(err.Error(), "missing value for query parameter @singer_id") {
t.Fatalf("Expected 'missing value for query parameter @singer_id' error, got %v", err)
}
})
}

func TestConvertParam(t *testing.T) {
check := func(in, want driver.Value) {
t.Helper()
Expand Down
17 changes: 17 additions & 0 deletions stmt_with_mockserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -943,3 +943,20 @@ func executeParamTest(t *testing.T, test paramTest, server *testutil.MockedSpann
}
}
}

func TestQueryMismatchedParameterName(t *testing.T) {
t.Parallel()

db, _, teardown := setupTestDBConnection(t)
defer teardown()
ctx := context.Background()

// SELECT with @my_id parameter but passing named parameter "id" instead
_, err := db.QueryContext(ctx, "select value from test where id=@my_id", sql.Named("id", 123))
if err == nil {
t.Fatal("expected error, got nil")
}
if !strings.Contains(err.Error(), "missing value for query parameter @my_id") {
t.Fatalf("expected missing value error, got: %v", err)
}
}
Loading