| OLD | NEW |
| 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 "chrome/browser/sync/test/integration/bookmarks_helper.h" | 5 #include "chrome/browser/sync/test/integration/bookmarks_helper.h" |
| 6 | 6 |
| 7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
| 8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
| 9 #include "base/path_service.h" | 9 #include "base/path_service.h" |
| 10 #include "base/rand_util.h" | 10 #include "base/rand_util.h" |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 : model_(model), | 68 : model_(model), |
| 69 node_(node), | 69 node_(node), |
| 70 wait_for_load_(false) { | 70 wait_for_load_(false) { |
| 71 model->AddObserver(this); | 71 model->AddObserver(this); |
| 72 } | 72 } |
| 73 virtual ~FaviconChangeObserver() { | 73 virtual ~FaviconChangeObserver() { |
| 74 model_->RemoveObserver(this); | 74 model_->RemoveObserver(this); |
| 75 } | 75 } |
| 76 void WaitForGetFavicon() { | 76 void WaitForGetFavicon() { |
| 77 wait_for_load_ = true; | 77 wait_for_load_ = true; |
| 78 content::RunMessageLoop(); | 78 run_loop_.Run(); |
| 79 ASSERT_TRUE(node_->is_favicon_loaded()); | 79 ASSERT_TRUE(node_->is_favicon_loaded()); |
| 80 ASSERT_FALSE(model_->GetFavicon(node_).IsEmpty()); | 80 ASSERT_FALSE(model_->GetFavicon(node_).IsEmpty()); |
| 81 } | 81 } |
| 82 void WaitForSetFavicon() { | 82 void WaitForSetFavicon() { |
| 83 wait_for_load_ = false; | 83 wait_for_load_ = false; |
| 84 content::RunMessageLoop(); | 84 run_loop_.Run(); |
| 85 } | 85 } |
| 86 virtual void BookmarkModelLoaded(BookmarkModel* model, | 86 virtual void BookmarkModelLoaded(BookmarkModel* model, |
| 87 bool ids_reassigned) OVERRIDE {} | 87 bool ids_reassigned) OVERRIDE {} |
| 88 virtual void BookmarkNodeMoved(BookmarkModel* model, | 88 virtual void BookmarkNodeMoved(BookmarkModel* model, |
| 89 const BookmarkNode* old_parent, | 89 const BookmarkNode* old_parent, |
| 90 int old_index, | 90 int old_index, |
| 91 const BookmarkNode* new_parent, | 91 const BookmarkNode* new_parent, |
| 92 int new_index) OVERRIDE {} | 92 int new_index) OVERRIDE {} |
| 93 virtual void BookmarkNodeAdded(BookmarkModel* model, | 93 virtual void BookmarkNodeAdded(BookmarkModel* model, |
| 94 const BookmarkNode* parent, | 94 const BookmarkNode* parent, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 109 model->GetFavicon(node); | 109 model->GetFavicon(node); |
| 110 } | 110 } |
| 111 virtual void BookmarkNodeChildrenReordered( | 111 virtual void BookmarkNodeChildrenReordered( |
| 112 BookmarkModel* model, | 112 BookmarkModel* model, |
| 113 const BookmarkNode* node) OVERRIDE {} | 113 const BookmarkNode* node) OVERRIDE {} |
| 114 virtual void BookmarkNodeFaviconChanged( | 114 virtual void BookmarkNodeFaviconChanged( |
| 115 BookmarkModel* model, | 115 BookmarkModel* model, |
| 116 const BookmarkNode* node) OVERRIDE { | 116 const BookmarkNode* node) OVERRIDE { |
| 117 if (model == model_ && node == node_) { | 117 if (model == model_ && node == node_) { |
| 118 if (!wait_for_load_ || (wait_for_load_ && node->is_favicon_loaded())) | 118 if (!wait_for_load_ || (wait_for_load_ && node->is_favicon_loaded())) |
| 119 base::MessageLoopForUI::current()->Quit(); | 119 run_loop_.Quit(); |
| 120 } | 120 } |
| 121 } | 121 } |
| 122 | 122 |
| 123 private: | 123 private: |
| 124 BookmarkModel* model_; | 124 BookmarkModel* model_; |
| 125 const BookmarkNode* node_; | 125 const BookmarkNode* node_; |
| 126 bool wait_for_load_; | 126 bool wait_for_load_; |
| 127 base::RunLoop run_loop_; |
| 127 DISALLOW_COPY_AND_ASSIGN(FaviconChangeObserver); | 128 DISALLOW_COPY_AND_ASSIGN(FaviconChangeObserver); |
| 128 }; | 129 }; |
| 129 | 130 |
| 130 // A collection of URLs for which we have added favicons. Since loading a | 131 // A collection of URLs for which we have added favicons. Since loading a |
| 131 // favicon is an asynchronous operation and doesn't necessarily invoke a | 132 // favicon is an asynchronous operation and doesn't necessarily invoke a |
| 132 // callback, this collection is used to determine if we must wait for a URL's | 133 // callback, this collection is used to determine if we must wait for a URL's |
| 133 // favicon to load or not. | 134 // favicon to load or not. |
| 134 std::set<GURL>* urls_with_favicons_ = NULL; | 135 std::set<GURL>* urls_with_favicons_ = NULL; |
| 135 | 136 |
| 136 // Returns the number of nodes of node type |node_type| in |model| whose | 137 // Returns the number of nodes of node type |node_type| in |model| whose |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 1.0f).sk_bitmap(); | 308 1.0f).sk_bitmap(); |
| 308 return FaviconRawBitmapsMatch(bitmap_a, bitmap_b); | 309 return FaviconRawBitmapsMatch(bitmap_a, bitmap_b); |
| 309 } | 310 } |
| 310 | 311 |
| 311 // Does a deep comparison of BookmarkNode fields in |model_a| and |model_b|. | 312 // Does a deep comparison of BookmarkNode fields in |model_a| and |model_b|. |
| 312 // Returns true if they are all equal. | 313 // Returns true if they are all equal. |
| 313 bool NodesMatch(const BookmarkNode* node_a, const BookmarkNode* node_b) { | 314 bool NodesMatch(const BookmarkNode* node_a, const BookmarkNode* node_b) { |
| 314 if (node_a == NULL || node_b == NULL) | 315 if (node_a == NULL || node_b == NULL) |
| 315 return node_a == node_b; | 316 return node_a == node_b; |
| 316 if (node_a->is_folder() != node_b->is_folder()) { | 317 if (node_a->is_folder() != node_b->is_folder()) { |
| 317 LOG(ERROR) << "Cannot compare folder with bookmark"; | 318 VLOG(1) << "Cannot compare folder with bookmark"; |
| 318 return false; | 319 return false; |
| 319 } | 320 } |
| 320 if (node_a->GetTitle() != node_b->GetTitle()) { | 321 if (node_a->GetTitle() != node_b->GetTitle()) { |
| 321 LOG(ERROR) << "Title mismatch: " << node_a->GetTitle() << " vs. " | 322 VLOG(1) << "Title mismatch: " << node_a->GetTitle() << " vs. " |
| 322 << node_b->GetTitle(); | 323 << node_b->GetTitle(); |
| 323 return false; | 324 return false; |
| 324 } | 325 } |
| 325 if (node_a->url() != node_b->url()) { | 326 if (node_a->url() != node_b->url()) { |
| 326 LOG(ERROR) << "URL mismatch: " << node_a->url() << " vs. " | 327 VLOG(1) << "URL mismatch: " << node_a->url() << " vs. " << node_b->url(); |
| 327 << node_b->url(); | |
| 328 return false; | 328 return false; |
| 329 } | 329 } |
| 330 if (node_a->parent()->GetIndexOf(node_a) != | 330 if (node_a->parent()->GetIndexOf(node_a) != |
| 331 node_b->parent()->GetIndexOf(node_b)) { | 331 node_b->parent()->GetIndexOf(node_b)) { |
| 332 LOG(ERROR) << "Index mismatch: " | 332 VLOG(1) << "Index mismatch: " << node_a->parent()->GetIndexOf(node_a) |
| 333 << node_a->parent()->GetIndexOf(node_a) << " vs. " | 333 << " vs. " << node_b->parent()->GetIndexOf(node_b); |
| 334 << node_b->parent()->GetIndexOf(node_b); | |
| 335 return false; | 334 return false; |
| 336 } | 335 } |
| 337 return true; | 336 return true; |
| 338 } | 337 } |
| 339 | 338 |
| 340 // Checks if the hierarchies in |model_a| and |model_b| are equivalent in | 339 // Checks if the hierarchies in |model_a| and |model_b| are equivalent in |
| 341 // terms of the data model and favicon. Returns true if they both match. | 340 // terms of the data model and favicon. Returns true if they both match. |
| 342 // Note: Some peripheral fields like creation times are allowed to mismatch. | 341 // Note: Some peripheral fields like creation times are allowed to mismatch. |
| 343 bool BookmarkModelsMatch(BookmarkModel* model_a, BookmarkModel* model_b) { | 342 bool BookmarkModelsMatch(BookmarkModel* model_a, BookmarkModel* model_b) { |
| 344 bool ret_val = true; | 343 bool ret_val = true; |
| 345 ui::TreeNodeIterator<const BookmarkNode> iterator_a(model_a->root_node()); | 344 ui::TreeNodeIterator<const BookmarkNode> iterator_a(model_a->root_node()); |
| 346 ui::TreeNodeIterator<const BookmarkNode> iterator_b(model_b->root_node()); | 345 ui::TreeNodeIterator<const BookmarkNode> iterator_b(model_b->root_node()); |
| 347 while (iterator_a.has_next()) { | 346 while (iterator_a.has_next()) { |
| 348 const BookmarkNode* node_a = iterator_a.Next(); | 347 const BookmarkNode* node_a = iterator_a.Next(); |
| 349 if (!iterator_b.has_next()) { | 348 if (!iterator_b.has_next()) { |
| 350 LOG(ERROR) << "Models do not match."; | 349 VLOG(1) << "Models do not match."; |
| 351 return false; | 350 return false; |
| 352 } | 351 } |
| 353 const BookmarkNode* node_b = iterator_b.Next(); | 352 const BookmarkNode* node_b = iterator_b.Next(); |
| 354 ret_val = ret_val && NodesMatch(node_a, node_b); | 353 ret_val = ret_val && NodesMatch(node_a, node_b); |
| 355 if (node_a->is_folder() || node_b->is_folder()) | 354 if (node_a->is_folder() || node_b->is_folder()) |
| 356 continue; | 355 continue; |
| 357 ret_val = ret_val && FaviconsMatch(model_a, model_b, node_a, node_b); | 356 ret_val = ret_val && FaviconsMatch(model_a, model_b, node_a, node_b); |
| 358 } | 357 } |
| 359 ret_val = ret_val && (!iterator_b.has_next()); | 358 ret_val = ret_val && (!iterator_b.has_next()); |
| 360 return ret_val; | 359 return ret_val; |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 651 } | 650 } |
| 652 | 651 |
| 653 bool AllModelsMatchVerifier() { | 652 bool AllModelsMatchVerifier() { |
| 654 // Ensure that all tasks have finished processing on the history thread | 653 // Ensure that all tasks have finished processing on the history thread |
| 655 // and that any notifications the history thread may have sent have been | 654 // and that any notifications the history thread may have sent have been |
| 656 // processed before comparing models. | 655 // processed before comparing models. |
| 657 WaitForHistoryToProcessPendingTasks(); | 656 WaitForHistoryToProcessPendingTasks(); |
| 658 | 657 |
| 659 for (int i = 0; i < sync_datatype_helper::test()->num_clients(); ++i) { | 658 for (int i = 0; i < sync_datatype_helper::test()->num_clients(); ++i) { |
| 660 if (!ModelMatchesVerifier(i)) { | 659 if (!ModelMatchesVerifier(i)) { |
| 661 LOG(ERROR) << "Model " << i << " does not match the verifier."; | 660 VLOG(1) << "Model " << i << " does not match the verifier."; |
| 662 return false; | 661 return false; |
| 663 } | 662 } |
| 664 } | 663 } |
| 665 return true; | 664 return true; |
| 666 } | 665 } |
| 667 | 666 |
| 668 bool ModelsMatch(int profile_a, int profile_b) { | 667 bool ModelsMatch(int profile_a, int profile_b) { |
| 669 return BookmarkModelsMatch(GetBookmarkModel(profile_a), | 668 return BookmarkModelsMatch(GetBookmarkModel(profile_a), |
| 670 GetBookmarkModel(profile_b)); | 669 GetBookmarkModel(profile_b)); |
| 671 } | 670 } |
| 672 | 671 |
| 673 bool AllModelsMatch() { | 672 bool AllModelsMatch() { |
| 674 // Ensure that all tasks have finished processing on the history thread | 673 // Ensure that all tasks have finished processing on the history thread |
| 675 // and that any notifications the history thread may have sent have been | 674 // and that any notifications the history thread may have sent have been |
| 676 // processed before comparing models. | 675 // processed before comparing models. |
| 677 WaitForHistoryToProcessPendingTasks(); | 676 WaitForHistoryToProcessPendingTasks(); |
| 678 | 677 |
| 679 for (int i = 1; i < sync_datatype_helper::test()->num_clients(); ++i) { | 678 for (int i = 1; i < sync_datatype_helper::test()->num_clients(); ++i) { |
| 680 if (!ModelsMatch(0, i)) { | 679 if (!ModelsMatch(0, i)) { |
| 681 LOG(ERROR) << "Model " << i << " does not match Model 0."; | 680 VLOG(1) << "Model " << i << " does not match Model 0."; |
| 682 return false; | 681 return false; |
| 683 } | 682 } |
| 684 } | 683 } |
| 685 return true; | 684 return true; |
| 686 } | 685 } |
| 687 | 686 |
| 688 namespace { | |
| 689 | |
| 690 // Helper class used in the implementation of AwaitAllModelsMatch. | |
| 691 class AllModelsMatchChecker : public MultiClientStatusChangeChecker { | |
| 692 public: | |
| 693 AllModelsMatchChecker(); | |
| 694 virtual ~AllModelsMatchChecker(); | |
| 695 | |
| 696 virtual bool IsExitConditionSatisfied() OVERRIDE; | |
| 697 virtual std::string GetDebugMessage() const OVERRIDE; | |
| 698 }; | |
| 699 | |
| 700 AllModelsMatchChecker::AllModelsMatchChecker() | |
| 701 : MultiClientStatusChangeChecker( | |
| 702 sync_datatype_helper::test()->GetSyncServices()) {} | |
| 703 | |
| 704 AllModelsMatchChecker::~AllModelsMatchChecker() {} | |
| 705 | |
| 706 bool AllModelsMatchChecker::IsExitConditionSatisfied() { | |
| 707 return AllModelsMatch(); | |
| 708 } | |
| 709 | |
| 710 std::string AllModelsMatchChecker::GetDebugMessage() const { | |
| 711 return "Waiting for matching models"; | |
| 712 } | |
| 713 | |
| 714 } // namespace | |
| 715 | |
| 716 bool AwaitAllModelsMatch() { | |
| 717 AllModelsMatchChecker checker; | |
| 718 checker.Wait(); | |
| 719 return !checker.TimedOut(); | |
| 720 } | |
| 721 | |
| 722 | |
| 723 bool ContainsDuplicateBookmarks(int profile) { | 687 bool ContainsDuplicateBookmarks(int profile) { |
| 724 ui::TreeNodeIterator<const BookmarkNode> iterator( | 688 ui::TreeNodeIterator<const BookmarkNode> iterator( |
| 725 GetBookmarkModel(profile)->root_node()); | 689 GetBookmarkModel(profile)->root_node()); |
| 726 while (iterator.has_next()) { | 690 while (iterator.has_next()) { |
| 727 const BookmarkNode* node = iterator.Next(); | 691 const BookmarkNode* node = iterator.Next(); |
| 728 if (node->is_folder()) | 692 if (node->is_folder()) |
| 729 continue; | 693 continue; |
| 730 std::vector<const BookmarkNode*> nodes; | 694 std::vector<const BookmarkNode*> nodes; |
| 731 GetBookmarkModel(profile)->GetNodesByURL(node->url(), &nodes); | 695 GetBookmarkModel(profile)->GetNodesByURL(node->url(), &nodes); |
| 732 EXPECT_TRUE(nodes.size() >= 1); | 696 EXPECT_TRUE(nodes.size() >= 1); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 815 } | 779 } |
| 816 | 780 |
| 817 std::string IndexedSubfolderName(int i) { | 781 std::string IndexedSubfolderName(int i) { |
| 818 return base::StringPrintf("Subfolder Name %d", i); | 782 return base::StringPrintf("Subfolder Name %d", i); |
| 819 } | 783 } |
| 820 | 784 |
| 821 std::string IndexedSubsubfolderName(int i) { | 785 std::string IndexedSubsubfolderName(int i) { |
| 822 return base::StringPrintf("Subsubfolder Name %d", i); | 786 return base::StringPrintf("Subsubfolder Name %d", i); |
| 823 } | 787 } |
| 824 | 788 |
| 789 class BookmarkConditionChecker : public StatusChangeChecker, |
| 790 public BookmarkModelObserver { |
| 791 public: |
| 792 BookmarkConditionChecker(base::Callback<bool()> exit_condition, |
| 793 const std::string& debug_message); |
| 794 virtual ~BookmarkConditionChecker(); |
| 795 |
| 796 // Implementation of StatusChangeChecker. |
| 797 virtual std::string GetDebugMessage() const OVERRIDE; |
| 798 virtual bool IsExitConditionSatisfied() OVERRIDE; |
| 799 |
| 800 // Implementation of BookmarkModelObserver. |
| 801 virtual void BookmarkModelLoaded(BookmarkModel* model, |
| 802 bool ids_reassigned) OVERRIDE; |
| 803 virtual void BookmarkNodeMoved(BookmarkModel* model, |
| 804 const BookmarkNode* old_parent, |
| 805 int old_index, |
| 806 const BookmarkNode* new_parent, |
| 807 int new_index) OVERRIDE; |
| 808 virtual void BookmarkNodeAdded(BookmarkModel* model, |
| 809 const BookmarkNode* parent, |
| 810 int index) OVERRIDE; |
| 811 virtual void BookmarkNodeRemoved(BookmarkModel* model, |
| 812 const BookmarkNode* parent, |
| 813 int old_index, |
| 814 const BookmarkNode* node, |
| 815 const std::set<GURL>& removed_urls) OVERRIDE; |
| 816 virtual void BookmarkNodeChanged(BookmarkModel* model, |
| 817 const BookmarkNode* node) OVERRIDE; |
| 818 virtual void BookmarkNodeFaviconChanged(BookmarkModel* model, |
| 819 const BookmarkNode* node) OVERRIDE; |
| 820 virtual void BookmarkNodeChildrenReordered(BookmarkModel* model, |
| 821 const BookmarkNode* node) OVERRIDE; |
| 822 virtual void BookmarkAllUserNodesRemoved( |
| 823 BookmarkModel* model, |
| 824 const std::set<GURL>& removed_urls) OVERRIDE; |
| 825 |
| 826 // Waits until the condition to be met or a timeout occurs. |
| 827 void Wait(); |
| 828 |
| 829 private: |
| 830 base::Callback<bool()> exit_condition_; |
| 831 std::string debug_message_; |
| 832 bool registered_; |
| 833 }; |
| 834 |
| 835 BookmarkConditionChecker::BookmarkConditionChecker( |
| 836 base::Callback<bool()> exit_condition, |
| 837 const std::string& debug_message) |
| 838 : exit_condition_(exit_condition), |
| 839 debug_message_(debug_message), |
| 840 registered_(false) { |
| 841 } |
| 842 |
| 843 BookmarkConditionChecker::~BookmarkConditionChecker() { |
| 844 if (!registered_) |
| 845 return; |
| 846 |
| 847 for (int i = 0; i < sync_datatype_helper::test()->num_clients(); ++i) { |
| 848 GetBookmarkModel(i)->RemoveObserver(this); |
| 849 } |
| 850 } |
| 851 |
| 852 std::string BookmarkConditionChecker::GetDebugMessage() const { |
| 853 return debug_message_; |
| 854 } |
| 855 |
| 856 bool BookmarkConditionChecker::IsExitConditionSatisfied() { |
| 857 return exit_condition_.Run(); |
| 858 } |
| 859 |
| 860 // Implementation of BookmarkModelObserver. |
| 861 void BookmarkConditionChecker::BookmarkModelLoaded(BookmarkModel* model, |
| 862 bool ids_reassigned) { |
| 863 CheckExitCondition(); |
| 864 } |
| 865 |
| 866 void BookmarkConditionChecker::BookmarkNodeMoved(BookmarkModel* model, |
| 867 const BookmarkNode* old_parent, |
| 868 int old_index, |
| 869 const BookmarkNode* new_parent, |
| 870 int new_index) { |
| 871 CheckExitCondition(); |
| 872 } |
| 873 |
| 874 void BookmarkConditionChecker::BookmarkNodeAdded(BookmarkModel* model, |
| 875 const BookmarkNode* parent, |
| 876 int index) { |
| 877 CheckExitCondition(); |
| 878 } |
| 879 |
| 880 void BookmarkConditionChecker::BookmarkNodeRemoved( |
| 881 BookmarkModel* model, |
| 882 const BookmarkNode* parent, |
| 883 int old_index, |
| 884 const BookmarkNode* node, |
| 885 const std::set<GURL>& removed_urls) { |
| 886 CheckExitCondition(); |
| 887 } |
| 888 |
| 889 void BookmarkConditionChecker::BookmarkNodeChanged(BookmarkModel* model, |
| 890 const BookmarkNode* node) { |
| 891 CheckExitCondition(); |
| 892 } |
| 893 |
| 894 void BookmarkConditionChecker::BookmarkNodeFaviconChanged( |
| 895 BookmarkModel* model, |
| 896 const BookmarkNode* node) { |
| 897 CheckExitCondition(); |
| 898 } |
| 899 |
| 900 void BookmarkConditionChecker::BookmarkNodeChildrenReordered( |
| 901 BookmarkModel* model, |
| 902 const BookmarkNode* node) { |
| 903 CheckExitCondition(); |
| 904 } |
| 905 |
| 906 void BookmarkConditionChecker::BookmarkAllUserNodesRemoved( |
| 907 BookmarkModel* model, |
| 908 const std::set<GURL>& removed_urls) { |
| 909 CheckExitCondition(); |
| 910 } |
| 911 |
| 912 void BookmarkConditionChecker::Wait() { |
| 913 for (int i = 0; i < sync_datatype_helper::test()->num_clients(); ++i) { |
| 914 GetBookmarkModel(i)->AddObserver(this); |
| 915 } |
| 916 registered_ = true; |
| 917 |
| 918 if (IsExitConditionSatisfied()) { |
| 919 VLOG(1) << "Finished without wait: " << GetDebugMessage(); |
| 920 return; |
| 921 } |
| 922 |
| 923 StartBlockingWait(); |
| 924 } |
| 925 |
| 926 bool AwaitAllModelsMatch() { |
| 927 BookmarkConditionChecker checker(base::Bind(&AllModelsMatch), |
| 928 "Waiting for models to match"); |
| 929 checker.Wait(); |
| 930 return !checker.TimedOut(); |
| 931 } |
| 932 |
| 933 bool AwaitAllModelsMatchVerifier() { |
| 934 BookmarkConditionChecker checker(base::Bind(&AllModelsMatchVerifier), |
| 935 "Waiting for models to match verifier"); |
| 936 checker.Wait(); |
| 937 return !checker.TimedOut(); |
| 938 } |
| 939 |
| 825 } // namespace bookmarks_helper | 940 } // namespace bookmarks_helper |
| OLD | NEW |