From 723142310912d729b20138d9af40d2aeea826838 Mon Sep 17 00:00:00 2001 From: Adam Jones Date: Fri, 24 May 2024 19:43:21 +0100 Subject: [PATCH] fix(bigtable/bttest): Error when applying a mutation with an empty row key (#9512) * fix(bigtable/bttest): Error when applying a mutation with an empty row key Against a real version of Bigtable, an attempt to apply a mutation with an empty row key leads to the following error being produced ``` unable to apply: rpc error: code = InvalidArgument desc = Row keys must be non-empty ``` bttest does not conform to this behaviour. This commit: - adds error-handling when given a mutation with an empty row key, and - adds a regression test. * chore(bigtable/bttest): Remove a deprecated option from the example grpc.WithInsecure is deprecated. It was marked as such by v1.43.0 of the library. See here: https://github.com/grpc/grpc-go/pull/4718 This commit removes a reference to this from the example comment. --------- Co-authored-by: Baha Aiman --- bigtable/bttest/inmem.go | 11 ++++++++- bigtable/bttest/inmem_test.go | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/bigtable/bttest/inmem.go b/bigtable/bttest/inmem.go index 556abc2a8555..b1cec05a0682 100644 --- a/bigtable/bttest/inmem.go +++ b/bigtable/bttest/inmem.go @@ -22,7 +22,9 @@ To use a Server, create it, and then connect to it with no security: srv, err := bttest.NewServer("localhost:0") ... - conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure()) + conn, err := grpc.Dial( + srv.Addr, + grpc.WithTransportCredentials(insecure.NewCredentials())) ... client, err := bigtable.NewClient(ctx, proj, instance, option.WithGRPCConn(conn)) @@ -1072,6 +1074,13 @@ func (s *server) PingAndWarm(ctx context.Context, req *btpb.PingAndWarmRequest) // fam should be a snapshot of the keys of tbl.families. // It assumes r.mu is locked. func applyMutations(tbl *table, r *row, muts []*btpb.Mutation, fs map[string]*columnFamily) error { + if len(r.key) == 0 { + return status.Errorf( + codes.InvalidArgument, + "Row keys must be non-empty", + ) + } + for _, mut := range muts { switch mut := mut.Mutation.(type) { default: diff --git a/bigtable/bttest/inmem_test.go b/bigtable/bttest/inmem_test.go index f5a4d267d5fa..9e2626213250 100644 --- a/bigtable/bttest/inmem_test.go +++ b/bigtable/bttest/inmem_test.go @@ -2426,6 +2426,48 @@ func TestMutateRowsEmptyMutationErrors(t *testing.T) { } } +func TestMutateRowEmptyRowKeyErrors(t *testing.T) { + srv := &server{tables: make(map[string]*table)} + ctx := context.Background() + + const tableID = "mytable" + tblReq := &btapb.CreateTableRequest{ + Parent: "cluster", + TableId: tableID, + Table: &btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{"cf": {}}, + }, + } + if _, err := srv.CreateTable(ctx, tblReq); err != nil { + t.Fatalf("Failed to create the table: %v", err) + } + + const name = "cluster/tables/" + tableID + req := &btpb.MutateRowRequest{ + TableName: name, + RowKey: []byte(""), + Mutations: []*btpb.Mutation{ + { + Mutation: &btpb.Mutation_SetCell_{ + SetCell: &btpb.Mutation_SetCell{ + FamilyName: "cf", + ColumnQualifier: []byte("col"), + TimestampMicros: 1000, + Value: []byte("hello, world!"), + }, + }, + }, + }, + } + + resp, err := srv.MutateRow(ctx, req) + if resp != nil || err == nil || err.Error() != + "rpc error: code = InvalidArgument"+ + " desc = Row keys must be non-empty" { + t.Fatalf("Failed to produce the expected error: %s", err) + } +} + func TestFilterRowCellsPerRowLimitFilterTruthiness(t *testing.T) { row := &row{ key: "row",