1 // Copyright 2014 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 #include "components/policy/core/browser/managed_bookmarks_tracker.h" 6 7 #include "base/bind.h" 8 #include "base/files/file_path.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/prefs/pref_registry_simple.h" 12 #include "base/prefs/testing_pref_service.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "components/bookmarks/browser/bookmark_model.h" 15 #include "components/bookmarks/browser/bookmark_model_observer.h" 16 #include "components/bookmarks/browser/bookmark_node.h" 17 #include "components/bookmarks/common/bookmark_pref_names.h" 18 #include "components/bookmarks/test/bookmark_test_helpers.h" 19 #include "components/bookmarks/test/mock_bookmark_model_observer.h" 20 #include "components/bookmarks/test/test_bookmark_client.h" 21 #include "grit/components_strings.h" 22 #include "testing/gmock/include/gmock/gmock.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 #include "ui/base/l10n/l10n_util.h" 25 #include "url/gurl.h" 26 27 using testing::Mock; 28 using testing::_; 29 30 namespace policy { 31 32 class ManagedBookmarksTrackerTest : public testing::Test { 33 public: 34 ManagedBookmarksTrackerTest() : managed_node_(NULL) {} 35 virtual ~ManagedBookmarksTrackerTest() {} 36 37 virtual void SetUp() OVERRIDE { 38 prefs_.registry()->RegisterListPref(bookmarks::prefs::kManagedBookmarks); 39 prefs_.registry()->RegisterListPref( 40 bookmarks::prefs::kBookmarkEditorExpandedNodes); 41 } 42 43 virtual void TearDown() OVERRIDE { 44 if (model_) 45 model_->RemoveObserver(&observer_); 46 } 47 48 void CreateModel() { 49 // Simulate the creation of the managed node by the BookmarkClient. 50 BookmarkPermanentNode* managed_node = new BookmarkPermanentNode(100); 51 policy::ManagedBookmarksTracker::LoadInitial( 52 managed_node, prefs_.GetList(bookmarks::prefs::kManagedBookmarks), 101); 53 managed_node->set_visible(!managed_node->empty()); 54 managed_node->SetTitle(l10n_util::GetStringUTF16( 55 IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME)); 56 57 bookmarks::BookmarkPermanentNodeList extra_nodes; 58 extra_nodes.push_back(managed_node); 59 client_.SetExtraNodesToLoad(extra_nodes.Pass()); 60 61 model_.reset(new BookmarkModel(&client_)); 62 model_->AddObserver(&observer_); 63 EXPECT_CALL(observer_, BookmarkModelLoaded(model_.get(), _)); 64 model_->Load(&prefs_, 65 std::string(), 66 base::FilePath(), 67 base::MessageLoopProxy::current(), 68 base::MessageLoopProxy::current()); 69 test::WaitForBookmarkModelToLoad(model_.get()); 70 Mock::VerifyAndClearExpectations(&observer_); 71 72 ASSERT_EQ(1u, client_.extra_nodes().size()); 73 managed_node_ = client_.extra_nodes()[0]; 74 ASSERT_EQ(managed_node, managed_node_); 75 76 managed_bookmarks_tracker_.reset(new ManagedBookmarksTracker( 77 model_.get(), 78 &prefs_, 79 base::Bind(&ManagedBookmarksTrackerTest::GetManagementDomain))); 80 managed_bookmarks_tracker_->Init(managed_node_); 81 } 82 83 const BookmarkNode* managed_node() { 84 return managed_node_; 85 } 86 87 bool IsManaged(const BookmarkNode* node) { 88 return node && node->HasAncestor(managed_node_); 89 } 90 91 static base::DictionaryValue* CreateBookmark(const std::string& title, 92 const std::string& url) { 93 EXPECT_TRUE(GURL(url).is_valid()); 94 base::DictionaryValue* dict = new base::DictionaryValue(); 95 dict->SetString("name", title); 96 dict->SetString("url", GURL(url).spec()); 97 return dict; 98 } 99 100 static base::DictionaryValue* CreateFolder(const std::string& title, 101 base::ListValue* children) { 102 base::DictionaryValue* dict = new base::DictionaryValue(); 103 dict->SetString("name", title); 104 dict->Set("children", children); 105 return dict; 106 } 107 108 static base::ListValue* CreateTestTree() { 109 base::ListValue* folder = new base::ListValue(); 110 base::ListValue* empty = new base::ListValue(); 111 folder->Append(CreateFolder("Empty", empty)); 112 folder->Append(CreateBookmark("Youtube", "http://youtube.com/")); 113 114 base::ListValue* list = new base::ListValue(); 115 list->Append(CreateBookmark("Google", "http://google.com/")); 116 list->Append(CreateFolder("Folder", folder)); 117 118 return list; 119 } 120 121 static std::string GetManagementDomain() { 122 return std::string(); 123 } 124 125 static std::string GetManagedFolderTitle() { 126 return l10n_util::GetStringUTF8( 127 IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME); 128 } 129 130 static base::DictionaryValue* CreateExpectedTree() { 131 return CreateFolder(GetManagedFolderTitle(), CreateTestTree()); 132 } 133 134 static bool NodeMatchesValue(const BookmarkNode* node, 135 const base::DictionaryValue* dict) { 136 base::string16 title; 137 if (!dict->GetString("name", &title) || node->GetTitle() != title) 138 return false; 139 140 if (node->is_folder()) { 141 const base::ListValue* children = NULL; 142 if (!dict->GetList("children", &children) || 143 node->child_count() != static_cast<int>(children->GetSize())) { 144 return false; 145 } 146 for (int i = 0; i < node->child_count(); ++i) { 147 const base::DictionaryValue* child = NULL; 148 if (!children->GetDictionary(i, &child) || 149 !NodeMatchesValue(node->GetChild(i), child)) { 150 return false; 151 } 152 } 153 } else if (node->is_url()) { 154 std::string url; 155 if (!dict->GetString("url", &url) || node->url() != GURL(url)) 156 return false; 157 } else { 158 return false; 159 } 160 return true; 161 } 162 163 base::MessageLoop loop_; 164 TestingPrefServiceSimple prefs_; 165 bookmarks::TestBookmarkClient client_; 166 scoped_ptr<BookmarkModel> model_; 167 bookmarks::MockBookmarkModelObserver observer_; 168 BookmarkPermanentNode* managed_node_; 169 scoped_ptr<ManagedBookmarksTracker> managed_bookmarks_tracker_; 170 }; 171 172 TEST_F(ManagedBookmarksTrackerTest, Empty) { 173 CreateModel(); 174 EXPECT_TRUE(model_->bookmark_bar_node()->empty()); 175 EXPECT_TRUE(model_->other_node()->empty()); 176 EXPECT_TRUE(managed_node()->empty()); 177 EXPECT_FALSE(managed_node()->IsVisible()); 178 } 179 180 TEST_F(ManagedBookmarksTrackerTest, LoadInitial) { 181 // Set a policy before loading the model. 182 prefs_.SetManagedPref(bookmarks::prefs::kManagedBookmarks, CreateTestTree()); 183 CreateModel(); 184 EXPECT_TRUE(model_->bookmark_bar_node()->empty()); 185 EXPECT_TRUE(model_->other_node()->empty()); 186 EXPECT_FALSE(managed_node()->empty()); 187 EXPECT_TRUE(managed_node()->IsVisible()); 188 189 scoped_ptr<base::DictionaryValue> expected(CreateExpectedTree()); 190 EXPECT_TRUE(NodeMatchesValue(managed_node(), expected.get())); 191 } 192 193 TEST_F(ManagedBookmarksTrackerTest, SwapNodes) { 194 prefs_.SetManagedPref(bookmarks::prefs::kManagedBookmarks, CreateTestTree()); 195 CreateModel(); 196 197 // Swap the Google bookmark with the Folder. 198 scoped_ptr<base::ListValue> updated(CreateTestTree()); 199 scoped_ptr<base::Value> removed; 200 ASSERT_TRUE(updated->Remove(0, &removed)); 201 updated->Append(removed.release()); 202 203 // These two nodes should just be swapped. 204 const BookmarkNode* parent = managed_node(); 205 EXPECT_CALL(observer_, BookmarkNodeMoved(model_.get(), parent, 1, parent, 0)); 206 prefs_.SetManagedPref(bookmarks::prefs::kManagedBookmarks, 207 updated->DeepCopy()); 208 Mock::VerifyAndClearExpectations(&observer_); 209 210 // Verify the final tree. 211 scoped_ptr<base::DictionaryValue> expected( 212 CreateFolder(GetManagedFolderTitle(), updated.release())); 213 EXPECT_TRUE(NodeMatchesValue(managed_node(), expected.get())); 214 } 215 216 TEST_F(ManagedBookmarksTrackerTest, RemoveNode) { 217 prefs_.SetManagedPref(bookmarks::prefs::kManagedBookmarks, CreateTestTree()); 218 CreateModel(); 219 220 // Remove the Folder. 221 scoped_ptr<base::ListValue> updated(CreateTestTree()); 222 ASSERT_TRUE(updated->Remove(1, NULL)); 223 224 const BookmarkNode* parent = managed_node(); 225 EXPECT_CALL(observer_, BookmarkNodeRemoved(model_.get(), parent, 1, _, _)); 226 prefs_.SetManagedPref(bookmarks::prefs::kManagedBookmarks, 227 updated->DeepCopy()); 228 Mock::VerifyAndClearExpectations(&observer_); 229 230 // Verify the final tree. 231 scoped_ptr<base::DictionaryValue> expected( 232 CreateFolder(GetManagedFolderTitle(), updated.release())); 233 EXPECT_TRUE(NodeMatchesValue(managed_node(), expected.get())); 234 } 235 236 TEST_F(ManagedBookmarksTrackerTest, CreateNewNodes) { 237 prefs_.SetManagedPref(bookmarks::prefs::kManagedBookmarks, CreateTestTree()); 238 CreateModel(); 239 240 // Put all the nodes inside another folder. 241 scoped_ptr<base::ListValue> updated(new base::ListValue); 242 updated->Append(CreateFolder("Container", CreateTestTree())); 243 244 EXPECT_CALL(observer_, BookmarkNodeAdded(model_.get(), _, _)).Times(5); 245 // The remaining nodes have been pushed to positions 1 and 2; they'll both be 246 // removed when at position 1. 247 const BookmarkNode* parent = managed_node(); 248 EXPECT_CALL(observer_, BookmarkNodeRemoved(model_.get(), parent, 1, _, _)) 249 .Times(2); 250 prefs_.SetManagedPref(bookmarks::prefs::kManagedBookmarks, 251 updated->DeepCopy()); 252 Mock::VerifyAndClearExpectations(&observer_); 253 254 // Verify the final tree. 255 scoped_ptr<base::DictionaryValue> expected( 256 CreateFolder(GetManagedFolderTitle(), updated.release())); 257 EXPECT_TRUE(NodeMatchesValue(managed_node(), expected.get())); 258 } 259 260 TEST_F(ManagedBookmarksTrackerTest, RemoveAll) { 261 prefs_.SetManagedPref(bookmarks::prefs::kManagedBookmarks, CreateTestTree()); 262 CreateModel(); 263 EXPECT_TRUE(managed_node()->IsVisible()); 264 265 // Remove the policy. 266 const BookmarkNode* parent = managed_node(); 267 EXPECT_CALL(observer_, BookmarkNodeRemoved(model_.get(), parent, 0, _, _)) 268 .Times(2); 269 prefs_.RemoveManagedPref(bookmarks::prefs::kManagedBookmarks); 270 Mock::VerifyAndClearExpectations(&observer_); 271 272 EXPECT_TRUE(managed_node()->empty()); 273 EXPECT_FALSE(managed_node()->IsVisible()); 274 } 275 276 TEST_F(ManagedBookmarksTrackerTest, IsManaged) { 277 prefs_.SetManagedPref(bookmarks::prefs::kManagedBookmarks, CreateTestTree()); 278 CreateModel(); 279 280 EXPECT_FALSE(IsManaged(model_->root_node())); 281 EXPECT_FALSE(IsManaged(model_->bookmark_bar_node())); 282 EXPECT_FALSE(IsManaged(model_->other_node())); 283 EXPECT_FALSE(IsManaged(model_->mobile_node())); 284 EXPECT_TRUE(IsManaged(managed_node())); 285 286 const BookmarkNode* parent = managed_node(); 287 ASSERT_EQ(2, parent->child_count()); 288 EXPECT_TRUE(IsManaged(parent->GetChild(0))); 289 EXPECT_TRUE(IsManaged(parent->GetChild(1))); 290 291 parent = parent->GetChild(1); 292 ASSERT_EQ(2, parent->child_count()); 293 EXPECT_TRUE(IsManaged(parent->GetChild(0))); 294 EXPECT_TRUE(IsManaged(parent->GetChild(1))); 295 } 296 297 TEST_F(ManagedBookmarksTrackerTest, RemoveAllUserBookmarksDoesntRemoveManaged) { 298 prefs_.SetManagedPref(bookmarks::prefs::kManagedBookmarks, CreateTestTree()); 299 CreateModel(); 300 EXPECT_EQ(2, managed_node()->child_count()); 301 302 EXPECT_CALL(observer_, 303 BookmarkNodeAdded(model_.get(), model_->bookmark_bar_node(), 0)); 304 EXPECT_CALL(observer_, 305 BookmarkNodeAdded(model_.get(), model_->bookmark_bar_node(), 1)); 306 model_->AddURL(model_->bookmark_bar_node(), 307 0, 308 base::ASCIIToUTF16("Test"), 309 GURL("http://google.com/")); 310 model_->AddFolder( 311 model_->bookmark_bar_node(), 1, base::ASCIIToUTF16("Test Folder")); 312 EXPECT_EQ(2, model_->bookmark_bar_node()->child_count()); 313 Mock::VerifyAndClearExpectations(&observer_); 314 315 EXPECT_CALL(observer_, BookmarkAllUserNodesRemoved(model_.get(), _)); 316 model_->RemoveAllUserBookmarks(); 317 EXPECT_EQ(2, managed_node()->child_count()); 318 EXPECT_EQ(0, model_->bookmark_bar_node()->child_count()); 319 Mock::VerifyAndClearExpectations(&observer_); 320 } 321 322 } // namespace policy 323