1 // Copyright 2020 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 
15 #include "google/cloud/bigtable/instance_admin.h"
16 #include "google/cloud/bigtable/testing/table_integration_test.h"
17 #include "google/cloud/internal/getenv.h"
18 #include "google/cloud/testing_util/assert_ok.h"
19 #include "google/cloud/testing_util/chrono_literals.h"
20 #include <gmock/gmock.h>
21 
22 namespace google {
23 namespace cloud {
24 namespace bigtable {
25 inline namespace BIGTABLE_CLIENT_NS {
26 namespace {
27 
28 using ::testing::Contains;
29 using ::testing::Not;
30 namespace btadmin = google::bigtable::admin::v2;
31 namespace bigtable = google::cloud::bigtable;
32 
33 class AdminIAMPolicyIntegrationTest
34     : public bigtable::testing::TableIntegrationTest {
35  protected:
36   std::shared_ptr<AdminClient> admin_client_;
37   std::unique_ptr<TableAdmin> table_admin_;
38   std::string service_account_;
39 
SetUp()40   void SetUp() override {
41     service_account_ = google::cloud::internal::GetEnv(
42                            "GOOGLE_CLOUD_CPP_BIGTABLE_TEST_SERVICE_ACCOUNT")
43                            .value_or("");
44     ASSERT_FALSE(service_account_.empty());
45 
46     TableIntegrationTest::SetUp();
47     admin_client_ = CreateDefaultAdminClient(
48         testing::TableTestEnvironment::project_id(), ClientOptions());
49     table_admin_ = absl::make_unique<TableAdmin>(
50         admin_client_, bigtable::testing::TableTestEnvironment::instance_id());
51   }
52 };
53 
TEST_F(AdminIAMPolicyIntegrationTest,AsyncSetGetTestIamAPIsTest)54 TEST_F(AdminIAMPolicyIntegrationTest, AsyncSetGetTestIamAPIsTest) {
55   std::string const table_id = RandomTableId();
56 
57   auto iam_policy = bigtable::IamPolicy({bigtable::IamBinding(
58       "roles/bigtable.reader", {"serviceAccount:" + service_account_})});
59 
60   TableConfig table_config({{"fam", GcRule::MaxNumVersions(5)},
61                             {"foo", GcRule::MaxAge(std::chrono::hours(24))}},
62                            {"a1000", "a2000", "b3000", "m5000"});
63 
64   CompletionQueue cq;
65   std::thread pool([&cq] { cq.Run(); });
66 
67   future<void> chain =
68       table_admin_->AsyncListTables(cq, btadmin::Table::NAME_ONLY)
69           .then([&](future<StatusOr<std::vector<btadmin::Table>>> fut) {
70             StatusOr<std::vector<btadmin::Table>> result = fut.get();
71             EXPECT_STATUS_OK(result);
72             EXPECT_THAT(TableNames(*result),
73                         Not(Contains(table_admin_->instance_name() +
74                                      "/tables/" + table_id)))
75                 << "Table (" << table_id << ") already exists."
76                 << " This is unexpected, as the table ids are"
77                 << " generated at random.";
78             return table_admin_->AsyncCreateTable(cq, table_id, table_config);
79           })
80           .then([&](future<StatusOr<btadmin::Table>> fut) {
81             StatusOr<btadmin::Table> result = fut.get();
82             EXPECT_STATUS_OK(result);
83             EXPECT_THAT(result->name(), ::testing::HasSubstr(table_id));
84             return table_admin_->AsyncSetIamPolicy(cq, table_id, iam_policy);
85           })
86           .then([&](future<StatusOr<google::iam::v1::Policy>> fut) {
87             StatusOr<google::iam::v1::Policy> get_result = fut.get();
88             EXPECT_STATUS_OK(get_result);
89             return table_admin_->AsyncGetIamPolicy(cq, table_id);
90           })
91           .then([&](future<StatusOr<google::iam::v1::Policy>> fut) {
92             StatusOr<google::iam::v1::Policy> get_result = fut.get();
93             EXPECT_STATUS_OK(get_result);
94             return table_admin_->AsyncTestIamPermissions(
95                 cq, table_id,
96                 {"bigtable.tables.get", "bigtable.tables.readRows"});
97           })
98           .then([&](future<StatusOr<std::vector<std::string>>> fut) {
99             StatusOr<std::vector<std::string>> get_result = fut.get();
100             EXPECT_STATUS_OK(get_result);
101             EXPECT_EQ(2, get_result->size());
102             return table_admin_->AsyncDeleteTable(cq, table_id);
103           })
104           .then([&](future<Status> fut) {
105             Status delete_result = fut.get();
106             EXPECT_STATUS_OK(delete_result);
107             return table_admin_->AsyncListTables(cq, btadmin::Table::NAME_ONLY);
108           })
109           .then([&](future<StatusOr<std::vector<btadmin::Table>>> fut) {
110             StatusOr<std::vector<btadmin::Table>> result = fut.get();
111             EXPECT_STATUS_OK(result);
112             EXPECT_THAT(TableNames(*result),
113                         Not(Contains(table_admin_->instance_name() +
114                                      "/tables/" + table_id)))
115                 << "Table (" << table_id << ") already exists."
116                 << " This is unexpected, as the table ids are"
117                 << " generated at random.";
118           });
119 
120   chain.get();
121   SUCCEED();  // we expect that previous operations do not fail.
122 
123   cq.Shutdown();
124   pool.join();
125 }
126 
127 /// @test Verify that IAM Policy APIs work as expected.
TEST_F(AdminIAMPolicyIntegrationTest,SetGetTestIamAPIsTest)128 TEST_F(AdminIAMPolicyIntegrationTest, SetGetTestIamAPIsTest) {
129   using GC = bigtable::GcRule;
130   std::string const table_id = RandomTableId();
131 
132   // verify new table id in current table list
133   auto previous_table_list =
134       table_admin_->ListTables(btadmin::Table::NAME_ONLY);
135   ASSERT_STATUS_OK(previous_table_list);
136   ASSERT_THAT(
137       TableNames(*previous_table_list),
138       Not(Contains(table_admin_->instance_name() + "/tables/" + table_id)))
139       << "Table (" << table_id << ") already exists."
140       << " This is unexpected, as the table ids are generated at random.";
141 
142   // create table config
143   bigtable::TableConfig table_config(
144       {{"fam", GC::MaxNumVersions(5)},
145        {"foo", GC::MaxAge(std::chrono::hours(24))}},
146       {"a1000", "a2000", "b3000", "m5000"});
147 
148   // create table
149   ASSERT_STATUS_OK(table_admin_->CreateTable(table_id, table_config));
150 
151   auto iam_policy = bigtable::IamPolicy({bigtable::IamBinding(
152       "roles/bigtable.reader", {"serviceAccount:" + service_account_})});
153 
154   auto initial_policy = table_admin_->SetIamPolicy(table_id, iam_policy);
155   ASSERT_STATUS_OK(initial_policy);
156 
157   auto fetched_policy = table_admin_->GetIamPolicy(table_id);
158   ASSERT_STATUS_OK(fetched_policy);
159 
160   EXPECT_EQ(initial_policy->version(), fetched_policy->version());
161   EXPECT_EQ(initial_policy->etag(), fetched_policy->etag());
162 
163   auto permission_set = table_admin_->TestIamPermissions(
164       table_id, {"bigtable.tables.get", "bigtable.tables.readRows"});
165   ASSERT_STATUS_OK(permission_set);
166 
167   EXPECT_EQ(2, permission_set->size());
168   EXPECT_STATUS_OK(table_admin_->DeleteTable(table_id));
169 }
170 
171 }  // namespace
172 }  // namespace BIGTABLE_CLIENT_NS
173 }  // namespace bigtable
174 }  // namespace cloud
175 }  // namespace google
176 
main(int argc,char * argv[])177 int main(int argc, char* argv[]) {
178   ::testing::InitGoogleMock(&argc, argv);
179   (void)::testing::AddGlobalTestEnvironment(
180       new google::cloud::bigtable::testing::TableTestEnvironment);
181   return RUN_ALL_TESTS();
182 }
183