1 // Copyright 2017 Google Inc.
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 
15 #include "google/cloud/bigtable/testing/table_integration_test.h"
16 #include "google/cloud/testing_util/assert_ok.h"
17 #include "google/cloud/testing_util/chrono_literals.h"
18 
19 namespace {
20 namespace bigtable = google::cloud::bigtable;
21 using ::google::cloud::testing_util::chrono_literals::operator"" _ms;
22 using ::std::chrono::duration_cast;
23 using ::std::chrono::microseconds;
24 using ::std::chrono::milliseconds;
25 
26 using DataIntegrationTest = bigtable::testing::TableIntegrationTest;
27 
28 /// Use Table::Apply() to insert a single row.
Apply(bigtable::Table & table,std::string const & row_key,std::vector<bigtable::Cell> const & cells)29 void Apply(bigtable::Table& table, std::string const& row_key,
30            std::vector<bigtable::Cell> const& cells) {
31   auto mutation = bigtable::SingleRowMutation(row_key);
32   for (auto const& cell : cells) {
33     mutation.emplace_back(bigtable::SetCell(
34         cell.family_name(), cell.column_qualifier(),
35         duration_cast<milliseconds>(microseconds(cell.timestamp())),
36         cell.value()));
37   }
38   auto status = table.Apply(std::move(mutation));
39   ASSERT_STATUS_OK(status);
40 }
41 
42 /// Use Table::BulkApply() to insert multiple rows.
BulkApply(bigtable::Table & table,std::vector<bigtable::Cell> const & cells)43 void BulkApply(bigtable::Table& table,
44                std::vector<bigtable::Cell> const& cells) {
45   std::map<bigtable::RowKeyType, bigtable::SingleRowMutation> mutations;
46   for (auto const& cell : cells) {
47     auto key = cell.row_key();
48     auto inserted = mutations.emplace(key, bigtable::SingleRowMutation(key));
49     inserted.first->second.emplace_back(bigtable::SetCell(
50         cell.family_name(), cell.column_qualifier(),
51         duration_cast<milliseconds>(microseconds(cell.timestamp())),
52         cell.value()));
53   }
54   bigtable::BulkMutation bulk;
55   for (auto& kv : mutations) {
56     bulk.emplace_back(std::move(kv.second));
57   }
58   auto failures = table.BulkApply(std::move(bulk));
59   ASSERT_TRUE(failures.empty());
60 }
61 
62 /// The column families used in this test.
63 std::string const kFamily1 = "family1";
64 std::string const kFamily2 = "family2";
65 std::string const kFamily3 = "family3";
66 std::string const kFamily4 = "family4";
67 
TEST_F(DataIntegrationTest,TableApply)68 TEST_F(DataIntegrationTest, TableApply) {
69   auto table = GetTable();
70 
71   std::string const row_key = "row-key-1";
72   std::vector<bigtable::Cell> created{{row_key, kFamily4, "c0", 1000, "v1000"},
73                                       {row_key, kFamily4, "c1", 2000, "v2000"}};
74   Apply(table, row_key, created);
75   std::vector<bigtable::Cell> expected{
76       {row_key, kFamily4, "c0", 1000, "v1000"},
77       {row_key, kFamily4, "c1", 2000, "v2000"}};
78 
79   auto actual = ReadRows(table, bigtable::Filter::PassAllFilter());
80   CheckEqualUnordered(expected, actual);
81 }
82 
TEST_F(DataIntegrationTest,TableBulkApply)83 TEST_F(DataIntegrationTest, TableBulkApply) {
84   auto table = GetTable();
85 
86   std::vector<bigtable::Cell> created{
87       {"row-key-1", kFamily4, "c0", 1000, "v1000"},
88       {"row-key-1", kFamily4, "c1", 2000, "v2000"},
89       {"row-key-2", kFamily4, "c0", 1000, "v1000"},
90       {"row-key-2", kFamily4, "c1", 2000, "v2000"},
91       {"row-key-3", kFamily4, "c0", 1000, "v1000"},
92       {"row-key-3", kFamily4, "c1", 2000, "v2000"},
93       {"row-key-4", kFamily4, "c0", 1000, "v1000"},
94       {"row-key-4", kFamily4, "c1", 2000, "v2000"}};
95   BulkApply(table, created);
96   std::vector<bigtable::Cell> expected{
97       {"row-key-1", kFamily4, "c0", 1000, "v1000"},
98       {"row-key-1", kFamily4, "c1", 2000, "v2000"},
99       {"row-key-2", kFamily4, "c0", 1000, "v1000"},
100       {"row-key-2", kFamily4, "c1", 2000, "v2000"},
101       {"row-key-3", kFamily4, "c0", 1000, "v1000"},
102       {"row-key-3", kFamily4, "c1", 2000, "v2000"},
103       {"row-key-4", kFamily4, "c0", 1000, "v1000"},
104       {"row-key-4", kFamily4, "c1", 2000, "v2000"}};
105 
106   auto actual = ReadRows(table, bigtable::Filter::PassAllFilter());
107   CheckEqualUnordered(expected, actual);
108 }
109 
TEST_F(DataIntegrationTest,TableSingleRow)110 TEST_F(DataIntegrationTest, TableSingleRow) {
111   std::string const row_key = "row-key-1";
112   auto table = GetTable();
113 
114   auto mutation = bigtable::SingleRowMutation(
115       row_key, bigtable::SetCell(kFamily4, "c1", 1_ms, "V1000"),
116       bigtable::SetCell(kFamily4, "c2", 2_ms, "V2000"),
117       bigtable::SetCell(kFamily4, "c3", 3_ms, "V3000"));
118   ASSERT_STATUS_OK(table.Apply(std::move(mutation)));
119   std::vector<bigtable::Cell> expected{
120       {row_key, kFamily4, "c1", 1000, "V1000"},
121       {row_key, kFamily4, "c2", 2000, "V2000"},
122       {row_key, kFamily4, "c3", 3000, "V3000"}};
123 
124   auto actual = ReadRows(table, bigtable::Filter::PassAllFilter());
125   CheckEqualUnordered(expected, actual);
126 }
127 
TEST_F(DataIntegrationTest,TableReadRowTest)128 TEST_F(DataIntegrationTest, TableReadRowTest) {
129   auto table = GetTable();
130   std::string const row_key1 = "row-key-1";
131   std::string const row_key2 = "row-key-2";
132 
133   std::vector<bigtable::Cell> created{
134       {row_key1, kFamily4, "c1", 1000, "v1000"},
135       {row_key2, kFamily4, "c2", 2000, "v2000"}};
136   std::vector<bigtable::Cell> expected{
137       {row_key1, kFamily4, "c1", 1000, "v1000"}};
138 
139   CreateCells(table, created);
140   auto row_cell = table.ReadRow(row_key1, bigtable::Filter::PassAllFilter());
141   ASSERT_STATUS_OK(row_cell);
142   std::vector<bigtable::Cell> actual;
143   actual.emplace_back(row_cell->second.cells().at(0));
144   CheckEqualUnordered(expected, actual);
145 }
146 
TEST_F(DataIntegrationTest,TableReadRowNotExistTest)147 TEST_F(DataIntegrationTest, TableReadRowNotExistTest) {
148   auto table = GetTable();
149   std::string const row_key1 = "row-key-1";
150   std::string const row_key2 = "row-key-2";
151 
152   std::vector<bigtable::Cell> created{
153       {row_key1, kFamily4, "c1", 1000, "v1000"}};
154 
155   CreateCells(table, created);
156   auto row_cell = table.ReadRow(row_key2, bigtable::Filter::PassAllFilter());
157   ASSERT_STATUS_OK(row_cell);
158   EXPECT_FALSE(row_cell->first);
159 }
160 
TEST_F(DataIntegrationTest,TableReadRowsAllRows)161 TEST_F(DataIntegrationTest, TableReadRowsAllRows) {
162   auto table = GetTable();
163   std::string const row_key1 = "row-key-1";
164   std::string const row_key2 = "row-key-2";
165   std::string const row_key3(1024, '3');    // a long key
166   std::string const long_value(1024, 'v');  // a long value
167 
168   std::vector<bigtable::Cell> created{
169       {row_key1, kFamily4, "c1", 1000, "data1"},
170       {row_key1, kFamily4, "c2", 1000, "data2"},
171       {row_key2, kFamily4, "c1", 1000, ""},
172       {row_key3, kFamily4, "c1", 1000, long_value}};
173 
174   CreateCells(table, created);
175 
176   // Some equivalent ways to read the three rows
177   auto read1 =
178       table.ReadRows(bigtable::RowSet(bigtable::RowRange::InfiniteRange()),
179                      bigtable::Filter::PassAllFilter());
180   CheckEqualUnordered(created, MoveCellsFromReader(read1));
181 
182   auto read2 =
183       table.ReadRows(bigtable::RowSet(bigtable::RowRange::InfiniteRange()), 3,
184                      bigtable::Filter::PassAllFilter());
185   CheckEqualUnordered(created, MoveCellsFromReader(read2));
186 
187   auto read3 = table.ReadRows(
188       bigtable::RowSet(bigtable::RowRange::InfiniteRange()),
189       bigtable::RowReader::NO_ROWS_LIMIT, bigtable::Filter::PassAllFilter());
190   CheckEqualUnordered(created, MoveCellsFromReader(read3));
191 
192   if (!UsingCloudBigtableEmulator()) {
193     // TODO(#151) - remove workarounds for emulator bug(s).
194     auto read4 =
195         table.ReadRows(bigtable::RowSet(), bigtable::Filter::PassAllFilter());
196     CheckEqualUnordered(created, MoveCellsFromReader(read4));
197   }
198 }
199 
TEST_F(DataIntegrationTest,TableReadRowsPartialRows)200 TEST_F(DataIntegrationTest, TableReadRowsPartialRows) {
201   auto table = GetTable();
202   std::string const row_key1 = "row-key-1";
203   std::string const row_key2 = "row-key-2";
204   std::string const row_key3 = "row-key-3";
205 
206   std::vector<bigtable::Cell> created{
207       {row_key1, kFamily4, "c1", 1000, "data1"},
208       {row_key1, kFamily4, "c2", 1000, "data2"},
209       {row_key2, kFamily4, "c1", 1000, "data3"},
210       {row_key3, kFamily4, "c1", 1000, "data4"}};
211 
212   CreateCells(table, created);
213 
214   std::vector<bigtable::Cell> expected{
215       {row_key1, kFamily4, "c1", 1000, "data1"},
216       {row_key1, kFamily4, "c2", 1000, "data2"},
217       {row_key2, kFamily4, "c1", 1000, "data3"}};
218 
219   // Some equivalent ways of reading just the first two rows
220   {
221     SCOPED_TRACE(table.table_name() + " ReadRows(key1, key2)");
222     bigtable::RowSet rows;
223     rows.Append(row_key1);
224     rows.Append(row_key2);
225     auto reader =
226         table.ReadRows(std::move(rows), bigtable::Filter::PassAllFilter());
227     CheckEqualUnordered(expected, MoveCellsFromReader(reader));
228   }
229 
230   {
231     SCOPED_TRACE(table.table_name() + " ReadRows(, limit = 2, )");
232     auto reader =
233         table.ReadRows(bigtable::RowSet(bigtable::RowRange::InfiniteRange()), 2,
234                        bigtable::Filter::PassAllFilter());
235     CheckEqualUnordered(expected, MoveCellsFromReader(reader));
236   }
237 
238   {
239     SCOPED_TRACE(table.table_name() + " ReadRows([key1, key2], ...)");
240     bigtable::RowSet rows(bigtable::RowRange::Closed(row_key1, row_key2));
241     auto reader =
242         table.ReadRows(std::move(rows), bigtable::Filter::PassAllFilter());
243     CheckEqualUnordered(expected, MoveCellsFromReader(reader));
244   }
245 }
246 
TEST_F(DataIntegrationTest,TableReadRowsNoRows)247 TEST_F(DataIntegrationTest, TableReadRowsNoRows) {
248   auto table = GetTable();
249   std::string const row_key1 = "row-key-1";
250   std::string const row_key2 = "row-key-2";
251   std::string const row_key3 = "row-key-3";
252 
253   std::vector<bigtable::Cell> created{
254       {row_key1, kFamily4, "c1", 1000, "data1"},
255       {row_key3, kFamily4, "c1", 1000, "data2"}};
256 
257   CreateCells(table, created);
258 
259   std::vector<bigtable::Cell> expected;  // empty
260 
261   // read nonexistent rows
262   auto read1 = table.ReadRows(bigtable::RowSet(row_key2),
263                               bigtable::Filter::PassAllFilter());
264   CheckEqualUnordered(expected, MoveCellsFromReader(read1));
265 
266   auto read2 =
267       table.ReadRows(bigtable::RowSet(bigtable::RowRange::Prefix(row_key2)),
268                      bigtable::Filter::PassAllFilter());
269   CheckEqualUnordered(expected, MoveCellsFromReader(read2));
270 
271   auto read3 = table.ReadRows(bigtable::RowSet(bigtable::RowRange::Empty()),
272                               bigtable::Filter::PassAllFilter());
273   CheckEqualUnordered(expected, MoveCellsFromReader(read3));
274 }
275 
TEST_F(DataIntegrationTest,TableReadRowsWrongTable)276 TEST_F(DataIntegrationTest, TableReadRowsWrongTable) {
277   std::string const table_id = RandomTableId();
278 
279   bigtable::Table table(data_client_, table_id);
280 
281   auto read1 =
282       table.ReadRows(bigtable::RowSet(bigtable::RowRange::InfiniteRange()),
283                      bigtable::Filter::PassAllFilter());
284 
285   auto it = read1.begin();
286   ASSERT_NE(read1.end(), it);
287   EXPECT_FALSE(*it);
288   ++it;
289   EXPECT_EQ(read1.end(), it);
290 }
291 
TEST_F(DataIntegrationTest,TableCheckAndMutateRowPass)292 TEST_F(DataIntegrationTest, TableCheckAndMutateRowPass) {
293   auto table = GetTable();
294   std::string const key = "row-key";
295 
296   std::vector<bigtable::Cell> created{{key, kFamily4, "c1", 0, "v1000"}};
297   CreateCells(table, created);
298   auto result = table.CheckAndMutateRow(
299       key, bigtable::Filter::ValueRegex("v1000"),
300       {bigtable::SetCell(kFamily4, "c2", 0_ms, "v2000")},
301       {bigtable::SetCell(kFamily4, "c3", 0_ms, "v3000")});
302   ASSERT_STATUS_OK(result);
303   EXPECT_EQ(bigtable::MutationBranch::kPredicateMatched, *result);
304   std::vector<bigtable::Cell> expected{{key, kFamily4, "c1", 0, "v1000"},
305                                        {key, kFamily4, "c2", 0, "v2000"}};
306   auto actual = ReadRows(table, bigtable::Filter::PassAllFilter());
307   CheckEqualUnordered(expected, actual);
308 }
309 
TEST_F(DataIntegrationTest,TableCheckAndMutateRowFail)310 TEST_F(DataIntegrationTest, TableCheckAndMutateRowFail) {
311   auto table = GetTable();
312   std::string const key = "row-key";
313 
314   std::vector<bigtable::Cell> created{{key, kFamily4, "c1", 0, "v1000"}};
315   CreateCells(table, created);
316   auto result = table.CheckAndMutateRow(
317       key, bigtable::Filter::ValueRegex("not-there"),
318       {bigtable::SetCell(kFamily4, "c2", 0_ms, "v2000")},
319       {bigtable::SetCell(kFamily4, "c3", 0_ms, "v3000")});
320   ASSERT_STATUS_OK(result);
321   EXPECT_EQ(bigtable::MutationBranch::kPredicateNotMatched, *result);
322   std::vector<bigtable::Cell> expected{{key, kFamily4, "c1", 0, "v1000"},
323                                        {key, kFamily4, "c3", 0, "v3000"}};
324   auto actual = ReadRows(table, bigtable::Filter::PassAllFilter());
325   CheckEqualUnordered(expected, actual);
326 }
327 
TEST_F(DataIntegrationTest,TableReadModifyWriteAppendValueTest)328 TEST_F(DataIntegrationTest, TableReadModifyWriteAppendValueTest) {
329   auto table = GetTable();
330   std::string const row_key1 = "row-key-1";
331   std::string const row_key2 = "row-key-2";
332   std::string const add_suffix1 = "-suffix";
333   std::string const add_suffix2 = "-next";
334   std::string const add_suffix3 = "-newrecord";
335 
336   std::vector<bigtable::Cell> created{
337       {row_key1, kFamily1, "column-id1", 1000, "v1000"},
338       {row_key1, kFamily2, "column-id2", 2000, "v2000"},
339       {row_key1, kFamily3, "column-id1", 2000, "v3000"},
340       {row_key1, kFamily1, "column-id3", 2000, "v5000"}};
341 
342   std::vector<bigtable::Cell> expected{
343       {row_key1, kFamily1, "column-id1", 1000, "v1000" + add_suffix1},
344       {row_key1, kFamily2, "column-id2", 2000, "v2000" + add_suffix2},
345       {row_key1, kFamily3, "column-id3", 2000, add_suffix3}};
346 
347   CreateCells(table, created);
348   auto result_row =
349       table.ReadModifyWriteRow(row_key1,
350                                bigtable::ReadModifyWriteRule::AppendValue(
351                                    kFamily1, "column-id1", add_suffix1),
352                                bigtable::ReadModifyWriteRule::AppendValue(
353                                    kFamily2, "column-id2", add_suffix2),
354                                bigtable::ReadModifyWriteRule::AppendValue(
355                                    kFamily3, "column-id3", add_suffix3));
356   ASSERT_STATUS_OK(result_row);
357   // Returned cells contains timestamp in microseconds which is
358   // not matching with the timestamp in expected cells, So creating
359   // cells by ignoring timestamp
360   auto expected_cells_ignore_timestamp = GetCellsIgnoringTimestamp(expected);
361   auto actual_cells_ignore_timestamp =
362       GetCellsIgnoringTimestamp(result_row->cells());
363 
364   CheckEqualUnordered(expected_cells_ignore_timestamp,
365                       actual_cells_ignore_timestamp);
366 }
367 
TEST_F(DataIntegrationTest,TableReadModifyWriteRowIncrementAmountTest)368 TEST_F(DataIntegrationTest, TableReadModifyWriteRowIncrementAmountTest) {
369   auto table = GetTable();
370   std::string const key = "row-key";
371 
372   // An initial; big-endian int64 number with value 0.
373   std::string v1("\x00\x00\x00\x00\x00\x00\x00\x00", 8);
374   std::vector<bigtable::Cell> created{{key, kFamily1, "c1", 0, v1}};
375 
376   // The expected values as buffers containing big-endian int64 numbers.
377   std::string e1("\x00\x00\x00\x00\x00\x00\x00\x2A", 8);
378   std::string e2("\x00\x00\x00\x00\x00\x00\x00\x07", 8);
379   std::vector<bigtable::Cell> expected{{key, kFamily1, "c1", 0, e1},
380                                        {key, kFamily1, "c2", 0, e2}};
381 
382   CreateCells(table, created);
383   auto row = table.ReadModifyWriteRow(
384       key, bigtable::ReadModifyWriteRule::IncrementAmount(kFamily1, "c1", 42),
385       bigtable::ReadModifyWriteRule::IncrementAmount(kFamily1, "c2", 7));
386   ASSERT_STATUS_OK(row);
387   // Ignore the server set timestamp on the returned cells because it is not
388   // predictable.
389   auto expected_ignore_timestamp = GetCellsIgnoringTimestamp(expected);
390   auto actual_ignore_timestamp = GetCellsIgnoringTimestamp(row->cells());
391 
392   CheckEqualUnordered(expected_ignore_timestamp, actual_ignore_timestamp);
393 }
394 
TEST_F(DataIntegrationTest,TableReadModifyWriteRowMultipleTest)395 TEST_F(DataIntegrationTest, TableReadModifyWriteRowMultipleTest) {
396   auto table = GetTable();
397   std::string const key = "row-key";
398 
399   std::string v1("\x00\x00\x00\x00\x00\x00\x00\x00", 8);
400   std::vector<bigtable::Cell> created{{key, kFamily1, "c1", 0, v1},
401                                       {key, kFamily1, "c3", 0, "start;"},
402                                       {key, kFamily2, "d1", 0, v1},
403                                       {key, kFamily2, "d3", 0, "start;"}};
404 
405   // The expected values as buffers containing big-endian int64 numbers.
406   std::string e1("\x00\x00\x00\x00\x00\x00\x00\x2A", 8);
407   std::string e2("\x00\x00\x00\x00\x00\x00\x00\x07", 8);
408   std::string e3("\x00\x00\x00\x00\x00\x00\x07\xD0", 8);
409   std::string e4("\x00\x00\x00\x00\x00\x00\x0B\xB8", 8);
410   std::vector<bigtable::Cell> expected{{key, kFamily1, "c1", 0, e1},
411                                        {key, kFamily1, "c2", 0, e2},
412                                        {key, kFamily1, "c3", 0, "start;suffix"},
413                                        {key, kFamily1, "c4", 0, "suffix"},
414                                        {key, kFamily2, "d1", 0, e3},
415                                        {key, kFamily2, "d2", 0, e4},
416                                        {key, kFamily2, "d3", 0, "start;suffix"},
417                                        {key, kFamily2, "d4", 0, "suffix"}};
418 
419   CreateCells(table, created);
420   using R = bigtable::ReadModifyWriteRule;
421   auto row =
422       table.ReadModifyWriteRow(key, R::IncrementAmount(kFamily1, "c1", 42),
423                                R::IncrementAmount(kFamily1, "c2", 7),
424                                R::IncrementAmount(kFamily2, "d1", 2000),
425                                R::IncrementAmount(kFamily2, "d2", 3000),
426                                R::AppendValue(kFamily1, "c3", "suffix"),
427                                R::AppendValue(kFamily1, "c4", "suffix"),
428                                R::AppendValue(kFamily2, "d3", "suffix"),
429                                R::AppendValue(kFamily2, "d4", "suffix"));
430   ASSERT_STATUS_OK(row);
431   // Ignore the server set timestamp on the returned cells because it is not
432   // predictable.
433   auto expected_ignore_timestamp = GetCellsIgnoringTimestamp(expected);
434   auto actual_ignore_timestamp = GetCellsIgnoringTimestamp(row->cells());
435 
436   CheckEqualUnordered(expected_ignore_timestamp, actual_ignore_timestamp);
437 }
438 
TEST_F(DataIntegrationTest,TableCellValueInt64Test)439 TEST_F(DataIntegrationTest, TableCellValueInt64Test) {
440   auto table = GetTable();
441   std::string const key = "row-key";
442 
443   std::vector<bigtable::Cell> created{{key, kFamily1, "c1", 0, 42},
444                                       {key, kFamily1, "c3", 0, "start;"},
445                                       {key, kFamily2, "d1", 0, 2},
446                                       {key, kFamily2, "d2", 0, 5012},
447                                       {key, kFamily2, "d3", 0, "start;"}};
448 
449   std::vector<bigtable::Cell> expected{
450       {key, kFamily1, "c1", 0, 40},
451       {key, kFamily1, "c2", 0, 7},
452       {key, kFamily1, "c3", 0, "start;suffix"},
453       {key, kFamily2, "d1", 0, 2002},
454       {key, kFamily2, "d2", 0, 9999998012},
455       {key, kFamily2, "d3", 0, "start;suffix"}};
456 
457   CreateCells(table, created);
458   using R = bigtable::ReadModifyWriteRule;
459   auto row =
460       table.ReadModifyWriteRow(key, R::IncrementAmount(kFamily1, "c1", -2),
461                                R::IncrementAmount(kFamily1, "c2", 7),
462                                R::IncrementAmount(kFamily2, "d1", 2000),
463                                R::IncrementAmount(kFamily2, "d2", 9999993000),
464                                R::AppendValue(kFamily1, "c3", "suffix"),
465                                R::AppendValue(kFamily2, "d3", "suffix"));
466   ASSERT_STATUS_OK(row);
467   // Ignore the server set timestamp on the returned cells because it is not
468   // predictable.
469   auto expected_ignore_timestamp = GetCellsIgnoringTimestamp(expected);
470   auto actual_ignore_timestamp = GetCellsIgnoringTimestamp(row->cells());
471 
472   CheckEqualUnordered(expected_ignore_timestamp, actual_ignore_timestamp);
473 }
474 
TEST_F(DataIntegrationTest,TableSampleRowKeysTest)475 TEST_F(DataIntegrationTest, TableSampleRowKeysTest) {
476   auto table = GetTable();
477 
478   // Create kBatchSize * kBatchCount rows.
479   int constexpr kBatchCount = 10;
480   int constexpr kBatchSize = 5000;
481   int constexpr kColumnCount = 10;
482   int rowid = 0;
483   for (int batch = 0; batch != kBatchCount; ++batch) {
484     bigtable::BulkMutation bulk;
485     for (int row = 0; row != kBatchSize; ++row) {
486       std::ostringstream os;
487       os << "row:" << std::setw(9) << std::setfill('0') << rowid;
488 
489       // Build a mutation that creates 10 columns.
490       bigtable::SingleRowMutation mutation(os.str());
491       for (int col = 0; col != kColumnCount; ++col) {
492         std::string colid = "c" + std::to_string(col);
493         std::string value = colid + "#" + os.str();
494         mutation.emplace_back(bigtable::SetCell(kFamily1, std::move(colid),
495                                                 std::chrono::milliseconds(0),
496                                                 std::move(value)));
497       }
498       bulk.emplace_back(std::move(mutation));
499       ++rowid;
500     }
501     auto failures = table.BulkApply(std::move(bulk));
502     ASSERT_TRUE(failures.empty()) << "failures=" << [&failures]() {
503       std::ostringstream os;
504       char const* sep = "[";
505       for (auto const& f : failures) {
506         os << sep << "failed[" << f.original_index() << "]=" << f.status();
507         sep = ", ";
508       }
509       os << "]";
510       return os.str();
511     }();
512   }
513   auto samples = table.SampleRows();
514   ASSERT_STATUS_OK(samples);
515 
516   // It is somewhat hard to verify that the values returned here are correct.
517   // We cannot check the specific values, not even the format, of the row keys
518   // because Cloud Bigtable might return an empty row key (for "end of table"),
519   // and it might return row keys that have never been written to.
520   // All we can check is that this is not empty, and that the offsets are in
521   // ascending order.
522   EXPECT_FALSE(samples->empty());
523   std::int64_t previous = 0;
524   for (auto const& s : *samples) {
525     EXPECT_LE(previous, s.offset_bytes);
526     previous = s.offset_bytes;
527   }
528   // At least one of the samples should have non-zero offset:
529   auto last = samples->back();
530   EXPECT_LT(0, last.offset_bytes);
531 }
532 
TEST_F(DataIntegrationTest,TableReadMultipleCellsBigValue)533 TEST_F(DataIntegrationTest, TableReadMultipleCellsBigValue) {
534   if (UsingCloudBigtableEmulator()) {
535     // TODO(#151) - remove workarounds for emulator bug(s).
536     return;
537   }
538 
539   auto table = GetTable();
540 
541   std::string const row_key = "row-key-1";
542   // cell vector contains 4 cells of 32 MiB each, or 128 MiB (without
543   // considering any overhead). That is much larger that the default gRPC
544   // message size (~4 MiB), and yet much smaller than the configured message
545   // size (~256MiB). Therefore, the row would not fit in a message if we failed
546   // to change the default configuration, but it is not so large that it will
547   // fail to work if we miss the overhead estimation.
548   auto constexpr kMib = 1024 * 1024UL;
549   auto constexpr kCellSize = 32 * kMib;
550   auto constexpr kCellCount = 4;
551   // Smaller rows than this size are not a good test, they would pass with the
552   // default setting, so only accept rows that are at least 10x the default
553   // setting of 4 MiB.
554   auto const min_row_size = 10 * 4 * kMib;
555   // Larger rows than this size are not a good test, they would fail even if the
556   // setting was working.
557   auto const max_row_size = 256 * kMib;
558 
559   std::string value(kCellSize, 'a');
560   std::vector<bigtable::Cell> created;
561   std::vector<bigtable::Cell> expected;
562 
563   for (int i = 0; i < kCellCount; i++) {
564     auto col_qualifier = "c" + std::to_string(i);
565     created.emplace_back(row_key, kFamily4, col_qualifier, 0, value);
566     expected.emplace_back(row_key, kFamily4, col_qualifier, 0, value);
567   }
568 
569   CreateCells(table, created);
570 
571   auto result = table.ReadRow(row_key, bigtable::Filter::PassAllFilter());
572   ASSERT_STATUS_OK(result);
573   EXPECT_TRUE(result->first);
574 
575   std::size_t total_row_size = 0;
576   for (auto const& cell : result->second.cells()) {
577     total_row_size += cell.value().size();
578   }
579   EXPECT_LT(total_row_size, max_row_size);
580   EXPECT_GT(total_row_size, min_row_size);
581 
582   // Ignore the server set timestamp on the returned cells because it is not
583   // predictable.
584   auto expected_ignore_timestamp = GetCellsIgnoringTimestamp(expected);
585   auto actual_ignore_timestamp =
586       GetCellsIgnoringTimestamp(result->second.cells());
587   CheckEqualUnordered(expected_ignore_timestamp, actual_ignore_timestamp);
588 }
589 
590 }  // anonymous namespace
591 
main(int argc,char * argv[])592 int main(int argc, char* argv[]) {
593   ::testing::InitGoogleMock(&argc, argv);
594   (void)::testing::AddGlobalTestEnvironment(
595       new ::bigtable::testing::TableTestEnvironment);
596 
597   return RUN_ALL_TESTS();
598 }
599