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