Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: sync/internal_api/public/base/unique_position_unittest.cc

Issue 11636006: WIP: The Bookmark Position Megapatch (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Various updates, including switch suffix to unique_client_tag style Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sync/internal_api/public/base/unique_position.cc ('k') | sync/internal_api/public/base_node.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sync/internal_api/public/base/unique_position.h" 5 #include "sync/internal_api/public/base/unique_position.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/base64.h"
10 #include "base/basictypes.h" 11 #include "base/basictypes.h"
11 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/sha1.h"
14 #include "base/string_number_conversions.h"
12 #include "testing/gtest/include/gtest/gtest.h" 15 #include "testing/gtest/include/gtest/gtest.h"
13 16
14 namespace syncer { 17 namespace syncer {
15 18
16 namespace { 19 namespace {
17 20
18 class UniquePositionTest : public ::testing::Test { 21 class UniquePositionTest : public ::testing::Test {
19 protected: 22 protected:
20 // Accessor to fetch the length of the position's internal representation. We 23 // Accessor to fetch the length of the position's internal representation
21 // don't have any test expectations on it because this is an implementation 24 // We try to avoid having any test expectations on it because this is an
22 // detail. 25 // implementation detail.
23 // 26 //
24 // We use it to see just how big our ordinals are getting in some of the 27 // If you run the tests with --v=1, we'll print out some of the lengths
25 // worst-case scenarios that occur in our tests. This can be useful when 28 // so you can see how well the algorithm performs in various insertion
26 // testing and comparing alternative implementations. Enable with --v=1. 29 // scenarios.
27 size_t GetLength(UniquePosition &pos) { 30 size_t GetLength(UniquePosition &pos) {
28 return pos.ToInternalValue().length(); 31 return pos.ToInternalValue().length();
29 } 32 }
30 }; 33 };
31 34
32 const size_t kMinLength = UniquePosition::kSuffixLength; 35 const size_t kMinLength = UniquePosition::kSuffixLength;
33 const size_t kGenericPredecessorLength = kMinLength + 2; 36 const size_t kGenericPredecessorLength = kMinLength + 2;
34 const size_t kGenericSuccessorLength = kMinLength + 1; 37 const size_t kGenericSuccessorLength = kMinLength + 1;
35 const size_t kBigPositionLength = kMinLength; 38 const size_t kBigPositionLength = kMinLength;
36 const size_t kSmallPositionLength = kMinLength; 39 const size_t kSmallPositionLength = kMinLength;
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 UniquePosition new_pos = 276 UniquePosition new_pos =
274 UniquePosition::Between(left_pos, right_pos, suffix); 277 UniquePosition::Between(left_pos, right_pos, suffix);
275 ASSERT_PRED_FORMAT2(LessThan, left_pos, new_pos); 278 ASSERT_PRED_FORMAT2(LessThan, left_pos, new_pos);
276 ASSERT_PRED_FORMAT2(LessThan, new_pos, right_pos); 279 ASSERT_PRED_FORMAT2(LessThan, new_pos, right_pos);
277 right_pos = new_pos; 280 right_pos = new_pos;
278 } 281 }
279 282
280 VLOG(1) << "Lengths: " << GetLength(left_pos) << ", " << GetLength(right_pos); 283 VLOG(1) << "Lengths: " << GetLength(left_pos) << ", " << GetLength(right_pos);
281 } 284 }
282 285
286 // Generates suffixes similar to those generated by the directory.
287 // This may become obsolete if the suffix generation code is modified.
288 class SuffixGenerator {
289 public:
290 explicit SuffixGenerator(const std::string& cache_guid)
291 : cache_guid_(cache_guid),
292 next_id_(-65535) {
293 }
294
295 std::string NextSuffix() {
296 // This is not entirely realistic, but that should be OK. The current
297 // suffix format is a base64'ed SHA1 hash, which should be fairly close to
298 // random anyway.
299 std::string input = cache_guid_ + base::Int64ToString(next_id_--);
300 std::string output;
301 CHECK(base::Base64Encode(base::SHA1HashString(input), &output));
302 return output;
303 }
304
305 private:
306 const std::string cache_guid_;
307 int64 next_id_;
308 };
309
310 // Cache guids generated in the same style as real clients.
311 static const char kCacheGuidStr1[] = "tuiWdG8hV+8y4RT9N5Aikg==";
312 static const char kCacheGuidStr2[] = "yaKb7zHtY06aue9a0vlZgw==";
313
314 class PositionScenariosTest : public UniquePositionTest {
315 public:
316 PositionScenariosTest()
317 : generator1_(std::string(kCacheGuidStr1, arraysize(kCacheGuidStr1)-1)),
318 generator2_(std::string(kCacheGuidStr2, arraysize(kCacheGuidStr2)-1)) {
319 }
320
321 std::string NextClient1Suffix() {
322 return generator1_.NextSuffix();
323 }
324
325 std::string NextClient2Suffix() {
326 return generator2_.NextSuffix();
327 }
328
329 private:
330 SuffixGenerator generator1_;
331 SuffixGenerator generator2_;
332 };
333
334 // One client creating new bookmarks, always inserting at the end.
335 TEST_F(PositionScenariosTest, OneClientInsertAtEnd) {
336 UniquePosition pos =
337 UniquePosition::InitialPosition(NextClient1Suffix());
338 for (int i = 0; i < 1024; i++) {
339 const std::string suffix = NextClient1Suffix();
340 UniquePosition new_pos = UniquePosition::After(pos, suffix);
341 ASSERT_PRED_FORMAT2(LessThan, pos, new_pos);
342 pos = new_pos;
343 }
344
345 VLOG(1) << "Length: " << GetLength(pos);
346
347 // Normally we wouldn't want to make an assertion about the internal
348 // representation of our data, but we make an exception for this case.
349 // If this scenario causes lengths to explode, we have a big problem.
350 EXPECT_LT(GetLength(pos), 500U);
351 }
352
353 // Two clients alternately inserting entries at the end, with a strong
354 // bias towards insertions by the first client.
355 TEST_F(PositionScenariosTest, TwoClientsInsertAtEnd_A) {
356 UniquePosition pos =
357 UniquePosition::InitialPosition(NextClient1Suffix());
358 for (int i = 0; i < 1024; i++) {
359 std::string suffix;
360 if (i % 5 == 0) {
361 suffix = NextClient2Suffix();
362 } else {
363 suffix = NextClient1Suffix();
364 }
365
366 UniquePosition new_pos = UniquePosition::After(pos, suffix);
367 ASSERT_PRED_FORMAT2(LessThan, pos, new_pos);
368 pos = new_pos;
369 }
370
371 VLOG(1) << "Length: " << GetLength(pos);
372 EXPECT_LT(GetLength(pos), 500U);
373 }
374
375 // Two clients alternately inserting entries at the end.
376 TEST_F(PositionScenariosTest, TwoClientsInsertAtEnd_B) {
377 UniquePosition pos =
378 UniquePosition::InitialPosition(NextClient1Suffix());
379 for (int i = 0; i < 1024; i++) {
380 std::string suffix;
381 if (i % 2 == 0) {
382 suffix = NextClient1Suffix();
383 } else {
384 suffix = NextClient2Suffix();
385 }
386
387 UniquePosition new_pos = UniquePosition::After(pos, suffix);
388 ASSERT_PRED_FORMAT2(LessThan, pos, new_pos);
389 pos = new_pos;
390 }
391
392 VLOG(1) << "Length: " << GetLength(pos);
393 EXPECT_LT(GetLength(pos), 500U);
394 }
395
283 INSTANTIATE_TEST_CASE_P(MinSuffix, PositionInsertTest, 396 INSTANTIATE_TEST_CASE_P(MinSuffix, PositionInsertTest,
284 ::testing::Values(kMinSuffix)); 397 ::testing::Values(kMinSuffix));
285 INSTANTIATE_TEST_CASE_P(MaxSuffix, PositionInsertTest, 398 INSTANTIATE_TEST_CASE_P(MaxSuffix, PositionInsertTest,
286 ::testing::Values(kMaxSuffix)); 399 ::testing::Values(kMaxSuffix));
287 INSTANTIATE_TEST_CASE_P(NormalSuffix, PositionInsertTest, 400 INSTANTIATE_TEST_CASE_P(NormalSuffix, PositionInsertTest,
288 ::testing::Values(kNormalSuffix)); 401 ::testing::Values(kNormalSuffix));
289 402
290 class PositionFromIntTest : public UniquePositionTest { 403 class PositionFromIntTest : public UniquePositionTest {
404 public:
405 PositionFromIntTest()
406 : generator_(std::string(kCacheGuidStr1, arraysize(kCacheGuidStr1)-1)) {
407 }
408
291 protected: 409 protected:
292 static std::string SuffixFromInt(int64 item_id) { 410 std::string NextSuffix() {
293 // Represents a cache_guid-like value. 411 return generator_.NextSuffix();
294 const std::string guid( 412 }
295 "\xFF\xFE\xFE\xFF\x00\x01\x01\x00"
296 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 16);
297 413
298 return UniquePosition::GenerateBookmarkSuffix(guid, item_id); 414 private:
299 } 415 SuffixGenerator generator_;
300 }; 416 };
301 417
302 const int64 kTestValues[] = { 418 const int64 kTestValues[] = {
303 0LL, 419 0LL,
304 1LL, -1LL, 420 1LL, -1LL,
305 2LL, -2LL, 421 2LL, -2LL,
306 3LL, -3LL, 422 3LL, -3LL,
307 0x79LL, -0x79LL, 423 0x79LL, -0x79LL,
308 0x80LL, -0x80LL, 424 0x80LL, -0x80LL,
309 0x81LL, -0x81LL, 425 0x81LL, -0x81LL,
(...skipping 13 matching lines...) Expand all
323 kint64min, 439 kint64min,
324 kint64min + 1, 440 kint64min + 1,
325 kint64max - 1 441 kint64max - 1
326 }; 442 };
327 443
328 const size_t kNumTestValues = arraysize(kTestValues); 444 const size_t kNumTestValues = arraysize(kTestValues);
329 445
330 TEST_F(PositionFromIntTest, IsValid) { 446 TEST_F(PositionFromIntTest, IsValid) {
331 for (size_t i = 0; i < kNumTestValues; ++i) { 447 for (size_t i = 0; i < kNumTestValues; ++i) {
332 const UniquePosition pos = 448 const UniquePosition pos =
333 UniquePosition::FromInt64(kTestValues[i], SuffixFromInt(i)); 449 UniquePosition::FromInt64(kTestValues[i], NextSuffix());
334 EXPECT_TRUE(pos.IsValid()) << "i = " << i << "; " << pos.ToDebugString(); 450 EXPECT_TRUE(pos.IsValid()) << "i = " << i << "; " << pos.ToDebugString();
335 } 451 }
336 } 452 }
337 453
338 TEST_F(PositionFromIntTest, RoundTripConversion) { 454 TEST_F(PositionFromIntTest, RoundTripConversion) {
339 for (size_t i = 0; i < kNumTestValues; ++i) { 455 for (size_t i = 0; i < kNumTestValues; ++i) {
340 const int64 expected_value = kTestValues[i]; 456 const int64 expected_value = kTestValues[i];
341 const UniquePosition pos = 457 const UniquePosition pos =
342 UniquePosition::FromInt64(kTestValues[i], SuffixFromInt(i)); 458 UniquePosition::FromInt64(kTestValues[i], NextSuffix());
343 const int64 value = pos.ToInt64(); 459 const int64 value = pos.ToInt64();
344 EXPECT_EQ(expected_value, value) << "i = " << i; 460 EXPECT_EQ(expected_value, value) << "i = " << i;
345 } 461 }
346 } 462 }
347 463
348 template <typename T, typename LessThan = std::less<T> > 464 template <typename T, typename LessThan = std::less<T> >
349 class IndexedLessThan { 465 class IndexedLessThan {
350 public: 466 public:
351 IndexedLessThan(const T* values) : values_(values) {} 467 IndexedLessThan(const T* values) : values_(values) {}
352 468
353 bool operator()(int i1, int i2) { 469 bool operator()(int i1, int i2) {
354 return less_than_(values_[i1], values_[i2]); 470 return less_than_(values_[i1], values_[i2]);
355 } 471 }
356 472
357 private: 473 private:
358 const T* values_; 474 const T* values_;
359 LessThan less_than_; 475 LessThan less_than_;
360 }; 476 };
361 477
362 TEST_F(PositionFromIntTest, ConsistentOrdering) { 478 TEST_F(PositionFromIntTest, ConsistentOrdering) {
363 UniquePosition positions[kNumTestValues]; 479 UniquePosition positions[kNumTestValues];
364 std::vector<int> original_ordering(kNumTestValues); 480 std::vector<int> original_ordering(kNumTestValues);
365 std::vector<int> int64_ordering(kNumTestValues); 481 std::vector<int> int64_ordering(kNumTestValues);
366 std::vector<int> position_ordering(kNumTestValues); 482 std::vector<int> position_ordering(kNumTestValues);
367 for (size_t i = 0; i < kNumTestValues; ++i) { 483 for (size_t i = 0; i < kNumTestValues; ++i) {
368 positions[i] = UniquePosition::FromInt64( 484 positions[i] = UniquePosition::FromInt64(
369 kTestValues[i], SuffixFromInt(i)); 485 kTestValues[i], NextSuffix());
370 original_ordering[i] = int64_ordering[i] = position_ordering[i] = i; 486 original_ordering[i] = int64_ordering[i] = position_ordering[i] = i;
371 } 487 }
372 488
373 std::sort(int64_ordering.begin(), int64_ordering.end(), 489 std::sort(int64_ordering.begin(), int64_ordering.end(),
374 IndexedLessThan<int64>(kTestValues)); 490 IndexedLessThan<int64>(kTestValues));
375 std::sort(position_ordering.begin(), position_ordering.end(), 491 std::sort(position_ordering.begin(), position_ordering.end(),
376 IndexedLessThan<UniquePosition, PositionLessThan>(positions)); 492 IndexedLessThan<UniquePosition, PositionLessThan>(positions));
377 EXPECT_NE(original_ordering, int64_ordering); 493 EXPECT_NE(original_ordering, int64_ordering);
378 EXPECT_EQ(int64_ordering, position_ordering); 494 EXPECT_EQ(int64_ordering, position_ordering);
379 } 495 }
380 496
381 } // namespace 497 } // namespace
382 498
383 } // namespace syncer 499 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/internal_api/public/base/unique_position.cc ('k') | sync/internal_api/public/base_node.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698