cordz_test.cc (17139B)
1 // Copyright 2021 The Abseil Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <cstddef> 16 #include <cstring> 17 #include <ostream> 18 #include <string> 19 #include <utility> 20 21 #include "gmock/gmock.h" 22 #include "gtest/gtest.h" 23 #include "absl/base/config.h" 24 #include "absl/strings/cord.h" 25 #include "absl/strings/cord_buffer.h" 26 #include "absl/strings/cord_test_helpers.h" 27 #include "absl/strings/cordz_test_helpers.h" 28 #include "absl/strings/internal/cord_internal.h" 29 #include "absl/strings/internal/cordz_info.h" 30 #include "absl/strings/internal/cordz_sample_token.h" 31 #include "absl/strings/internal/cordz_statistics.h" 32 #include "absl/strings/internal/cordz_update_tracker.h" 33 #include "absl/strings/str_cat.h" 34 #include "absl/strings/string_view.h" 35 36 #ifdef ABSL_INTERNAL_CORDZ_ENABLED 37 38 using testing::Eq; 39 using testing::AnyOf; 40 41 namespace absl { 42 ABSL_NAMESPACE_BEGIN 43 44 using cord_internal::CordzInfo; 45 using cord_internal::CordzSampleToken; 46 using cord_internal::CordzStatistics; 47 using cord_internal::CordzUpdateTracker; 48 using Method = CordzUpdateTracker::MethodIdentifier; 49 50 // Do not print cord contents, we only care about 'size' perhaps. 51 // Note that this method must be inside the named namespace. 52 inline void PrintTo(const Cord& cord, std::ostream* s) { 53 if (s) *s << "Cord[" << cord.size() << "]"; 54 } 55 56 namespace { 57 58 auto constexpr kMaxInline = cord_internal::kMaxInline; 59 60 // Returns a string_view value of the specified length 61 // We do this to avoid 'consuming' large strings in Cord by default. 62 absl::string_view MakeString(size_t size) { 63 thread_local std::string str; 64 str = std::string(size, '.'); 65 return str; 66 } 67 68 absl::string_view MakeString(TestCordSize size) { 69 return MakeString(Length(size)); 70 } 71 72 // Returns a cord with a sampled method of kAppendString. 73 absl::Cord MakeAppendStringCord(TestCordSize size) { 74 CordzSamplingIntervalHelper always(1); 75 absl::Cord cord; 76 cord.Append(MakeString(size)); 77 return cord; 78 } 79 80 std::string TestParamToString(::testing::TestParamInfo<TestCordSize> size) { 81 return absl::StrCat("On", ToString(size.param), "Cord"); 82 } 83 84 class CordzUpdateTest : public testing::TestWithParam<TestCordSize> { 85 public: 86 Cord& cord() { return cord_; } 87 88 Method InitialOr(Method method) const { 89 return (GetParam() > TestCordSize::kInlined) ? Method::kConstructorString 90 : method; 91 } 92 93 private: 94 CordzSamplingIntervalHelper sample_every_{1}; 95 Cord cord_{MakeString(GetParam())}; 96 }; 97 98 template <typename T> 99 std::string ParamToString(::testing::TestParamInfo<T> param) { 100 return std::string(ToString(param.param)); 101 } 102 103 INSTANTIATE_TEST_SUITE_P(WithParam, CordzUpdateTest, 104 testing::Values(TestCordSize::kEmpty, 105 TestCordSize::kInlined, 106 TestCordSize::kLarge), 107 TestParamToString); 108 109 class CordzStringTest : public testing::TestWithParam<TestCordSize> { 110 private: 111 CordzSamplingIntervalHelper sample_every_{1}; 112 }; 113 114 INSTANTIATE_TEST_SUITE_P(WithParam, CordzStringTest, 115 testing::Values(TestCordSize::kInlined, 116 TestCordSize::kStringSso1, 117 TestCordSize::kStringSso2, 118 TestCordSize::kSmall, 119 TestCordSize::kLarge), 120 ParamToString<TestCordSize>); 121 122 TEST(CordzTest, ConstructSmallArray) { 123 CordzSamplingIntervalHelper sample_every{1}; 124 Cord cord(MakeString(TestCordSize::kSmall)); 125 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); 126 } 127 128 TEST(CordzTest, ConstructLargeArray) { 129 CordzSamplingIntervalHelper sample_every{1}; 130 Cord cord(MakeString(TestCordSize::kLarge)); 131 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); 132 } 133 134 TEST_P(CordzStringTest, ConstructString) { 135 CordzSamplingIntervalHelper sample_every{1}; 136 Cord cord(std::string(Length(GetParam()), '.')); 137 if (Length(GetParam()) > kMaxInline) { 138 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); 139 } 140 } 141 142 TEST(CordzTest, CopyConstructFromUnsampled) { 143 CordzSamplingIntervalHelper sample_every{1}; 144 Cord src = UnsampledCord(MakeString(TestCordSize::kLarge)); 145 Cord cord(src); 146 EXPECT_THAT(GetCordzInfoForTesting(cord), Eq(nullptr)); 147 } 148 149 TEST(CordzTest, CopyConstructFromSampled) { 150 CordzSamplingIntervalHelper sample_never{99999}; 151 Cord src = MakeAppendStringCord(TestCordSize::kLarge); 152 Cord cord(src); 153 ASSERT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorCord)); 154 CordzStatistics stats = GetCordzInfoForTesting(cord)->GetCordzStatistics(); 155 EXPECT_THAT(stats.parent_method, Eq(Method::kAppendString)); 156 EXPECT_THAT(stats.update_tracker.Value(Method::kAppendString), Eq(1)); 157 } 158 159 TEST(CordzTest, MoveConstruct) { 160 CordzSamplingIntervalHelper sample_every{1}; 161 Cord src(MakeString(TestCordSize::kLarge)); 162 Cord cord(std::move(src)); 163 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); 164 } 165 166 TEST_P(CordzUpdateTest, AssignUnsampledCord) { 167 Cord src = UnsampledCord(MakeString(TestCordSize::kLarge)); 168 const CordzInfo* info = GetCordzInfoForTesting(cord()); 169 cord() = src; 170 EXPECT_THAT(GetCordzInfoForTesting(cord()), Eq(nullptr)); 171 EXPECT_FALSE(CordzInfoIsListed(info)); 172 } 173 174 TEST_P(CordzUpdateTest, AssignSampledCord) { 175 Cord src = MakeAppendStringCord(TestCordSize::kLarge); 176 cord() = src; 177 ASSERT_THAT(cord(), HasValidCordzInfoOf(Method::kAssignCord)); 178 CordzStatistics stats = GetCordzInfoForTesting(cord())->GetCordzStatistics(); 179 EXPECT_THAT(stats.parent_method, Eq(Method::kAppendString)); 180 EXPECT_THAT(stats.update_tracker.Value(Method::kAppendString), Eq(1)); 181 EXPECT_THAT(stats.update_tracker.Value(Method::kConstructorString), Eq(0)); 182 } 183 184 TEST(CordzUpdateTest, AssignSampledCordToInlined) { 185 CordzSamplingIntervalHelper sample_never{99999}; 186 Cord cord; 187 Cord src = MakeAppendStringCord(TestCordSize::kLarge); 188 cord = src; 189 ASSERT_THAT(cord, HasValidCordzInfoOf(Method::kAssignCord)); 190 CordzStatistics stats = GetCordzInfoForTesting(cord)->GetCordzStatistics(); 191 EXPECT_THAT(stats.parent_method, Eq(Method::kAppendString)); 192 EXPECT_THAT(stats.update_tracker.Value(Method::kAppendString), Eq(1)); 193 EXPECT_THAT(stats.update_tracker.Value(Method::kConstructorString), Eq(0)); 194 } 195 196 TEST(CordzUpdateTest, AssignSampledCordToUnsampledCord) { 197 CordzSamplingIntervalHelper sample_never{99999}; 198 Cord cord = UnsampledCord(MakeString(TestCordSize::kLarge)); 199 Cord src = MakeAppendStringCord(TestCordSize::kLarge); 200 cord = src; 201 ASSERT_THAT(cord, HasValidCordzInfoOf(Method::kAssignCord)); 202 CordzStatistics stats = GetCordzInfoForTesting(cord)->GetCordzStatistics(); 203 EXPECT_THAT(stats.parent_method, Eq(Method::kAppendString)); 204 EXPECT_THAT(stats.update_tracker.Value(Method::kAppendString), Eq(1)); 205 EXPECT_THAT(stats.update_tracker.Value(Method::kConstructorString), Eq(0)); 206 } 207 208 TEST(CordzUpdateTest, AssignUnsampledCordToSampledCordWithoutSampling) { 209 CordzSamplingIntervalHelper sample_never{99999}; 210 Cord cord = MakeAppendStringCord(TestCordSize::kLarge); 211 const CordzInfo* info = GetCordzInfoForTesting(cord); 212 Cord src = UnsampledCord(MakeString(TestCordSize::kLarge)); 213 cord = src; 214 EXPECT_THAT(GetCordzInfoForTesting(cord), Eq(nullptr)); 215 EXPECT_FALSE(CordzInfoIsListed(info)); 216 } 217 218 TEST(CordzUpdateTest, AssignUnsampledCordToSampledCordWithSampling) { 219 CordzSamplingIntervalHelper sample_every{1}; 220 Cord cord = MakeAppendStringCord(TestCordSize::kLarge); 221 const CordzInfo* info = GetCordzInfoForTesting(cord); 222 Cord src = UnsampledCord(MakeString(TestCordSize::kLarge)); 223 cord = src; 224 EXPECT_THAT(GetCordzInfoForTesting(cord), Eq(nullptr)); 225 EXPECT_FALSE(CordzInfoIsListed(info)); 226 } 227 228 TEST(CordzUpdateTest, AssignSampledCordToSampledCord) { 229 CordzSamplingIntervalHelper sample_every{1}; 230 Cord src = MakeAppendStringCord(TestCordSize::kLarge); 231 Cord cord(MakeString(TestCordSize::kLarge)); 232 cord = src; 233 ASSERT_THAT(cord, HasValidCordzInfoOf(Method::kAssignCord)); 234 CordzStatistics stats = GetCordzInfoForTesting(cord)->GetCordzStatistics(); 235 EXPECT_THAT(stats.parent_method, Eq(Method::kAppendString)); 236 EXPECT_THAT(stats.update_tracker.Value(Method::kAppendString), Eq(1)); 237 EXPECT_THAT(stats.update_tracker.Value(Method::kConstructorString), Eq(0)); 238 } 239 240 TEST(CordzUpdateTest, AssignUnsampledCordToSampledCord) { 241 CordzSamplingIntervalHelper sample_every{1}; 242 Cord src = MakeAppendStringCord(TestCordSize::kLarge); 243 Cord cord(MakeString(TestCordSize::kLarge)); 244 cord = src; 245 ASSERT_THAT(cord, HasValidCordzInfoOf(Method::kAssignCord)); 246 CordzStatistics stats = GetCordzInfoForTesting(cord)->GetCordzStatistics(); 247 EXPECT_THAT(stats.parent_method, Eq(Method::kAppendString)); 248 EXPECT_THAT(stats.update_tracker.Value(Method::kAppendString), Eq(1)); 249 EXPECT_THAT(stats.update_tracker.Value(Method::kConstructorString), Eq(0)); 250 } 251 252 TEST(CordzTest, AssignInlinedCordToSampledCord) { 253 CordzSampleToken token; 254 CordzSamplingIntervalHelper sample_every{1}; 255 Cord cord(MakeString(TestCordSize::kLarge)); 256 const CordzInfo* info = GetCordzInfoForTesting(cord); 257 Cord src = UnsampledCord(MakeString(TestCordSize::kInlined)); 258 cord = src; 259 EXPECT_THAT(GetCordzInfoForTesting(cord), Eq(nullptr)); 260 EXPECT_FALSE(CordzInfoIsListed(info)); 261 } 262 263 TEST(CordzUpdateTest, MoveAssignCord) { 264 CordzSamplingIntervalHelper sample_every{1}; 265 Cord cord; 266 Cord src(MakeString(TestCordSize::kLarge)); 267 cord = std::move(src); 268 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); 269 } 270 271 TEST_P(CordzUpdateTest, AssignLargeArray) { 272 cord() = MakeString(TestCordSize::kSmall); 273 EXPECT_THAT(cord(), HasValidCordzInfoOf(Method::kAssignString)); 274 } 275 276 TEST_P(CordzUpdateTest, AssignSmallArray) { 277 cord() = MakeString(TestCordSize::kSmall); 278 EXPECT_THAT(cord(), HasValidCordzInfoOf(Method::kAssignString)); 279 } 280 281 TEST_P(CordzUpdateTest, AssignInlinedArray) { 282 cord() = MakeString(TestCordSize::kInlined); 283 EXPECT_THAT(GetCordzInfoForTesting(cord()), Eq(nullptr)); 284 } 285 286 TEST_P(CordzStringTest, AssignStringToInlined) { 287 Cord cord; 288 cord = std::string(Length(GetParam()), '.'); 289 if (Length(GetParam()) > kMaxInline) { 290 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kAssignString)); 291 } 292 } 293 294 TEST_P(CordzStringTest, AssignStringToCord) { 295 Cord cord(MakeString(TestCordSize::kLarge)); 296 cord = std::string(Length(GetParam()), '.'); 297 if (Length(GetParam()) > kMaxInline) { 298 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); 299 EXPECT_THAT(cord, CordzMethodCountEq(Method::kAssignString, 1)); 300 } 301 } 302 303 TEST_P(CordzUpdateTest, AssignInlinedString) { 304 cord() = std::string(Length(TestCordSize::kInlined), '.'); 305 EXPECT_THAT(GetCordzInfoForTesting(cord()), Eq(nullptr)); 306 } 307 308 TEST_P(CordzUpdateTest, AppendCord) { 309 Cord src = UnsampledCord(MakeString(TestCordSize::kLarge)); 310 cord().Append(src); 311 EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kAppendCord))); 312 } 313 314 TEST_P(CordzUpdateTest, MoveAppendCord) { 315 cord().Append(UnsampledCord(MakeString(TestCordSize::kLarge))); 316 EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kAppendCord))); 317 } 318 319 TEST_P(CordzUpdateTest, AppendSmallArray) { 320 cord().Append(MakeString(TestCordSize::kSmall)); 321 EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kAppendString))); 322 } 323 324 TEST_P(CordzUpdateTest, AppendLargeArray) { 325 cord().Append(MakeString(TestCordSize::kLarge)); 326 EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kAppendString))); 327 } 328 329 TEST_P(CordzStringTest, AppendStringToEmpty) { 330 Cord cord; 331 cord.Append(std::string(Length(GetParam()), '.')); 332 if (Length(GetParam()) > kMaxInline) { 333 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kAppendString)); 334 } 335 } 336 337 TEST_P(CordzStringTest, AppendStringToInlined) { 338 Cord cord(MakeString(TestCordSize::kInlined)); 339 cord.Append(std::string(Length(GetParam()), '.')); 340 if (Length(TestCordSize::kInlined) + Length(GetParam()) > kMaxInline) { 341 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kAppendString)); 342 } 343 } 344 345 TEST_P(CordzStringTest, AppendStringToCord) { 346 Cord cord(MakeString(TestCordSize::kLarge)); 347 cord.Append(std::string(Length(GetParam()), '.')); 348 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); 349 EXPECT_THAT(cord, CordzMethodCountEq(Method::kAppendString, 1)); 350 } 351 352 TEST(CordzTest, MakeCordFromExternal) { 353 CordzSamplingIntervalHelper sample_every{1}; 354 Cord cord = MakeCordFromExternal("Hello world", [](absl::string_view) {}); 355 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kMakeCordFromExternal)); 356 } 357 358 TEST(CordzTest, MakeCordFromEmptyExternal) { 359 CordzSamplingIntervalHelper sample_every{1}; 360 Cord cord = MakeCordFromExternal({}, [](absl::string_view) {}); 361 EXPECT_THAT(GetCordzInfoForTesting(cord), Eq(nullptr)); 362 } 363 364 TEST_P(CordzUpdateTest, PrependCord) { 365 Cord src = UnsampledCord(MakeString(TestCordSize::kLarge)); 366 cord().Prepend(src); 367 EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kPrependCord))); 368 } 369 370 TEST_P(CordzUpdateTest, PrependSmallArray) { 371 cord().Prepend(MakeString(TestCordSize::kSmall)); 372 EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kPrependString))); 373 } 374 375 TEST_P(CordzUpdateTest, PrependLargeArray) { 376 cord().Prepend(MakeString(TestCordSize::kLarge)); 377 EXPECT_THAT(cord(), HasValidCordzInfoOf(InitialOr(Method::kPrependString))); 378 } 379 380 TEST_P(CordzStringTest, PrependStringToEmpty) { 381 Cord cord; 382 cord.Prepend(std::string(Length(GetParam()), '.')); 383 if (Length(GetParam()) > kMaxInline) { 384 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kPrependString)); 385 } 386 } 387 388 TEST_P(CordzStringTest, PrependStringToInlined) { 389 Cord cord(MakeString(TestCordSize::kInlined)); 390 cord.Prepend(std::string(Length(GetParam()), '.')); 391 if (Length(TestCordSize::kInlined) + Length(GetParam()) > kMaxInline) { 392 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kPrependString)); 393 } 394 } 395 396 TEST_P(CordzStringTest, PrependStringToCord) { 397 Cord cord(MakeString(TestCordSize::kLarge)); 398 cord.Prepend(std::string(Length(GetParam()), '.')); 399 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); 400 EXPECT_THAT(cord, CordzMethodCountEq(Method::kPrependString, 1)); 401 } 402 403 TEST(CordzTest, RemovePrefix) { 404 CordzSamplingIntervalHelper sample_every(1); 405 Cord cord(MakeString(TestCordSize::kLarge)); 406 407 // Half the cord 408 cord.RemovePrefix(cord.size() / 2); 409 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); 410 EXPECT_THAT(cord, CordzMethodCountEq(Method::kRemovePrefix, 1)); 411 412 // TODO(mvels): RemovePrefix does not reset to inlined, except if empty? 413 cord.RemovePrefix(cord.size() - kMaxInline); 414 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); 415 EXPECT_THAT(cord, CordzMethodCountEq(Method::kRemovePrefix, 2)); 416 417 cord.RemovePrefix(cord.size()); 418 EXPECT_THAT(GetCordzInfoForTesting(cord), Eq(nullptr)); 419 } 420 421 TEST(CordzTest, RemoveSuffix) { 422 CordzSamplingIntervalHelper sample_every(1); 423 Cord cord(MakeString(TestCordSize::kLarge)); 424 425 // Half the cord 426 cord.RemoveSuffix(cord.size() / 2); 427 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); 428 EXPECT_THAT(cord, CordzMethodCountEq(Method::kRemoveSuffix, 1)); 429 430 // TODO(mvels): RemoveSuffix does not reset to inlined, except if empty? 431 cord.RemoveSuffix(cord.size() - kMaxInline); 432 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kConstructorString)); 433 EXPECT_THAT(cord, CordzMethodCountEq(Method::kRemoveSuffix, 2)); 434 435 cord.RemoveSuffix(cord.size()); 436 EXPECT_THAT(GetCordzInfoForTesting(cord), Eq(nullptr)); 437 } 438 439 TEST(CordzTest, SubCordFromUnsampledCord) { 440 CordzSamplingIntervalHelper sample_every{1}; 441 Cord src = UnsampledCord(MakeString(TestCordSize::kLarge)); 442 Cord cord = src.Subcord(10, src.size() / 2); 443 EXPECT_THAT(GetCordzInfoForTesting(cord), Eq(nullptr)); 444 } 445 446 TEST(CordzTest, SubCordFromSampledCord) { 447 CordzSamplingIntervalHelper sample_never{99999}; 448 Cord src = MakeAppendStringCord(TestCordSize::kLarge); 449 Cord cord = src.Subcord(10, src.size() / 2); 450 ASSERT_THAT(cord, HasValidCordzInfoOf(Method::kSubCord)); 451 CordzStatistics stats = GetCordzInfoForTesting(cord)->GetCordzStatistics(); 452 EXPECT_THAT(stats.parent_method, Eq(Method::kAppendString)); 453 EXPECT_THAT(stats.update_tracker.Value(Method::kAppendString), Eq(1)); 454 } 455 456 TEST(CordzTest, SmallSubCord) { 457 CordzSamplingIntervalHelper sample_never{99999}; 458 Cord src = MakeAppendStringCord(TestCordSize::kLarge); 459 Cord cord = src.Subcord(10, kMaxInline + 1); 460 EXPECT_THAT(cord, HasValidCordzInfoOf(Method::kSubCord)); 461 } 462 463 } // namespace 464 465 ABSL_NAMESPACE_END 466 } // namespace absl 467 468 #endif // ABSL_INTERNAL_CORDZ_ENABLED