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 |