You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

806 lines
23 KiB

  1. // Copyright 2016 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package bttest
  15. import (
  16. "fmt"
  17. "math/rand"
  18. "strconv"
  19. "sync"
  20. "sync/atomic"
  21. "testing"
  22. "time"
  23. "github.com/google/go-cmp/cmp"
  24. "github.com/google/go-cmp/cmp/cmpopts"
  25. "golang.org/x/net/context"
  26. btapb "google.golang.org/genproto/googleapis/bigtable/admin/v2"
  27. btpb "google.golang.org/genproto/googleapis/bigtable/v2"
  28. "google.golang.org/grpc"
  29. )
  30. func TestConcurrentMutationsReadModifyAndGC(t *testing.T) {
  31. s := &server{
  32. tables: make(map[string]*table),
  33. }
  34. ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
  35. defer cancel()
  36. if _, err := s.CreateTable(
  37. ctx,
  38. &btapb.CreateTableRequest{Parent: "cluster", TableId: "t"}); err != nil {
  39. t.Fatal(err)
  40. }
  41. const name = `cluster/tables/t`
  42. tbl := s.tables[name]
  43. req := &btapb.ModifyColumnFamiliesRequest{
  44. Name: name,
  45. Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{
  46. Id: "cf",
  47. Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Create{Create: &btapb.ColumnFamily{}},
  48. }},
  49. }
  50. _, err := s.ModifyColumnFamilies(ctx, req)
  51. if err != nil {
  52. t.Fatal(err)
  53. }
  54. req = &btapb.ModifyColumnFamiliesRequest{
  55. Name: name,
  56. Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{
  57. Id: "cf",
  58. Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Update{Update: &btapb.ColumnFamily{
  59. GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}},
  60. }},
  61. }},
  62. }
  63. if _, err := s.ModifyColumnFamilies(ctx, req); err != nil {
  64. t.Fatal(err)
  65. }
  66. var wg sync.WaitGroup
  67. var ts int64
  68. ms := func() []*btpb.Mutation {
  69. return []*btpb.Mutation{{
  70. Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{
  71. FamilyName: "cf",
  72. ColumnQualifier: []byte(`col`),
  73. TimestampMicros: atomic.AddInt64(&ts, 1000),
  74. }},
  75. }}
  76. }
  77. rmw := func() *btpb.ReadModifyWriteRowRequest {
  78. return &btpb.ReadModifyWriteRowRequest{
  79. TableName: name,
  80. RowKey: []byte(fmt.Sprint(rand.Intn(100))),
  81. Rules: []*btpb.ReadModifyWriteRule{{
  82. FamilyName: "cf",
  83. ColumnQualifier: []byte("col"),
  84. Rule: &btpb.ReadModifyWriteRule_IncrementAmount{IncrementAmount: 1},
  85. }},
  86. }
  87. }
  88. for i := 0; i < 100; i++ {
  89. wg.Add(1)
  90. go func() {
  91. defer wg.Done()
  92. for ctx.Err() == nil {
  93. req := &btpb.MutateRowRequest{
  94. TableName: name,
  95. RowKey: []byte(fmt.Sprint(rand.Intn(100))),
  96. Mutations: ms(),
  97. }
  98. if _, err := s.MutateRow(ctx, req); err != nil {
  99. panic(err) // can't use t.Fatal in goroutine
  100. }
  101. }
  102. }()
  103. wg.Add(1)
  104. go func() {
  105. defer wg.Done()
  106. for ctx.Err() == nil {
  107. _, _ = s.ReadModifyWriteRow(ctx, rmw())
  108. }
  109. }()
  110. wg.Add(1)
  111. go func() {
  112. defer wg.Done()
  113. tbl.gc()
  114. }()
  115. }
  116. done := make(chan struct{})
  117. go func() {
  118. wg.Wait()
  119. close(done)
  120. }()
  121. select {
  122. case <-done:
  123. case <-time.After(1 * time.Second):
  124. t.Error("Concurrent mutations and GCs haven't completed after 1s")
  125. }
  126. }
  127. func TestCreateTableWithFamily(t *testing.T) {
  128. // The Go client currently doesn't support creating a table with column families
  129. // in one operation but it is allowed by the API. This must still be supported by the
  130. // fake server so this test lives here instead of in the main bigtable
  131. // integration test.
  132. s := &server{
  133. tables: make(map[string]*table),
  134. }
  135. ctx := context.Background()
  136. newTbl := btapb.Table{
  137. ColumnFamilies: map[string]*btapb.ColumnFamily{
  138. "cf1": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 123}}},
  139. "cf2": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 456}}},
  140. },
  141. }
  142. cTbl, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl})
  143. if err != nil {
  144. t.Fatalf("Creating table: %v", err)
  145. }
  146. tbl, err := s.GetTable(ctx, &btapb.GetTableRequest{Name: cTbl.Name})
  147. if err != nil {
  148. t.Fatalf("Getting table: %v", err)
  149. }
  150. cf := tbl.ColumnFamilies["cf1"]
  151. if cf == nil {
  152. t.Fatalf("Missing col family cf1")
  153. }
  154. if got, want := cf.GcRule.GetMaxNumVersions(), int32(123); got != want {
  155. t.Errorf("Invalid MaxNumVersions: wanted:%d, got:%d", want, got)
  156. }
  157. cf = tbl.ColumnFamilies["cf2"]
  158. if cf == nil {
  159. t.Fatalf("Missing col family cf2")
  160. }
  161. if got, want := cf.GcRule.GetMaxNumVersions(), int32(456); got != want {
  162. t.Errorf("Invalid MaxNumVersions: wanted:%d, got:%d", want, got)
  163. }
  164. }
  165. type MockSampleRowKeysServer struct {
  166. responses []*btpb.SampleRowKeysResponse
  167. grpc.ServerStream
  168. }
  169. func (s *MockSampleRowKeysServer) Send(resp *btpb.SampleRowKeysResponse) error {
  170. s.responses = append(s.responses, resp)
  171. return nil
  172. }
  173. func TestSampleRowKeys(t *testing.T) {
  174. s := &server{
  175. tables: make(map[string]*table),
  176. }
  177. ctx := context.Background()
  178. newTbl := btapb.Table{
  179. ColumnFamilies: map[string]*btapb.ColumnFamily{
  180. "cf": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}},
  181. },
  182. }
  183. tbl, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl})
  184. if err != nil {
  185. t.Fatalf("Creating table: %v", err)
  186. }
  187. // Populate the table
  188. val := []byte("value")
  189. rowCount := 1000
  190. for i := 0; i < rowCount; i++ {
  191. req := &btpb.MutateRowRequest{
  192. TableName: tbl.Name,
  193. RowKey: []byte("row-" + strconv.Itoa(i)),
  194. Mutations: []*btpb.Mutation{{
  195. Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{
  196. FamilyName: "cf",
  197. ColumnQualifier: []byte("col"),
  198. TimestampMicros: 1000,
  199. Value: val,
  200. }},
  201. }},
  202. }
  203. if _, err := s.MutateRow(ctx, req); err != nil {
  204. t.Fatalf("Populating table: %v", err)
  205. }
  206. }
  207. mock := &MockSampleRowKeysServer{}
  208. if err := s.SampleRowKeys(&btpb.SampleRowKeysRequest{TableName: tbl.Name}, mock); err != nil {
  209. t.Errorf("SampleRowKeys error: %v", err)
  210. }
  211. if len(mock.responses) == 0 {
  212. t.Fatal("Response count: got 0, want > 0")
  213. }
  214. // Make sure the offset of the final response is the offset of the final row
  215. got := mock.responses[len(mock.responses)-1].OffsetBytes
  216. want := int64((rowCount - 1) * len(val))
  217. if got != want {
  218. t.Errorf("Invalid offset: got %d, want %d", got, want)
  219. }
  220. }
  221. func TestDropRowRange(t *testing.T) {
  222. s := &server{
  223. tables: make(map[string]*table),
  224. }
  225. ctx := context.Background()
  226. newTbl := btapb.Table{
  227. ColumnFamilies: map[string]*btapb.ColumnFamily{
  228. "cf": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}},
  229. },
  230. }
  231. tblInfo, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl})
  232. if err != nil {
  233. t.Fatalf("Creating table: %v", err)
  234. }
  235. tbl := s.tables[tblInfo.Name]
  236. // Populate the table
  237. prefixes := []string{"AAA", "BBB", "CCC", "DDD"}
  238. count := 3
  239. doWrite := func() {
  240. for _, prefix := range prefixes {
  241. for i := 0; i < count; i++ {
  242. req := &btpb.MutateRowRequest{
  243. TableName: tblInfo.Name,
  244. RowKey: []byte(prefix + strconv.Itoa(i)),
  245. Mutations: []*btpb.Mutation{{
  246. Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{
  247. FamilyName: "cf",
  248. ColumnQualifier: []byte("col"),
  249. TimestampMicros: 1000,
  250. Value: []byte{},
  251. }},
  252. }},
  253. }
  254. if _, err := s.MutateRow(ctx, req); err != nil {
  255. t.Fatalf("Populating table: %v", err)
  256. }
  257. }
  258. }
  259. }
  260. doWrite()
  261. tblSize := tbl.rows.Len()
  262. req := &btapb.DropRowRangeRequest{
  263. Name: tblInfo.Name,
  264. Target: &btapb.DropRowRangeRequest_RowKeyPrefix{RowKeyPrefix: []byte("AAA")},
  265. }
  266. if _, err = s.DropRowRange(ctx, req); err != nil {
  267. t.Fatalf("Dropping first range: %v", err)
  268. }
  269. got, want := tbl.rows.Len(), tblSize-count
  270. if got != want {
  271. t.Errorf("Row count after first drop: got %d (%v), want %d", got, tbl.rows, want)
  272. }
  273. req = &btapb.DropRowRangeRequest{
  274. Name: tblInfo.Name,
  275. Target: &btapb.DropRowRangeRequest_RowKeyPrefix{RowKeyPrefix: []byte("DDD")},
  276. }
  277. if _, err = s.DropRowRange(ctx, req); err != nil {
  278. t.Fatalf("Dropping second range: %v", err)
  279. }
  280. got, want = tbl.rows.Len(), tblSize-(2*count)
  281. if got != want {
  282. t.Errorf("Row count after second drop: got %d (%v), want %d", got, tbl.rows, want)
  283. }
  284. req = &btapb.DropRowRangeRequest{
  285. Name: tblInfo.Name,
  286. Target: &btapb.DropRowRangeRequest_RowKeyPrefix{RowKeyPrefix: []byte("XXX")},
  287. }
  288. if _, err = s.DropRowRange(ctx, req); err != nil {
  289. t.Fatalf("Dropping invalid range: %v", err)
  290. }
  291. got, want = tbl.rows.Len(), tblSize-(2*count)
  292. if got != want {
  293. t.Errorf("Row count after invalid drop: got %d (%v), want %d", got, tbl.rows, want)
  294. }
  295. req = &btapb.DropRowRangeRequest{
  296. Name: tblInfo.Name,
  297. Target: &btapb.DropRowRangeRequest_DeleteAllDataFromTable{DeleteAllDataFromTable: true},
  298. }
  299. if _, err = s.DropRowRange(ctx, req); err != nil {
  300. t.Fatalf("Dropping all data: %v", err)
  301. }
  302. got, want = tbl.rows.Len(), 0
  303. if got != want {
  304. t.Errorf("Row count after drop all: got %d, want %d", got, want)
  305. }
  306. // Test that we can write rows, delete some and then write them again.
  307. count = 1
  308. doWrite()
  309. req = &btapb.DropRowRangeRequest{
  310. Name: tblInfo.Name,
  311. Target: &btapb.DropRowRangeRequest_DeleteAllDataFromTable{DeleteAllDataFromTable: true},
  312. }
  313. if _, err = s.DropRowRange(ctx, req); err != nil {
  314. t.Fatalf("Dropping all data: %v", err)
  315. }
  316. got, want = tbl.rows.Len(), 0
  317. if got != want {
  318. t.Errorf("Row count after drop all: got %d, want %d", got, want)
  319. }
  320. doWrite()
  321. got, want = tbl.rows.Len(), len(prefixes)
  322. if got != want {
  323. t.Errorf("Row count after rewrite: got %d, want %d", got, want)
  324. }
  325. req = &btapb.DropRowRangeRequest{
  326. Name: tblInfo.Name,
  327. Target: &btapb.DropRowRangeRequest_RowKeyPrefix{RowKeyPrefix: []byte("BBB")},
  328. }
  329. if _, err = s.DropRowRange(ctx, req); err != nil {
  330. t.Fatalf("Dropping range: %v", err)
  331. }
  332. doWrite()
  333. got, want = tbl.rows.Len(), len(prefixes)
  334. if got != want {
  335. t.Errorf("Row count after drop range: got %d, want %d", got, want)
  336. }
  337. }
  338. type MockReadRowsServer struct {
  339. responses []*btpb.ReadRowsResponse
  340. grpc.ServerStream
  341. }
  342. func (s *MockReadRowsServer) Send(resp *btpb.ReadRowsResponse) error {
  343. s.responses = append(s.responses, resp)
  344. return nil
  345. }
  346. func TestReadRows(t *testing.T) {
  347. ctx := context.Background()
  348. s := &server{
  349. tables: make(map[string]*table),
  350. }
  351. newTbl := btapb.Table{
  352. ColumnFamilies: map[string]*btapb.ColumnFamily{
  353. "cf0": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}},
  354. },
  355. }
  356. tblInfo, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl})
  357. if err != nil {
  358. t.Fatalf("Creating table: %v", err)
  359. }
  360. mreq := &btpb.MutateRowRequest{
  361. TableName: tblInfo.Name,
  362. RowKey: []byte("row"),
  363. Mutations: []*btpb.Mutation{{
  364. Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{
  365. FamilyName: "cf0",
  366. ColumnQualifier: []byte("col"),
  367. TimestampMicros: 1000,
  368. Value: []byte{},
  369. }},
  370. }},
  371. }
  372. if _, err := s.MutateRow(ctx, mreq); err != nil {
  373. t.Fatalf("Populating table: %v", err)
  374. }
  375. for _, rowset := range []*btpb.RowSet{
  376. {RowKeys: [][]byte{[]byte("row")}},
  377. {RowRanges: []*btpb.RowRange{{StartKey: &btpb.RowRange_StartKeyClosed{StartKeyClosed: []byte("")}}}},
  378. {RowRanges: []*btpb.RowRange{{StartKey: &btpb.RowRange_StartKeyClosed{StartKeyClosed: []byte("r")}}}},
  379. {RowRanges: []*btpb.RowRange{{
  380. StartKey: &btpb.RowRange_StartKeyClosed{StartKeyClosed: []byte("")},
  381. EndKey: &btpb.RowRange_EndKeyOpen{EndKeyOpen: []byte("s")},
  382. }}},
  383. } {
  384. mock := &MockReadRowsServer{}
  385. req := &btpb.ReadRowsRequest{TableName: tblInfo.Name, Rows: rowset}
  386. if err = s.ReadRows(req, mock); err != nil {
  387. t.Fatalf("ReadRows error: %v", err)
  388. }
  389. if got, want := len(mock.responses), 1; got != want {
  390. t.Errorf("%+v: response count: got %d, want %d", rowset, got, want)
  391. }
  392. }
  393. }
  394. func TestReadRowsOrder(t *testing.T) {
  395. s := &server{
  396. tables: make(map[string]*table),
  397. }
  398. ctx := context.Background()
  399. newTbl := btapb.Table{
  400. ColumnFamilies: map[string]*btapb.ColumnFamily{
  401. "cf0": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}},
  402. },
  403. }
  404. tblInfo, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl})
  405. if err != nil {
  406. t.Fatalf("Creating table: %v", err)
  407. }
  408. count := 3
  409. mcf := func(i int) *btapb.ModifyColumnFamiliesRequest {
  410. return &btapb.ModifyColumnFamiliesRequest{
  411. Name: tblInfo.Name,
  412. Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{
  413. Id: "cf" + strconv.Itoa(i),
  414. Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Create{Create: &btapb.ColumnFamily{}},
  415. }},
  416. }
  417. }
  418. for i := 1; i <= count; i++ {
  419. _, err = s.ModifyColumnFamilies(ctx, mcf(i))
  420. if err != nil {
  421. t.Fatal(err)
  422. }
  423. }
  424. // Populate the table
  425. for fc := 0; fc < count; fc++ {
  426. for cc := count; cc > 0; cc-- {
  427. for tc := 0; tc < count; tc++ {
  428. req := &btpb.MutateRowRequest{
  429. TableName: tblInfo.Name,
  430. RowKey: []byte("row"),
  431. Mutations: []*btpb.Mutation{{
  432. Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{
  433. FamilyName: "cf" + strconv.Itoa(fc),
  434. ColumnQualifier: []byte("col" + strconv.Itoa(cc)),
  435. TimestampMicros: int64((tc + 1) * 1000),
  436. Value: []byte{},
  437. }},
  438. }},
  439. }
  440. if _, err := s.MutateRow(ctx, req); err != nil {
  441. t.Fatalf("Populating table: %v", err)
  442. }
  443. }
  444. }
  445. }
  446. req := &btpb.ReadRowsRequest{
  447. TableName: tblInfo.Name,
  448. Rows: &btpb.RowSet{RowKeys: [][]byte{[]byte("row")}},
  449. }
  450. mock := &MockReadRowsServer{}
  451. if err = s.ReadRows(req, mock); err != nil {
  452. t.Errorf("ReadRows error: %v", err)
  453. }
  454. if len(mock.responses) == 0 {
  455. t.Fatal("Response count: got 0, want > 0")
  456. }
  457. if len(mock.responses[0].Chunks) != 27 {
  458. t.Fatalf("Chunk count: got %d, want 27", len(mock.responses[0].Chunks))
  459. }
  460. testOrder := func(ms *MockReadRowsServer) {
  461. var prevFam, prevCol string
  462. var prevTime int64
  463. for _, cc := range ms.responses[0].Chunks {
  464. if prevFam == "" {
  465. prevFam = cc.FamilyName.Value
  466. prevCol = string(cc.Qualifier.Value)
  467. prevTime = cc.TimestampMicros
  468. continue
  469. }
  470. if cc.FamilyName.Value < prevFam {
  471. t.Errorf("Family order is not correct: got %s < %s", cc.FamilyName.Value, prevFam)
  472. } else if cc.FamilyName.Value == prevFam {
  473. if string(cc.Qualifier.Value) < prevCol {
  474. t.Errorf("Column order is not correct: got %s < %s", string(cc.Qualifier.Value), prevCol)
  475. } else if string(cc.Qualifier.Value) == prevCol {
  476. if cc.TimestampMicros > prevTime {
  477. t.Errorf("cell order is not correct: got %d > %d", cc.TimestampMicros, prevTime)
  478. }
  479. }
  480. }
  481. prevFam = cc.FamilyName.Value
  482. prevCol = string(cc.Qualifier.Value)
  483. prevTime = cc.TimestampMicros
  484. }
  485. }
  486. testOrder(mock)
  487. // Read with interleave filter
  488. inter := &btpb.RowFilter_Interleave{}
  489. fnr := &btpb.RowFilter{Filter: &btpb.RowFilter_FamilyNameRegexFilter{FamilyNameRegexFilter: "1"}}
  490. cqr := &btpb.RowFilter{Filter: &btpb.RowFilter_ColumnQualifierRegexFilter{ColumnQualifierRegexFilter: []byte("2")}}
  491. inter.Filters = append(inter.Filters, fnr, cqr)
  492. req = &btpb.ReadRowsRequest{
  493. TableName: tblInfo.Name,
  494. Rows: &btpb.RowSet{RowKeys: [][]byte{[]byte("row")}},
  495. Filter: &btpb.RowFilter{
  496. Filter: &btpb.RowFilter_Interleave_{Interleave: inter},
  497. },
  498. }
  499. mock = &MockReadRowsServer{}
  500. if err = s.ReadRows(req, mock); err != nil {
  501. t.Errorf("ReadRows error: %v", err)
  502. }
  503. if len(mock.responses) == 0 {
  504. t.Fatal("Response count: got 0, want > 0")
  505. }
  506. if len(mock.responses[0].Chunks) != 18 {
  507. t.Fatalf("Chunk count: got %d, want 18", len(mock.responses[0].Chunks))
  508. }
  509. testOrder(mock)
  510. // Check order after ReadModifyWriteRow
  511. rmw := func(i int) *btpb.ReadModifyWriteRowRequest {
  512. return &btpb.ReadModifyWriteRowRequest{
  513. TableName: tblInfo.Name,
  514. RowKey: []byte("row"),
  515. Rules: []*btpb.ReadModifyWriteRule{{
  516. FamilyName: "cf3",
  517. ColumnQualifier: []byte("col" + strconv.Itoa(i)),
  518. Rule: &btpb.ReadModifyWriteRule_IncrementAmount{IncrementAmount: 1},
  519. }},
  520. }
  521. }
  522. for i := count; i > 0; i-- {
  523. if _, err := s.ReadModifyWriteRow(ctx, rmw(i)); err != nil {
  524. t.Fatal(err)
  525. }
  526. }
  527. req = &btpb.ReadRowsRequest{
  528. TableName: tblInfo.Name,
  529. Rows: &btpb.RowSet{RowKeys: [][]byte{[]byte("row")}},
  530. }
  531. mock = &MockReadRowsServer{}
  532. if err = s.ReadRows(req, mock); err != nil {
  533. t.Errorf("ReadRows error: %v", err)
  534. }
  535. if len(mock.responses) == 0 {
  536. t.Fatal("Response count: got 0, want > 0")
  537. }
  538. if len(mock.responses[0].Chunks) != 30 {
  539. t.Fatalf("Chunk count: got %d, want 30", len(mock.responses[0].Chunks))
  540. }
  541. testOrder(mock)
  542. }
  543. func TestCheckAndMutateRowWithoutPredicate(t *testing.T) {
  544. s := &server{
  545. tables: make(map[string]*table),
  546. }
  547. ctx := context.Background()
  548. newTbl := btapb.Table{
  549. ColumnFamilies: map[string]*btapb.ColumnFamily{
  550. "cf": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}},
  551. },
  552. }
  553. tbl, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl})
  554. if err != nil {
  555. t.Fatalf("Creating table: %v", err)
  556. }
  557. // Populate the table
  558. val := []byte("value")
  559. mrreq := &btpb.MutateRowRequest{
  560. TableName: tbl.Name,
  561. RowKey: []byte("row-present"),
  562. Mutations: []*btpb.Mutation{{
  563. Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{
  564. FamilyName: "cf",
  565. ColumnQualifier: []byte("col"),
  566. TimestampMicros: 1000,
  567. Value: val,
  568. }},
  569. }},
  570. }
  571. if _, err := s.MutateRow(ctx, mrreq); err != nil {
  572. t.Fatalf("Populating table: %v", err)
  573. }
  574. req := &btpb.CheckAndMutateRowRequest{
  575. TableName: tbl.Name,
  576. RowKey: []byte("row-not-present"),
  577. }
  578. if res, err := s.CheckAndMutateRow(ctx, req); err != nil {
  579. t.Errorf("CheckAndMutateRow error: %v", err)
  580. } else if got, want := res.PredicateMatched, false; got != want {
  581. t.Errorf("Invalid PredicateMatched value: got %t, want %t", got, want)
  582. }
  583. req = &btpb.CheckAndMutateRowRequest{
  584. TableName: tbl.Name,
  585. RowKey: []byte("row-present"),
  586. }
  587. if res, err := s.CheckAndMutateRow(ctx, req); err != nil {
  588. t.Errorf("CheckAndMutateRow error: %v", err)
  589. } else if got, want := res.PredicateMatched, true; got != want {
  590. t.Errorf("Invalid PredicateMatched value: got %t, want %t", got, want)
  591. }
  592. }
  593. func TestServer_ReadModifyWriteRow(t *testing.T) {
  594. s := &server{
  595. tables: make(map[string]*table),
  596. }
  597. ctx := context.Background()
  598. newTbl := btapb.Table{
  599. ColumnFamilies: map[string]*btapb.ColumnFamily{
  600. "cf": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}},
  601. },
  602. }
  603. tbl, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl})
  604. if err != nil {
  605. t.Fatalf("Creating table: %v", err)
  606. }
  607. req := &btpb.ReadModifyWriteRowRequest{
  608. TableName: tbl.Name,
  609. RowKey: []byte("row-key"),
  610. Rules: []*btpb.ReadModifyWriteRule{
  611. {
  612. FamilyName: "cf",
  613. ColumnQualifier: []byte("q1"),
  614. Rule: &btpb.ReadModifyWriteRule_AppendValue{
  615. AppendValue: []byte("a"),
  616. },
  617. },
  618. // multiple ops for same cell
  619. {
  620. FamilyName: "cf",
  621. ColumnQualifier: []byte("q1"),
  622. Rule: &btpb.ReadModifyWriteRule_AppendValue{
  623. AppendValue: []byte("b"),
  624. },
  625. },
  626. // different cell whose qualifier should sort before the prior rules
  627. {
  628. FamilyName: "cf",
  629. ColumnQualifier: []byte("q0"),
  630. Rule: &btpb.ReadModifyWriteRule_IncrementAmount{
  631. IncrementAmount: 1,
  632. },
  633. },
  634. },
  635. }
  636. got, err := s.ReadModifyWriteRow(ctx, req)
  637. if err != nil {
  638. t.Fatalf("ReadModifyWriteRow error: %v", err)
  639. }
  640. want := &btpb.ReadModifyWriteRowResponse{
  641. Row: &btpb.Row{
  642. Key: []byte("row-key"),
  643. Families: []*btpb.Family{{
  644. Name: "cf",
  645. Columns: []*btpb.Column{
  646. {
  647. Qualifier: []byte("q0"),
  648. Cells: []*btpb.Cell{{
  649. Value: []byte{0, 0, 0, 0, 0, 0, 0, 1},
  650. }},
  651. },
  652. {
  653. Qualifier: []byte("q1"),
  654. Cells: []*btpb.Cell{{
  655. Value: []byte("ab"),
  656. }},
  657. },
  658. },
  659. }},
  660. },
  661. }
  662. diff := cmp.Diff(got, want, cmpopts.IgnoreFields(btpb.Cell{}, "TimestampMicros"))
  663. if diff != "" {
  664. t.Errorf("unexpected response: %s", diff)
  665. }
  666. }
  667. // helper function to populate table data
  668. func populateTable(ctx context.Context, s *server) (*btapb.Table, error) {
  669. newTbl := btapb.Table{
  670. ColumnFamilies: map[string]*btapb.ColumnFamily{
  671. "cf0": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{1}}},
  672. },
  673. }
  674. tblInfo, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl})
  675. if err != nil {
  676. return nil, err
  677. }
  678. count := 3
  679. mcf := func(i int) *btapb.ModifyColumnFamiliesRequest {
  680. return &btapb.ModifyColumnFamiliesRequest{
  681. Name: tblInfo.Name,
  682. Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{
  683. Id: "cf" + strconv.Itoa(i),
  684. Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Create{&btapb.ColumnFamily{}},
  685. }},
  686. }
  687. }
  688. for i := 1; i <= count; i++ {
  689. _, err = s.ModifyColumnFamilies(ctx, mcf(i))
  690. if err != nil {
  691. return nil, err
  692. }
  693. }
  694. // Populate the table
  695. for fc := 0; fc < count; fc++ {
  696. for cc := count; cc > 0; cc-- {
  697. for tc := 0; tc < count; tc++ {
  698. req := &btpb.MutateRowRequest{
  699. TableName: tblInfo.Name,
  700. RowKey: []byte("row"),
  701. Mutations: []*btpb.Mutation{{
  702. Mutation: &btpb.Mutation_SetCell_{&btpb.Mutation_SetCell{
  703. FamilyName: "cf" + strconv.Itoa(fc),
  704. ColumnQualifier: []byte("col" + strconv.Itoa(cc)),
  705. TimestampMicros: int64((tc + 1) * 1000),
  706. Value: []byte{},
  707. }},
  708. }},
  709. }
  710. if _, err := s.MutateRow(ctx, req); err != nil {
  711. return nil, err
  712. }
  713. }
  714. }
  715. }
  716. return tblInfo, nil
  717. }
  718. func TestFilters(t *testing.T) {
  719. tests := []struct {
  720. in *btpb.RowFilter
  721. out int
  722. }{
  723. {in: &btpb.RowFilter{Filter: &btpb.RowFilter_BlockAllFilter{true}}, out: 0},
  724. {in: &btpb.RowFilter{Filter: &btpb.RowFilter_BlockAllFilter{false}}, out: 1},
  725. {in: &btpb.RowFilter{Filter: &btpb.RowFilter_PassAllFilter{true}}, out: 1},
  726. {in: &btpb.RowFilter{Filter: &btpb.RowFilter_PassAllFilter{false}}, out: 0},
  727. }
  728. ctx := context.Background()
  729. s := &server{
  730. tables: make(map[string]*table),
  731. }
  732. tblInfo, err := populateTable(ctx, s)
  733. if err != nil {
  734. t.Fatal(err)
  735. }
  736. req := &btpb.ReadRowsRequest{
  737. TableName: tblInfo.Name,
  738. Rows: &btpb.RowSet{RowKeys: [][]byte{[]byte("row")}},
  739. }
  740. for _, tc := range tests {
  741. req.Filter = tc.in
  742. mock := &MockReadRowsServer{}
  743. if err = s.ReadRows(req, mock); err != nil {
  744. t.Errorf("ReadRows error: %v", err)
  745. continue
  746. }
  747. if len(mock.responses) != tc.out {
  748. t.Errorf("Response count: got %d, want %d", len(mock.responses), tc.out)
  749. continue
  750. }
  751. }
  752. }