/Users/deen/code/yugabyte-db/src/yb/master/master-test.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // or more contributor license agreements. See the NOTICE file |
2 | | // distributed with this work for additional information |
3 | | // regarding copyright ownership. The ASF licenses this file |
4 | | // to you under the Apache License, Version 2.0 (the |
5 | | // "License"); you may not use this file except in compliance |
6 | | // with the License. You may obtain a copy of the License at |
7 | | // |
8 | | // http://www.apache.org/licenses/LICENSE-2.0 |
9 | | // |
10 | | // Unless required by applicable law or agreed to in writing, |
11 | | // software distributed under the License is distributed on an |
12 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
13 | | // KIND, either express or implied. See the License for the |
14 | | // specific language governing permissions and limitations |
15 | | // under the License. |
16 | | // |
17 | | // The following only applies to changes made to this file as part of YugaByte development. |
18 | | // |
19 | | // Portions Copyright (c) YugaByte, Inc. |
20 | | // |
21 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
22 | | // in compliance with the License. You may obtain a copy of the License at |
23 | | // |
24 | | // http://www.apache.org/licenses/LICENSE-2.0 |
25 | | // |
26 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
27 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
28 | | // or implied. See the License for the specific language governing permissions and limitations |
29 | | // under the License. |
30 | | // |
31 | | |
32 | | #include <algorithm> |
33 | | #include <memory> |
34 | | #include <sstream> |
35 | | #include <string> |
36 | | #include <tuple> |
37 | | #include <vector> |
38 | | |
39 | | #include <gtest/gtest.h> |
40 | | |
41 | | #include "yb/common/ql_type.h" |
42 | | #include "yb/common/schema.h" |
43 | | #include "yb/common/wire_protocol.h" |
44 | | |
45 | | #include "yb/gutil/casts.h" |
46 | | #include "yb/gutil/strings/substitute.h" |
47 | | |
48 | | #include "yb/master/call_home.h" |
49 | | #include "yb/master/catalog_manager.h" |
50 | | #include "yb/master/master-test-util.h" |
51 | | #include "yb/master/master-test_base.h" |
52 | | #include "yb/master/master.h" |
53 | | #include "yb/master/master_client.proxy.h" |
54 | | #include "yb/master/master_cluster.proxy.h" |
55 | | #include "yb/master/master_ddl.proxy.h" |
56 | | #include "yb/master/master_heartbeat.proxy.h" |
57 | | #include "yb/master/master_error.h" |
58 | | #include "yb/master/mini_master.h" |
59 | | #include "yb/master/sys_catalog.h" |
60 | | |
61 | | #include "yb/rpc/messenger.h" |
62 | | #include "yb/rpc/proxy.h" |
63 | | |
64 | | #include "yb/server/server_base.proxy.h" |
65 | | |
66 | | #include "yb/util/countdown_latch.h" |
67 | | #include "yb/util/jsonreader.h" |
68 | | #include "yb/util/metrics.h" |
69 | | #include "yb/util/monotime.h" |
70 | | #include "yb/util/random_util.h" |
71 | | #include "yb/util/status.h" |
72 | | #include "yb/util/status_log.h" |
73 | | #include "yb/util/test_util.h" |
74 | | #include "yb/util/thread.h" |
75 | | #include "yb/util/tsan_util.h" |
76 | | #include "yb/util/user.h" |
77 | | |
78 | | DECLARE_string(callhome_collection_level); |
79 | | DECLARE_string(callhome_tag); |
80 | | DECLARE_string(callhome_url); |
81 | | DECLARE_bool(callhome_enabled); |
82 | | DECLARE_int32(callhome_interval_secs); |
83 | | DECLARE_double(leader_failure_max_missed_heartbeat_periods); |
84 | | DECLARE_int32(TEST_simulate_slow_table_create_secs); |
85 | | DECLARE_bool(TEST_return_error_if_namespace_not_found); |
86 | | DECLARE_bool(TEST_hang_on_namespace_transition); |
87 | | DECLARE_bool(TEST_simulate_crash_after_table_marked_deleting); |
88 | | DECLARE_int32(TEST_sys_catalog_write_rejection_percentage); |
89 | | DECLARE_bool(TEST_tablegroup_master_only); |
90 | | DECLARE_bool(TEST_simulate_port_conflict_error); |
91 | | |
92 | | METRIC_DECLARE_counter(block_cache_misses); |
93 | | METRIC_DECLARE_counter(block_cache_hits); |
94 | | |
95 | | namespace yb { |
96 | | namespace master { |
97 | | |
98 | | using strings::Substitute; |
99 | | |
100 | | class MasterTest : public MasterTestBase { |
101 | | }; |
102 | | |
103 | 1 | TEST_F(MasterTest, TestPingServer) { |
104 | | // Ping the server. |
105 | 1 | server::PingRequestPB req; |
106 | 1 | server::PingResponsePB resp; |
107 | | |
108 | 1 | rpc::ProxyCache proxy_cache(client_messenger_.get()); |
109 | 1 | server::GenericServiceProxy generic_proxy(&proxy_cache, mini_master_->bound_rpc_addr()); |
110 | 1 | ASSERT_OK(generic_proxy.Ping(req, &resp, ResetAndGetController())); |
111 | 1 | } |
112 | | |
113 | 2 | static void MakeHostPortPB(const std::string& host, uint32_t port, HostPortPB* pb) { |
114 | 2 | pb->set_host(host); |
115 | 2 | pb->set_port(port); |
116 | 2 | } |
117 | | |
118 | | // Test that shutting down a MiniMaster without starting it does not |
119 | | // SEGV. |
120 | 1 | TEST_F(MasterTest, TestShutdownWithoutStart) { |
121 | 1 | MiniMaster m(Env::Default(), "/xxxx", AllocateFreePort(), AllocateFreePort(), 0); |
122 | 1 | m.Shutdown(); |
123 | 1 | } |
124 | | |
125 | 1 | TEST_F(MasterTest, TestCallHome) { |
126 | 1 | string json; |
127 | 1 | CountDownLatch latch(1); |
128 | 1 | const char* tag_value = "callhome-test"; |
129 | | |
130 | 1 | auto webserver_dir = GetTestPath("webserver-docroot"); |
131 | 1 | CHECK_OK(env_->CreateDir(webserver_dir)); |
132 | | |
133 | 1 | WebserverOptions opts; |
134 | 1 | opts.port = 0; |
135 | 1 | opts.doc_root = webserver_dir; |
136 | 1 | Webserver webserver(opts, "WebserverTest"); |
137 | 1 | ASSERT_OK(webserver.Start()); |
138 | | |
139 | 1 | std::vector<Endpoint> addrs; |
140 | 1 | ASSERT_OK(webserver.GetBoundAddresses(&addrs)); |
141 | 1 | ASSERT_EQ(addrs.size(), 1); |
142 | 1 | auto addr = addrs[0]; |
143 | | |
144 | 3 | auto handler = [&json, &latch] (const Webserver::WebRequest& req, Webserver::WebResponse* resp) { |
145 | 3 | ASSERT_EQ(req.request_method, "POST"); |
146 | 3 | ASSERT_EQ(json, req.post_data); |
147 | 3 | latch.CountDown(); |
148 | 3 | }; |
149 | | |
150 | 1 | webserver.RegisterPathHandler("/callhome", "callhome", handler); |
151 | 1 | FLAGS_callhome_tag = tag_value; |
152 | 1 | FLAGS_callhome_url = Format("http://$0/callhome", addr); |
153 | | |
154 | 1 | set<string> low {"cluster_uuid", "node_uuid", "server_type", "version_info", |
155 | 1 | "timestamp", "tables", "masters", "tservers", "tablets", "gflags"}; |
156 | 1 | std::unordered_map<string, set<string>> collection_levels; |
157 | 1 | collection_levels["low"] = low; |
158 | 1 | collection_levels["medium"] = low; |
159 | 1 | collection_levels["medium"].insert({"hostname", "current_user"}); |
160 | 1 | collection_levels["high"] = collection_levels["medium"]; |
161 | 1 | collection_levels["high"].insert({"metrics", "rpcs"}); |
162 | | |
163 | 3 | for (const auto& collection_level : collection_levels) { |
164 | 3 | LOG(INFO) << "Collection level: " << collection_level.first; |
165 | 3 | FLAGS_callhome_collection_level = collection_level.first; |
166 | 3 | CallHome call_home(mini_master_->master(), ServerType::MASTER); |
167 | 3 | json = call_home.BuildJson(); |
168 | 3 | ASSERT_TRUE(!json.empty()); |
169 | 3 | JsonReader reader(json); |
170 | 3 | ASSERT_OK(reader.Init()); |
171 | 36 | for (const auto& field : collection_level.second) { |
172 | 36 | LOG(INFO) << "Checking json has field: " << field; |
173 | 36 | ASSERT_TRUE(reader.root()->HasMember(field.c_str())); |
174 | 36 | } |
175 | 3 | LOG(INFO) << "Checking json has field: tag"; |
176 | 3 | ASSERT_TRUE(reader.root()->HasMember("tag")); |
177 | | |
178 | 3 | string received_tag; |
179 | 3 | ASSERT_OK(reader.ExtractString(reader.root(), "tag", &received_tag)); |
180 | 3 | ASSERT_EQ(received_tag, tag_value); |
181 | | |
182 | 3 | if (collection_level.second.find("hostname") != collection_level.second.end()) { |
183 | 2 | string received_hostname; |
184 | 2 | ASSERT_OK(reader.ExtractString(reader.root(), "hostname", &received_hostname)); |
185 | 2 | ASSERT_EQ(received_hostname, mini_master_->master()->get_hostname()); |
186 | 2 | } |
187 | | |
188 | 3 | if (collection_level.second.find("current_user") != collection_level.second.end()) { |
189 | 2 | string received_user; |
190 | 2 | ASSERT_OK(reader.ExtractString(reader.root(), "current_user", &received_user)); |
191 | 2 | auto expected_user = ASSERT_RESULT(GetLoggedInUser()); |
192 | 2 | ASSERT_EQ(received_user, expected_user); |
193 | 2 | } |
194 | | |
195 | 3 | auto count = reader.root()->MemberEnd() - reader.root()->MemberBegin(); |
196 | 3 | LOG(INFO) << "Number of elements for level " << collection_level.first << ": " << count; |
197 | | // The number of fields should be equal to the number of collectors plus one for the tag field. |
198 | 3 | ASSERT_EQ(count, collection_level.second.size() + 1); |
199 | | |
200 | 3 | call_home.SendData(json); |
201 | 3 | ASSERT_TRUE(latch.WaitFor(MonoDelta::FromSeconds(10))); |
202 | 3 | latch.Reset(1); |
203 | 3 | } |
204 | 1 | } |
205 | | |
206 | | // This tests whether the enabling/disabling of callhome is happening dynamically |
207 | | // during runtime. |
208 | 1 | TEST_F(MasterTest, TestCallHomeFlag) { |
209 | 1 | CountDownLatch latch(1); |
210 | 1 | const char* tag_value = "callhome-test"; |
211 | 1 | bool disabled = false; |
212 | | |
213 | | // Set up the webserver. |
214 | 1 | auto webserver_dir = GetTestPath("webserver-docroot"); |
215 | 1 | CHECK_OK(env_->CreateDir(webserver_dir)); |
216 | | |
217 | 1 | WebserverOptions opts; |
218 | 1 | opts.port = 0; |
219 | 1 | opts.doc_root = webserver_dir; |
220 | 1 | Webserver webserver(opts, "WebserverTest"); |
221 | 1 | ASSERT_OK(webserver.Start()); |
222 | | |
223 | 1 | std::vector<Endpoint> addrs; |
224 | 1 | ASSERT_OK(webserver.GetBoundAddresses(&addrs)); |
225 | 1 | ASSERT_EQ(addrs.size(), 1); |
226 | 1 | auto addr = addrs[0]; |
227 | | |
228 | | // By default callhome is enabled. This handler is expected to be called |
229 | | // before disabling the flag. Once the flag is disabled, there shouldn't be any http posts. |
230 | 1 | auto handler = [&latch, &disabled] (const Webserver::WebRequest& req, |
231 | 1 | Webserver::WebResponse* resp) { |
232 | 1 | ASSERT_EQ(req.request_method, "POST"); |
233 | | // After callhome is disabled, assert if we get any more POST. |
234 | 1 | ASSERT_FALSE(disabled); |
235 | 1 | LOG(INFO) << "Received callhome data\n" << req.post_data; |
236 | 1 | latch.CountDown(); |
237 | 1 | }; |
238 | | |
239 | 1 | webserver.RegisterPathHandler("/callhome", "callhome", handler); |
240 | 1 | LOG(INFO) << "Started webserver to listen for callhome post requests."; |
241 | | |
242 | 1 | FLAGS_callhome_tag = tag_value; |
243 | 1 | FLAGS_callhome_url = Format("http://$0/callhome", addr); |
244 | | // Set the interval to 3 secs. |
245 | 1 | FLAGS_callhome_interval_secs = 3 * kTimeMultiplier; |
246 | | // Start with the default value i.e. callhome enabled. |
247 | 1 | disabled = false; |
248 | | |
249 | 1 | CallHome call_home(mini_master_->master(), ServerType::MASTER); |
250 | 1 | call_home.ScheduleCallHome(1 * kTimeMultiplier); |
251 | | |
252 | | // Wait for at least one non-empty response. |
253 | 1 | ASSERT_TRUE(latch.WaitFor(MonoDelta::FromSeconds(10 * kTimeMultiplier))); |
254 | | |
255 | | // Disable the callhome flag now. |
256 | 1 | disabled = true; |
257 | 1 | ANNOTATE_UNPROTECTED_WRITE(FLAGS_callhome_enabled) = false; |
258 | 1 | LOG(INFO) << "Callhome disabled. No more traffic"; |
259 | | |
260 | | // Wait for 3 cycles for no callhome posts. The handler is expected to assert |
261 | | // if it gets any new HTTP POST now. |
262 | 1 | SleepFor(MonoDelta::FromSeconds(3 * FLAGS_callhome_interval_secs * kTimeMultiplier)); |
263 | 1 | } |
264 | | |
265 | 1 | TEST_F(MasterTest, TestRegisterAndHeartbeat) { |
266 | 1 | const char *kTsUUID = "my-ts-uuid"; |
267 | | |
268 | 1 | TSToMasterCommonPB common; |
269 | 1 | common.mutable_ts_instance()->set_permanent_uuid(kTsUUID); |
270 | 1 | common.mutable_ts_instance()->set_instance_seqno(1); |
271 | | |
272 | | // Try a heartbeat. The server hasn't heard of us, so should ask us to re-register. |
273 | 1 | { |
274 | 1 | TSHeartbeatRequestPB req; |
275 | 1 | TSHeartbeatResponsePB resp; |
276 | 1 | req.mutable_common()->CopyFrom(common); |
277 | 1 | ASSERT_OK(proxy_heartbeat_->TSHeartbeat(req, &resp, ResetAndGetController())); |
278 | | |
279 | 1 | ASSERT_TRUE(resp.needs_reregister()); |
280 | 1 | ASSERT_TRUE(resp.needs_full_tablet_report()); |
281 | 1 | } |
282 | | |
283 | 1 | vector<shared_ptr<TSDescriptor> > descs; |
284 | 1 | mini_master_->master()->ts_manager()->GetAllDescriptors(&descs); |
285 | 2 | ASSERT_EQ(0, descs.size()) << "Should not have registered anything"; |
286 | | |
287 | 1 | shared_ptr<TSDescriptor> ts_desc; |
288 | 1 | ASSERT_FALSE(mini_master_->master()->ts_manager()->LookupTSByUUID(kTsUUID, &ts_desc)); |
289 | | |
290 | | // Register the fake TS, without sending any tablet report. |
291 | 1 | TSRegistrationPB fake_reg; |
292 | 1 | MakeHostPortPB("localhost", 1000, fake_reg.mutable_common()->add_private_rpc_addresses()); |
293 | 1 | MakeHostPortPB("localhost", 2000, fake_reg.mutable_common()->add_http_addresses()); |
294 | | |
295 | 1 | { |
296 | 1 | TSHeartbeatRequestPB req; |
297 | 1 | TSHeartbeatResponsePB resp; |
298 | 1 | req.mutable_common()->CopyFrom(common); |
299 | 1 | req.mutable_registration()->CopyFrom(fake_reg); |
300 | 1 | ASSERT_OK(proxy_heartbeat_->TSHeartbeat(req, &resp, ResetAndGetController())); |
301 | | |
302 | 1 | ASSERT_FALSE(resp.needs_reregister()); |
303 | 1 | ASSERT_TRUE(resp.needs_full_tablet_report()); |
304 | 1 | ASSERT_FALSE(resp.has_tablet_report_limit()); // No limit unless capability registered. |
305 | 1 | } |
306 | | |
307 | 1 | descs.clear(); |
308 | 1 | mini_master_->master()->ts_manager()->GetAllDescriptors(&descs); |
309 | 2 | ASSERT_EQ(1, descs.size()) << "Should have registered the TS"; |
310 | 1 | TSRegistrationPB reg = descs[0]->GetRegistration(); |
311 | 2 | ASSERT_EQ(fake_reg.DebugString(), reg.DebugString()) << "Master got different registration"; |
312 | | |
313 | 1 | ASSERT_TRUE(mini_master_->master()->ts_manager()->LookupTSByUUID(kTsUUID, &ts_desc)); |
314 | 1 | ASSERT_EQ(ts_desc, descs[0]); |
315 | | |
316 | | // Add capabilities in next registration. |
317 | 1 | auto cap = Capabilities(); |
318 | 1 | *fake_reg.mutable_capabilities() = |
319 | 1 | google::protobuf::RepeatedField<CapabilityId>(cap.begin(), cap.end()); |
320 | | |
321 | | // If the tablet server somehow lost the response to its registration RPC, it would |
322 | | // attempt to register again. In that case, we shouldn't reject it -- we should |
323 | | // just respond the same. |
324 | 1 | { |
325 | 1 | TSHeartbeatRequestPB req; |
326 | 1 | TSHeartbeatResponsePB resp; |
327 | 1 | req.mutable_common()->CopyFrom(common); |
328 | 1 | req.mutable_registration()->CopyFrom(fake_reg); |
329 | 1 | ASSERT_OK(proxy_heartbeat_->TSHeartbeat(req, &resp, ResetAndGetController())); |
330 | | |
331 | 1 | ASSERT_FALSE(resp.needs_reregister()); |
332 | 1 | ASSERT_TRUE(resp.needs_full_tablet_report()); |
333 | 1 | ASSERT_TRUE(resp.has_tablet_report_limit()); // Limit given, since TS capability registered. |
334 | 1 | } |
335 | | |
336 | | // Now begin sending full tablet report |
337 | 1 | { |
338 | 1 | TSHeartbeatRequestPB req; |
339 | 1 | TSHeartbeatResponsePB resp; |
340 | 1 | req.mutable_common()->CopyFrom(common); |
341 | 1 | TabletReportPB* tr = req.mutable_tablet_report(); |
342 | 1 | tr->set_is_incremental(false); |
343 | 1 | tr->set_sequence_number(0); |
344 | 1 | tr->set_remaining_tablet_count(1); |
345 | 1 | ASSERT_OK(proxy_heartbeat_->TSHeartbeat(req, &resp, ResetAndGetController())); |
346 | | |
347 | 1 | ASSERT_FALSE(resp.needs_reregister()); |
348 | 1 | ASSERT_FALSE(resp.needs_full_tablet_report()); |
349 | 1 | } |
350 | | |
351 | | // ...and finish the full tablet report. |
352 | 1 | { |
353 | 1 | TSHeartbeatRequestPB req; |
354 | 1 | TSHeartbeatResponsePB resp; |
355 | 1 | req.mutable_common()->CopyFrom(common); |
356 | 1 | TabletReportPB* tr = req.mutable_tablet_report(); |
357 | 1 | tr->set_is_incremental(false); |
358 | 1 | tr->set_sequence_number(0); |
359 | 1 | tr->set_remaining_tablet_count(0); |
360 | 1 | ASSERT_OK(proxy_heartbeat_->TSHeartbeat(req, &resp, ResetAndGetController())); |
361 | | |
362 | 1 | ASSERT_FALSE(resp.needs_reregister()); |
363 | 1 | ASSERT_FALSE(resp.needs_full_tablet_report()); |
364 | 1 | } |
365 | | |
366 | 1 | descs.clear(); |
367 | 1 | mini_master_->master()->ts_manager()->GetAllDescriptors(&descs); |
368 | 2 | ASSERT_EQ(1, descs.size()) << "Should still only have one TS registered"; |
369 | | |
370 | 1 | ASSERT_TRUE(mini_master_->master()->ts_manager()->LookupTSByUUID(kTsUUID, &ts_desc)); |
371 | 1 | ASSERT_EQ(ts_desc, descs[0]); |
372 | | |
373 | | // Ensure that the ListTabletServers shows the faked server. |
374 | 1 | { |
375 | 1 | ListTabletServersRequestPB req; |
376 | 1 | ListTabletServersResponsePB resp; |
377 | 1 | ASSERT_OK(proxy_cluster_->ListTabletServers(req, &resp, ResetAndGetController())); |
378 | 1 | LOG(INFO) << resp.DebugString(); |
379 | 1 | ASSERT_EQ(1, resp.servers_size()); |
380 | 1 | ASSERT_EQ("my-ts-uuid", resp.servers(0).instance_id().permanent_uuid()); |
381 | 1 | ASSERT_EQ(1, resp.servers(0).instance_id().instance_seqno()); |
382 | 1 | } |
383 | 1 | } |
384 | | |
385 | 1 | TEST_F(MasterTest, TestListTablesWithoutMasterCrash) { |
386 | 1 | FLAGS_TEST_simulate_slow_table_create_secs = 10; |
387 | | |
388 | 1 | const char *kNamespaceName = "testnamespace"; |
389 | 1 | CreateNamespaceResponsePB resp; |
390 | 1 | ASSERT_OK(CreateNamespace(kNamespaceName, YQLDatabase::YQL_DATABASE_CQL, &resp)); |
391 | | |
392 | 1 | auto task = [kNamespaceName, this]() { |
393 | 1 | const char *kTableName = "testtable"; |
394 | 1 | const Schema kTableSchema({ ColumnSchema("key", INT32) }, 1); |
395 | 1 | shared_ptr<RpcController> controller; |
396 | | // Set an RPC timeout for the controllers. |
397 | 1 | controller = make_shared<RpcController>(); |
398 | 1 | controller->set_timeout(MonoDelta::FromSeconds(FLAGS_TEST_simulate_slow_table_create_secs * 2)); |
399 | | |
400 | 1 | CreateTableRequestPB req; |
401 | 1 | CreateTableResponsePB resp; |
402 | | |
403 | 1 | req.set_name(kTableName); |
404 | 1 | SchemaToPB(kTableSchema, req.mutable_schema()); |
405 | 1 | req.mutable_namespace_()->set_name(kNamespaceName); |
406 | 1 | req.mutable_partition_schema()->set_hash_schema(PartitionSchemaPB::MULTI_COLUMN_HASH_SCHEMA); |
407 | 1 | req.mutable_schema()->mutable_table_properties()->set_num_tablets(8); |
408 | 1 | ASSERT_OK(this->proxy_ddl_->CreateTable(req, &resp, controller.get())); |
409 | 1 | ASSERT_FALSE(resp.has_error()); |
410 | 1 | LOG(INFO) << "Done creating table"; |
411 | 1 | }; |
412 | | |
413 | 1 | std::thread t(task); |
414 | | |
415 | | // Delete the namespace (by NAME). |
416 | 1 | { |
417 | | // Give the CreateTable request some time to start and find the namespace. |
418 | 1 | SleepFor(MonoDelta::FromSeconds(FLAGS_TEST_simulate_slow_table_create_secs / 2)); |
419 | 1 | DeleteNamespaceRequestPB req; |
420 | 1 | DeleteNamespaceResponsePB resp; |
421 | 1 | req.mutable_namespace_()->set_name(kNamespaceName); |
422 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(req, &resp, ResetAndGetController())); |
423 | 1 | SCOPED_TRACE(resp.DebugString()); |
424 | 1 | ASSERT_FALSE(resp.has_error()); |
425 | 1 | } |
426 | | |
427 | 1 | t.join(); |
428 | | |
429 | 1 | { |
430 | 1 | FLAGS_TEST_return_error_if_namespace_not_found = true; |
431 | 1 | ListTablesRequestPB req; |
432 | 1 | ListTablesResponsePB resp; |
433 | 1 | ASSERT_OK(proxy_ddl_->ListTables(req, &resp, ResetAndGetController())); |
434 | 1 | LOG(INFO) << "Finished first ListTables request"; |
435 | 1 | ASSERT_TRUE(resp.has_error()); |
436 | 1 | string msg = resp.error().status().message(); |
437 | 1 | ASSERT_TRUE(msg.find("Keyspace identifier not found") != string::npos); |
438 | | |
439 | | // After turning off this flag, ListTables should skip the table with the error. |
440 | 1 | FLAGS_TEST_return_error_if_namespace_not_found = false; |
441 | 1 | ASSERT_OK(proxy_ddl_->ListTables(req, &resp, ResetAndGetController())); |
442 | 1 | LOG(INFO) << "Finished second ListTables request"; |
443 | 1 | ASSERT_FALSE(resp.has_error()); |
444 | 1 | } |
445 | 1 | } |
446 | | |
447 | 1 | TEST_F(MasterTest, TestCatalog) { |
448 | 1 | const char *kTableName = "testtb"; |
449 | 1 | const char *kOtherTableName = "tbtest"; |
450 | 1 | const Schema kTableSchema({ ColumnSchema("key", INT32), |
451 | 1 | ColumnSchema("v1", UINT64), |
452 | 1 | ColumnSchema("v2", STRING) }, |
453 | 1 | 1); |
454 | | |
455 | 1 | ASSERT_OK(CreateTable(kTableName, kTableSchema)); |
456 | | |
457 | 1 | ListTablesResponsePB tables; |
458 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
459 | 1 | ASSERT_EQ(1 + kNumSystemTables, tables.tables_size()); |
460 | 1 | CheckTables( |
461 | 1 | { |
462 | 1 | std::make_tuple(kTableName, default_namespace_name, default_namespace_id, |
463 | 1 | USER_TABLE_RELATION), |
464 | 1 | EXPECTED_SYSTEM_TABLES |
465 | 1 | }, tables); |
466 | | |
467 | | // Delete the table |
468 | 1 | TableId id; |
469 | 1 | ASSERT_OK(DeleteTableSync(default_namespace_name, kTableName, &id)); |
470 | | |
471 | | // List tables, should show only system table |
472 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
473 | 1 | ASSERT_EQ(kNumSystemTables, tables.tables_size()); |
474 | 1 | CheckTables( |
475 | 1 | { |
476 | 1 | EXPECTED_SYSTEM_TABLES |
477 | 1 | }, tables); |
478 | | |
479 | | // Re-create the table |
480 | 1 | ASSERT_OK(CreateTable(kTableName, kTableSchema)); |
481 | | |
482 | | // Restart the master, verify the table still shows up. |
483 | 1 | ASSERT_OK(mini_master_->Restart()); |
484 | 1 | ASSERT_OK(mini_master_->master()->WaitUntilCatalogManagerIsLeaderAndReadyForTests()); |
485 | | |
486 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
487 | 1 | ASSERT_EQ(1 + kNumSystemTables, tables.tables_size()); |
488 | 1 | CheckTables( |
489 | 1 | { |
490 | 1 | std::make_tuple(kTableName, default_namespace_name, default_namespace_id, |
491 | 1 | USER_TABLE_RELATION), |
492 | 1 | EXPECTED_SYSTEM_TABLES |
493 | 1 | }, tables); |
494 | | |
495 | | // Test listing tables with a filter. |
496 | 1 | ASSERT_OK(CreateTable(kOtherTableName, kTableSchema)); |
497 | | |
498 | 1 | { |
499 | 1 | ListTablesRequestPB req; |
500 | 1 | req.set_name_filter("test"); |
501 | 1 | DoListTables(req, &tables); |
502 | 1 | ASSERT_EQ(2, tables.tables_size()); |
503 | 1 | } |
504 | | |
505 | 1 | { |
506 | 1 | ListTablesRequestPB req; |
507 | 1 | req.set_name_filter("tb"); |
508 | 1 | DoListTables(req, &tables); |
509 | 1 | ASSERT_EQ(2, tables.tables_size()); |
510 | 1 | } |
511 | | |
512 | 1 | { |
513 | 1 | ListTablesRequestPB req; |
514 | 1 | req.set_name_filter(kTableName); |
515 | 1 | DoListTables(req, &tables); |
516 | 1 | ASSERT_EQ(1, tables.tables_size()); |
517 | 1 | ASSERT_EQ(kTableName, tables.tables(0).name()); |
518 | 1 | } |
519 | | |
520 | 1 | { |
521 | 1 | ListTablesRequestPB req; |
522 | 1 | req.set_name_filter("btes"); |
523 | 1 | DoListTables(req, &tables); |
524 | 1 | ASSERT_EQ(1, tables.tables_size()); |
525 | 1 | ASSERT_EQ(kOtherTableName, tables.tables(0).name()); |
526 | 1 | } |
527 | | |
528 | 1 | { |
529 | 1 | ListTablesRequestPB req; |
530 | 1 | req.set_name_filter("randomname"); |
531 | 1 | DoListTables(req, &tables); |
532 | 1 | ASSERT_EQ(0, tables.tables_size()); |
533 | 1 | } |
534 | | |
535 | 1 | { |
536 | 1 | ListTablesRequestPB req; |
537 | 1 | req.set_name_filter("peer"); |
538 | 1 | DoListTables(req, &tables); |
539 | 1 | ASSERT_EQ(1, tables.tables_size()); |
540 | 1 | ASSERT_EQ(kSystemPeersTableName, tables.tables(0).name()); |
541 | 1 | } |
542 | | |
543 | 1 | { |
544 | 1 | ListTablesRequestPB req; |
545 | 1 | req.add_relation_type_filter(USER_TABLE_RELATION); |
546 | 1 | DoListTables(req, &tables); |
547 | 1 | ASSERT_EQ(2, tables.tables_size()); |
548 | 1 | } |
549 | | |
550 | 1 | { |
551 | 1 | ListTablesRequestPB req; |
552 | 1 | req.add_relation_type_filter(INDEX_TABLE_RELATION); |
553 | 1 | DoListTables(req, &tables); |
554 | 1 | ASSERT_EQ(0, tables.tables_size()); |
555 | 1 | } |
556 | | |
557 | 1 | { |
558 | 1 | ListTablesRequestPB req; |
559 | 1 | req.add_relation_type_filter(SYSTEM_TABLE_RELATION); |
560 | 1 | DoListTables(req, &tables); |
561 | 1 | ASSERT_EQ(kNumSystemTables, tables.tables_size()); |
562 | 1 | } |
563 | | |
564 | 1 | { |
565 | 1 | ListTablesRequestPB req; |
566 | 1 | req.add_relation_type_filter(SYSTEM_TABLE_RELATION); |
567 | 1 | req.add_relation_type_filter(USER_TABLE_RELATION); |
568 | 1 | DoListTables(req, &tables); |
569 | 1 | ASSERT_EQ(kNumSystemTables + 2, tables.tables_size()); |
570 | 1 | } |
571 | 1 | } |
572 | | |
573 | 1 | TEST_F(MasterTest, TestCatalogHasBlockCache) { |
574 | | // Restart mini_master |
575 | 1 | ASSERT_OK(mini_master_->Restart()); |
576 | 1 | ASSERT_OK(mini_master_->master()->WaitUntilCatalogManagerIsLeaderAndReadyForTests()); |
577 | | |
578 | | // Check prometheus metrics via webserver to verify block_cache metrics exist |
579 | 1 | string addr = AsString(mini_master_->bound_http_addr()); |
580 | 1 | string url = strings::Substitute("http://$0/prometheus-metrics", AsString(addr)); |
581 | 1 | EasyCurl curl; |
582 | 1 | faststring buf; |
583 | | |
584 | 1 | ASSERT_OK(curl.FetchURL(url, &buf)); |
585 | 1 | ASSERT_STR_CONTAINS(buf.ToString(), "block_cache_misses"); |
586 | 1 | ASSERT_STR_CONTAINS(buf.ToString(), "block_cache_hits"); |
587 | | |
588 | | // Check block cache metrics directly and verify |
589 | | // that the counters are greater than 0 |
590 | 1 | const auto metric_map = mini_master_->master()->metric_entity()->UnsafeMetricsMapForTests(); |
591 | | |
592 | 1 | scoped_refptr<Counter> cache_misses_counter = down_cast<Counter *>( |
593 | 1 | FindOrDie(metric_map, |
594 | 1 | &METRIC_block_cache_misses).get()); |
595 | 1 | scoped_refptr<Counter> cache_hits_counter = down_cast<Counter *>( |
596 | 1 | FindOrDie(metric_map, |
597 | 1 | &METRIC_block_cache_hits).get()); |
598 | | |
599 | 1 | ASSERT_GT(cache_misses_counter->value(), 0); |
600 | 1 | ASSERT_GT(cache_hits_counter->value(), 0); |
601 | 1 | } |
602 | | |
603 | 1 | TEST_F(MasterTest, TestTablegroups) { |
604 | | // Tablegroup ID must be 32 characters in length |
605 | 1 | const char *kTablegroupId = "test_tablegroup00000000000000000"; |
606 | 1 | const char *kTableName = "test_table"; |
607 | 1 | const Schema kTableSchema({ ColumnSchema("key", INT32) }, 1); |
608 | 1 | const NamespaceName ns_name = "test_tablegroup_ns"; |
609 | | |
610 | | // Create a new namespace. |
611 | 1 | NamespaceId ns_id; |
612 | 1 | ListNamespacesResponsePB namespaces; |
613 | 1 | { |
614 | 1 | CreateNamespaceResponsePB resp; |
615 | 1 | ASSERT_OK(CreateNamespace(ns_name, YQL_DATABASE_PGSQL, &resp)); |
616 | 1 | ns_id = resp.id(); |
617 | 1 | } |
618 | 1 | { |
619 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
620 | 1 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
621 | 1 | CheckNamespaces( |
622 | 1 | { |
623 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
624 | 1 | std::make_tuple(ns_name, ns_id) |
625 | 1 | }, namespaces); |
626 | 1 | } |
627 | | |
628 | 1 | SetAtomicFlag(true, &FLAGS_TEST_tablegroup_master_only); |
629 | | // Create tablegroup and ensure it exists in catalog manager maps. |
630 | 1 | ASSERT_OK(CreateTablegroup(kTablegroupId, ns_id, ns_name, "" /* tablespace_id */)); |
631 | 1 | SetAtomicFlag(false, &FLAGS_TEST_tablegroup_master_only); |
632 | | |
633 | 1 | ListTablegroupsRequestPB req; |
634 | 1 | ListTablegroupsResponsePB resp; |
635 | 1 | req.set_namespace_id(ns_id); |
636 | 1 | ASSERT_NO_FATALS(DoListTablegroups(req, &resp)); |
637 | | |
638 | 1 | bool tablegroup_found = false; |
639 | 1 | for (auto& tg : *resp.mutable_tablegroups()) { |
640 | 1 | if (tg.id().compare(kTablegroupId) == 0) { |
641 | 1 | tablegroup_found = true; |
642 | 1 | } |
643 | 1 | } |
644 | 1 | ASSERT_TRUE(tablegroup_found); |
645 | | |
646 | | // Restart the master, verify the tablegroup still shows up |
647 | 1 | ASSERT_OK(mini_master_->Restart()); |
648 | 1 | ASSERT_OK(mini_master_->master()->WaitUntilCatalogManagerIsLeaderAndReadyForTests()); |
649 | | |
650 | 1 | ListTablegroupsResponsePB new_resp; |
651 | 1 | ASSERT_NO_FATALS(DoListTablegroups(req, &new_resp)); |
652 | | |
653 | 1 | tablegroup_found = false; |
654 | 1 | for (auto& tg : *new_resp.mutable_tablegroups()) { |
655 | 1 | if (tg.id().compare(kTablegroupId) == 0) { |
656 | 1 | tablegroup_found = true; |
657 | 1 | } |
658 | 1 | } |
659 | 1 | ASSERT_TRUE(tablegroup_found); |
660 | | |
661 | | // Now ensure that a table can be created in the tablegroup. |
662 | 1 | ASSERT_OK(CreateTablegroupTable(ns_id, kTableName, kTablegroupId, kTableSchema)); |
663 | | |
664 | | // Delete the tablegroup |
665 | 1 | ASSERT_OK(DeleteTablegroup(kTablegroupId, ns_id)); |
666 | 1 | } |
667 | | |
668 | | // Regression test for KUDU-253/KUDU-592: crash if the schema passed to CreateTable |
669 | | // is invalid. |
670 | 1 | TEST_F(MasterTest, TestCreateTableInvalidSchema) { |
671 | 1 | CreateTableRequestPB req; |
672 | 1 | CreateTableResponsePB resp; |
673 | | |
674 | 1 | req.set_name("table"); |
675 | 1 | req.mutable_namespace_()->set_name(default_namespace_name); |
676 | 3 | for (int i = 0; i < 2; i++) { |
677 | 2 | ColumnSchemaPB* col = req.mutable_schema()->add_columns(); |
678 | 2 | col->set_name("col"); |
679 | 2 | QLType::Create(INT32)->ToQLTypePB(col->mutable_type()); |
680 | 2 | col->set_is_key(true); |
681 | 2 | } |
682 | | |
683 | 1 | ASSERT_OK(proxy_ddl_->CreateTable(req, &resp, ResetAndGetController())); |
684 | 1 | SCOPED_TRACE(resp.DebugString()); |
685 | 1 | ASSERT_TRUE(resp.has_error()); |
686 | 1 | ASSERT_EQ(AppStatusPB::INVALID_ARGUMENT, resp.error().status().code()); |
687 | 1 | ASSERT_EQ("Duplicate column name: col", resp.error().status().message()); |
688 | 1 | } |
689 | | |
690 | 1 | TEST_F(MasterTest, TestTabletsDeletedWhenTableInDeletingState) { |
691 | 1 | FLAGS_TEST_simulate_crash_after_table_marked_deleting = true; |
692 | 1 | const char *kTableName = "testtb"; |
693 | 1 | const Schema kTableSchema({ ColumnSchema("key", INT32)}, |
694 | 1 | 1); |
695 | | |
696 | 1 | ASSERT_OK(CreateTable(kTableName, kTableSchema)); |
697 | 1 | vector<TabletId> tablet_ids; |
698 | 1 | { |
699 | 1 | CatalogManager::SharedLock lock(mini_master_->catalog_manager_impl().mutex_); |
700 | 25 | for (auto elem : *mini_master_->catalog_manager_impl().tablet_map_) { |
701 | 25 | auto tablet = elem.second; |
702 | 25 | if (tablet->table()->name() == kTableName) { |
703 | 8 | tablet_ids.push_back(elem.first); |
704 | 8 | } |
705 | 25 | } |
706 | 1 | } |
707 | | |
708 | | // Delete the table |
709 | 1 | TableId id; |
710 | 1 | ASSERT_OK(DeleteTable(default_namespace_name, kTableName, &id)); |
711 | | |
712 | | // Restart the master to force a reload of the tablets. |
713 | 1 | ASSERT_OK(mini_master_->Restart()); |
714 | 1 | ASSERT_OK(mini_master_->master()->WaitUntilCatalogManagerIsLeaderAndReadyForTests()); |
715 | | |
716 | | // Verify that the test table's tablets are in the DELETED state. |
717 | 1 | { |
718 | 1 | CatalogManager::SharedLock lock(mini_master_->catalog_manager_impl().mutex_); |
719 | 8 | for (const auto& tablet_id : tablet_ids) { |
720 | 8 | auto iter = mini_master_->catalog_manager_impl().tablet_map_->find(tablet_id); |
721 | 8 | ASSERT_NE(iter, mini_master_->catalog_manager_impl().tablet_map_->end()); |
722 | 8 | auto l = iter->second->LockForRead(); |
723 | 8 | ASSERT_EQ(l->pb.state(), SysTabletsEntryPB::DELETED); |
724 | 8 | } |
725 | 1 | } |
726 | 1 | } |
727 | | |
728 | | // Regression test for KUDU-253/KUDU-592: crash if the GetTableLocations RPC call is |
729 | | // invalid. |
730 | 1 | TEST_F(MasterTest, TestInvalidGetTableLocations) { |
731 | 1 | const TableName kTableName = "test"; |
732 | 1 | Schema schema({ ColumnSchema("key", INT32) }, 1); |
733 | 1 | ASSERT_OK(CreateTable(kTableName, schema)); |
734 | 1 | { |
735 | 1 | GetTableLocationsRequestPB req; |
736 | 1 | GetTableLocationsResponsePB resp; |
737 | 1 | req.mutable_table()->set_table_name(kTableName); |
738 | | // Set the "start" key greater than the "end" key. |
739 | 1 | req.set_partition_key_start("zzzz"); |
740 | 1 | req.set_partition_key_end("aaaa"); |
741 | 1 | ASSERT_OK(proxy_client_->GetTableLocations(req, &resp, ResetAndGetController())); |
742 | 1 | SCOPED_TRACE(resp.DebugString()); |
743 | 1 | ASSERT_TRUE(resp.has_error()); |
744 | 1 | ASSERT_EQ(AppStatusPB::INVALID_ARGUMENT, resp.error().status().code()); |
745 | 1 | ASSERT_EQ("start partition key is greater than the end partition key", |
746 | 1 | resp.error().status().message()); |
747 | 1 | } |
748 | 1 | } |
749 | | |
750 | 1 | TEST_F(MasterTest, TestInvalidPlacementInfo) { |
751 | 1 | const TableName kTableName = "test"; |
752 | 1 | Schema schema({ColumnSchema("key", INT32)}, 1); |
753 | 1 | GetMasterClusterConfigRequestPB config_req; |
754 | 1 | GetMasterClusterConfigResponsePB config_resp; |
755 | 1 | ASSERT_OK(proxy_cluster_->GetMasterClusterConfig( |
756 | 1 | config_req, &config_resp, ResetAndGetController())); |
757 | 1 | ASSERT_FALSE(config_resp.has_error()); |
758 | 1 | ASSERT_TRUE(config_resp.has_cluster_config()); |
759 | 1 | auto cluster_config = config_resp.cluster_config(); |
760 | | |
761 | 1 | CreateTableRequestPB req; |
762 | | |
763 | | // Fail due to not cloud_info. |
764 | 1 | auto* live_replicas = cluster_config.mutable_replication_info()->mutable_live_replicas(); |
765 | 1 | live_replicas->set_num_replicas(5); |
766 | 1 | auto* pb = live_replicas->add_placement_blocks(); |
767 | 1 | UpdateMasterClusterConfig(&cluster_config); |
768 | 1 | Status s = DoCreateTable(kTableName, schema, &req); |
769 | 1 | ASSERT_TRUE(s.IsInvalidArgument()); |
770 | | |
771 | | // Fail due to min_num_replicas being more than num_replicas. |
772 | 1 | auto* cloud_info = pb->mutable_cloud_info(); |
773 | 1 | pb->set_min_num_replicas(live_replicas->num_replicas() + 1); |
774 | 1 | UpdateMasterClusterConfig(&cluster_config); |
775 | 1 | s = DoCreateTable(kTableName, schema, &req); |
776 | 1 | ASSERT_TRUE(s.IsInvalidArgument()); |
777 | | |
778 | | // Fail because there are no TServers matching the given placement policy. |
779 | 1 | pb->set_min_num_replicas(live_replicas->num_replicas()); |
780 | 1 | cloud_info->set_placement_cloud("fail"); |
781 | 1 | UpdateMasterClusterConfig(&cluster_config); |
782 | 1 | s = DoCreateTable(kTableName, schema, &req); |
783 | 1 | ASSERT_TRUE(s.IsInvalidArgument()); |
784 | 1 | } |
785 | | |
786 | 1 | TEST_F(MasterTest, TestNamespaces) { |
787 | 1 | ListNamespacesResponsePB namespaces; |
788 | | |
789 | | // Check default namespace. |
790 | 1 | { |
791 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
792 | | // Including system namespace. |
793 | 1 | ASSERT_EQ(1 + kNumSystemNamespaces, namespaces.namespaces_size()); |
794 | 1 | CheckNamespaces( |
795 | 1 | { |
796 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES |
797 | 1 | }, namespaces); |
798 | 1 | } |
799 | | |
800 | | // Create a new namespace. |
801 | 1 | const NamespaceName other_ns_name = "testns"; |
802 | 1 | NamespaceId other_ns_id; |
803 | 1 | { |
804 | 1 | CreateNamespaceResponsePB resp; |
805 | 1 | ASSERT_OK(CreateNamespace(other_ns_name, &resp)); |
806 | 1 | other_ns_id = resp.id(); |
807 | 1 | } |
808 | 1 | { |
809 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
810 | | // Including system namespace. |
811 | 1 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
812 | 1 | CheckNamespaces( |
813 | 1 | { |
814 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
815 | 1 | std::make_tuple(other_ns_name, other_ns_id), |
816 | 1 | }, namespaces); |
817 | 1 | } |
818 | | |
819 | | // Try to create the existing namespace twice. |
820 | 1 | { |
821 | 1 | CreateNamespaceResponsePB resp; |
822 | 1 | const Status s = CreateNamespace(other_ns_name, &resp); |
823 | 2 | ASSERT_TRUE(s.IsAlreadyPresent()) << s.ToString(); |
824 | 1 | ASSERT_STR_CONTAINS(s.ToString(), |
825 | 1 | Substitute("Keyspace '$0' already exists", other_ns_name)); |
826 | 1 | } |
827 | 1 | { |
828 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
829 | | // Including system namespace. |
830 | 1 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
831 | 1 | CheckNamespaces( |
832 | 1 | { |
833 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
834 | 1 | std::make_tuple(other_ns_name, other_ns_id), |
835 | 1 | }, namespaces); |
836 | 1 | } |
837 | | |
838 | | // Delete the namespace (by ID). |
839 | 1 | { |
840 | 1 | DeleteNamespaceRequestPB req; |
841 | 1 | DeleteNamespaceResponsePB resp; |
842 | 1 | req.mutable_namespace_()->set_id(other_ns_id); |
843 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(req, &resp, ResetAndGetController())); |
844 | 1 | SCOPED_TRACE(resp.DebugString()); |
845 | 1 | ASSERT_FALSE(resp.has_error()); |
846 | 1 | } |
847 | 1 | { |
848 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
849 | | // Including system namespace. |
850 | 1 | ASSERT_EQ(1 + kNumSystemNamespaces, namespaces.namespaces_size()); |
851 | 1 | CheckNamespaces( |
852 | 1 | { |
853 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES |
854 | 1 | }, namespaces); |
855 | 1 | } |
856 | | |
857 | | // Re-create the namespace once again. |
858 | 1 | { |
859 | 1 | CreateNamespaceResponsePB resp; |
860 | 1 | ASSERT_OK(CreateNamespace(other_ns_name, &resp)); |
861 | 1 | other_ns_id = resp.id(); |
862 | 1 | } |
863 | 1 | { |
864 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
865 | | // Including system namespace. |
866 | 1 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
867 | 1 | CheckNamespaces( |
868 | 1 | { |
869 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
870 | 1 | std::make_tuple(other_ns_name, other_ns_id), |
871 | 1 | }, namespaces); |
872 | 1 | } |
873 | | |
874 | | // Delete the namespace (by NAME). |
875 | 1 | { |
876 | 1 | DeleteNamespaceRequestPB req; |
877 | 1 | DeleteNamespaceResponsePB resp; |
878 | 1 | req.mutable_namespace_()->set_name(other_ns_name); |
879 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(req, &resp, ResetAndGetController())); |
880 | 1 | SCOPED_TRACE(resp.DebugString()); |
881 | 1 | ASSERT_FALSE(resp.has_error()); |
882 | 1 | } |
883 | 1 | { |
884 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
885 | | // Including system namespace. |
886 | 1 | ASSERT_EQ(1 + kNumSystemNamespaces, namespaces.namespaces_size()); |
887 | 1 | CheckNamespaces( |
888 | 1 | { |
889 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES |
890 | 1 | }, namespaces); |
891 | 1 | } |
892 | | |
893 | | // Try to create the 'default' namespace. |
894 | 1 | { |
895 | 1 | CreateNamespaceResponsePB resp; |
896 | 1 | const Status s = CreateNamespace(default_namespace_name, &resp); |
897 | 2 | ASSERT_TRUE(s.IsAlreadyPresent()) << s.ToString(); |
898 | 1 | ASSERT_STR_CONTAINS(s.ToString(), |
899 | 1 | Substitute("Keyspace '$0' already exists", default_namespace_name)); |
900 | 1 | } |
901 | 1 | { |
902 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
903 | | // Including system namespace. |
904 | 1 | ASSERT_EQ(1 + kNumSystemNamespaces, namespaces.namespaces_size()); |
905 | 1 | CheckNamespaces( |
906 | 1 | { |
907 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES |
908 | 1 | }, namespaces); |
909 | 1 | } |
910 | | |
911 | | // Try to delete a non-existing namespace - by NAME. |
912 | 1 | { |
913 | 1 | DeleteNamespaceRequestPB req; |
914 | 1 | DeleteNamespaceResponsePB resp; |
915 | | |
916 | 1 | req.mutable_namespace_()->set_name("nonexistingns"); |
917 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(req, &resp, ResetAndGetController())); |
918 | 1 | SCOPED_TRACE(resp.DebugString()); |
919 | 1 | ASSERT_TRUE(resp.has_error()); |
920 | 1 | ASSERT_EQ(resp.error().code(), MasterErrorPB::NAMESPACE_NOT_FOUND); |
921 | 1 | ASSERT_EQ(resp.error().status().code(), AppStatusPB::NOT_FOUND); |
922 | 1 | ASSERT_STR_CONTAINS(resp.error().status().ShortDebugString(), "Keyspace name not found"); |
923 | 1 | } |
924 | 1 | { |
925 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
926 | | // Including system namespace. |
927 | 1 | ASSERT_EQ(1 + kNumSystemNamespaces, namespaces.namespaces_size()); |
928 | 1 | CheckNamespaces( |
929 | 1 | { |
930 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES |
931 | 1 | }, namespaces); |
932 | 1 | } |
933 | 1 | } |
934 | | |
935 | 1 | TEST_F(MasterTest, TestNamespaceSeparation) { |
936 | 1 | ListNamespacesResponsePB namespaces; |
937 | | |
938 | | // Check default namespace. |
939 | 1 | { |
940 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
941 | | // Including system namespace. |
942 | 1 | ASSERT_EQ(1 + kNumSystemNamespaces, namespaces.namespaces_size()); |
943 | 1 | CheckNamespaces( |
944 | 1 | { |
945 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES |
946 | 1 | }, namespaces); |
947 | 1 | } |
948 | | |
949 | | // Create a new namespace for each of YCQL, YSQL and YEDIS database types. |
950 | 1 | CreateNamespaceResponsePB resp; |
951 | 1 | ASSERT_OK(CreateNamespace("test_cql", YQLDatabase::YQL_DATABASE_CQL, &resp)); |
952 | 1 | const NamespaceId cql_ns_id = resp.id(); |
953 | 1 | ASSERT_OK(CreateNamespace("test_pgsql", YQLDatabase::YQL_DATABASE_PGSQL, &resp)); |
954 | 1 | const NamespaceId pgsql_ns_id = resp.id(); |
955 | 1 | ASSERT_OK(CreateNamespace("test_redis", YQLDatabase::YQL_DATABASE_REDIS, &resp)); |
956 | 1 | const NamespaceId redis_ns_id = resp.id(); |
957 | | |
958 | | // List all namespaces and by each database type. |
959 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
960 | 1 | ASSERT_EQ(4 + kNumSystemNamespaces, namespaces.namespaces_size()); |
961 | 1 | CheckNamespaces( |
962 | 1 | { |
963 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
964 | 1 | std::make_tuple("test_cql", cql_ns_id), |
965 | 1 | std::make_tuple("test_pgsql", pgsql_ns_id), |
966 | 1 | std::make_tuple("test_redis", redis_ns_id), |
967 | 1 | }, namespaces); |
968 | | |
969 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(YQLDatabase::YQL_DATABASE_CQL, &namespaces)); |
970 | 1 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
971 | 1 | CheckNamespaces( |
972 | 1 | { |
973 | | // Defalt and system namespaces are created in YCQL. |
974 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
975 | 1 | std::make_tuple("test_cql", cql_ns_id), |
976 | 1 | }, namespaces); |
977 | | |
978 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(YQLDatabase::YQL_DATABASE_PGSQL, &namespaces)); |
979 | 1 | ASSERT_EQ(1, namespaces.namespaces_size()); |
980 | 1 | CheckNamespaces( |
981 | 1 | { |
982 | 1 | std::make_tuple("test_pgsql", pgsql_ns_id), |
983 | 1 | }, namespaces); |
984 | | |
985 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(YQLDatabase::YQL_DATABASE_REDIS, &namespaces)); |
986 | 1 | ASSERT_EQ(1, namespaces.namespaces_size()); |
987 | 1 | CheckNamespaces( |
988 | 1 | { |
989 | 1 | std::make_tuple("test_redis", redis_ns_id), |
990 | 1 | }, namespaces); |
991 | 1 | } |
992 | | |
993 | 1 | TEST_F(MasterTest, TestDeletingNonEmptyNamespace) { |
994 | 1 | ListNamespacesResponsePB namespaces; |
995 | | |
996 | | // Create a new namespace. |
997 | 1 | const NamespaceName other_ns_name = "testns"; |
998 | 1 | NamespaceId other_ns_id; |
999 | 1 | const NamespaceName other_ns_pgsql_name = "testns_pgsql"; |
1000 | 1 | NamespaceId other_ns_pgsql_id; |
1001 | 1 | { |
1002 | 1 | CreateNamespaceResponsePB resp; |
1003 | 1 | ASSERT_OK(CreateNamespace(other_ns_name, &resp)); |
1004 | 1 | other_ns_id = resp.id(); |
1005 | 1 | } |
1006 | 1 | { |
1007 | 1 | CreateNamespaceResponsePB resp; |
1008 | 1 | ASSERT_OK(CreateNamespace(other_ns_pgsql_name, YQLDatabase::YQL_DATABASE_PGSQL, &resp)); |
1009 | 1 | other_ns_pgsql_id = resp.id(); |
1010 | 1 | } |
1011 | 1 | { |
1012 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1013 | 1 | ASSERT_EQ(3 + kNumSystemNamespaces, namespaces.namespaces_size()); |
1014 | 1 | CheckNamespaces( |
1015 | 1 | { |
1016 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
1017 | 1 | std::make_tuple(other_ns_name, other_ns_id), |
1018 | 1 | std::make_tuple(other_ns_pgsql_name, other_ns_pgsql_id) |
1019 | 1 | }, namespaces); |
1020 | 1 | } |
1021 | 1 | { |
1022 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(YQLDatabase::YQL_DATABASE_PGSQL, &namespaces)); |
1023 | 1 | ASSERT_EQ(1, namespaces.namespaces_size()); |
1024 | 1 | CheckNamespaces( |
1025 | 1 | { |
1026 | 1 | std::make_tuple(other_ns_pgsql_name, other_ns_pgsql_id) |
1027 | 1 | }, namespaces); |
1028 | 1 | } |
1029 | | |
1030 | | // Create a table. |
1031 | 1 | const TableName kTableName = "testtb"; |
1032 | 1 | const TableName kTableNamePgsql = "testtb_pgsql"; |
1033 | 1 | const Schema kTableSchema({ ColumnSchema("key", INT32) }, 1); |
1034 | | |
1035 | 1 | ASSERT_OK(CreateTable(other_ns_name, kTableName, kTableSchema)); |
1036 | 1 | ASSERT_OK(CreatePgsqlTable(other_ns_pgsql_id, kTableNamePgsql + "_1", kTableSchema)); |
1037 | 1 | ASSERT_OK(CreatePgsqlTable(other_ns_pgsql_id, kTableNamePgsql + "_2", kTableSchema)); |
1038 | | |
1039 | 1 | { |
1040 | 1 | ListTablesResponsePB tables; |
1041 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1042 | 1 | ASSERT_EQ(3 + kNumSystemTables, tables.tables_size()); |
1043 | 1 | CheckTables( |
1044 | 1 | { |
1045 | 1 | std::make_tuple(kTableName, other_ns_name, other_ns_id, USER_TABLE_RELATION), |
1046 | 1 | std::make_tuple(kTableNamePgsql + "_1", other_ns_pgsql_name, other_ns_pgsql_id, |
1047 | 1 | USER_TABLE_RELATION), |
1048 | 1 | std::make_tuple(kTableNamePgsql + "_2", other_ns_pgsql_name, other_ns_pgsql_id, |
1049 | 1 | USER_TABLE_RELATION), |
1050 | 1 | EXPECTED_SYSTEM_TABLES |
1051 | 1 | }, tables); |
1052 | 1 | } |
1053 | | |
1054 | | // You should be able to successfully delete a non-empty PGSQL Database - by ID only |
1055 | 1 | { |
1056 | 1 | DeleteNamespaceRequestPB req; |
1057 | 1 | DeleteNamespaceResponsePB resp; |
1058 | 1 | req.set_database_type(YQLDatabase::YQL_DATABASE_PGSQL); |
1059 | 1 | req.mutable_namespace_()->set_id(other_ns_pgsql_id); |
1060 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(req, &resp, ResetAndGetController())); |
1061 | 1 | SCOPED_TRACE(resp.DebugString()); |
1062 | 1 | ASSERT_FALSE(resp.has_error()); |
1063 | | |
1064 | | // Must wait for IsDeleteNamespaceDone with PGSQL Namespaces. |
1065 | 1 | IsDeleteNamespaceDoneRequestPB del_req; |
1066 | 1 | del_req.mutable_namespace_()->set_id(other_ns_pgsql_id); |
1067 | 1 | del_req.mutable_namespace_()->set_database_type(YQLDatabase::YQL_DATABASE_PGSQL); |
1068 | 1 | ASSERT_OK(DeleteNamespaceWait(del_req)); |
1069 | 1 | } |
1070 | 1 | { |
1071 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1072 | 1 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
1073 | 1 | CheckNamespaces( |
1074 | 1 | { |
1075 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
1076 | 1 | std::make_tuple(other_ns_name, other_ns_id) |
1077 | 1 | }, namespaces); |
1078 | 1 | } |
1079 | 1 | { |
1080 | | // verify that the table for that database also went away |
1081 | 1 | ListTablesResponsePB tables; |
1082 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1083 | 1 | ASSERT_EQ(1 + kNumSystemTables, tables.tables_size()); |
1084 | 1 | CheckTables( |
1085 | 1 | { |
1086 | 1 | std::make_tuple(kTableName, other_ns_name, other_ns_id, USER_TABLE_RELATION), |
1087 | 1 | EXPECTED_SYSTEM_TABLES |
1088 | 1 | }, tables); |
1089 | 1 | } |
1090 | | |
1091 | | // Try to delete the non-empty namespace - by NAME. |
1092 | 1 | { |
1093 | 1 | DeleteNamespaceRequestPB req; |
1094 | 1 | DeleteNamespaceResponsePB resp; |
1095 | | |
1096 | 1 | req.mutable_namespace_()->set_name(other_ns_name); |
1097 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(req, &resp, ResetAndGetController())); |
1098 | 1 | SCOPED_TRACE(resp.DebugString()); |
1099 | 1 | ASSERT_TRUE(resp.has_error()); |
1100 | 1 | ASSERT_EQ(resp.error().code(), MasterErrorPB::NAMESPACE_IS_NOT_EMPTY); |
1101 | 1 | ASSERT_EQ(resp.error().status().code(), AppStatusPB::INVALID_ARGUMENT); |
1102 | 1 | ASSERT_STR_CONTAINS(resp.error().status().ShortDebugString(), |
1103 | 1 | "Cannot delete keyspace which has table: " + kTableName); |
1104 | 1 | } |
1105 | 1 | { |
1106 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1107 | 1 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
1108 | 1 | CheckNamespaces( |
1109 | 1 | { |
1110 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
1111 | 1 | std::make_tuple(other_ns_name, other_ns_id), |
1112 | 1 | }, namespaces); |
1113 | 1 | } |
1114 | | |
1115 | | // Try to delete the non-empty namespace - by ID. |
1116 | 1 | { |
1117 | 1 | DeleteNamespaceRequestPB req; |
1118 | 1 | DeleteNamespaceResponsePB resp; |
1119 | | |
1120 | 1 | req.mutable_namespace_()->set_id(other_ns_id); |
1121 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(req, &resp, ResetAndGetController())); |
1122 | 1 | SCOPED_TRACE(resp.DebugString()); |
1123 | 1 | ASSERT_TRUE(resp.has_error()); |
1124 | 1 | ASSERT_EQ(resp.error().code(), MasterErrorPB::NAMESPACE_IS_NOT_EMPTY); |
1125 | 1 | ASSERT_EQ(resp.error().status().code(), AppStatusPB::INVALID_ARGUMENT); |
1126 | 1 | ASSERT_STR_CONTAINS(resp.error().status().ShortDebugString(), |
1127 | 1 | "Cannot delete keyspace which has table: " + kTableName); |
1128 | 1 | } |
1129 | 1 | { |
1130 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1131 | 1 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
1132 | 1 | CheckNamespaces( |
1133 | 1 | { |
1134 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
1135 | 1 | std::make_tuple(other_ns_name, other_ns_id), |
1136 | 1 | }, namespaces); |
1137 | 1 | } |
1138 | | |
1139 | | // Delete the table. |
1140 | 1 | ASSERT_OK(DeleteTable(other_ns_name, kTableName)); |
1141 | | |
1142 | | // List tables, should show only system table. |
1143 | 1 | { |
1144 | 1 | ListTablesResponsePB tables; |
1145 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1146 | 1 | ASSERT_EQ(kNumSystemTables, tables.tables_size()); |
1147 | 1 | CheckTables( |
1148 | 1 | { |
1149 | 1 | EXPECTED_SYSTEM_TABLES |
1150 | 1 | }, tables); |
1151 | 1 | } |
1152 | | |
1153 | | // Delete the namespace (by NAME). |
1154 | 1 | { |
1155 | 1 | DeleteNamespaceRequestPB req; |
1156 | 1 | DeleteNamespaceResponsePB resp; |
1157 | 1 | req.mutable_namespace_()->set_name(other_ns_name); |
1158 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(req, &resp, ResetAndGetController())); |
1159 | 1 | SCOPED_TRACE(resp.DebugString()); |
1160 | 1 | ASSERT_FALSE(resp.has_error()); |
1161 | 1 | } |
1162 | 1 | { |
1163 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1164 | 1 | ASSERT_EQ(1 + kNumSystemNamespaces, namespaces.namespaces_size()); |
1165 | 1 | CheckNamespaces( |
1166 | 1 | { |
1167 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES |
1168 | 1 | }, namespaces); |
1169 | 1 | } |
1170 | 1 | } |
1171 | | |
1172 | 1 | TEST_F(MasterTest, TestTablesWithNamespace) { |
1173 | 1 | const TableName kTableName = "testtb"; |
1174 | 1 | const Schema kTableSchema({ ColumnSchema("key", INT32) }, 1); |
1175 | 1 | ListTablesResponsePB tables; |
1176 | | |
1177 | | // Create a table with default namespace. |
1178 | 1 | ASSERT_OK(CreateTable(kTableName, kTableSchema)); |
1179 | | |
1180 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1181 | 1 | ASSERT_EQ(1 + kNumSystemTables, tables.tables_size()); |
1182 | 1 | CheckTables( |
1183 | 1 | { |
1184 | 1 | std::make_tuple(kTableName, default_namespace_name, default_namespace_id, |
1185 | 1 | USER_TABLE_RELATION), |
1186 | 1 | EXPECTED_SYSTEM_TABLES |
1187 | 1 | }, tables); |
1188 | | |
1189 | | // Delete the table. |
1190 | 1 | ASSERT_OK(DeleteTable(kTableName)); |
1191 | | |
1192 | | // List tables, should show 1 table. |
1193 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1194 | 1 | ASSERT_EQ(kNumSystemTables, tables.tables_size()); |
1195 | 1 | CheckTables( |
1196 | 1 | { |
1197 | 1 | EXPECTED_SYSTEM_TABLES |
1198 | 1 | }, tables); |
1199 | | |
1200 | | // Create a table with the default namespace. |
1201 | 1 | ASSERT_OK(CreateTable(default_namespace_name, kTableName, kTableSchema)); |
1202 | | |
1203 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1204 | 1 | ASSERT_EQ(1 + kNumSystemTables, tables.tables_size()); |
1205 | 1 | CheckTables( |
1206 | 1 | { |
1207 | 1 | std::make_tuple(kTableName, default_namespace_name, default_namespace_id, |
1208 | 1 | USER_TABLE_RELATION), |
1209 | 1 | EXPECTED_SYSTEM_TABLES |
1210 | 1 | }, tables); |
1211 | | |
1212 | | // Delete the table. |
1213 | 1 | ASSERT_OK(DeleteTable(default_namespace_name, kTableName)); |
1214 | | |
1215 | | // List tables, should show 1 table. |
1216 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1217 | 1 | ASSERT_EQ(kNumSystemTables, tables.tables_size()); |
1218 | 1 | CheckTables( |
1219 | 1 | { |
1220 | 1 | EXPECTED_SYSTEM_TABLES |
1221 | 1 | }, tables); |
1222 | | |
1223 | | // Try to create a table with an unknown namespace. |
1224 | 1 | { |
1225 | 1 | Status s = CreateTable("nonexistingns", kTableName, kTableSchema); |
1226 | 2 | ASSERT_TRUE(s.IsNotFound()) << s.ToString(); |
1227 | 1 | ASSERT_STR_CONTAINS(s.ToString(), "Keyspace name not found"); |
1228 | 1 | } |
1229 | | |
1230 | | // List tables, should show 1 table. |
1231 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1232 | 1 | ASSERT_EQ(kNumSystemTables, tables.tables_size()); |
1233 | 1 | CheckTables( |
1234 | 1 | { |
1235 | 1 | EXPECTED_SYSTEM_TABLES |
1236 | 1 | }, tables); |
1237 | | |
1238 | 1 | const NamespaceName other_ns_name = "testns"; |
1239 | | |
1240 | | // Create a new namespace. |
1241 | 1 | NamespaceId other_ns_id; |
1242 | 1 | ListNamespacesResponsePB namespaces; |
1243 | 1 | { |
1244 | 1 | CreateNamespaceResponsePB resp; |
1245 | 1 | ASSERT_OK(CreateNamespace(other_ns_name, &resp)); |
1246 | 1 | other_ns_id = resp.id(); |
1247 | 1 | } |
1248 | 1 | { |
1249 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1250 | 1 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
1251 | 1 | CheckNamespaces( |
1252 | 1 | { |
1253 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
1254 | 1 | std::make_tuple(other_ns_name, other_ns_id), |
1255 | 1 | }, namespaces); |
1256 | 1 | } |
1257 | | |
1258 | | // Create a table with the defined new namespace. |
1259 | 1 | ASSERT_OK(CreateTable(other_ns_name, kTableName, kTableSchema)); |
1260 | | |
1261 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1262 | 1 | ASSERT_EQ(1 + kNumSystemTables, tables.tables_size()); |
1263 | 1 | CheckTables( |
1264 | 1 | { |
1265 | 1 | std::make_tuple(kTableName, other_ns_name, other_ns_id, USER_TABLE_RELATION), |
1266 | 1 | EXPECTED_SYSTEM_TABLES |
1267 | 1 | }, tables); |
1268 | | |
1269 | | // Alter table: try to change the table namespace name into an invalid one. |
1270 | 1 | { |
1271 | 1 | AlterTableRequestPB req; |
1272 | 1 | AlterTableResponsePB resp; |
1273 | 1 | req.mutable_table()->set_table_name(kTableName); |
1274 | 1 | req.mutable_table()->mutable_namespace_()->set_name(other_ns_name); |
1275 | 1 | req.mutable_new_namespace()->set_name("nonexistingns"); |
1276 | 1 | ASSERT_OK(proxy_ddl_->AlterTable(req, &resp, ResetAndGetController())); |
1277 | 1 | SCOPED_TRACE(resp.DebugString()); |
1278 | 1 | ASSERT_TRUE(resp.has_error()); |
1279 | 1 | ASSERT_EQ(resp.error().code(), MasterErrorPB::NAMESPACE_NOT_FOUND); |
1280 | 1 | ASSERT_EQ(resp.error().status().code(), AppStatusPB::NOT_FOUND); |
1281 | 1 | ASSERT_STR_CONTAINS(resp.error().status().ShortDebugString(), "Keyspace name not found"); |
1282 | 1 | } |
1283 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1284 | 1 | ASSERT_EQ(1 + kNumSystemTables, tables.tables_size()); |
1285 | 1 | CheckTables( |
1286 | 1 | { |
1287 | 1 | std::make_tuple(kTableName, other_ns_name, other_ns_id, USER_TABLE_RELATION), |
1288 | 1 | EXPECTED_SYSTEM_TABLES |
1289 | 1 | }, tables); |
1290 | | |
1291 | | // Alter table: try to change the table namespace id into an invalid one. |
1292 | 1 | { |
1293 | 1 | AlterTableRequestPB req; |
1294 | 1 | AlterTableResponsePB resp; |
1295 | 1 | req.mutable_table()->set_table_name(kTableName); |
1296 | 1 | req.mutable_table()->mutable_namespace_()->set_name(other_ns_name); |
1297 | 1 | req.mutable_new_namespace()->set_id("deadbeafdeadbeafdeadbeafdeadbeaf"); |
1298 | 1 | ASSERT_OK(proxy_ddl_->AlterTable(req, &resp, ResetAndGetController())); |
1299 | 1 | SCOPED_TRACE(resp.DebugString()); |
1300 | 1 | ASSERT_TRUE(resp.has_error()); |
1301 | 1 | ASSERT_EQ(resp.error().code(), MasterErrorPB::NAMESPACE_NOT_FOUND); |
1302 | 1 | ASSERT_EQ(resp.error().status().code(), AppStatusPB::NOT_FOUND); |
1303 | 1 | ASSERT_STR_CONTAINS(resp.error().status().ShortDebugString(), "Keyspace identifier not found"); |
1304 | 1 | } |
1305 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1306 | 1 | ASSERT_EQ(1 + kNumSystemTables, tables.tables_size()); |
1307 | 1 | CheckTables( |
1308 | 1 | { |
1309 | 1 | std::make_tuple(kTableName, other_ns_name, other_ns_id, USER_TABLE_RELATION), |
1310 | 1 | EXPECTED_SYSTEM_TABLES |
1311 | 1 | }, tables); |
1312 | | |
1313 | | // Alter table: change namespace name into the default one. |
1314 | 1 | { |
1315 | 1 | AlterTableRequestPB req; |
1316 | 1 | AlterTableResponsePB resp; |
1317 | 1 | req.mutable_table()->set_table_name(kTableName); |
1318 | 1 | req.mutable_table()->mutable_namespace_()->set_name(other_ns_name); |
1319 | 1 | req.mutable_new_namespace()->set_name(default_namespace_name); |
1320 | 1 | ASSERT_OK(proxy_ddl_->AlterTable(req, &resp, ResetAndGetController())); |
1321 | 1 | SCOPED_TRACE(resp.DebugString()); |
1322 | 1 | ASSERT_FALSE(resp.has_error()); |
1323 | 1 | } |
1324 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1325 | 1 | ASSERT_EQ(1 + kNumSystemTables, tables.tables_size()); |
1326 | 1 | CheckTables( |
1327 | 1 | { |
1328 | 1 | std::make_tuple(kTableName, default_namespace_name, default_namespace_id, |
1329 | 1 | USER_TABLE_RELATION), |
1330 | 1 | EXPECTED_SYSTEM_TABLES |
1331 | 1 | }, tables); |
1332 | | |
1333 | | // Delete the table. |
1334 | 1 | ASSERT_OK(DeleteTable(default_namespace_name, kTableName)); |
1335 | | |
1336 | | // List tables, should show 1 table. |
1337 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1338 | 1 | ASSERT_EQ(kNumSystemTables, tables.tables_size()); |
1339 | 1 | CheckTables( |
1340 | 1 | { |
1341 | 1 | EXPECTED_SYSTEM_TABLES |
1342 | 1 | }, tables); |
1343 | | |
1344 | | // Delete the namespace (by NAME). |
1345 | 1 | { |
1346 | 1 | DeleteNamespaceRequestPB req; |
1347 | 1 | DeleteNamespaceResponsePB resp; |
1348 | 1 | req.mutable_namespace_()->set_name(other_ns_name); |
1349 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(req, &resp, ResetAndGetController())); |
1350 | 1 | SCOPED_TRACE(resp.DebugString()); |
1351 | 1 | ASSERT_FALSE(resp.has_error()); |
1352 | 1 | } |
1353 | 1 | { |
1354 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1355 | 1 | ASSERT_EQ(1 + kNumSystemNamespaces, namespaces.namespaces_size()); |
1356 | 1 | CheckNamespaces( |
1357 | 1 | { |
1358 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES |
1359 | 1 | }, namespaces); |
1360 | 1 | } |
1361 | 1 | } |
1362 | | |
1363 | 1 | TEST_F(MasterTest, TestNamespaceCreateStates) { |
1364 | 1 | NamespaceName test_name = "test_pgsql"; |
1365 | | |
1366 | | // Don't allow the BG thread to process namespaces. |
1367 | 1 | SetAtomicFlag(true, &FLAGS_TEST_hang_on_namespace_transition); |
1368 | | |
1369 | | // Create a new PGSQL namespace. |
1370 | 1 | CreateNamespaceResponsePB resp; |
1371 | 1 | NamespaceId nsid; |
1372 | 1 | ASSERT_OK(CreateNamespaceAsync(test_name, YQLDatabase::YQL_DATABASE_PGSQL, &resp)); |
1373 | 1 | nsid = resp.id(); |
1374 | | |
1375 | | // ListNamespaces should not yet show the Namespace, because it's in the PREPARING state. |
1376 | 1 | ListNamespacesResponsePB namespaces; |
1377 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1378 | 1 | ASSERT_FALSE(FindNamespace(std::make_tuple(test_name, nsid), namespaces)); |
1379 | | |
1380 | | // Test that Basic Access is not allowed to a Namespace while INITIALIZING. |
1381 | | // 1. CANNOT Create a Table on the namespace. |
1382 | 1 | const Schema kTableSchema({ ColumnSchema("key", INT32) }, 1); |
1383 | 1 | ASSERT_NOK(CreatePgsqlTable(nsid, "test_table", kTableSchema)); |
1384 | | // 2. CANNOT Alter the namespace. |
1385 | 1 | { |
1386 | 1 | AlterNamespaceResponsePB alter_resp; |
1387 | 1 | ASSERT_NOK(AlterNamespace(test_name, nsid, YQLDatabase::YQL_DATABASE_PGSQL, |
1388 | 1 | "new_" + test_name, &alter_resp)); |
1389 | 1 | ASSERT_TRUE(alter_resp.has_error()); |
1390 | 1 | ASSERT_EQ(alter_resp.error().code(), MasterErrorPB::IN_TRANSITION_CAN_RETRY); |
1391 | 1 | } |
1392 | | // 3. CANNOT Delete the namespace. |
1393 | 1 | { |
1394 | 1 | DeleteNamespaceRequestPB req; |
1395 | 1 | DeleteNamespaceResponsePB resp; |
1396 | 1 | req.mutable_namespace_()->set_name(test_name); |
1397 | 1 | req.mutable_namespace_()->set_database_type(YQLDatabase::YQL_DATABASE_PGSQL); |
1398 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(req, &resp, ResetAndGetController())); |
1399 | 1 | ASSERT_TRUE(resp.has_error()); |
1400 | 1 | ASSERT_EQ(resp.error().code(), MasterErrorPB::IN_TRANSITION_CAN_RETRY); |
1401 | 1 | } |
1402 | | |
1403 | | // Finish Namespace create. |
1404 | 1 | SetAtomicFlag(false, &FLAGS_TEST_hang_on_namespace_transition); |
1405 | 1 | ASSERT_OK(CreateNamespaceWait(nsid, YQLDatabase::YQL_DATABASE_PGSQL)); |
1406 | | |
1407 | | // Verify that Basic Access to a Namespace is now available. |
1408 | | // 1. Create a Table within the Schema. |
1409 | 1 | ASSERT_OK(CreatePgsqlTable(nsid, "test_table", kTableSchema)); |
1410 | | // 2. Alter the namespace. |
1411 | 1 | { |
1412 | 1 | AlterNamespaceResponsePB alter_resp; |
1413 | 1 | ASSERT_OK(AlterNamespace(test_name, nsid, YQLDatabase::YQL_DATABASE_PGSQL, |
1414 | 1 | "new_" + test_name, &alter_resp) ); |
1415 | 1 | ASSERT_FALSE(alter_resp.has_error()); |
1416 | 1 | } |
1417 | | // 3. Delete the namespace. |
1418 | 1 | { |
1419 | 1 | SetAtomicFlag(true, &FLAGS_TEST_hang_on_namespace_transition); |
1420 | | |
1421 | 1 | DeleteNamespaceRequestPB del_req; |
1422 | 1 | DeleteNamespaceResponsePB del_resp; |
1423 | 1 | del_req.mutable_namespace_()->set_name("new_" + test_name); |
1424 | 1 | del_req.mutable_namespace_()->set_database_type(YQLDatabase::YQL_DATABASE_PGSQL); |
1425 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(del_req, &del_resp, ResetAndGetController())); |
1426 | 1 | ASSERT_FALSE(del_resp.has_error()); |
1427 | | |
1428 | | // ListNamespaces should not show the Namespace, because it's in the DELETING state. |
1429 | 1 | ListNamespacesResponsePB namespaces; |
1430 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1431 | 1 | ASSERT_FALSE(FindNamespace(std::make_tuple("new_" + test_name, nsid), namespaces)); |
1432 | | |
1433 | | // Resume finishing both [1] the delete and [2] the create. |
1434 | 1 | SetAtomicFlag(false, &FLAGS_TEST_hang_on_namespace_transition); |
1435 | | |
1436 | | // Verify the old namespace finishes deletion. |
1437 | 1 | IsDeleteNamespaceDoneRequestPB is_del_req; |
1438 | 1 | is_del_req.mutable_namespace_()->set_id(nsid); |
1439 | 1 | is_del_req.mutable_namespace_()->set_database_type(YQLDatabase::YQL_DATABASE_PGSQL); |
1440 | 1 | ASSERT_OK(DeleteNamespaceWait(is_del_req)); |
1441 | | |
1442 | | // We should be able to create a namespace with the same NAME at this time. |
1443 | 1 | ASSERT_OK(CreateNamespaceAsync("new_" + test_name, YQLDatabase::YQL_DATABASE_PGSQL, &resp)); |
1444 | 1 | ASSERT_OK(CreateNamespaceWait(resp.id(), YQLDatabase::YQL_DATABASE_PGSQL)); |
1445 | 1 | } |
1446 | 1 | } |
1447 | | |
1448 | 1 | TEST_F(MasterTest, TestNamespaceCreateFailure) { |
1449 | 1 | NamespaceName test_name = "test_pgsql"; |
1450 | | |
1451 | | // Don't allow the BG thread to process namespaces. |
1452 | 1 | SetAtomicFlag(true, &FLAGS_TEST_hang_on_namespace_transition); |
1453 | | |
1454 | | // Create a new PGSQL namespace. |
1455 | 1 | CreateNamespaceResponsePB resp; |
1456 | 1 | NamespaceId nsid; |
1457 | 1 | ASSERT_OK(CreateNamespaceAsync(test_name, YQLDatabase::YQL_DATABASE_PGSQL, &resp)); |
1458 | 1 | nsid = resp.id(); |
1459 | | |
1460 | 1 | { |
1461 | | // Public ListNamespaces should not show the Namespace, because it's in the PREPARING state. |
1462 | 1 | ListNamespacesResponsePB namespace_pb; |
1463 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespace_pb)); |
1464 | 1 | ASSERT_FALSE(FindNamespace(std::make_tuple(test_name, nsid), namespace_pb)); |
1465 | | |
1466 | | // Internal search of CatalogManager should reveal it's state (debug UI uses this function). |
1467 | 1 | std::vector<scoped_refptr<NamespaceInfo>> namespace_internal; |
1468 | 1 | mini_master_->catalog_manager().GetAllNamespaces(&namespace_internal, false); |
1469 | 1 | auto pos = std::find_if(namespace_internal.begin(), namespace_internal.end(), |
1470 | 1 | [&nsid](const scoped_refptr<NamespaceInfo>& ns) { |
1471 | 1 | return ns && ns->id() == nsid; |
1472 | 1 | }); |
1473 | 1 | ASSERT_NE(pos, namespace_internal.end()); |
1474 | 1 | ASSERT_EQ((*pos)->state(), SysNamespaceEntryPB::PREPARING); |
1475 | 1 | } |
1476 | | |
1477 | | // Restart the master (Shutdown kills Namespace BG Thread). |
1478 | 1 | ASSERT_OK(mini_master_->Restart()); |
1479 | 1 | ASSERT_OK(mini_master_->master()->WaitUntilCatalogManagerIsLeaderAndReadyForTests()); |
1480 | | |
1481 | 1 | { |
1482 | | // ListNamespaces should not show the Namespace on restart because it didn't finish. |
1483 | 1 | ListNamespacesResponsePB namespaces; |
1484 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1485 | 1 | ASSERT_FALSE(FindNamespace(std::make_tuple(test_name, nsid), namespaces)); |
1486 | | |
1487 | | // Internal search of CatalogManager should reveal it's DELETING to cleanup any partial apply. |
1488 | 1 | std::vector<scoped_refptr<NamespaceInfo>> namespace_internal; |
1489 | 1 | mini_master_->catalog_manager().GetAllNamespaces(&namespace_internal, false); |
1490 | 1 | auto pos = std::find_if(namespace_internal.begin(), namespace_internal.end(), |
1491 | 1 | [&nsid](const scoped_refptr<NamespaceInfo>& ns) { |
1492 | 1 | return ns && ns->id() == nsid; |
1493 | 1 | }); |
1494 | 1 | ASSERT_NE(pos, namespace_internal.end()); |
1495 | 1 | ASSERT_EQ((*pos)->state(), SysNamespaceEntryPB::DELETING); |
1496 | 1 | } |
1497 | | |
1498 | | // Resume BG thread work and verify that the Namespace is eventually DELETED internally. |
1499 | 1 | SetAtomicFlag(false, &FLAGS_TEST_hang_on_namespace_transition); |
1500 | | |
1501 | 1 | ASSERT_OK(LoggedWaitFor([&]() -> Result<bool> { |
1502 | 1 | std::vector<scoped_refptr<NamespaceInfo>> namespace_internal; |
1503 | 1 | mini_master_->catalog_manager().GetAllNamespaces(&namespace_internal, false); |
1504 | 1 | auto pos = std::find_if(namespace_internal.begin(), namespace_internal.end(), |
1505 | 1 | [&nsid](const scoped_refptr<NamespaceInfo>& ns) { |
1506 | 1 | return ns && ns->id() == nsid; |
1507 | 1 | }); |
1508 | 1 | return pos != namespace_internal.end() && (*pos)->state() == SysNamespaceEntryPB::DELETED; |
1509 | 1 | }, MonoDelta::FromSeconds(10), "Verify Namespace was DELETED")); |
1510 | | |
1511 | | // Restart the master #2, this round should completely remove the Namespace from memory. |
1512 | 1 | ASSERT_OK(mini_master_->Restart()); |
1513 | 1 | ASSERT_OK(mini_master_->master()->WaitUntilCatalogManagerIsLeaderAndReadyForTests()); |
1514 | | |
1515 | 1 | ASSERT_OK(LoggedWaitFor([&]() -> Result<bool> { |
1516 | 1 | std::vector<scoped_refptr<NamespaceInfo>> namespace_internal; |
1517 | 1 | mini_master_->catalog_manager().GetAllNamespaces(&namespace_internal, false); |
1518 | 1 | auto pos = std::find_if(namespace_internal.begin(), namespace_internal.end(), |
1519 | 1 | [&nsid](const scoped_refptr<NamespaceInfo>& ns) { |
1520 | 1 | return ns && ns->id() == nsid; |
1521 | 1 | }); |
1522 | 1 | return pos == namespace_internal.end(); |
1523 | 1 | }, MonoDelta::FromSeconds(10), "Verify Namespace was completely removed")); |
1524 | 1 | } |
1525 | | |
1526 | | class LoopedMasterTest : public MasterTest, public testing::WithParamInterface<int> {}; |
1527 | | INSTANTIATE_TEST_CASE_P(Loops, LoopedMasterTest, ::testing::Values(10)); |
1528 | | |
1529 | 1 | TEST_P(LoopedMasterTest, TestNamespaceCreateSysCatalogFailure) { |
1530 | 1 | NamespaceName test_name = "test_pgsql"; // Reuse name to find errors with delete cleanup. |
1531 | 1 | CreateNamespaceResponsePB resp; |
1532 | 1 | DeleteNamespaceRequestPB del_req; |
1533 | 1 | del_req.mutable_namespace_()->set_name(test_name); |
1534 | 1 | del_req.mutable_namespace_()->set_database_type(YQLDatabase::YQL_DATABASE_PGSQL); |
1535 | 1 | IsDeleteNamespaceDoneRequestPB is_del_req; |
1536 | 1 | is_del_req.mutable_namespace_()->set_name(test_name); |
1537 | 1 | is_del_req.mutable_namespace_()->set_database_type(YQLDatabase::YQL_DATABASE_PGSQL); |
1538 | | |
1539 | 1 | int failures = 0, created = 0, iter = 0; |
1540 | 1 | int loops = GetParam(); |
1541 | 1 | LOG(INFO) << "Loops = " << loops; |
1542 | | |
1543 | | // Loop this to cover a spread of random failure situations. |
1544 | 18 | while (failures < loops) { |
1545 | | // Inject Frequent failures into sys catalog commit. |
1546 | | // The below code should eventually succeed but require a lot of restarts. |
1547 | 17 | FLAGS_TEST_sys_catalog_write_rejection_percentage = 50; |
1548 | | |
1549 | | // CreateNamespace : Inject IO Errors. |
1550 | 17 | LOG(INFO) << "Iteration " << ++iter; |
1551 | 17 | Status s = CreateNamespace(test_name, YQLDatabase::YQL_DATABASE_PGSQL, &resp); |
1552 | 17 | if (!s.ok()) { |
1553 | 10 | WARN_NOT_OK(s, "CreateNamespace with injected failures"); |
1554 | 10 | ++failures; |
1555 | 10 | } |
1556 | | |
1557 | | // Turn off random failures. |
1558 | 17 | FLAGS_TEST_sys_catalog_write_rejection_percentage = 0; |
1559 | | |
1560 | | // Internal search of CatalogManager should reveal whether it was partially created. |
1561 | 17 | std::vector<scoped_refptr<NamespaceInfo>> namespace_internal; |
1562 | 17 | mini_master_->catalog_manager().GetAllNamespaces(&namespace_internal, false); |
1563 | 17 | auto was_internally_created = std::any_of(namespace_internal.begin(), namespace_internal.end(), |
1564 | 96 | [&test_name](const scoped_refptr<NamespaceInfo>& ns) { |
1565 | 96 | if (ns && ns->name() == test_name && ns->state() != SysNamespaceEntryPB::DELETED) { |
1566 | 9 | LOG(INFO) << "Namespace " << ns->name() << " = " << ns->state(); |
1567 | 9 | return true; |
1568 | 9 | } |
1569 | 87 | return false; |
1570 | 87 | }); |
1571 | | |
1572 | 17 | if (was_internally_created) { |
1573 | 9 | ++created; |
1574 | | // Ensure we can delete the failed namespace. |
1575 | 9 | DeleteNamespaceResponsePB del_resp; |
1576 | 9 | ASSERT_OK(proxy_ddl_->DeleteNamespace(del_req, &del_resp, ResetAndGetController())); |
1577 | 9 | if (del_resp.has_error()) { |
1578 | 0 | LOG(INFO) << del_resp.error().DebugString(); |
1579 | 0 | } |
1580 | 9 | ASSERT_FALSE(del_resp.has_error()); |
1581 | 9 | ASSERT_OK(DeleteNamespaceWait(is_del_req)); |
1582 | 9 | } |
1583 | 17 | } |
1584 | 1 | ASSERT_EQ(failures, loops); |
1585 | 1 | LOG(INFO) << "created = " << created; |
1586 | 1 | } |
1587 | | |
1588 | 1 | TEST_P(LoopedMasterTest, TestNamespaceDeleteSysCatalogFailure) { |
1589 | 1 | NamespaceName test_name = "test_pgsql"; |
1590 | 1 | CreateNamespaceResponsePB resp; |
1591 | 1 | DeleteNamespaceRequestPB del_req; |
1592 | 1 | DeleteNamespaceResponsePB del_resp; |
1593 | 1 | del_req.mutable_namespace_()->set_name(test_name); |
1594 | 1 | del_req.mutable_namespace_()->set_database_type(YQLDatabase::YQL_DATABASE_PGSQL); |
1595 | 1 | IsDeleteNamespaceDoneRequestPB is_del_req; |
1596 | 1 | is_del_req.mutable_namespace_()->set_name(test_name); |
1597 | 1 | is_del_req.mutable_namespace_()->set_database_type(YQLDatabase::YQL_DATABASE_PGSQL); |
1598 | 1 | int failures = 0, iter = 0; |
1599 | 1 | int loops = GetParam(); |
1600 | 1 | LOG(INFO) << "Loops = " << loops; |
1601 | | |
1602 | | // Loop this to cover a spread of random failure situations. |
1603 | 11 | while (failures < loops) { |
1604 | | // CreateNamespace to setup test |
1605 | 10 | CreateNamespaceResponsePB resp; |
1606 | 10 | NamespaceId nsid; |
1607 | 10 | ASSERT_OK(CreateNamespaceAsync(test_name, YQLDatabase::YQL_DATABASE_PGSQL, &resp)); |
1608 | 10 | nsid = resp.id(); |
1609 | | |
1610 | | // The below code should eventually succeed but require a lot of restarts. |
1611 | 10 | FLAGS_TEST_sys_catalog_write_rejection_percentage = 50; |
1612 | | |
1613 | | // DeleteNamespace : Inject IO Errors. |
1614 | 10 | LOG(INFO) << "Iteration " << ++iter; |
1615 | 10 | bool delete_failed = false; |
1616 | | |
1617 | 10 | ASSERT_OK(proxy_ddl_->DeleteNamespace(del_req, &del_resp, ResetAndGetController())); |
1618 | | |
1619 | 10 | delete_failed = del_resp.has_error(); |
1620 | 10 | if (del_resp.has_error()) { |
1621 | 5 | LOG(INFO) << "Expected failure: " << del_resp.error().DebugString(); |
1622 | 5 | } |
1623 | | |
1624 | 10 | if (!del_resp.has_error()) { |
1625 | 5 | Status s = DeleteNamespaceWait(is_del_req); |
1626 | 10 | ASSERT_FALSE(s.IsTimedOut()) << "Unexpected timeout: " << s; |
1627 | 5 | WARN_NOT_OK(s, "Expected failure"); |
1628 | 5 | delete_failed = !s.ok(); |
1629 | 5 | } |
1630 | | |
1631 | | // Turn off random failures. |
1632 | 10 | FLAGS_TEST_sys_catalog_write_rejection_percentage = 0; |
1633 | | |
1634 | 10 | if (delete_failed) { |
1635 | 10 | ++failures; |
1636 | 10 | LOG(INFO) << "Next Delete should succeed"; |
1637 | | |
1638 | | // If the namespace delete fails, Ensure that we can restart the delete and it succeeds. |
1639 | 10 | ASSERT_OK(proxy_ddl_->DeleteNamespace(del_req, &del_resp, ResetAndGetController())); |
1640 | 10 | ASSERT_FALSE(del_resp.has_error()); |
1641 | 10 | ASSERT_OK(DeleteNamespaceWait(is_del_req)); |
1642 | 10 | } |
1643 | 10 | } |
1644 | 1 | ASSERT_EQ(failures, loops); |
1645 | 1 | } |
1646 | | |
1647 | 1 | TEST_F(MasterTest, TestFullTableName) { |
1648 | 1 | const TableName kTableName = "testtb"; |
1649 | 1 | const Schema kTableSchema({ ColumnSchema("key", INT32) }, 1); |
1650 | 1 | ListTablesResponsePB tables; |
1651 | | |
1652 | | // Create a table with the default namespace. |
1653 | 1 | ASSERT_OK(CreateTable(default_namespace_name, kTableName, kTableSchema)); |
1654 | | |
1655 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1656 | 1 | ASSERT_EQ(1 + kNumSystemTables, tables.tables_size()); |
1657 | 1 | CheckTables( |
1658 | 1 | { |
1659 | 1 | std::make_tuple(kTableName, default_namespace_name, default_namespace_id, |
1660 | 1 | USER_TABLE_RELATION), |
1661 | 1 | EXPECTED_SYSTEM_TABLES |
1662 | 1 | }, tables); |
1663 | | |
1664 | 1 | const NamespaceName other_ns_name = "testns"; |
1665 | | |
1666 | | // Create a new namespace. |
1667 | 1 | NamespaceId other_ns_id; |
1668 | 1 | ListNamespacesResponsePB namespaces; |
1669 | 1 | { |
1670 | 1 | CreateNamespaceResponsePB resp; |
1671 | 1 | ASSERT_OK(CreateNamespace(other_ns_name, &resp)); |
1672 | 1 | other_ns_id = resp.id(); |
1673 | 1 | } |
1674 | 1 | { |
1675 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1676 | 1 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
1677 | 1 | CheckNamespaces( |
1678 | 1 | { |
1679 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
1680 | 1 | std::make_tuple(other_ns_name, other_ns_id) |
1681 | 1 | }, namespaces); |
1682 | 1 | } |
1683 | | |
1684 | | // Create a table with the defined new namespace. |
1685 | 1 | ASSERT_OK(CreateTable(other_ns_name, kTableName, kTableSchema)); |
1686 | | |
1687 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1688 | 1 | ASSERT_EQ(2 + kNumSystemTables, tables.tables_size()); |
1689 | 1 | CheckTables( |
1690 | 1 | { |
1691 | 1 | std::make_tuple(kTableName, default_namespace_name, default_namespace_id, |
1692 | 1 | USER_TABLE_RELATION), |
1693 | 1 | std::make_tuple(kTableName, other_ns_name, other_ns_id, USER_TABLE_RELATION), |
1694 | 1 | EXPECTED_SYSTEM_TABLES |
1695 | 1 | }, tables); |
1696 | | |
1697 | | // Test ListTables() for one particular namespace. |
1698 | | // There are 2 tables now: 'default_namespace::testtb' and 'testns::testtb'. |
1699 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables, default_namespace_name)); |
1700 | 1 | ASSERT_EQ(1, tables.tables_size()); |
1701 | 1 | CheckTables( |
1702 | 1 | { |
1703 | 1 | std::make_tuple(kTableName, default_namespace_name, default_namespace_id, |
1704 | 1 | USER_TABLE_RELATION), |
1705 | 1 | }, tables); |
1706 | | |
1707 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables, other_ns_name)); |
1708 | 1 | ASSERT_EQ(1, tables.tables_size()); |
1709 | 1 | CheckTables( |
1710 | 1 | { |
1711 | 1 | std::make_tuple(kTableName, other_ns_name, other_ns_id, USER_TABLE_RELATION) |
1712 | 1 | }, tables); |
1713 | | |
1714 | | // Try to alter table: change namespace name into the default one. |
1715 | | // Try to change 'testns::testtb' into 'default_namespace::testtb', but the target table exists, |
1716 | | // so it must fail. |
1717 | 1 | { |
1718 | 1 | AlterTableRequestPB req; |
1719 | 1 | AlterTableResponsePB resp; |
1720 | 1 | req.mutable_table()->set_table_name(kTableName); |
1721 | 1 | req.mutable_table()->mutable_namespace_()->set_name(other_ns_name); |
1722 | 1 | req.mutable_new_namespace()->set_name(default_namespace_name); |
1723 | 1 | ASSERT_OK(proxy_ddl_->AlterTable(req, &resp, ResetAndGetController())); |
1724 | 1 | SCOPED_TRACE(resp.DebugString()); |
1725 | 1 | ASSERT_TRUE(resp.has_error()); |
1726 | 1 | ASSERT_EQ(resp.error().code(), MasterErrorPB::OBJECT_ALREADY_PRESENT); |
1727 | 1 | ASSERT_EQ(resp.error().status().code(), AppStatusPB::ALREADY_PRESENT); |
1728 | 1 | ASSERT_STR_CONTAINS(resp.error().status().ShortDebugString(), |
1729 | 1 | " already exists"); |
1730 | 1 | } |
1731 | | // Check that nothing's changed (still have 3 tables). |
1732 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1733 | 1 | ASSERT_EQ(2 + kNumSystemTables, tables.tables_size()); |
1734 | 1 | CheckTables( |
1735 | 1 | { |
1736 | 1 | std::make_tuple(kTableName, other_ns_name, other_ns_id, USER_TABLE_RELATION), |
1737 | 1 | std::make_tuple(kTableName, default_namespace_name, default_namespace_id, |
1738 | 1 | USER_TABLE_RELATION), |
1739 | 1 | EXPECTED_SYSTEM_TABLES |
1740 | 1 | }, tables); |
1741 | | |
1742 | | // Delete the table in the namespace 'testns'. |
1743 | 1 | ASSERT_OK(DeleteTable(other_ns_name, kTableName)); |
1744 | | |
1745 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1746 | 1 | ASSERT_EQ(1 + kNumSystemTables, tables.tables_size()); |
1747 | 1 | CheckTables( |
1748 | 1 | { |
1749 | 1 | std::make_tuple(kTableName, default_namespace_name, default_namespace_id, |
1750 | 1 | USER_TABLE_RELATION), |
1751 | 1 | EXPECTED_SYSTEM_TABLES |
1752 | 1 | }, tables); |
1753 | | |
1754 | | // Try to delete the table from wrong namespace (table 'default_namespace::testtbl'). |
1755 | 1 | { |
1756 | 1 | DeleteTableRequestPB req; |
1757 | 1 | DeleteTableResponsePB resp; |
1758 | 1 | req.mutable_table()->set_table_name(kTableName); |
1759 | 1 | req.mutable_table()->mutable_namespace_()->set_name(other_ns_name); |
1760 | 1 | ASSERT_OK(proxy_ddl_->DeleteTable(req, &resp, ResetAndGetController())); |
1761 | 1 | SCOPED_TRACE(resp.DebugString()); |
1762 | 1 | ASSERT_TRUE(resp.has_error()); |
1763 | 1 | ASSERT_EQ(resp.error().code(), MasterErrorPB::OBJECT_NOT_FOUND); |
1764 | 1 | ASSERT_EQ(resp.error().status().code(), AppStatusPB::NOT_FOUND); |
1765 | 1 | auto status = StatusFromPB(resp.error().status()); |
1766 | 1 | ASSERT_EQ(MasterError(status), MasterErrorPB::OBJECT_NOT_FOUND); |
1767 | 1 | } |
1768 | | |
1769 | | // Delete the table. |
1770 | 1 | ASSERT_OK(DeleteTable(default_namespace_name, kTableName)); |
1771 | | |
1772 | | // List tables, should show only system tables. |
1773 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1774 | 1 | ASSERT_EQ(kNumSystemTables, tables.tables_size()); |
1775 | 1 | CheckTables( |
1776 | 1 | { |
1777 | 1 | EXPECTED_SYSTEM_TABLES |
1778 | 1 | }, tables); |
1779 | | |
1780 | | // Delete the namespace (by NAME). |
1781 | 1 | { |
1782 | 1 | DeleteNamespaceRequestPB req; |
1783 | 1 | DeleteNamespaceResponsePB resp; |
1784 | 1 | req.mutable_namespace_()->set_name(other_ns_name); |
1785 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(req, &resp, ResetAndGetController())); |
1786 | 1 | SCOPED_TRACE(resp.DebugString()); |
1787 | 1 | ASSERT_FALSE(resp.has_error()); |
1788 | 1 | } |
1789 | 1 | { |
1790 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1791 | 1 | ASSERT_EQ(1 + kNumSystemNamespaces, namespaces.namespaces_size()); |
1792 | 1 | CheckNamespaces( |
1793 | 1 | { |
1794 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES |
1795 | 1 | }, namespaces); |
1796 | 1 | } |
1797 | 1 | } |
1798 | | |
1799 | 1 | TEST_F(MasterTest, TestGetTableSchema) { |
1800 | | // Create a new namespace. |
1801 | 1 | const NamespaceName other_ns_name = "testns"; |
1802 | 1 | NamespaceId other_ns_id; |
1803 | 1 | ListNamespacesResponsePB namespaces; |
1804 | 1 | { |
1805 | 1 | CreateNamespaceResponsePB resp; |
1806 | 1 | ASSERT_OK(CreateNamespace(other_ns_name, &resp)); |
1807 | 1 | other_ns_id = resp.id(); |
1808 | 1 | } |
1809 | 1 | { |
1810 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1811 | 1 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
1812 | 1 | CheckNamespaces( |
1813 | 1 | { |
1814 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
1815 | 1 | std::make_tuple(other_ns_name, other_ns_id), |
1816 | 1 | }, namespaces); |
1817 | 1 | } |
1818 | | |
1819 | | // Create a table with the defined new namespace. |
1820 | 1 | const TableName kTableName = "testtb"; |
1821 | 1 | const Schema kTableSchema({ ColumnSchema("key", INT32) }, 1); |
1822 | 1 | ASSERT_OK(CreateTable(other_ns_name, kTableName, kTableSchema)); |
1823 | | |
1824 | 1 | ListTablesResponsePB tables; |
1825 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1826 | 1 | ASSERT_EQ(1 + kNumSystemTables, tables.tables_size()); |
1827 | 1 | CheckTables( |
1828 | 1 | { |
1829 | 1 | std::make_tuple(kTableName, other_ns_name, other_ns_id, USER_TABLE_RELATION), |
1830 | 1 | EXPECTED_SYSTEM_TABLES |
1831 | 1 | }, tables); |
1832 | | |
1833 | 1 | TableId table_id; |
1834 | 16 | for (int i = 0; i < tables.tables_size(); ++i) { |
1835 | 16 | if (tables.tables(i).name() == kTableName) { |
1836 | 1 | table_id = tables.tables(i).id(); |
1837 | 1 | break; |
1838 | 1 | } |
1839 | 16 | } |
1840 | | |
1841 | 2 | ASSERT_FALSE(table_id.empty()) << "Couldn't get table id for table " << kTableName; |
1842 | | |
1843 | | // Check GetTableSchema(). |
1844 | 1 | { |
1845 | 1 | GetTableSchemaRequestPB req; |
1846 | 1 | GetTableSchemaResponsePB resp; |
1847 | 1 | req.mutable_table()->set_table_name(kTableName); |
1848 | 1 | req.mutable_table()->mutable_namespace_()->set_name(other_ns_name); |
1849 | | |
1850 | | // Check the request. |
1851 | 1 | ASSERT_OK(proxy_ddl_->GetTableSchema(req, &resp, ResetAndGetController())); |
1852 | | |
1853 | | // Check the responsed data. |
1854 | 1 | SCOPED_TRACE(resp.DebugString()); |
1855 | 1 | ASSERT_FALSE(resp.has_error()); |
1856 | 1 | ASSERT_TRUE(resp.has_table_type()); |
1857 | 1 | ASSERT_TRUE(resp.has_create_table_done()); |
1858 | | // SchemaPB schema. |
1859 | 1 | ASSERT_TRUE(resp.has_schema()); |
1860 | 1 | ASSERT_EQ(1, resp.schema().columns_size()); |
1861 | 1 | ASSERT_EQ(Schema::first_column_id(), resp.schema().columns(0).id()); |
1862 | 1 | ASSERT_EQ("key", resp.schema().columns(0).name()); |
1863 | 1 | ASSERT_EQ(INT32, resp.schema().columns(0).type().main()); |
1864 | 1 | ASSERT_TRUE(resp.schema().columns(0).is_key()); |
1865 | 1 | ASSERT_FALSE(resp.schema().columns(0).is_nullable()); |
1866 | 1 | ASSERT_EQ(1, resp.schema().columns(0).sorting_type()); |
1867 | | // PartitionSchemaPB partition_schema. |
1868 | 1 | ASSERT_TRUE(resp.has_partition_schema()); |
1869 | 1 | ASSERT_EQ(resp.partition_schema().hash_schema(), PartitionSchemaPB::MULTI_COLUMN_HASH_SCHEMA); |
1870 | | // TableIdentifierPB identifier. |
1871 | 1 | ASSERT_TRUE(resp.has_identifier()); |
1872 | 1 | ASSERT_TRUE(resp.identifier().has_table_name()); |
1873 | 1 | ASSERT_EQ(kTableName, resp.identifier().table_name()); |
1874 | 1 | ASSERT_TRUE(resp.identifier().has_table_id()); |
1875 | 1 | ASSERT_EQ(table_id, resp.identifier().table_id()); |
1876 | 1 | ASSERT_TRUE(resp.identifier().has_namespace_()); |
1877 | 1 | ASSERT_TRUE(resp.identifier().namespace_().has_name()); |
1878 | 1 | ASSERT_EQ(other_ns_name, resp.identifier().namespace_().name()); |
1879 | 1 | ASSERT_TRUE(resp.identifier().namespace_().has_id()); |
1880 | 1 | ASSERT_EQ(other_ns_id, resp.identifier().namespace_().id()); |
1881 | 1 | } |
1882 | | |
1883 | | // Delete the table in the namespace 'testns'. |
1884 | 1 | ASSERT_OK(DeleteTable(other_ns_name, kTableName)); |
1885 | | |
1886 | | // List tables, should show only system tables. |
1887 | 1 | ASSERT_NO_FATALS(DoListAllTables(&tables)); |
1888 | 1 | ASSERT_EQ(kNumSystemTables, tables.tables_size()); |
1889 | 1 | CheckTables( |
1890 | 1 | { |
1891 | 1 | EXPECTED_SYSTEM_TABLES |
1892 | 1 | }, tables); |
1893 | | |
1894 | | // Delete the namespace (by NAME). |
1895 | 1 | { |
1896 | 1 | DeleteNamespaceRequestPB req; |
1897 | 1 | DeleteNamespaceResponsePB resp; |
1898 | 1 | req.mutable_namespace_()->set_name(other_ns_name); |
1899 | 1 | ASSERT_OK(proxy_ddl_->DeleteNamespace(req, &resp, ResetAndGetController())); |
1900 | 1 | SCOPED_TRACE(resp.DebugString()); |
1901 | 1 | ASSERT_FALSE(resp.has_error()); |
1902 | 1 | } |
1903 | 1 | { |
1904 | 1 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
1905 | 1 | ASSERT_EQ(1 + kNumSystemNamespaces, namespaces.namespaces_size()); |
1906 | 1 | CheckNamespaces( |
1907 | 1 | { |
1908 | 1 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES |
1909 | 1 | }, namespaces); |
1910 | 1 | } |
1911 | 1 | } |
1912 | | |
1913 | 1 | TEST_F(MasterTest, TestFailedMasterRestart) { |
1914 | 1 | TearDown(); |
1915 | | |
1916 | 1 | mini_master_.reset(new MiniMaster(Env::Default(), GetTestPath("Master-test"), |
1917 | 1 | AllocateFreePort(), AllocateFreePort(), 0)); |
1918 | 1 | ASSERT_NOK(mini_master_->Start(true)); |
1919 | | // Restart master should succeed. |
1920 | 1 | ASSERT_OK(mini_master_->Start()); |
1921 | 1 | } |
1922 | | |
1923 | 1 | TEST_F(MasterTest, TestNetworkErrorOnFirstRun) { |
1924 | 1 | TearDown(); |
1925 | 1 | mini_master_.reset(new MiniMaster(Env::Default(), GetTestPath("Master-test"), |
1926 | 1 | AllocateFreePort(), AllocateFreePort(), 0)); |
1927 | 1 | FLAGS_TEST_simulate_port_conflict_error = true; |
1928 | 1 | ASSERT_NOK(mini_master_->Start()); |
1929 | | // Instance file should be properly initialized, but consensus metadata is not initialized. |
1930 | 1 | FLAGS_TEST_simulate_port_conflict_error = false; |
1931 | | // Restarting master should succeed. |
1932 | 1 | ASSERT_OK(mini_master_->Start()); |
1933 | 1 | } |
1934 | | |
1935 | | namespace { |
1936 | | |
1937 | | void GetTableSchema(const char* table_name, |
1938 | | const char* namespace_name, |
1939 | | const Schema* kSchema, |
1940 | | const MasterDdlProxy& proxy, |
1941 | | CountDownLatch* started, |
1942 | 1 | AtomicBool* done) { |
1943 | 1 | GetTableSchemaRequestPB req; |
1944 | 1 | GetTableSchemaResponsePB resp; |
1945 | 1 | req.mutable_table()->set_table_name(table_name); |
1946 | 1 | req.mutable_table()->mutable_namespace_()->set_name(namespace_name); |
1947 | | |
1948 | 1 | started->CountDown(); |
1949 | 4 | while (!done->Load()) { |
1950 | 3 | RpcController controller; |
1951 | | |
1952 | 3 | CHECK_OK(proxy.GetTableSchema(req, &resp, &controller)); |
1953 | 3 | SCOPED_TRACE(resp.DebugString()); |
1954 | | |
1955 | | // There are two possible outcomes: |
1956 | | // |
1957 | | // 1. GetTableSchema() happened before CreateTable(): we expect to see a |
1958 | | // TABLE_NOT_FOUND error. |
1959 | | // 2. GetTableSchema() happened after CreateTable(): we expect to see the |
1960 | | // full table schema. |
1961 | | // |
1962 | | // Any other outcome is an error. |
1963 | 3 | if (resp.has_error()) { |
1964 | 2 | CHECK_EQ(MasterErrorPB::OBJECT_NOT_FOUND, resp.error().code()); |
1965 | 1 | } else { |
1966 | 1 | Schema receivedSchema; |
1967 | 1 | CHECK_OK(SchemaFromPB(resp.schema(), &receivedSchema)); |
1968 | 0 | CHECK(kSchema->Equals(receivedSchema)) << |
1969 | 0 | strings::Substitute("$0 not equal to $1", |
1970 | 0 | kSchema->ToString(), receivedSchema.ToString()); |
1971 | 1 | } |
1972 | 3 | } |
1973 | 1 | } |
1974 | | |
1975 | | } // namespace |
1976 | | |
1977 | | // The catalog manager had a bug wherein GetTableSchema() interleaved with |
1978 | | // CreateTable() could expose intermediate uncommitted state to clients. This |
1979 | | // test ensures that bug does not regress. |
1980 | 1 | TEST_F(MasterTest, TestGetTableSchemaIsAtomicWithCreateTable) { |
1981 | 1 | const char *kTableName = "testtb"; |
1982 | 1 | const Schema kTableSchema({ ColumnSchema("key", INT32), |
1983 | 1 | ColumnSchema("v1", UINT64), |
1984 | 1 | ColumnSchema("v2", STRING) }, |
1985 | 1 | 1); |
1986 | | |
1987 | 1 | CountDownLatch started(1); |
1988 | 1 | AtomicBool done(false); |
1989 | | |
1990 | | // Kick off a thread that calls GetTableSchema() in a loop. |
1991 | 1 | scoped_refptr<Thread> t; |
1992 | 1 | ASSERT_OK(Thread::Create("test", "test", |
1993 | 1 | &GetTableSchema, kTableName, default_namespace_name.c_str(), |
1994 | 1 | &kTableSchema, std::cref(*proxy_ddl_), &started, &done, &t)); |
1995 | | |
1996 | | // Only create the table after the thread has started. |
1997 | 1 | started.Wait(); |
1998 | 1 | ASSERT_OK(CreateTable(kTableName, kTableSchema)); |
1999 | | |
2000 | 1 | done.Store(true); |
2001 | 1 | t->Join(); |
2002 | 1 | } |
2003 | | |
2004 | | class NamespaceTest : public MasterTest, public testing::WithParamInterface<YQLDatabase> {}; |
2005 | | |
2006 | 2 | TEST_P(NamespaceTest, RenameNamespace) { |
2007 | 2 | ListNamespacesResponsePB namespaces; |
2008 | | |
2009 | | // Check default namespace. |
2010 | 2 | { |
2011 | 2 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
2012 | | // Including system namespace. |
2013 | 2 | ASSERT_EQ(1 + kNumSystemNamespaces, namespaces.namespaces_size()); |
2014 | 2 | CheckNamespaces( |
2015 | 2 | { |
2016 | 2 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES |
2017 | 2 | }, namespaces); |
2018 | 2 | } |
2019 | | |
2020 | | // Create a new namespace. |
2021 | 2 | const NamespaceName other_ns_name = "testns"; |
2022 | 2 | NamespaceId other_ns_id; |
2023 | 2 | { |
2024 | 2 | CreateNamespaceResponsePB resp; |
2025 | 2 | ASSERT_OK(CreateNamespace(other_ns_name, GetParam() /* database_type */, &resp)); |
2026 | 2 | other_ns_id = resp.id(); |
2027 | 2 | } |
2028 | 2 | { |
2029 | 2 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
2030 | | // Including system namespace. |
2031 | 2 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
2032 | 2 | CheckNamespaces( |
2033 | 2 | { |
2034 | 2 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
2035 | 2 | std::make_tuple(other_ns_name, other_ns_id), |
2036 | 2 | }, namespaces); |
2037 | 2 | } |
2038 | | |
2039 | | // Rename the namespace |
2040 | 2 | const NamespaceName other_ns_new_name = "testns_newname"; |
2041 | 2 | { |
2042 | 2 | AlterNamespaceResponsePB resp; |
2043 | 2 | ASSERT_OK(AlterNamespace(other_ns_name, |
2044 | 2 | other_ns_id, |
2045 | 2 | boost::none /* database_type */, |
2046 | 2 | other_ns_new_name, |
2047 | 2 | &resp)); |
2048 | 2 | } |
2049 | 2 | { |
2050 | 2 | ASSERT_NO_FATALS(DoListAllNamespaces(&namespaces)); |
2051 | | // Including system namespace. |
2052 | 2 | ASSERT_EQ(2 + kNumSystemNamespaces, namespaces.namespaces_size()); |
2053 | 2 | CheckNamespaces( |
2054 | 2 | { |
2055 | 2 | EXPECTED_DEFAULT_AND_SYSTEM_NAMESPACES, |
2056 | 2 | std::make_tuple(other_ns_new_name, other_ns_id), |
2057 | 2 | }, namespaces); |
2058 | 2 | } |
2059 | 2 | } |
2060 | | |
2061 | | INSTANTIATE_TEST_CASE_P( |
2062 | | DatabaseType, NamespaceTest, |
2063 | | ::testing::Values(YQLDatabase::YQL_DATABASE_CQL, YQLDatabase::YQL_DATABASE_PGSQL)); |
2064 | | |
2065 | | } // namespace master |
2066 | | } // namespace yb |