Skip to content

Commit d2b08ea

Browse files
authored
build: add static analysis tools (#269)
* feat: add linting * fix: handle trailing ; in findParams * fix(examples): vet issue * chore: move linting to unit-tests workflow * feat: check for consistent formatting * feat: add staticcheck * fix(tests): check for unused errors SA400* * fix(tests): check errors on close (SA5001) * fix(tests): avoid calling rand.Seed * fix: don't use deprecated pb types * fix: avoid deprecated grpc.WithInsecure * fix: avoid deprecated grpc.Dial * fix(testutil): avoid using deprecated rand funcs * fix: remove deprecated spanner options * fix: some staticcheck warnings * fix: ignore field in test instead of removing * fix: improve error output * fix(testutil): remove unnecessary nil check * fix(examples): don't use deprecated type * fix(examples): additional staticcheck fixes * fix(examples/dml-batches): use short style if statement * fix: remove previously ineffective code
1 parent 1ceb9ee commit d2b08ea

File tree

21 files changed

+191
-66
lines changed

21 files changed

+191
-66
lines changed

.github/workflows/unit-tests.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,49 @@ jobs:
2020
uses: actions/checkout@v4
2121
- name: Run unit tests
2222
run: go test -race -short
23+
24+
lint:
25+
runs-on: ubuntu-latest
26+
steps:
27+
- name: Install Go
28+
uses: actions/setup-go@v5
29+
with:
30+
go-version: 1.23.x
31+
- name: Checkout code
32+
uses: actions/checkout@v4
33+
34+
- name: vet .
35+
run: go vet ./...
36+
37+
- name: vet ./examples
38+
working-directory: ./examples
39+
run: go vet ./...
40+
41+
- name: vet ./benchmarks
42+
working-directory: ./benchmarks
43+
run: go vet ./...
44+
45+
- name: gofmt
46+
run: |
47+
OUT=$(gofmt -s -d .)
48+
if [ -n "$OUT" ]; then
49+
echo -e "$OUT"
50+
echo "Code unformatted, please run 'gofmt -w -s .'"
51+
exit 1
52+
fi
53+
54+
- name: staticcheck .
55+
uses: dominikh/staticcheck-action@v1.3.1
56+
with:
57+
version: "latest"
58+
install-go: false
59+
checks: "inherit,-U1000"
60+
working-directory: "."
61+
62+
- name: staticcheck ./examples
63+
uses: dominikh/staticcheck-action@v1.3.1
64+
with:
65+
version: "latest"
66+
install-go: false
67+
checks: "inherit,-U1000"
68+
working-directory: "./examples"

checksum_row_iterator_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ func TestUpdateChecksumForNullValues(t *testing.T) {
196196
enc2 := gob.NewEncoder(buffer2)
197197
initial2 := new([32]byte)
198198
checksum2, err := updateChecksum(enc2, buffer2, initial2, row)
199+
if err != nil {
200+
t.Fatalf("failed to update checksum: %v", err)
201+
}
199202
if *checksum != *checksum2 {
200203
t.Fatalf("recalculated checksum does not match the initial calculation")
201204
}

client_side_statement.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525
"time"
2626

2727
"cloud.google.com/go/spanner"
28-
sppb "google.golang.org/genproto/googleapis/spanner/v1"
28+
"cloud.google.com/go/spanner/apiv1/spannerpb"
2929
"google.golang.org/grpc/codes"
3030
"google.golang.org/grpc/status"
3131
)
@@ -232,33 +232,33 @@ func matchesToMap(re *regexp.Regexp, s string) map[string]string {
232232
// one row. This is used for client side statements that return a result set
233233
// containing a BOOL value.
234234
func createBooleanIterator(column string, value bool) (*clientSideIterator, error) {
235-
return createSingleValueIterator(column, value, sppb.TypeCode_BOOL)
235+
return createSingleValueIterator(column, value, spannerpb.TypeCode_BOOL)
236236
}
237237

238238
// createStringIterator creates a row iterator with a single STRING column with
239239
// one row. This is used for client side statements that return a result set
240240
// containing a STRING value.
241241
func createStringIterator(column string, value string) (*clientSideIterator, error) {
242-
return createSingleValueIterator(column, value, sppb.TypeCode_STRING)
242+
return createSingleValueIterator(column, value, spannerpb.TypeCode_STRING)
243243
}
244244

245245
// createTimestampIterator creates a row iterator with a single TIMESTAMP column with
246246
// one row. This is used for client side statements that return a result set
247247
// containing a TIMESTAMP value.
248248
func createTimestampIterator(column string, value *time.Time) (*clientSideIterator, error) {
249-
return createSingleValueIterator(column, value, sppb.TypeCode_TIMESTAMP)
249+
return createSingleValueIterator(column, value, spannerpb.TypeCode_TIMESTAMP)
250250
}
251251

252-
func createSingleValueIterator(column string, value interface{}, code sppb.TypeCode) (*clientSideIterator, error) {
252+
func createSingleValueIterator(column string, value interface{}, code spannerpb.TypeCode) (*clientSideIterator, error) {
253253
row, err := spanner.NewRow([]string{column}, []interface{}{value})
254254
if err != nil {
255255
return nil, err
256256
}
257257
return &clientSideIterator{
258-
metadata: &sppb.ResultSetMetadata{
259-
RowType: &sppb.StructType{
260-
Fields: []*sppb.StructType_Field{
261-
{Name: column, Type: &sppb.Type{Code: code}},
258+
metadata: &spannerpb.ResultSetMetadata{
259+
RowType: &spannerpb.StructType{
260+
Fields: []*spannerpb.StructType_Field{
261+
{Name: column, Type: &spannerpb.Type{Code: code}},
262262
},
263263
},
264264
},
@@ -270,7 +270,7 @@ func createSingleValueIterator(column string, value interface{}, code sppb.TypeC
270270
// statements. All values are created and kept in memory, and this struct
271271
// should only be used for small result sets.
272272
type clientSideIterator struct {
273-
metadata *sppb.ResultSetMetadata
273+
metadata *spannerpb.ResultSetMetadata
274274
rows []*spanner.Row
275275
index int
276276
stopped bool
@@ -291,6 +291,6 @@ func (t *clientSideIterator) Stop() {
291291
t.metadata = nil
292292
}
293293

294-
func (t *clientSideIterator) Metadata() *sppb.ResultSetMetadata {
294+
func (t *clientSideIterator) Metadata() *spannerpb.ResultSetMetadata {
295295
return t.metadata
296296
}

driver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ func newConnector(d *Driver, dsn string) (*connector, error) {
238238
}
239239
if strval, ok := connectorConfig.params["numchannels"]; ok {
240240
if val, err := strconv.Atoi(strval); err == nil && val > 0 {
241-
config.NumChannels = val
241+
opts = append(opts, option.WithGRPCConnectionPool(val))
242242
}
243243
}
244244
if strval, ok := connectorConfig.params["rpcpriority"]; ok {

driver_test.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,11 @@ func TestExtractDnsParts(t *testing.T) {
183183
WriteSessions: 0.2,
184184
HealthCheckInterval: spanner.DefaultSessionPoolConfig.HealthCheckInterval,
185185
HealthCheckWorkers: spanner.DefaultSessionPoolConfig.HealthCheckWorkers,
186-
MaxBurst: spanner.DefaultSessionPoolConfig.MaxBurst,
186+
MaxBurst: spanner.DefaultSessionPoolConfig.MaxBurst, //lint:ignore SA1019 because it's a spanner default.
187187
MaxIdle: spanner.DefaultSessionPoolConfig.MaxIdle,
188188
TrackSessionHandles: spanner.DefaultSessionPoolConfig.TrackSessionHandles,
189189
InactiveTransactionRemovalOptions: spanner.DefaultSessionPoolConfig.InactiveTransactionRemovalOptions,
190190
},
191-
NumChannels: 10,
192191
UserAgent: userAgent,
193192
DisableRouteToLeader: true,
194193
EnableEndToEndTracing: true,
@@ -216,15 +215,15 @@ func TestExtractDnsParts(t *testing.T) {
216215
if tc.wantErr {
217216
t.Error("did not encounter expected error")
218217
}
219-
if !cmp.Equal(config, tc.wantConnectorConfig, cmp.AllowUnexported(connectorConfig{})) {
220-
t.Errorf("connector config mismatch for %q\ngot: %v\nwant %v", tc.input, config, tc.wantConnectorConfig)
218+
if diff := cmp.Diff(config, tc.wantConnectorConfig, cmp.AllowUnexported(connectorConfig{})); diff != "" {
219+
t.Errorf("connector config mismatch for %q\n%v", tc.input, diff)
221220
}
222221
conn, err := newConnector(&Driver{connectors: make(map[string]*connector)}, tc.input)
223222
if err != nil {
224223
t.Errorf("failed to get connector for %q: %v", tc.input, err)
225224
}
226-
if !cmp.Equal(conn.spannerClientConfig, tc.wantSpannerConfig, cmpopts.IgnoreUnexported(spanner.ClientConfig{}, spanner.SessionPoolConfig{}, spanner.InactiveTransactionRemovalOptions{}, spannerpb.ExecuteSqlRequest_QueryOptions{})) {
227-
t.Errorf("connector Spanner client config mismatch for %q\n Got: %v\nWant: %v", tc.input, conn.spannerClientConfig, tc.wantSpannerConfig)
225+
if diff := cmp.Diff(conn.spannerClientConfig, tc.wantSpannerConfig, cmpopts.IgnoreUnexported(spanner.ClientConfig{}, spanner.SessionPoolConfig{}, spanner.InactiveTransactionRemovalOptions{}, spannerpb.ExecuteSqlRequest_QueryOptions{})); diff != "" {
226+
t.Errorf("connector Spanner client config mismatch for %q\n%v", tc.input, diff)
228227
}
229228
}
230229
})

driver_with_mockserver_test.go

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,9 @@ func TestDdlBatch(t *testing.T) {
15021502

15031503
statements := []string{"CREATE TABLE FOO", "CREATE TABLE BAR"}
15041504
conn, err := db.Conn(ctx)
1505+
if err != nil {
1506+
t.Fatal(err)
1507+
}
15051508
defer conn.Close()
15061509

15071510
if _, err = conn.ExecContext(ctx, "START BATCH DDL"); err != nil {
@@ -1543,6 +1546,9 @@ func TestAbortDdlBatch(t *testing.T) {
15431546

15441547
statements := []string{"CREATE TABLE FOO", "CREATE TABLE BAR"}
15451548
c, err := db.Conn(ctx)
1549+
if err != nil {
1550+
t.Fatal(err)
1551+
}
15461552
defer c.Close()
15471553

15481554
if _, err = c.ExecContext(ctx, "START BATCH DDL"); err != nil {
@@ -1912,7 +1918,11 @@ func TestCommitTimestamp(t *testing.T) {
19121918
defer teardown()
19131919

19141920
conn, err := db.Conn(ctx)
1915-
defer conn.Close()
1921+
defer func() {
1922+
if err := conn.Close(); err != nil {
1923+
t.Fatal(err)
1924+
}
1925+
}()
19161926
if err != nil {
19171927
t.Fatalf("failed to get a connection: %v", err)
19181928
}
@@ -1947,7 +1957,11 @@ func TestCommitTimestampAutocommit(t *testing.T) {
19471957
defer teardown()
19481958

19491959
conn, err := db.Conn(ctx)
1950-
defer conn.Close()
1960+
defer func() {
1961+
if err := conn.Close(); err != nil {
1962+
t.Fatal(err)
1963+
}
1964+
}()
19511965
if err != nil {
19521966
t.Fatalf("failed to get a connection: %v", err)
19531967
}
@@ -1978,7 +1992,11 @@ func TestCommitTimestampFailsAfterRollback(t *testing.T) {
19781992
defer teardown()
19791993

19801994
conn, err := db.Conn(ctx)
1981-
defer conn.Close()
1995+
defer func() {
1996+
if err := conn.Close(); err != nil {
1997+
t.Fatal(err)
1998+
}
1999+
}()
19822000
if err != nil {
19832001
t.Fatalf("failed to get a connection: %v", err)
19842002
}
@@ -2007,7 +2025,11 @@ func TestCommitTimestampFailsAfterAutocommitQuery(t *testing.T) {
20072025
defer teardown()
20082026

20092027
conn, err := db.Conn(ctx)
2010-
defer conn.Close()
2028+
defer func() {
2029+
if err := conn.Close(); err != nil {
2030+
t.Fatal(err)
2031+
}
2032+
}()
20112033
if err != nil {
20122034
t.Fatalf("failed to get a connection: %v", err)
20132035
}
@@ -2034,7 +2056,11 @@ func TestShowVariableCommitTimestamp(t *testing.T) {
20342056
defer teardown()
20352057

20362058
conn, err := db.Conn(ctx)
2037-
defer conn.Close()
2059+
defer func() {
2060+
if err := conn.Close(); err != nil {
2061+
t.Fatal(err)
2062+
}
2063+
}()
20382064
if err != nil {
20392065
t.Fatalf("failed to get a connection: %v", err)
20402066
}
@@ -2199,7 +2225,8 @@ func TestStressClientReuse(t *testing.T) {
21992225
_, server, teardown := setupTestDBConnection(t)
22002226
defer teardown()
22012227

2202-
rand.Seed(time.Now().UnixNano())
2228+
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
2229+
22032230
numSessions := 10
22042231
numClients := 5
22052232
numParallel := 50
@@ -2215,14 +2242,16 @@ func TestStressClientReuse(t *testing.T) {
22152242
}
22162243
// Execute random operations in parallel on the database.
22172244
for i := 0; i < numParallel; i++ {
2245+
doUpdate := rng.Int()%2 == 0
2246+
22182247
wg.Add(1)
22192248
go func() {
22202249
defer wg.Done()
22212250
conn, err := db.Conn(ctx)
22222251
if err != nil {
22232252
t.Errorf("failed to get a connection: %v", err)
22242253
}
2225-
if rand.Int()%2 == 0 {
2254+
if doUpdate {
22262255
if _, err := conn.ExecContext(ctx, testutil.UpdateBarSetFoo); err != nil {
22272256
t.Errorf("failed to execute update on connection: %v", err)
22282257
}
@@ -2262,7 +2291,11 @@ func TestExcludeTxnFromChangeStreams_AutoCommitUpdate(t *testing.T) {
22622291
defer teardown()
22632292

22642293
conn, err := db.Conn(ctx)
2265-
defer conn.Close()
2294+
defer func() {
2295+
if err := conn.Close(); err != nil {
2296+
t.Fatal(err)
2297+
}
2298+
}()
22662299
if err != nil {
22672300
t.Fatalf("failed to get a connection: %v", err)
22682301
}
@@ -2306,7 +2339,11 @@ func TestExcludeTxnFromChangeStreams_AutoCommitBatchDml(t *testing.T) {
23062339
defer teardown()
23072340

23082341
conn, err := db.Conn(ctx)
2309-
defer conn.Close()
2342+
defer func() {
2343+
if err := conn.Close(); err != nil {
2344+
t.Fatal(err)
2345+
}
2346+
}()
23102347
if err != nil {
23112348
t.Fatalf("failed to get a connection: %v", err)
23122349
}
@@ -2341,7 +2378,11 @@ func TestExcludeTxnFromChangeStreams_PartitionedDml(t *testing.T) {
23412378
defer teardown()
23422379

23432380
conn, err := db.Conn(ctx)
2344-
defer conn.Close()
2381+
defer func() {
2382+
if err := conn.Close(); err != nil {
2383+
t.Fatal(err)
2384+
}
2385+
}()
23452386
if err != nil {
23462387
t.Fatalf("failed to get a connection: %v", err)
23472388
}
@@ -2368,7 +2409,11 @@ func TestExcludeTxnFromChangeStreams_Transaction(t *testing.T) {
23682409
defer teardown()
23692410

23702411
conn, err := db.Conn(ctx)
2371-
defer conn.Close()
2412+
defer func() {
2413+
if err := conn.Close(); err != nil {
2414+
t.Fatal(err)
2415+
}
2416+
}()
23722417
if err != nil {
23732418
t.Fatalf("failed to get a connection: %v", err)
23742419
}

examples/commit-timestamp/main.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"fmt"
2121
"time"
2222

23-
_ "github.com/googleapis/go-sql-spanner"
2423
spannerdriver "github.com/googleapis/go-sql-spanner"
2524
"github.com/googleapis/go-sql-spanner/examples"
2625
)

examples/data-types/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func dataTypes(projectId, instanceId, databaseId string) error {
5959
ctx := context.Background()
6060
db, err := sql.Open("spanner", fmt.Sprintf("projects/%s/instances/%s/databases/%s", projectId, instanceId, databaseId))
6161
if err != nil {
62-
return fmt.Errorf("failed to open database connection: %v\n", err)
62+
return fmt.Errorf("failed to open database connection: %v", err)
6363
}
6464
defer db.Close()
6565

@@ -75,7 +75,7 @@ func dataTypes(projectId, instanceId, databaseId string) error {
7575
1, true, "string", []byte("bytes"), 100, float32(3.14), 3.14, *big.NewRat(1, 1), civil.DateOf(time.Now()), time.Now(),
7676
[]bool{true, false}, []string{"s1", "s2"}, [][]byte{[]byte("b1"), []byte("b2")}, []int64{1, 2},
7777
[]float32{1.1, 2.2}, []float64{1.1, 2.2}, []big.Rat{*big.NewRat(1, 2), *big.NewRat(1, 3)},
78-
[]civil.Date{{2021, 10, 12}, {2021, 10, 13}},
78+
[]civil.Date{{Year: 2021, Month: 10, Day: 12}, {Year: 2021, Month: 10, Day: 13}},
7979
[]time.Time{time.Now(), time.Now().Add(24 * time.Hour)}); err != nil {
8080
return fmt.Errorf("failed to insert a record with all non-null values using DML: %v", err)
8181
}

examples/ddl-batches/main.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"database/sql"
2020
"fmt"
2121

22-
_ "github.com/googleapis/go-sql-spanner"
2322
spannerdriver "github.com/googleapis/go-sql-spanner"
2423
"github.com/googleapis/go-sql-spanner/examples"
2524
)
@@ -40,7 +39,7 @@ func ddlBatches(projectId, instanceId, databaseId string) error {
4039
ctx := context.Background()
4140
db, err := sql.Open("spanner", fmt.Sprintf("projects/%s/instances/%s/databases/%s", projectId, instanceId, databaseId))
4241
if err != nil {
43-
return fmt.Errorf("failed to open database connection: %v\n", err)
42+
return fmt.Errorf("failed to open database connection: %v", err)
4443
}
4544
defer db.Close()
4645

0 commit comments

Comments
 (0)