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/internal/time_utils.h"
19 #include "google/cloud/testing_util/assert_ok.h"
20 #include "google/cloud/testing_util/chrono_literals.h"
21 #include "google/cloud/testing_util/contains_once.h"
22 #include <google/protobuf/util/time_util.h>
23 #include <gmock/gmock.h>
24
25 namespace google {
26 namespace cloud {
27 namespace bigtable {
28 inline namespace BIGTABLE_CLIENT_NS {
29 namespace {
30
31 using ::google::cloud::testing_util::ContainsOnce;
32 using ::testing::Contains;
33 using ::testing::Not;
34 namespace btadmin = google::bigtable::admin::v2;
35 namespace bigtable = google::cloud::bigtable;
36
37 class AdminBackupAsyncFutureIntegrationTest
38 : public bigtable::testing::TableIntegrationTest {
39 protected:
40 std::shared_ptr<AdminClient> admin_client_;
41 std::unique_ptr<TableAdmin> table_admin_;
42 std::unique_ptr<bigtable::InstanceAdmin> instance_admin_;
43
SetUp()44 void SetUp() override {
45 if (google::cloud::internal::GetEnv(
46 "ENABLE_BIGTABLE_ADMIN_INTEGRATION_TESTS")
47 .value_or("") != "yes") {
48 GTEST_SKIP();
49 }
50
51 TableIntegrationTest::SetUp();
52 admin_client_ = CreateDefaultAdminClient(
53 testing::TableTestEnvironment::project_id(), ClientOptions());
54 table_admin_ = absl::make_unique<TableAdmin>(
55 admin_client_, bigtable::testing::TableTestEnvironment::instance_id());
56 auto instance_admin_client = bigtable::CreateDefaultInstanceAdminClient(
57 bigtable::testing::TableTestEnvironment::project_id(),
58 bigtable::ClientOptions());
59 instance_admin_ =
60 absl::make_unique<bigtable::InstanceAdmin>(instance_admin_client);
61 }
62 };
63
64 /// @test Verify that `bigtable::TableAdmin` Backup Async CRUD operations work
65 /// as expected.
TEST_F(AdminBackupAsyncFutureIntegrationTest,CreateListGetUpdateRestoreDeleteBackup)66 TEST_F(AdminBackupAsyncFutureIntegrationTest,
67 CreateListGetUpdateRestoreDeleteBackup) {
68 std::string const table_id = RandomTableId();
69 CompletionQueue cq;
70 std::thread pool([&cq] { cq.Run(); });
71
72 // verify new table id in current table list
73 auto previous_table_list =
74 table_admin_->ListTables(btadmin::Table::NAME_ONLY);
75 ASSERT_STATUS_OK(previous_table_list);
76 ASSERT_THAT(
77 TableNames(*previous_table_list),
78 Not(Contains(table_admin_->instance_name() + "/tables/" + table_id)))
79 << "Table (" << table_id << ") already exists."
80 << " This is unexpected, as the table ids are"
81 << " generated at random.";
82
83 TableConfig table_config({{"fam", GcRule::MaxNumVersions(5)},
84 {"foo", GcRule::MaxAge(std::chrono::hours(24))}},
85 {"a1000", "a2000", "b3000", "m5000"});
86
87 // create table
88 ASSERT_STATUS_OK(table_admin_->CreateTable(table_id, table_config));
89
90 auto clusters_list =
91 instance_admin_->ListClusters(table_admin_->instance_id());
92 ASSERT_STATUS_OK(clusters_list);
93 std::string const backup_cluster_full_name =
94 clusters_list->clusters.begin()->name();
95 std::string const backup_cluster_id = backup_cluster_full_name.substr(
96 backup_cluster_full_name.rfind('/') + 1,
97 backup_cluster_full_name.size() - backup_cluster_full_name.rfind('/'));
98 std::string const backup_id = RandomBackupId();
99 std::string const backup_full_name =
100 backup_cluster_full_name + "/backups/" + backup_id;
101 google::protobuf::Timestamp const expire_time =
102 google::protobuf::util::TimeUtil::GetCurrentTime() +
103 google::protobuf::util::TimeUtil::HoursToDuration(12);
104 google::protobuf::Timestamp const updated_expire_time =
105 expire_time + google::protobuf::util::TimeUtil::HoursToDuration(12);
106
107 future<void> chain =
108 table_admin_->AsyncListBackups(cq, {})
109 .then([&](future<StatusOr<std::vector<btadmin::Backup>>> fut) {
110 StatusOr<std::vector<btadmin::Backup>> result = fut.get();
111 EXPECT_STATUS_OK(result);
112 EXPECT_THAT(BackupNames(*result),
113 Not(Contains(table_admin_->instance_name() +
114 "/backups/" + backup_id)))
115 << "Backup (" << backup_id << ") already exists."
116 << " This is unexpected, as the backup ids are"
117 << " generated at random.";
118 return table_admin_->AsyncCreateBackup(
119 cq, {backup_cluster_id, backup_id, table_id,
120 google::cloud::internal::ToChronoTimePoint(expire_time)});
121 })
122 .then([&](future<StatusOr<btadmin::Backup>> fut) {
123 StatusOr<btadmin::Backup> result = fut.get();
124 EXPECT_STATUS_OK(result);
125 EXPECT_THAT(result->name(), ::testing::HasSubstr(backup_id));
126 return table_admin_->AsyncGetBackup(cq, backup_cluster_id,
127 backup_id);
128 })
129 .then([&](future<StatusOr<btadmin::Backup>> fut) {
130 StatusOr<btadmin::Backup> get_result = fut.get();
131 EXPECT_STATUS_OK(get_result);
132 EXPECT_EQ(get_result->name(), backup_full_name);
133 return table_admin_->AsyncUpdateBackup(
134 cq, {backup_cluster_id, backup_id,
135 google::cloud::internal::ToChronoTimePoint(
136 updated_expire_time)});
137 })
138 .then([&](future<StatusOr<btadmin::Backup>> fut) {
139 StatusOr<btadmin::Backup> update_result = fut.get();
140 EXPECT_STATUS_OK(update_result);
141 EXPECT_EQ(update_result->name(), backup_full_name);
142 EXPECT_EQ(update_result->expire_time(), updated_expire_time);
143 return table_admin_->AsyncDeleteTable(cq, table_id);
144 })
145 .then([&](future<Status> fut) {
146 Status delete_table_result = fut.get();
147 EXPECT_STATUS_OK(delete_table_result);
148 return table_admin_->AsyncRestoreTable(
149 cq, {table_id, backup_cluster_id, backup_id});
150 })
151 .then([&](future<StatusOr<btadmin::Table>> fut) {
152 auto restore_result = fut.get();
153 EXPECT_STATUS_OK(restore_result);
154 return table_admin_->AsyncDeleteBackup(cq, backup_cluster_id,
155 backup_id);
156 })
157 .then([&](future<Status> fut) {
158 Status delete_result = fut.get();
159 EXPECT_STATUS_OK(delete_result);
160 });
161 chain.get();
162
163 // verify table was restored
164 auto current_table_list = table_admin_->ListTables(btadmin::Table::NAME_ONLY);
165 ASSERT_STATUS_OK(current_table_list);
166 EXPECT_THAT(
167 TableNames(*current_table_list),
168 ContainsOnce(table_admin_->instance_name() + "/tables/" + table_id));
169
170 // delete table
171 EXPECT_STATUS_OK(table_admin_->DeleteTable(table_id));
172
173 SUCCEED(); // we expect that previous operations do not fail.
174
175 cq.Shutdown();
176 pool.join();
177 }
178
179 } // namespace
180 } // namespace BIGTABLE_CLIENT_NS
181 } // namespace bigtable
182 } // namespace cloud
183 } // namespace google
184
main(int argc,char * argv[])185 int main(int argc, char* argv[]) {
186 ::testing::InitGoogleMock(&argc, argv);
187 (void)::testing::AddGlobalTestEnvironment(
188 new google::cloud::bigtable::testing::TableTestEnvironment);
189 return RUN_ALL_TESTS();
190 }
191