/Users/deen/code/yugabyte-db/src/yb/common/schema-test.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | #include <unordered_map> |
33 | | #include <vector> |
34 | | |
35 | | #include <glog/logging.h> |
36 | | #include <gtest/gtest.h> |
37 | | |
38 | | #include "yb/common/common.pb.h" |
39 | | #include "yb/common/row.h" |
40 | | #include "yb/common/schema.h" |
41 | | |
42 | | #include "yb/gutil/strings/substitute.h" |
43 | | #include "yb/util/test_macros.h" |
44 | | |
45 | | namespace yb { |
46 | | namespace tablet { |
47 | | |
48 | | using std::unordered_map; |
49 | | using std::vector; |
50 | | using strings::Substitute; |
51 | | |
52 | | // Copy a row and its referenced data into the given Arena. |
53 | | static Status CopyRowToArena(const Slice &row, |
54 | | const Schema &schema, |
55 | | Arena *dst_arena, |
56 | 2 | ContiguousRow *copied) { |
57 | 2 | Slice row_data; |
58 | | |
59 | | // Copy the direct row data to arena |
60 | 2 | if (!dst_arena->RelocateSlice(row, &row_data)) { |
61 | 0 | return STATUS(IOError, "no space for row data in arena"); |
62 | 0 | } |
63 | | |
64 | 2 | copied->Reset(row_data.mutable_data()); |
65 | 2 | RETURN_NOT_OK(RelocateIndirectDataToArena(copied, dst_arena)); |
66 | 2 | return Status::OK(); |
67 | 2 | } |
68 | | |
69 | | |
70 | | |
71 | | // Test basic functionality of Schema definition |
72 | 1 | TEST(TestSchema, TestSchema) { |
73 | 1 | Schema empty_schema; |
74 | 1 | ASSERT_GT(empty_schema.memory_footprint_excluding_this(), 0); |
75 | | |
76 | 1 | ColumnSchema col1("key", STRING); |
77 | 1 | ColumnSchema col2("uint32val", UINT32, true); |
78 | 1 | ColumnSchema col3("int32val", INT32); |
79 | | |
80 | 1 | vector<ColumnSchema> cols = { col1, col2, col3 }; |
81 | 1 | Schema schema(cols, 1); |
82 | | |
83 | 1 | ASSERT_EQ(sizeof(Slice) + sizeof(uint32_t) + sizeof(int32_t), |
84 | 1 | schema.byte_size()); |
85 | 1 | ASSERT_EQ(3, schema.num_columns()); |
86 | 1 | ASSERT_EQ(0, schema.column_offset(0)); |
87 | 1 | ASSERT_EQ(sizeof(Slice), schema.column_offset(1)); |
88 | 1 | ASSERT_GT(schema.memory_footprint_excluding_this(), |
89 | 1 | empty_schema.memory_footprint_excluding_this()); |
90 | | |
91 | 1 | EXPECT_EQ("Schema [\n" |
92 | 1 | "\tkey[string NOT NULL NOT A PARTITION KEY],\n" |
93 | 1 | "\tuint32val[uint32 NULLABLE NOT A PARTITION KEY],\n" |
94 | 1 | "\tint32val[int32 NOT NULL NOT A PARTITION KEY]\n" |
95 | 1 | "]\nproperties: contain_counters: false is_transactional: false " |
96 | 1 | "consistency_level: STRONG " |
97 | 1 | "use_mangled_column_name: false " |
98 | 1 | "is_ysql_catalog_table: false " |
99 | 1 | "retain_delete_markers: false", |
100 | 1 | schema.ToString()); |
101 | 1 | EXPECT_EQ("key[string NOT NULL NOT A PARTITION KEY]", schema.column(0).ToString()); |
102 | 1 | EXPECT_EQ("uint32 NULLABLE NOT A PARTITION KEY", schema.column(1).TypeToString()); |
103 | 1 | } |
104 | | |
105 | 1 | TEST(TestSchema, TestSwap) { |
106 | 1 | TableProperties properties1; |
107 | 1 | properties1.SetDefaultTimeToLive(1000); |
108 | 1 | Schema schema1({ ColumnSchema("col1", STRING), |
109 | 1 | ColumnSchema("col2", STRING), |
110 | 1 | ColumnSchema("col3", UINT32) }, |
111 | 1 | 2, properties1); |
112 | 1 | TableProperties properties2; |
113 | 1 | properties2.SetDefaultTimeToLive(2000); |
114 | 1 | Schema schema2({ ColumnSchema("col3", UINT32), |
115 | 1 | ColumnSchema("col2", STRING) }, |
116 | 1 | 1, properties2); |
117 | 1 | schema1.swap(schema2); |
118 | 1 | ASSERT_EQ(2, schema1.num_columns()); |
119 | 1 | ASSERT_EQ(1, schema1.num_key_columns()); |
120 | 1 | ASSERT_EQ(3, schema2.num_columns()); |
121 | 1 | ASSERT_EQ(2, schema2.num_key_columns()); |
122 | 1 | ASSERT_EQ(2000, schema1.table_properties().DefaultTimeToLive()); |
123 | 1 | ASSERT_EQ(1000, schema2.table_properties().DefaultTimeToLive()); |
124 | 1 | } |
125 | | |
126 | 1 | TEST(TestSchema, TestReset) { |
127 | 1 | Schema schema; |
128 | 1 | ASSERT_FALSE(schema.initialized()); |
129 | | |
130 | 1 | ASSERT_OK(schema.Reset({ ColumnSchema("col3", UINT32), |
131 | 1 | ColumnSchema("col2", STRING) }, |
132 | 1 | 1)); |
133 | 1 | ASSERT_TRUE(schema.initialized()); |
134 | | |
135 | | // Swap the initialized schema with an uninitialized one. |
136 | 1 | Schema schema2; |
137 | 1 | schema2.swap(schema); |
138 | 1 | ASSERT_FALSE(schema.initialized()); |
139 | 1 | ASSERT_TRUE(schema2.initialized()); |
140 | 1 | } |
141 | | |
142 | | // Test for KUDU-943, a bug where we suspected that Variant didn't behave |
143 | | // correctly with empty strings. |
144 | 1 | TEST(TestSchema, TestEmptyVariant) { |
145 | 1 | Slice empty_val(""); |
146 | 1 | Slice nonempty_val("test"); |
147 | | |
148 | 1 | Variant v(STRING, &nonempty_val); |
149 | 1 | ASSERT_EQ("test", (static_cast<const Slice*>(v.value()))->ToString()); |
150 | 1 | v.Reset(STRING, &empty_val); |
151 | 1 | ASSERT_EQ("", (static_cast<const Slice*>(v.value()))->ToString()); |
152 | 1 | v.Reset(STRING, &nonempty_val); |
153 | 1 | ASSERT_EQ("test", (static_cast<const Slice*>(v.value()))->ToString()); |
154 | 1 | } |
155 | | |
156 | 1 | TEST(TestSchema, TestProjectSubset) { |
157 | 1 | Schema schema1({ ColumnSchema("col1", STRING), |
158 | 1 | ColumnSchema("col2", STRING), |
159 | 1 | ColumnSchema("col3", UINT32) }, |
160 | 1 | 1); |
161 | | |
162 | 1 | Schema schema2({ ColumnSchema("col3", UINT32), |
163 | 1 | ColumnSchema("col2", STRING) }, |
164 | 1 | 0); |
165 | | |
166 | 1 | RowProjector row_projector(&schema1, &schema2); |
167 | 1 | ASSERT_OK(row_projector.Init()); |
168 | | |
169 | | // Verify the mapping |
170 | 1 | ASSERT_EQ(2, row_projector.base_cols_mapping().size()); |
171 | 1 | ASSERT_EQ(0, row_projector.adapter_cols_mapping().size()); |
172 | | |
173 | 1 | const vector<RowProjector::ProjectionIdxMapping>& mapping = row_projector.base_cols_mapping(); |
174 | 1 | ASSERT_EQ(mapping[0].first, 0); // col3 schema2 |
175 | 1 | ASSERT_EQ(mapping[0].second, 2); // col3 schema1 |
176 | 1 | ASSERT_EQ(mapping[1].first, 1); // col2 schema2 |
177 | 1 | ASSERT_EQ(mapping[1].second, 1); // col2 schema1 |
178 | 1 | } |
179 | | |
180 | | // Test projection when the type of the projected column |
181 | | // doesn't match the original type. |
182 | 1 | TEST(TestSchema, TestProjectTypeMismatch) { |
183 | 1 | Schema schema1({ ColumnSchema("key", STRING), |
184 | 1 | ColumnSchema("val", UINT32) }, |
185 | 1 | 1); |
186 | 1 | Schema schema2({ ColumnSchema("val", STRING) }, 0); |
187 | | |
188 | 1 | RowProjector row_projector(&schema1, &schema2); |
189 | 1 | Status s = row_projector.Init(); |
190 | 1 | ASSERT_TRUE(s.IsInvalidArgument()); |
191 | 1 | ASSERT_STR_CONTAINS(s.message().ToString(), "must have type"); |
192 | 1 | } |
193 | | |
194 | | // Test projection when the some columns in the projection |
195 | | // are not present in the base schema |
196 | 1 | TEST(TestSchema, TestProjectMissingColumn) { |
197 | 1 | Schema schema1({ ColumnSchema("key", STRING), ColumnSchema("val", UINT32) }, 1); |
198 | 1 | Schema schema2({ ColumnSchema("val", UINT32), ColumnSchema("non_present", STRING) }, 0); |
199 | 1 | Schema schema3({ ColumnSchema("val", UINT32), ColumnSchema("non_present", UINT32, true) }, 0); |
200 | | |
201 | 1 | RowProjector row_projector(&schema1, &schema2); |
202 | 1 | Status s = row_projector.Init(); |
203 | 1 | ASSERT_TRUE(s.IsInvalidArgument()); |
204 | 1 | ASSERT_STR_CONTAINS(s.message().ToString(), |
205 | 1 | "does not exist in the projection, and it does not have a nullable type"); |
206 | | |
207 | | // Verify Default nullable column with no default value |
208 | 1 | ASSERT_OK(row_projector.Reset(&schema1, &schema3)); |
209 | | |
210 | 1 | ASSERT_EQ(1, row_projector.base_cols_mapping().size()); |
211 | 1 | ASSERT_EQ(0, row_projector.adapter_cols_mapping().size()); |
212 | | |
213 | 1 | ASSERT_EQ(row_projector.base_cols_mapping()[0].first, 0); // val schema2 |
214 | 1 | ASSERT_EQ(row_projector.base_cols_mapping()[0].second, 1); // val schema1 |
215 | 1 | } |
216 | | |
217 | | // Test projection mapping using IDs. |
218 | | // This simulate a column rename ('val' -> 'val_renamed') |
219 | | // and a new column added ('non_present') |
220 | 1 | TEST(TestSchema, TestProjectRename) { |
221 | 1 | SchemaBuilder builder; |
222 | 1 | ASSERT_OK(builder.AddKeyColumn("key", STRING)); |
223 | 1 | ASSERT_OK(builder.AddColumn("val", UINT32)); |
224 | 1 | Schema schema1 = builder.Build(); |
225 | | |
226 | 1 | builder.Reset(schema1); |
227 | 1 | ASSERT_OK(builder.AddNullableColumn("non_present", UINT32)); |
228 | 1 | ASSERT_OK(builder.RenameColumn("val", "val_renamed")); |
229 | 1 | Schema schema2 = builder.Build(); |
230 | | |
231 | 1 | RowProjector row_projector(&schema1, &schema2); |
232 | 1 | ASSERT_OK(row_projector.Init()); |
233 | | |
234 | 1 | ASSERT_EQ(2, row_projector.base_cols_mapping().size()); |
235 | 1 | ASSERT_EQ(0, row_projector.adapter_cols_mapping().size()); |
236 | | |
237 | 1 | ASSERT_EQ(row_projector.base_cols_mapping()[0].first, 0); // key schema2 |
238 | 1 | ASSERT_EQ(row_projector.base_cols_mapping()[0].second, 0); // key schema1 |
239 | | |
240 | 1 | ASSERT_EQ(row_projector.base_cols_mapping()[1].first, 1); // val_renamed schema2 |
241 | 1 | ASSERT_EQ(row_projector.base_cols_mapping()[1].second, 1); // val schema1 |
242 | 1 | } |
243 | | |
244 | | |
245 | | // Test that the schema can be used to compare and stringify rows. |
246 | 1 | TEST(TestSchema, TestRowOperations) { |
247 | 1 | Schema schema({ ColumnSchema("col1", STRING), |
248 | 1 | ColumnSchema("col2", STRING), |
249 | 1 | ColumnSchema("col3", UINT32), |
250 | 1 | ColumnSchema("col4", INT32) }, |
251 | 1 | 1); |
252 | | |
253 | 1 | Arena arena(1024, 256*1024); |
254 | | |
255 | 1 | RowBuilder rb(schema); |
256 | 1 | rb.AddString(string("row_a_1")); |
257 | 1 | rb.AddString(string("row_a_2")); |
258 | 1 | rb.AddUint32(3); |
259 | 1 | rb.AddInt32(-3); |
260 | 1 | ContiguousRow row_a(&schema); |
261 | 1 | ASSERT_OK(CopyRowToArena(rb.data(), schema, &arena, &row_a)); |
262 | | |
263 | 1 | rb.Reset(); |
264 | 1 | rb.AddString(string("row_b_1")); |
265 | 1 | rb.AddString(string("row_b_2")); |
266 | 1 | rb.AddUint32(3); |
267 | 1 | rb.AddInt32(-3); |
268 | 1 | ContiguousRow row_b(&schema); |
269 | 1 | ASSERT_OK(CopyRowToArena(rb.data(), schema, &arena, &row_b)); |
270 | | |
271 | 1 | ASSERT_GT(schema.Compare(row_b, row_a), 0); |
272 | 1 | ASSERT_LT(schema.Compare(row_a, row_b), 0); |
273 | | |
274 | 1 | ASSERT_EQ(string("(string col1=row_a_1, string col2=row_a_2, uint32 col3=3, int32 col4=-3)"), |
275 | 1 | schema.DebugRow(row_a)); |
276 | 1 | } |
277 | | |
278 | 1 | TEST(TestSchema, TestDecodeKeys_CompoundStringKey) { |
279 | 1 | Schema schema({ ColumnSchema("col1", STRING), |
280 | 1 | ColumnSchema("col2", STRING), |
281 | 1 | ColumnSchema("col3", STRING) }, |
282 | 1 | 2); |
283 | | |
284 | 1 | EXPECT_EQ("(string col1=foo, string col2=bar)", |
285 | 1 | schema.DebugEncodedRowKey(Slice("foo\0\0bar", 8), Schema::START_KEY)); |
286 | 1 | EXPECT_EQ("(string col1=fo\\000o, string col2=bar)", |
287 | 1 | schema.DebugEncodedRowKey(Slice("fo\x00\x01o\0\0""bar", 10), Schema::START_KEY)); |
288 | 1 | EXPECT_EQ("(string col1=fo\\000o, string col2=bar\\000xy)", |
289 | 1 | schema.DebugEncodedRowKey(Slice("fo\x00\x01o\0\0""bar\0xy", 13), Schema::START_KEY)); |
290 | | |
291 | 1 | EXPECT_EQ("<start of table>", |
292 | 1 | schema.DebugEncodedRowKey("", Schema::START_KEY)); |
293 | 1 | EXPECT_EQ("<end of table>", |
294 | 1 | schema.DebugEncodedRowKey("", Schema::END_KEY)); |
295 | 1 | } |
296 | | |
297 | | // Test that appropriate statuses are returned when trying to decode an invalid |
298 | | // encoded key. |
299 | 1 | TEST(TestSchema, TestDecodeKeys_InvalidKeys) { |
300 | 1 | Schema schema({ ColumnSchema("col1", STRING), |
301 | 1 | ColumnSchema("col2", UINT32), |
302 | 1 | ColumnSchema("col3", STRING) }, |
303 | 1 | 2); |
304 | | |
305 | 1 | EXPECT_EQ("<invalid key: Invalid argument: Error decoding composite key component" |
306 | 1 | " 'col1': Missing separator after composite key string component: foo>", |
307 | 1 | schema.DebugEncodedRowKey(Slice("foo"), Schema::START_KEY)); |
308 | 1 | EXPECT_EQ("<invalid key: Invalid argument: Error decoding composite key component 'col2': " |
309 | 1 | "key too short>", |
310 | 1 | schema.DebugEncodedRowKey(Slice("foo\x00\x00", 5), Schema::START_KEY)); |
311 | 1 | EXPECT_EQ("<invalid key: Invalid argument: Error decoding composite key component 'col2': " |
312 | 1 | "key too short: FFFF>", |
313 | 1 | schema.DebugEncodedRowKey(Slice("foo\x00\x00\xff\xff", 7), Schema::START_KEY)); |
314 | 1 | } |
315 | | |
316 | 1 | TEST(TestSchema, TestCreateProjection) { |
317 | 1 | Schema schema({ ColumnSchema("col1", STRING), |
318 | 1 | ColumnSchema("col2", STRING), |
319 | 1 | ColumnSchema("col3", STRING), |
320 | 1 | ColumnSchema("col4", STRING), |
321 | 1 | ColumnSchema("col5", STRING) }, |
322 | 1 | 2); |
323 | 1 | Schema schema_with_ids = SchemaBuilder(schema).Build(); |
324 | 1 | Schema partial_schema; |
325 | | |
326 | | // By names, without IDs |
327 | 1 | ASSERT_OK(schema.CreateProjectionByNames({ "col1", "col2", "col4" }, &partial_schema)); |
328 | 1 | EXPECT_EQ("Schema [\n" |
329 | 1 | "\tcol1[string NOT NULL NOT A PARTITION KEY],\n" |
330 | 1 | "\tcol2[string NOT NULL NOT A PARTITION KEY],\n" |
331 | 1 | "\tcol4[string NOT NULL NOT A PARTITION KEY]\n" |
332 | 1 | "]\nproperties: contain_counters: false is_transactional: false " |
333 | 1 | "consistency_level: STRONG " |
334 | 1 | "use_mangled_column_name: false " |
335 | 1 | "is_ysql_catalog_table: false " |
336 | 1 | "retain_delete_markers: false", |
337 | 1 | partial_schema.ToString()); |
338 | | |
339 | | // By names, with IDS |
340 | 1 | ASSERT_OK(schema_with_ids.CreateProjectionByNames({ "col1", "col2", "col4" }, &partial_schema)); |
341 | 1 | EXPECT_EQ(Format("Schema [\n" |
342 | 1 | "\t$0:col1[string NOT NULL NOT A PARTITION KEY],\n" |
343 | 1 | "\t$1:col2[string NOT NULL NOT A PARTITION KEY],\n" |
344 | 1 | "\t$2:col4[string NOT NULL NOT A PARTITION KEY]\n" |
345 | 1 | "]\nproperties: contain_counters: false is_transactional: false " |
346 | 1 | "consistency_level: STRONG " |
347 | 1 | "use_mangled_column_name: false " |
348 | 1 | "is_ysql_catalog_table: false " |
349 | 1 | "retain_delete_markers: false", |
350 | 1 | schema_with_ids.column_id(0), |
351 | 1 | schema_with_ids.column_id(1), |
352 | 1 | schema_with_ids.column_id(3)), |
353 | 1 | partial_schema.ToString()); |
354 | | |
355 | | // By names, with missing names. |
356 | 1 | Status s = schema.CreateProjectionByNames({ "foobar" }, &partial_schema); |
357 | 1 | EXPECT_EQ("Not found: Column not found: foobar", s.ToString(/* no file/line */ false)); |
358 | | |
359 | | // By IDs |
360 | 1 | ASSERT_OK(schema_with_ids.CreateProjectionByIdsIgnoreMissing({ schema_with_ids.column_id(0), |
361 | 1 | schema_with_ids.column_id(1), |
362 | 1 | ColumnId(1000), // missing column |
363 | 1 | schema_with_ids.column_id(3) }, |
364 | 1 | &partial_schema)); |
365 | 1 | EXPECT_EQ(Format("Schema [\n" |
366 | 1 | "\t$0:col1[string NOT NULL NOT A PARTITION KEY],\n" |
367 | 1 | "\t$1:col2[string NOT NULL NOT A PARTITION KEY],\n" |
368 | 1 | "\t$2:col4[string NOT NULL NOT A PARTITION KEY]\n" |
369 | 1 | "]\nproperties: contain_counters: false is_transactional: false " |
370 | 1 | "consistency_level: STRONG " |
371 | 1 | "use_mangled_column_name: false " |
372 | 1 | "is_ysql_catalog_table: false " |
373 | 1 | "retain_delete_markers: false", |
374 | 1 | schema_with_ids.column_id(0), |
375 | 1 | schema_with_ids.column_id(1), |
376 | 1 | schema_with_ids.column_id(3)), |
377 | 1 | partial_schema.ToString()); |
378 | 1 | } |
379 | | |
380 | 1 | TEST(TestSchema, TestCopyFrom) { |
381 | 1 | TableProperties properties; |
382 | 1 | properties.SetDefaultTimeToLive(1000); |
383 | 1 | Schema schema1({ ColumnSchema("col1", STRING), |
384 | 1 | ColumnSchema("col2", STRING), |
385 | 1 | ColumnSchema("col3", UINT32) }, |
386 | 1 | 2, properties); |
387 | 1 | Schema schema2; |
388 | 1 | schema2.CopyFrom(schema1); |
389 | 1 | ASSERT_EQ(3, schema2.num_columns()); |
390 | 1 | ASSERT_EQ(2, schema2.num_key_columns()); |
391 | 1 | ASSERT_EQ(1000, schema2.table_properties().DefaultTimeToLive()); |
392 | 1 | } |
393 | | |
394 | 1 | TEST(TestSchema, TestSchemaBuilder) { |
395 | 1 | TableProperties properties; |
396 | 1 | properties.SetDefaultTimeToLive(1000); |
397 | 1 | Schema schema1({ ColumnSchema("col1", STRING), |
398 | 1 | ColumnSchema("col2", STRING), |
399 | 1 | ColumnSchema("col3", UINT32) }, |
400 | 1 | 2, properties); |
401 | 1 | SchemaBuilder builder(schema1); |
402 | 1 | Schema schema2 = builder.Build(); |
403 | 1 | ASSERT_TRUE(schema1.Equals(schema2)); |
404 | 1 | } |
405 | | |
406 | 1 | TEST(TestSchema, TestTableProperties) { |
407 | 1 | TableProperties properties; |
408 | 1 | ASSERT_FALSE(properties.HasDefaultTimeToLive()); |
409 | | |
410 | 1 | properties.SetDefaultTimeToLive(1000); |
411 | 1 | ASSERT_TRUE(properties.HasDefaultTimeToLive()); |
412 | 1 | ASSERT_EQ(1000, properties.DefaultTimeToLive()); |
413 | | |
414 | 1 | TableProperties properties1; |
415 | 1 | properties1.SetDefaultTimeToLive(1000); |
416 | 1 | ASSERT_EQ(properties, properties1); |
417 | | |
418 | 1 | TablePropertiesPB pb; |
419 | 1 | properties.ToTablePropertiesPB(&pb); |
420 | 1 | ASSERT_TRUE(pb.has_default_time_to_live()); |
421 | 1 | ASSERT_EQ(1000, pb.default_time_to_live()); |
422 | | |
423 | 1 | auto properties2 = TableProperties::FromTablePropertiesPB(pb); |
424 | 1 | ASSERT_TRUE(properties2.HasDefaultTimeToLive()); |
425 | 1 | ASSERT_EQ(1000, properties2.DefaultTimeToLive()); |
426 | | |
427 | 1 | properties.Reset(); |
428 | 1 | pb.Clear(); |
429 | 1 | ASSERT_FALSE(properties.HasDefaultTimeToLive()); |
430 | 1 | properties.ToTablePropertiesPB(&pb); |
431 | 1 | ASSERT_FALSE(pb.has_default_time_to_live()); |
432 | 1 | auto properties3 = TableProperties::FromTablePropertiesPB(pb); |
433 | 1 | ASSERT_FALSE(properties3.HasDefaultTimeToLive()); |
434 | 1 | } |
435 | | |
436 | | } // namespace tablet |
437 | | } // namespace yb |