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/table.h"
16 #include "google/cloud/bigtable/testing/mock_read_rows_reader.h"
17 #include "google/cloud/bigtable/testing/table_test_fixture.h"
18 #include "google/cloud/testing_util/assert_ok.h"
19 
20 namespace bigtable = google::cloud::bigtable;
21 using testing::_;
22 using testing::DoAll;
23 using testing::Return;
24 using testing::SetArgPointee;
25 
26 /// Define helper types and functions for this test.
27 namespace {
28 class TableReadRowsTest : public bigtable::testing::TableTestFixture {};
29 using bigtable::testing::MockReadRowsReader;
30 }  // anonymous namespace
31 
TEST_F(TableReadRowsTest,ReadRowsCanReadOneRow)32 TEST_F(TableReadRowsTest, ReadRowsCanReadOneRow) {
33   auto response = bigtable::testing::ReadRowsResponseFromString(R"(
34       chunks {
35         row_key: "r1"
36         family_name { value: "fam" }
37         qualifier { value: "qual" }
38         timestamp_micros: 42000
39         value: "value"
40         commit_row: true
41       }
42       )");
43 
44   // must be a new pointer, it is wrapped in unique_ptr by ReadRows
45   auto stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows");
46   EXPECT_CALL(*stream, Read(_))
47       .WillOnce(DoAll(SetArgPointee<0>(response), Return(true)))
48       .WillOnce(Return(false));
49   EXPECT_CALL(*stream, Finish()).WillOnce(Return(grpc::Status::OK));
50   EXPECT_CALL(*client_, ReadRows(_, _)).WillOnce(stream->MakeMockReturner());
51 
52   auto reader =
53       table_.ReadRows(bigtable::RowSet(), bigtable::Filter::PassAllFilter());
54 
55   auto it = reader.begin();
56   EXPECT_NE(it, reader.end());
57   ASSERT_STATUS_OK(*it);
58   EXPECT_EQ((*it)->row_key(), "r1");
59   EXPECT_EQ(++it, reader.end());
60 }
61 
TEST_F(TableReadRowsTest,ReadRowsCanReadWithRetries)62 TEST_F(TableReadRowsTest, ReadRowsCanReadWithRetries) {
63   auto response = bigtable::testing::ReadRowsResponseFromString(R"(
64       chunks {
65         row_key: "r1"
66         family_name { value: "fam" }
67         qualifier { value: "qual" }
68         timestamp_micros: 42000
69         value: "value"
70         commit_row: true
71       }
72       )");
73 
74   auto response_retry = bigtable::testing::ReadRowsResponseFromString(R"(
75       chunks {
76         row_key: "r2"
77         family_name { value: "fam" }
78         qualifier { value: "qual" }
79         timestamp_micros: 42000
80         value: "value"
81         commit_row: true
82       }
83       )");
84 
85   // must be a new pointer, it is wrapped in unique_ptr by ReadRows
86   auto stream = new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows");
87   auto stream_retry =
88       new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows");
89 
90   EXPECT_CALL(*client_, ReadRows(_, _))
91       .WillOnce(stream->MakeMockReturner())
92       .WillOnce(stream_retry->MakeMockReturner());
93 
94   EXPECT_CALL(*stream, Read(_))
95       .WillOnce(DoAll(SetArgPointee<0>(response), Return(true)))
96       .WillOnce(Return(false));
97 
98   EXPECT_CALL(*stream, Finish())
99       .WillOnce(
100           Return(grpc::Status(grpc::StatusCode::UNAVAILABLE, "try-again")));
101 
102   EXPECT_CALL(*stream_retry, Read(_))
103       .WillOnce(DoAll(SetArgPointee<0>(response_retry), Return(true)))
104       .WillOnce(Return(false));
105 
106   EXPECT_CALL(*stream_retry, Finish()).WillOnce(Return(grpc::Status::OK));
107 
108   auto reader =
109       table_.ReadRows(bigtable::RowSet(), bigtable::Filter::PassAllFilter());
110 
111   auto it = reader.begin();
112   EXPECT_NE(it, reader.end());
113   ASSERT_STATUS_OK(*it);
114   EXPECT_EQ((*it)->row_key(), "r1");
115   ++it;
116   EXPECT_NE(it, reader.end());
117   ASSERT_STATUS_OK(*it);
118   EXPECT_EQ((*it)->row_key(), "r2");
119   EXPECT_EQ(++it, reader.end());
120 }
121 
TEST_F(TableReadRowsTest,ReadRowsThrowsWhenTooManyErrors)122 TEST_F(TableReadRowsTest, ReadRowsThrowsWhenTooManyErrors) {
123   EXPECT_CALL(*client_, ReadRows(_, _)).WillRepeatedly(testing::WithoutArgs([] {
124     auto stream =
125         new MockReadRowsReader("google.bigtable.v2.Bigtable.ReadRows");
126     EXPECT_CALL(*stream, Read(_)).WillOnce(Return(false));
127     EXPECT_CALL(*stream, Finish())
128         .WillOnce(
129             Return(grpc::Status(grpc::StatusCode::UNAVAILABLE, "broken")));
130     return stream->AsUniqueMocked();
131   }));
132 
133   auto table = bigtable::Table(
134       client_, "table_id", bigtable::LimitedErrorCountRetryPolicy(3),
135       bigtable::ExponentialBackoffPolicy(std::chrono::seconds(0),
136                                          std::chrono::seconds(0)),
137       bigtable::SafeIdempotentMutationPolicy());
138   auto reader =
139       table.ReadRows(bigtable::RowSet(), bigtable::Filter::PassAllFilter());
140 
141   auto it = reader.begin();
142   ASSERT_NE(reader.end(), it);
143   ASSERT_FALSE(*it);
144   ++it;
145   ASSERT_EQ(reader.end(), it);
146 }
147