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",