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