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 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_SYNC_TEST_INTEGRATION_BOOKMARKS_HELPER_H_ 6 #define CHROME_BROWSER_SYNC_TEST_INTEGRATION_BOOKMARKS_HELPER_H_ 7 8 #include <memory> 9 #include <set> 10 #include <string> 11 #include <utility> 12 #include <vector> 13 14 #include "base/callback_forward.h" 15 #include "base/compiler_specific.h" 16 #include "base/memory/weak_ptr.h" 17 #include "base/sequence_checker.h" 18 #include "chrome/browser/sync/test/integration/await_match_status_change_checker.h" 19 #include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h" 20 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" 21 #include "components/bookmarks/browser/bookmark_model_observer.h" 22 #include "components/bookmarks/browser/bookmark_node.h" 23 #include "components/bookmarks/browser/bookmark_test_util.h" 24 #include "components/sync/engine_impl/loopback_server/loopback_server_entity.h" 25 #include "components/sync/nigori/cryptographer.h" 26 #include "components/sync/test/fake_server/fake_server.h" 27 #include "testing/gmock/include/gmock/gmock.h" 28 #include "third_party/skia/include/core/SkColor.h" 29 #include "url/gurl.h" 30 31 class BookmarkUndoService; 32 class GURL; 33 34 namespace bookmarks { 35 class BookmarkModel; 36 } // namespace bookmarks 37 38 namespace gfx { 39 class Image; 40 } // namespace gfx 41 42 namespace bookmarks_helper { 43 44 MATCHER_P(HasGuid, expected_guid, "") { 45 const bookmarks::BookmarkNode* actual_node = arg; 46 return actual_node->guid() == expected_guid; 47 } 48 49 // Used to access the bookmark undo service within a particular sync profile. 50 BookmarkUndoService* GetBookmarkUndoService(int index) WARN_UNUSED_RESULT; 51 52 // Used to access the bookmark model within a particular sync profile. 53 bookmarks::BookmarkModel* GetBookmarkModel(int index) WARN_UNUSED_RESULT; 54 55 // Used to access the bookmark bar within a particular sync profile. 56 const bookmarks::BookmarkNode* GetBookmarkBarNode(int index) WARN_UNUSED_RESULT; 57 58 // Used to access the "other bookmarks" node within a particular sync profile. 59 const bookmarks::BookmarkNode* GetOtherNode(int index) WARN_UNUSED_RESULT; 60 61 // Used to access the "Synced Bookmarks" node within a particular sync profile. 62 const bookmarks::BookmarkNode* GetSyncedBookmarksNode(int index) 63 WARN_UNUSED_RESULT; 64 65 // Used to access the "Managed Bookmarks" node for the given profile. 66 const bookmarks::BookmarkNode* GetManagedNode(int index) WARN_UNUSED_RESULT; 67 68 // Used to access the bookmarks within the verifier sync profile. 69 bookmarks::BookmarkModel* GetVerifierBookmarkModel() WARN_UNUSED_RESULT; 70 71 // Adds a URL with address |url| and title |title| to the bookmark bar of 72 // profile |profile|. Returns a pointer to the node that was added. 73 const bookmarks::BookmarkNode* AddURL(int profile, 74 const std::string& title, 75 const GURL& url) WARN_UNUSED_RESULT; 76 77 // Adds a URL with address |url| and title |title| to the bookmark bar of 78 // profile |profile| at position |index|. Returns a pointer to the node that 79 // was added. 80 const bookmarks::BookmarkNode* AddURL(int profile, 81 size_t index, 82 const std::string& title, 83 const GURL& url) WARN_UNUSED_RESULT; 84 85 // Adds a URL with address |url| and title |title| under the node |parent| of 86 // profile |profile| at position |index|. Returns a pointer to the node that 87 // was added. 88 const bookmarks::BookmarkNode* AddURL(int profile, 89 const bookmarks::BookmarkNode* parent, 90 size_t index, 91 const std::string& title, 92 const GURL& url) WARN_UNUSED_RESULT; 93 94 // Adds a folder named |title| to the bookmark bar of profile |profile|. 95 // Returns a pointer to the folder that was added. 96 const bookmarks::BookmarkNode* AddFolder(int profile, const std::string& title) 97 WARN_UNUSED_RESULT; 98 99 // Adds a folder named |title| to the bookmark bar of profile |profile| at 100 // position |index|. Returns a pointer to the folder that was added. 101 const bookmarks::BookmarkNode* AddFolder(int profile, 102 size_t index, 103 const std::string& title) 104 WARN_UNUSED_RESULT; 105 106 // Adds a folder named |title| to the node |parent| in the bookmark model of 107 // profile |profile| at position |index|. Returns a pointer to the node that 108 // was added. 109 const bookmarks::BookmarkNode* AddFolder(int profile, 110 const bookmarks::BookmarkNode* parent, 111 size_t index, 112 const std::string& title) 113 WARN_UNUSED_RESULT; 114 115 // Changes the title of the node |node| in the bookmark model of profile 116 // |profile| to |new_title|. 117 void SetTitle(int profile, 118 const bookmarks::BookmarkNode* node, 119 const std::string& new_title); 120 121 // The source of the favicon. 122 enum FaviconSource { 123 FROM_UI, 124 FROM_SYNC 125 }; 126 127 // Sets the |icon_url| and |image| data for the favicon for |node| in the 128 // bookmark model for |profile|. 129 void SetFavicon(int profile, 130 const bookmarks::BookmarkNode* node, 131 const GURL& icon_url, 132 const gfx::Image& image, 133 FaviconSource source); 134 135 // Expires the favicon for |node| in the bookmark model for |profile|. 136 void ExpireFavicon(int profile, const bookmarks::BookmarkNode* node); 137 138 // Checks whether the favicon at |icon_url| for |profile| is expired; 139 void CheckFaviconExpired(int profile, const GURL& icon_url); 140 141 // Deletes the favicon mappings for |node| in the bookmark model for |profile|. 142 void DeleteFaviconMappings(int profile, 143 const bookmarks::BookmarkNode* node, 144 FaviconSource favicon_source); 145 146 // Checks whether |page_url| for |profile| has no favicon mappings. 147 void CheckHasNoFavicon(int profile, const GURL& page_url); 148 149 // Changes the url of the node |node| in the bookmark model of profile 150 // |profile| to |new_url|. Returns a pointer to the node with the changed url. 151 const bookmarks::BookmarkNode* SetURL(int profile, 152 const bookmarks::BookmarkNode* node, 153 const GURL& new_url) WARN_UNUSED_RESULT; 154 155 // Moves the node |node| in the bookmark model of profile |profile| so it ends 156 // up under the node |new_parent| at position |index|. 157 void Move(int profile, 158 const bookmarks::BookmarkNode* node, 159 const bookmarks::BookmarkNode* new_parent, 160 size_t index); 161 162 // Removes the node in the bookmark model of profile |profile| under the node 163 // |parent| at position |index|. 164 void Remove(int profile, const bookmarks::BookmarkNode* parent, size_t index); 165 166 // Removes all non-permanent nodes in the bookmark model of profile |profile|. 167 void RemoveAll(int profile); 168 169 // Sorts the children of the node |parent| in the bookmark model of profile 170 // |profile|. 171 void SortChildren(int profile, const bookmarks::BookmarkNode* parent); 172 173 // Reverses the order of the children of the node |parent| in the bookmark 174 // model of profile |profile|. 175 void ReverseChildOrder(int profile, const bookmarks::BookmarkNode* parent); 176 177 // Checks if the bookmark model of profile |profile| matches the verifier 178 // bookmark model. Returns true if they match. 179 bool ModelMatchesVerifier(int profile) WARN_UNUSED_RESULT; 180 181 // Checks if the bookmark models of all sync profiles match the verifier 182 // bookmark model. Returns true if they match. 183 bool AllModelsMatchVerifier() WARN_UNUSED_RESULT; 184 185 // Checks if the bookmark models of |profile_a| and |profile_b| match each 186 // other. Returns true if they match. 187 bool ModelsMatch(int profile_a, int profile_b) WARN_UNUSED_RESULT; 188 189 // Checks if the bookmark models of all sync profiles match each other. Does 190 // not compare them with the verifier bookmark model. Returns true if they 191 // match. 192 bool AllModelsMatch() WARN_UNUSED_RESULT; 193 194 // Checks if the bookmark model of profile |profile| contains any instances of 195 // two bookmarks with the same URL under the same parent folder. Returns true 196 // if even one instance is found. 197 bool ContainsDuplicateBookmarks(int profile); 198 199 // Returns whether a node exists with the specified url. 200 bool HasNodeWithURL(int profile, const GURL& url); 201 202 // Gets the node in the bookmark model of profile |profile| that has the url 203 // |url|. Note: Only one instance of |url| is assumed to be present. 204 const bookmarks::BookmarkNode* GetUniqueNodeByURL(int profile, const GURL& url) 205 WARN_UNUSED_RESULT; 206 207 // Returns the number of bookmarks in bookmark model of profile |profile|. 208 size_t CountAllBookmarks(int profile) WARN_UNUSED_RESULT; 209 210 // Returns the number of bookmarks in bookmark model of profile |profile| 211 // whose titles match the string |title|. 212 size_t CountBookmarksWithTitlesMatching(int profile, const std::string& title) 213 WARN_UNUSED_RESULT; 214 215 // Returns the number of bookmarks in bookmark model of profile |profile| 216 // whose URLs match the |url|. 217 size_t CountBookmarksWithUrlsMatching(int profile, 218 const GURL& url) WARN_UNUSED_RESULT; 219 220 // Returns the number of bookmark folders in the bookmark model of profile 221 // |profile| whose titles contain the query string |title|. 222 size_t CountFoldersWithTitlesMatching(int profile, const std::string& title) 223 WARN_UNUSED_RESULT; 224 225 // Returns whether there exists a BookmarkNode in the bookmark model of 226 // profile |profile| whose GUID matches the string |guid|. 227 bool ContainsBookmarkNodeWithGUID(int profile, const std::string& guid); 228 229 // Creates a favicon of |color| with image reps of the platform's supported 230 // scale factors (eg MacOS) in addition to 1x. 231 gfx::Image CreateFavicon(SkColor color); 232 233 // Creates a 1x only favicon from the PNG file at |path|. 234 gfx::Image Create1xFaviconFromPNGFile(const std::string& path); 235 236 // Returns a URL identifiable by |i|. 237 std::string IndexedURL(size_t i); 238 239 // Returns a URL title identifiable by |i|. 240 std::string IndexedURLTitle(size_t i); 241 242 // Returns a folder name identifiable by |i|. 243 std::string IndexedFolderName(size_t i); 244 245 // Returns a subfolder name identifiable by |i|. 246 std::string IndexedSubfolderName(size_t i); 247 248 // Returns a subsubfolder name identifiable by |i|. 249 std::string IndexedSubsubfolderName(size_t i); 250 251 // Creates a server-side entity representing a bookmark with the given title and 252 // URL. 253 std::unique_ptr<syncer::LoopbackServerEntity> CreateBookmarkServerEntity( 254 const std::string& title, 255 const GURL& url); 256 257 // Helper class that reacts to any BookmarkModelObserver event by running a 258 // callback provided in the constructor. 259 class AnyBookmarkChangeObserver : public bookmarks::BookmarkModelObserver { 260 public: 261 explicit AnyBookmarkChangeObserver(const base::RepeatingClosure& cb); 262 ~AnyBookmarkChangeObserver() override; 263 264 AnyBookmarkChangeObserver(const AnyBookmarkChangeObserver&) = delete; 265 AnyBookmarkChangeObserver& operator=(const AnyBookmarkChangeObserver&) = 266 delete; 267 268 // BookmarkModelObserver overrides. 269 void BookmarkModelLoaded(bookmarks::BookmarkModel* model, 270 bool ids_reassigned) override; 271 void BookmarkModelBeingDeleted(bookmarks::BookmarkModel* model) override; 272 void BookmarkNodeMoved(bookmarks::BookmarkModel* model, 273 const bookmarks::BookmarkNode* old_parent, 274 size_t old_index, 275 const bookmarks::BookmarkNode* new_parent, 276 size_t new_index) override; 277 void BookmarkNodeAdded(bookmarks::BookmarkModel* model, 278 const bookmarks::BookmarkNode* parent, 279 size_t index) override; 280 void OnWillRemoveBookmarks(bookmarks::BookmarkModel* model, 281 const bookmarks::BookmarkNode* parent, 282 size_t old_index, 283 const bookmarks::BookmarkNode* node) override; 284 void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, 285 const bookmarks::BookmarkNode* parent, 286 size_t old_index, 287 const bookmarks::BookmarkNode* node, 288 const std::set<GURL>& no_longer_bookmarked) override; 289 void OnWillChangeBookmarkNode(bookmarks::BookmarkModel* model, 290 const bookmarks::BookmarkNode* node) override; 291 void BookmarkNodeChanged(bookmarks::BookmarkModel* model, 292 const bookmarks::BookmarkNode* node) override; 293 void OnWillChangeBookmarkMetaInfo( 294 bookmarks::BookmarkModel* model, 295 const bookmarks::BookmarkNode* node) override; 296 void BookmarkMetaInfoChanged(bookmarks::BookmarkModel* model, 297 const bookmarks::BookmarkNode* node) override; 298 void BookmarkNodeFaviconChanged(bookmarks::BookmarkModel* model, 299 const bookmarks::BookmarkNode* node) override; 300 void OnWillReorderBookmarkNode(bookmarks::BookmarkModel* model, 301 const bookmarks::BookmarkNode* node) override; 302 void BookmarkNodeChildrenReordered( 303 bookmarks::BookmarkModel* model, 304 const bookmarks::BookmarkNode* node) override; 305 void ExtensiveBookmarkChangesBeginning( 306 bookmarks::BookmarkModel* model) override; 307 void ExtensiveBookmarkChangesEnded(bookmarks::BookmarkModel* model) override; 308 void OnWillRemoveAllUserBookmarks(bookmarks::BookmarkModel* model) override; 309 void BookmarkAllUserNodesRemoved(bookmarks::BookmarkModel* model, 310 const std::set<GURL>& removed_urls) override; 311 void GroupedBookmarkChangesBeginning( 312 bookmarks::BookmarkModel* model) override; 313 void GroupedBookmarkChangesEnded(bookmarks::BookmarkModel* model) override; 314 315 private: 316 const base::RepeatingClosure cb_; 317 }; 318 319 // Base class used for checkers that verify the state of an arbitrary number 320 // of BookmarkModel instances. 321 class BookmarkModelStatusChangeChecker : public StatusChangeChecker { 322 public: 323 BookmarkModelStatusChangeChecker(); 324 ~BookmarkModelStatusChangeChecker() override; 325 326 BookmarkModelStatusChangeChecker(const BookmarkModelStatusChangeChecker&) = 327 delete; 328 BookmarkModelStatusChangeChecker& operator=( 329 const BookmarkModelStatusChangeChecker&) = delete; 330 331 protected: 332 void Observe(bookmarks::BookmarkModel* model); 333 334 // StatusChangeChecker override. 335 void CheckExitCondition() override; 336 337 private: 338 // Equivalent of CheckExitCondition() that instead posts a task in the current 339 // task runner. 340 void PostCheckExitCondition(); 341 342 SEQUENCE_CHECKER(sequence_checker_); 343 344 std::vector<std::pair<bookmarks::BookmarkModel*, 345 std::unique_ptr<AnyBookmarkChangeObserver>>> 346 observers_; 347 348 bool pending_check_exit_condition_ = false; 349 base::WeakPtrFactory<BookmarkModelStatusChangeChecker> weak_ptr_factory_{ 350 this}; 351 }; 352 353 // Checker used to block until bookmarks match on all clients. 354 class BookmarksMatchChecker : public BookmarkModelStatusChangeChecker { 355 public: 356 BookmarksMatchChecker(); 357 358 // StatusChangeChecker implementation. 359 bool IsExitConditionSatisfied(std::ostream* os) override; 360 bool Wait() override; 361 }; 362 363 // Base class used for checkers that verify the state of a single BookmarkModel 364 // instance. 365 class SingleBookmarkModelStatusChangeChecker 366 : public BookmarkModelStatusChangeChecker { 367 public: 368 explicit SingleBookmarkModelStatusChangeChecker(int profile_index); 369 ~SingleBookmarkModelStatusChangeChecker() override; 370 371 SingleBookmarkModelStatusChangeChecker( 372 const SingleBookmarkModelStatusChangeChecker&) = delete; 373 SingleBookmarkModelStatusChangeChecker& operator=( 374 const SingleBookmarkModelStatusChangeChecker&) = delete; 375 376 protected: 377 int profile_index() const; 378 bookmarks::BookmarkModel* bookmark_model() const; 379 380 private: 381 const int profile_index_; 382 bookmarks::BookmarkModel* bookmark_model_; 383 }; 384 385 // Checker used to block until bookmarks match the verifier bookmark model. 386 class BookmarksMatchVerifierChecker : public BookmarkModelStatusChangeChecker { 387 public: 388 BookmarksMatchVerifierChecker(); 389 390 // StatusChangeChecker implementation. 391 bool IsExitConditionSatisfied(std::ostream* os) override; 392 bool Wait() override; 393 }; 394 395 // Generic status change checker that waits until a predicate as defined by 396 // a gMock matches becomes true. 397 class SingleBookmarksModelMatcherChecker 398 : public SingleBookmarkModelStatusChangeChecker { 399 public: 400 using Matcher = testing::Matcher<std::vector<const bookmarks::BookmarkNode*>>; 401 402 SingleBookmarksModelMatcherChecker(int profile_index, const Matcher& matcher); 403 ~SingleBookmarksModelMatcherChecker(); 404 405 // StatusChangeChecker implementation. 406 bool IsExitConditionSatisfied(std::ostream* os) final; 407 408 private: 409 const Matcher matcher_; 410 }; 411 412 // Checker used to block until the actual number of bookmarks with the given 413 // title match the expected count. 414 class BookmarksTitleChecker : public SingleBookmarkModelStatusChangeChecker { 415 public: 416 BookmarksTitleChecker(int profile_index, 417 const std::string& title, 418 int expected_count); 419 420 // StatusChangeChecker implementation. 421 bool IsExitConditionSatisfied(std::ostream* os) override; 422 423 private: 424 const int profile_index_; 425 const std::string title_; 426 const int expected_count_; 427 }; 428 429 // Checker used to wait until the favicon of a bookmark has been loaded. It 430 // doesn't itself trigger the load of the favicon. 431 class BookmarkFaviconLoadedChecker 432 : public SingleBookmarkModelStatusChangeChecker { 433 public: 434 // There must be exactly one bookmark for |page_url| in the BookmarkModel in 435 // |profile_index|. 436 BookmarkFaviconLoadedChecker(int profile_index, const GURL& page_url); 437 438 // StatusChangeChecker implementation. 439 bool IsExitConditionSatisfied(std::ostream* os) override; 440 441 private: 442 const bookmarks::BookmarkNode* const bookmark_node_; 443 }; 444 445 // Checker used to block until the bookmarks on the server match a given set of 446 // expected bookmarks. The |title| is comapred to both legacy and full titles. 447 class ServerBookmarksEqualityChecker : public SingleClientStatusChangeChecker { 448 public: 449 struct ExpectedBookmark { 450 // Used to check both legacy and full titles in specifics. 451 std::string title; 452 GURL url; 453 }; 454 455 // If a |cryptographer| is provided (i.e. is not nullptr), it is assumed that 456 // the server-side data should be encrypted, and the provided cryptographer 457 // will be used to decrypt the data prior to checking for equality. 458 // |fake_server| must not be nullptr and must outlive this object. 459 ServerBookmarksEqualityChecker( 460 syncer::ProfileSyncService* service, 461 fake_server::FakeServer* fake_server, 462 std::vector<ExpectedBookmark> expected_bookmarks, 463 syncer::Cryptographer* cryptographer); 464 465 bool IsExitConditionSatisfied(std::ostream* os) override; 466 467 ~ServerBookmarksEqualityChecker() override; 468 469 private: 470 fake_server::FakeServer* fake_server_; 471 syncer::Cryptographer* cryptographer_; 472 const std::vector<ExpectedBookmark> expected_bookmarks_; 473 474 DISALLOW_COPY_AND_ASSIGN(ServerBookmarksEqualityChecker); 475 }; 476 477 // Checker used to block until the actual number of bookmarks with the given url 478 // match the expected count. 479 class BookmarksUrlChecker : public SingleBookmarkModelStatusChangeChecker { 480 public: 481 BookmarksUrlChecker(int profile, const GURL& url, int expected_count); 482 483 // StatusChangeChecker implementation. 484 bool IsExitConditionSatisfied(std::ostream* os) override; 485 486 private: 487 const GURL url_; 488 const int expected_count_; 489 }; 490 491 // Checker used to block until there exists a bookmark with the given GUID. 492 class BookmarksGUIDChecker : public SingleBookmarksModelMatcherChecker { 493 public: 494 BookmarksGUIDChecker(int profile, const std::string& guid); 495 ~BookmarksGUIDChecker() override; 496 }; 497 498 } // namespace bookmarks_helper 499 500 #endif // CHROME_BROWSER_SYNC_TEST_INTEGRATION_BOOKMARKS_HELPER_H_ 501