1// Copyright (c) 2011 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 "chrome/browser/cookies_tree_model.h"
6
7#include <string>
8
9#include "chrome/browser/content_settings/stub_settings_observer.h"
10#include "chrome/browser/mock_browsing_data_appcache_helper.h"
11#include "chrome/browser/mock_browsing_data_database_helper.h"
12#include "chrome/browser/mock_browsing_data_indexed_db_helper.h"
13#include "chrome/browser/mock_browsing_data_local_storage_helper.h"
14#include "chrome/test/testing_profile.h"
15#include "content/common/notification_details.h"
16#include "content/common/notification_type.h"
17#include "net/url_request/url_request_context.h"
18#include "net/url_request/url_request_context_getter.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21
22namespace {
23
24class CookiesTreeModelTest : public testing::Test {
25 public:
26  CookiesTreeModelTest() : ui_thread_(BrowserThread::UI, &message_loop_),
27                           io_thread_(BrowserThread::IO, &message_loop_) {
28  }
29
30  virtual ~CookiesTreeModelTest() {
31  }
32
33  virtual void SetUp() {
34    profile_.reset(new TestingProfile());
35    profile_->CreateRequestContext();
36    mock_browsing_data_database_helper_ =
37      new MockBrowsingDataDatabaseHelper(profile_.get());
38    mock_browsing_data_local_storage_helper_ =
39      new MockBrowsingDataLocalStorageHelper(profile_.get());
40    mock_browsing_data_session_storage_helper_ =
41      new MockBrowsingDataLocalStorageHelper(profile_.get());
42    mock_browsing_data_appcache_helper_ =
43      new MockBrowsingDataAppCacheHelper(profile_.get());
44    mock_browsing_data_indexed_db_helper_ =
45      new MockBrowsingDataIndexedDBHelper(profile_.get());
46  }
47
48  CookiesTreeModel* CreateCookiesTreeModelWithInitialSample() {
49    net::CookieMonster* monster = profile_->GetCookieMonster();
50    monster->SetCookie(GURL("http://foo1"), "A=1");
51    monster->SetCookie(GURL("http://foo2"), "B=1");
52    monster->SetCookie(GURL("http://foo3"), "C=1");
53    CookiesTreeModel* cookies_model = new CookiesTreeModel(
54        monster, mock_browsing_data_database_helper_,
55        mock_browsing_data_local_storage_helper_,
56        mock_browsing_data_session_storage_helper_,
57        mock_browsing_data_appcache_helper_,
58        mock_browsing_data_indexed_db_helper_,
59        false);
60    mock_browsing_data_database_helper_->AddDatabaseSamples();
61    mock_browsing_data_database_helper_->Notify();
62    mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
63    mock_browsing_data_local_storage_helper_->Notify();
64    mock_browsing_data_session_storage_helper_->AddLocalStorageSamples();
65    mock_browsing_data_session_storage_helper_->Notify();
66    mock_browsing_data_indexed_db_helper_->AddIndexedDBSamples();
67    mock_browsing_data_indexed_db_helper_->Notify();
68    {
69      SCOPED_TRACE("Initial State 3 cookies, 2 databases, 2 local storages, "
70                   "2 session storages, 2 indexed DBs");
71      // 32 because there's the root, then foo1 -> cookies -> a,
72      // foo2 -> cookies -> b, foo3 -> cookies -> c,
73      // dbhost1 -> database -> db1, dbhost2 -> database -> db2,
74      // host1 -> localstorage -> http://host1:1/,
75      // host2 -> localstorage -> http://host2:2/.
76      // host1 -> sessionstorage -> http://host1:1/,
77      // host2 -> sessionstorage -> http://host2:2/,
78      // idbhost1 -> indexeddb -> http://idbhost1:1/,
79      // idbhost2 -> indexeddb -> http://idbhost2:2/.
80      EXPECT_EQ(32, cookies_model->GetRoot()->GetTotalNodeCount());
81      EXPECT_EQ("db1,db2", GetDisplayedDatabases(cookies_model));
82      EXPECT_EQ("http://host1:1/,http://host2:2/",
83                GetDisplayedLocalStorages(cookies_model));
84      EXPECT_EQ("http://host1:1/,http://host2:2/",
85                GetDisplayedSessionStorages(cookies_model));
86      EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
87                GetDisplayedIndexedDBs(cookies_model));
88    }
89    return cookies_model;
90  }
91
92  // Get the cookie names in the cookie list, as a comma seperated string.
93  // (Note that the CookieMonster cookie list is sorted by domain.)
94  // Ex:
95  //   monster->SetCookie(GURL("http://b"), "X=1")
96  //   monster->SetCookie(GURL("http://a"), "Y=1")
97  //   EXPECT_STREQ("Y,X", GetMonsterCookies(monster).c_str());
98  std::string GetMonsterCookies(net::CookieMonster* monster) {
99    std::vector<std::string> parts;
100    net::CookieList cookie_list = monster->GetAllCookies();
101    for (size_t i = 0; i < cookie_list.size(); ++i)
102      parts.push_back(cookie_list[i].Name());
103    return JoinString(parts, ',');
104  }
105
106  std::string GetNodesOfChildren(
107      const CookieTreeNode* node,
108      CookieTreeNode::DetailedInfo::NodeType node_type) {
109    if (node->child_count()) {
110      std::string retval;
111      for (int i = 0; i < node->child_count(); ++i) {
112        retval += GetNodesOfChildren(node->GetChild(i), node_type);
113      }
114      return retval;
115    } else {
116      if (node->GetDetailedInfo().node_type == node_type) {
117        switch (node_type) {
118          case CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE:
119            return node->GetDetailedInfo().session_storage_info->origin + ",";
120          case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE:
121            return node->GetDetailedInfo().local_storage_info->origin + ",";
122          case CookieTreeNode::DetailedInfo::TYPE_DATABASE:
123            return node->GetDetailedInfo().database_info->database_name + ",";
124          case CookieTreeNode::DetailedInfo::TYPE_COOKIE:
125            return node->GetDetailedInfo().cookie->Name() + ",";
126          case CookieTreeNode::DetailedInfo::TYPE_APPCACHE:
127            return node->GetDetailedInfo().appcache_info->manifest_url.spec() +
128                   ",";
129          case CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB:
130            return node->GetDetailedInfo().indexed_db_info->origin + ",";
131          default:
132            return "";
133        }
134      } else {
135        return "";
136      }
137    }
138  }
139
140  std::string GetCookiesOfChildren(const CookieTreeNode* node) {
141    return GetNodesOfChildren(node, CookieTreeNode::DetailedInfo::TYPE_COOKIE);
142  }
143
144  std::string GetDatabasesOfChildren(const CookieTreeNode* node) {
145    return GetNodesOfChildren(node,
146                              CookieTreeNode::DetailedInfo::TYPE_DATABASE);
147  }
148
149  std::string GetLocalStoragesOfChildren(const CookieTreeNode* node) {
150    return GetNodesOfChildren(node,
151                              CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE);
152  }
153
154  std::string GetSessionStoragesOfChildren(const CookieTreeNode* node) {
155    return GetNodesOfChildren(
156        node, CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE);
157  }
158
159  std::string GetIndexedDBsOfChildren(const CookieTreeNode* node) {
160    return GetNodesOfChildren(
161        node, CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB);
162  }
163
164  // Get the nodes names displayed in the view (if we had one) in the order
165  // they are displayed, as a comma seperated string.
166  // Ex: EXPECT_STREQ("X,Y", GetDisplayedNodes(cookies_view, type).c_str());
167  std::string GetDisplayedNodes(CookiesTreeModel* cookies_model,
168                                CookieTreeNode::DetailedInfo::NodeType type) {
169    CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(
170        cookies_model->GetRoot());
171    std::string retval = GetNodesOfChildren(root, type);
172    if (retval.length() && retval[retval.length() - 1] == ',')
173      retval.erase(retval.length() - 1);
174    return retval;
175  }
176
177  std::string GetDisplayedCookies(CookiesTreeModel* cookies_model) {
178    return GetDisplayedNodes(cookies_model,
179                             CookieTreeNode::DetailedInfo::TYPE_COOKIE);
180  }
181
182  std::string GetDisplayedDatabases(CookiesTreeModel* cookies_model) {
183    return GetDisplayedNodes(cookies_model,
184                             CookieTreeNode::DetailedInfo::TYPE_DATABASE);
185  }
186
187  std::string GetDisplayedLocalStorages(CookiesTreeModel* cookies_model) {
188    return GetDisplayedNodes(cookies_model,
189                             CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE);
190  }
191
192  std::string GetDisplayedSessionStorages(CookiesTreeModel* cookies_model) {
193    return GetDisplayedNodes(
194        cookies_model, CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE);
195  }
196
197  std::string GetDisplayedAppCaches(CookiesTreeModel* cookies_model) {
198    return GetDisplayedNodes(cookies_model,
199                             CookieTreeNode::DetailedInfo::TYPE_APPCACHE);
200  }
201
202  std::string GetDisplayedIndexedDBs(CookiesTreeModel* cookies_model) {
203    return GetDisplayedNodes(cookies_model,
204                             CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB);
205  }
206
207  // Do not call on the root.
208  void DeleteStoredObjects(CookieTreeNode* node) {
209    node->DeleteStoredObjects();
210    CookieTreeNode* parent_node = node->parent();
211    DCHECK(parent_node);
212    delete parent_node->GetModel()->Remove(parent_node, node);
213  }
214
215 protected:
216  MessageLoop message_loop_;
217  BrowserThread ui_thread_;
218  BrowserThread io_thread_;
219
220  scoped_ptr<TestingProfile> profile_;
221  scoped_refptr<MockBrowsingDataDatabaseHelper>
222      mock_browsing_data_database_helper_;
223  scoped_refptr<MockBrowsingDataLocalStorageHelper>
224      mock_browsing_data_local_storage_helper_;
225  scoped_refptr<MockBrowsingDataLocalStorageHelper>
226      mock_browsing_data_session_storage_helper_;
227  scoped_refptr<MockBrowsingDataAppCacheHelper>
228      mock_browsing_data_appcache_helper_;
229  scoped_refptr<MockBrowsingDataIndexedDBHelper>
230      mock_browsing_data_indexed_db_helper_;
231};
232
233TEST_F(CookiesTreeModelTest, RemoveAll) {
234  scoped_ptr<CookiesTreeModel> cookies_model(
235      CreateCookiesTreeModelWithInitialSample());
236  net::CookieMonster* monster = profile_->GetCookieMonster();
237
238  // Reset the selection of the first row.
239  {
240    SCOPED_TRACE("Before removing");
241    EXPECT_EQ(GetMonsterCookies(monster),
242              GetDisplayedCookies(cookies_model.get()));
243    EXPECT_EQ("db1,db2",
244              GetDisplayedDatabases(cookies_model.get()));
245    EXPECT_EQ("http://host1:1/,http://host2:2/",
246              GetDisplayedLocalStorages(cookies_model.get()));
247    EXPECT_EQ("http://host1:1/,http://host2:2/",
248              GetDisplayedSessionStorages(cookies_model.get()));
249    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
250              GetDisplayedIndexedDBs(cookies_model.get()));
251  }
252
253  mock_browsing_data_database_helper_->Reset();
254  mock_browsing_data_local_storage_helper_->Reset();
255  mock_browsing_data_session_storage_helper_->Reset();
256  mock_browsing_data_indexed_db_helper_->Reset();
257
258  cookies_model->DeleteAllStoredObjects();
259
260  {
261    SCOPED_TRACE("After removing");
262    EXPECT_EQ(1, cookies_model->GetRoot()->GetTotalNodeCount());
263    EXPECT_EQ(0, cookies_model->GetRoot()->child_count());
264    EXPECT_EQ(std::string(""), GetMonsterCookies(monster));
265    EXPECT_EQ(GetMonsterCookies(monster),
266              GetDisplayedCookies(cookies_model.get()));
267    EXPECT_TRUE(mock_browsing_data_database_helper_->AllDeleted());
268    EXPECT_TRUE(mock_browsing_data_local_storage_helper_->AllDeleted());
269    EXPECT_FALSE(mock_browsing_data_session_storage_helper_->AllDeleted());
270    EXPECT_TRUE(mock_browsing_data_indexed_db_helper_->AllDeleted());
271  }
272}
273
274TEST_F(CookiesTreeModelTest, Remove) {
275  scoped_ptr<CookiesTreeModel> cookies_model(
276      CreateCookiesTreeModelWithInitialSample());
277  net::CookieMonster* monster = profile_->GetCookieMonster();
278
279  DeleteStoredObjects(cookies_model->GetRoot()->GetChild(0));
280  {
281    SCOPED_TRACE("First cookie origin removed");
282    EXPECT_STREQ("B,C", GetMonsterCookies(monster).c_str());
283    EXPECT_STREQ("B,C", GetDisplayedCookies(cookies_model.get()).c_str());
284    EXPECT_EQ("db1,db2", GetDisplayedDatabases(cookies_model.get()));
285    EXPECT_EQ("http://host1:1/,http://host2:2/",
286              GetDisplayedLocalStorages(cookies_model.get()));
287    EXPECT_EQ("http://host1:1/,http://host2:2/",
288              GetDisplayedSessionStorages(cookies_model.get()));
289    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
290              GetDisplayedIndexedDBs(cookies_model.get()));
291    EXPECT_EQ(29, cookies_model->GetRoot()->GetTotalNodeCount());
292  }
293
294  DeleteStoredObjects(cookies_model->GetRoot()->GetChild(2));
295  {
296    SCOPED_TRACE("First database origin removed");
297    EXPECT_STREQ("B,C", GetMonsterCookies(monster).c_str());
298    EXPECT_STREQ("B,C", GetDisplayedCookies(cookies_model.get()).c_str());
299    EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
300    EXPECT_EQ("http://host1:1/,http://host2:2/",
301              GetDisplayedLocalStorages(cookies_model.get()));
302    EXPECT_EQ("http://host1:1/,http://host2:2/",
303              GetDisplayedSessionStorages(cookies_model.get()));
304    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
305              GetDisplayedIndexedDBs(cookies_model.get()));
306    EXPECT_EQ(26, cookies_model->GetRoot()->GetTotalNodeCount());
307  }
308
309  DeleteStoredObjects(cookies_model->GetRoot()->GetChild(3));
310  {
311    SCOPED_TRACE("First local storage origin removed");
312    EXPECT_STREQ("B,C", GetMonsterCookies(monster).c_str());
313    EXPECT_STREQ("B,C", GetDisplayedCookies(cookies_model.get()).c_str());
314    EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
315    EXPECT_EQ("http://host2:2/",
316              GetDisplayedLocalStorages(cookies_model.get()));
317    EXPECT_EQ("http://host2:2/",
318              GetDisplayedSessionStorages(cookies_model.get()));
319    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
320              GetDisplayedIndexedDBs(cookies_model.get()));
321    EXPECT_EQ(21, cookies_model->GetRoot()->GetTotalNodeCount());
322  }
323
324  DeleteStoredObjects(cookies_model->GetRoot()->GetChild(4));
325  {
326    SCOPED_TRACE("First IndexedDB origin removed");
327    EXPECT_STREQ("B,C", GetMonsterCookies(monster).c_str());
328    EXPECT_STREQ("B,C", GetDisplayedCookies(cookies_model.get()).c_str());
329    EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
330    EXPECT_EQ("http://host2:2/",
331              GetDisplayedLocalStorages(cookies_model.get()));
332    EXPECT_EQ("http://host2:2/",
333              GetDisplayedSessionStorages(cookies_model.get()));
334    EXPECT_EQ("http://idbhost2:2/",
335              GetDisplayedIndexedDBs(cookies_model.get()));
336    EXPECT_EQ(18, cookies_model->GetRoot()->GetTotalNodeCount());
337  }
338}
339
340TEST_F(CookiesTreeModelTest, RemoveCookiesNode) {
341  scoped_ptr<CookiesTreeModel> cookies_model(
342      CreateCookiesTreeModelWithInitialSample());
343  net::CookieMonster* monster = profile_->GetCookieMonster();
344
345  DeleteStoredObjects(cookies_model->GetRoot()->GetChild(0)->GetChild(0));
346  {
347    SCOPED_TRACE("First origin removed");
348    EXPECT_STREQ("B,C", GetMonsterCookies(monster).c_str());
349    EXPECT_STREQ("B,C", GetDisplayedCookies(cookies_model.get()).c_str());
350    // 28 because in this case, the origin remains, although the COOKIES
351    // node beneath it has been deleted. So, we have
352    // root -> foo1 -> cookies -> a, foo2, foo3 -> cookies -> c
353    // dbhost1 -> database -> db1, dbhost2 -> database -> db2,
354    // host1 -> localstorage -> http://host1:1/,
355    // host2 -> localstorage -> http://host2:2/,
356    // idbhost1 -> sessionstorage -> http://idbhost1:1/,
357    // idbhost2 -> sessionstorage -> http://idbhost2:2/.
358    EXPECT_EQ(30, cookies_model->GetRoot()->GetTotalNodeCount());
359    EXPECT_EQ("db1,db2", GetDisplayedDatabases(cookies_model.get()));
360    EXPECT_EQ("http://host1:1/,http://host2:2/",
361              GetDisplayedLocalStorages(cookies_model.get()));
362    EXPECT_EQ("http://host1:1/,http://host2:2/",
363              GetDisplayedSessionStorages(cookies_model.get()));
364    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
365              GetDisplayedIndexedDBs(cookies_model.get()));
366  }
367
368  DeleteStoredObjects(cookies_model->GetRoot()->GetChild(3)->GetChild(0));
369  {
370    SCOPED_TRACE("First database removed");
371    EXPECT_STREQ("B,C", GetMonsterCookies(monster).c_str());
372    EXPECT_STREQ("B,C", GetDisplayedCookies(cookies_model.get()).c_str());
373    EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
374    EXPECT_EQ("http://host1:1/,http://host2:2/",
375              GetDisplayedLocalStorages(cookies_model.get()));
376    EXPECT_EQ("http://host1:1/,http://host2:2/",
377              GetDisplayedSessionStorages(cookies_model.get()));
378    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
379              GetDisplayedIndexedDBs(cookies_model.get()));
380    EXPECT_EQ(28, cookies_model->GetRoot()->GetTotalNodeCount());
381  }
382
383  DeleteStoredObjects(cookies_model->GetRoot()->GetChild(5)->GetChild(0));
384  {
385    SCOPED_TRACE("First origin removed");
386    EXPECT_STREQ("B,C", GetMonsterCookies(monster).c_str());
387    EXPECT_STREQ("B,C", GetDisplayedCookies(cookies_model.get()).c_str());
388    EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
389    EXPECT_EQ("http://host2:2/",
390              GetDisplayedLocalStorages(cookies_model.get()));
391    EXPECT_EQ("http://host1:1/,http://host2:2/",
392              GetDisplayedSessionStorages(cookies_model.get()));
393    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
394              GetDisplayedIndexedDBs(cookies_model.get()));
395    EXPECT_EQ(26, cookies_model->GetRoot()->GetTotalNodeCount());
396  }
397}
398
399TEST_F(CookiesTreeModelTest, RemoveCookieNode) {
400  scoped_ptr<CookiesTreeModel> cookies_model(
401      CreateCookiesTreeModelWithInitialSample());
402  net::CookieMonster* monster = profile_->GetCookieMonster();
403
404  DeleteStoredObjects(cookies_model->GetRoot()->GetChild(1)->GetChild(0));
405  {
406    SCOPED_TRACE("Second origin COOKIES node removed");
407    EXPECT_STREQ("A,C", GetMonsterCookies(monster).c_str());
408    EXPECT_STREQ("A,C", GetDisplayedCookies(cookies_model.get()).c_str());
409    EXPECT_EQ("db1,db2", GetDisplayedDatabases(cookies_model.get()));
410    EXPECT_EQ("http://host1:1/,http://host2:2/",
411              GetDisplayedLocalStorages(cookies_model.get()));
412    EXPECT_EQ("http://host1:1/,http://host2:2/",
413              GetDisplayedSessionStorages(cookies_model.get()));
414    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
415              GetDisplayedIndexedDBs(cookies_model.get()));
416    // 28 because in this case, the origin remains, although the COOKIES
417    // node beneath it has been deleted. So, we have
418    // root -> foo1 -> cookies -> a, foo2, foo3 -> cookies -> c
419    // dbhost1 -> database -> db1, dbhost2 -> database -> db2,
420    // host1 -> localstorage -> http://host1:1/,
421    // host2 -> localstorage -> http://host2:2/.
422    // host1 -> sessionstorage -> http://host1:1/,
423    // host2 -> sessionstorage -> http://host2:2/,
424    // idbhost1 -> sessionstorage -> http://idbhost1:1/,
425    // idbhost2 -> sessionstorage -> http://idbhost2:2/.
426    EXPECT_EQ(30, cookies_model->GetRoot()->GetTotalNodeCount());
427  }
428
429  DeleteStoredObjects(cookies_model->GetRoot()->GetChild(3)->GetChild(0));
430  {
431    SCOPED_TRACE("First database removed");
432    EXPECT_STREQ("A,C", GetMonsterCookies(monster).c_str());
433    EXPECT_STREQ("A,C", GetDisplayedCookies(cookies_model.get()).c_str());
434    EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
435    EXPECT_EQ("http://host1:1/,http://host2:2/",
436              GetDisplayedLocalStorages(cookies_model.get()));
437    EXPECT_EQ("http://host1:1/,http://host2:2/",
438              GetDisplayedSessionStorages(cookies_model.get()));
439    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
440              GetDisplayedIndexedDBs(cookies_model.get()));
441    EXPECT_EQ(28, cookies_model->GetRoot()->GetTotalNodeCount());
442  }
443
444  DeleteStoredObjects(cookies_model->GetRoot()->GetChild(5)->GetChild(0));
445  {
446    SCOPED_TRACE("First origin removed");
447    EXPECT_STREQ("A,C", GetMonsterCookies(monster).c_str());
448    EXPECT_STREQ("A,C", GetDisplayedCookies(cookies_model.get()).c_str());
449    EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
450    EXPECT_EQ("http://host2:2/",
451              GetDisplayedLocalStorages(cookies_model.get()));
452    EXPECT_EQ("http://host1:1/,http://host2:2/",
453              GetDisplayedSessionStorages(cookies_model.get()));
454    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
455              GetDisplayedIndexedDBs(cookies_model.get()));
456    EXPECT_EQ(26, cookies_model->GetRoot()->GetTotalNodeCount());
457  }
458}
459
460TEST_F(CookiesTreeModelTest, RemoveSingleCookieNode) {
461  net::CookieMonster* monster = profile_->GetCookieMonster();
462  monster->SetCookie(GURL("http://foo1"), "A=1");
463  monster->SetCookie(GURL("http://foo2"), "B=1");
464  monster->SetCookie(GURL("http://foo3"), "C=1");
465  monster->SetCookie(GURL("http://foo3"), "D=1");
466  CookiesTreeModel cookies_model(monster,
467                                 mock_browsing_data_database_helper_,
468                                 mock_browsing_data_local_storage_helper_,
469                                 mock_browsing_data_session_storage_helper_,
470                                 mock_browsing_data_appcache_helper_,
471                                 mock_browsing_data_indexed_db_helper_,
472                                 false);
473  mock_browsing_data_database_helper_->AddDatabaseSamples();
474  mock_browsing_data_database_helper_->Notify();
475  mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
476  mock_browsing_data_local_storage_helper_->Notify();
477  mock_browsing_data_session_storage_helper_->AddLocalStorageSamples();
478  mock_browsing_data_session_storage_helper_->Notify();
479  mock_browsing_data_indexed_db_helper_->AddIndexedDBSamples();
480  mock_browsing_data_indexed_db_helper_->Notify();
481
482  {
483    SCOPED_TRACE("Initial State 4 cookies, 2 databases, 2 local storages, "
484        "2 session storages, 2 indexed DBs");
485    // 33 because there's the root, then foo1 -> cookies -> a,
486    // foo2 -> cookies -> b, foo3 -> cookies -> c,d
487    // dbhost1 -> database -> db1, dbhost2 -> database -> db2,
488    // host1 -> localstorage -> http://host1:1/,
489    // host2 -> localstorage -> http://host2:2/.
490    // host1 -> sessionstorage -> http://host1:1/,
491    // host2 -> sessionstorage -> http://host2:2/,
492    // idbhost1 -> sessionstorage -> http://idbhost1:1/,
493    // idbhost2 -> sessionstorage -> http://idbhost2:2/.
494    EXPECT_EQ(33, cookies_model.GetRoot()->GetTotalNodeCount());
495    EXPECT_STREQ("A,B,C,D", GetMonsterCookies(monster).c_str());
496    EXPECT_STREQ("A,B,C,D", GetDisplayedCookies(&cookies_model).c_str());
497    EXPECT_EQ("db1,db2", GetDisplayedDatabases(&cookies_model));
498    EXPECT_EQ("http://host1:1/,http://host2:2/",
499              GetDisplayedLocalStorages(&cookies_model));
500    EXPECT_EQ("http://host1:1/,http://host2:2/",
501              GetDisplayedSessionStorages(&cookies_model));
502    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
503              GetDisplayedIndexedDBs(&cookies_model));
504  }
505  DeleteStoredObjects(cookies_model.GetRoot()->GetChild(2));
506  {
507    SCOPED_TRACE("Third origin removed");
508    EXPECT_STREQ("A,B", GetMonsterCookies(monster).c_str());
509    EXPECT_STREQ("A,B", GetDisplayedCookies(&cookies_model).c_str());
510    EXPECT_EQ("db1,db2", GetDisplayedDatabases(&cookies_model));
511    EXPECT_EQ("http://host1:1/,http://host2:2/",
512              GetDisplayedLocalStorages(&cookies_model));
513    EXPECT_EQ("http://host1:1/,http://host2:2/",
514              GetDisplayedSessionStorages(&cookies_model));
515    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
516              GetDisplayedIndexedDBs(&cookies_model));
517    EXPECT_EQ(29, cookies_model.GetRoot()->GetTotalNodeCount());
518  }
519}
520
521TEST_F(CookiesTreeModelTest, RemoveSingleCookieNodeOf3) {
522  net::CookieMonster* monster = profile_->GetCookieMonster();
523  monster->SetCookie(GURL("http://foo1"), "A=1");
524  monster->SetCookie(GURL("http://foo2"), "B=1");
525  monster->SetCookie(GURL("http://foo3"), "C=1");
526  monster->SetCookie(GURL("http://foo3"), "D=1");
527  monster->SetCookie(GURL("http://foo3"), "E=1");
528  CookiesTreeModel cookies_model(monster,
529                                 mock_browsing_data_database_helper_,
530                                 mock_browsing_data_local_storage_helper_,
531                                 mock_browsing_data_session_storage_helper_,
532                                 mock_browsing_data_appcache_helper_,
533                                 mock_browsing_data_indexed_db_helper_,
534                                 false);
535  mock_browsing_data_database_helper_->AddDatabaseSamples();
536  mock_browsing_data_database_helper_->Notify();
537  mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
538  mock_browsing_data_local_storage_helper_->Notify();
539  mock_browsing_data_session_storage_helper_->AddLocalStorageSamples();
540  mock_browsing_data_session_storage_helper_->Notify();
541  mock_browsing_data_indexed_db_helper_->AddIndexedDBSamples();
542  mock_browsing_data_indexed_db_helper_->Notify();
543
544  {
545    SCOPED_TRACE("Initial State 5 cookies, 2 databases, 2 local storages, "
546                 "2 session storages, 2 indexed DBs");
547    // 34 because there's the root, then foo1 -> cookies -> a,
548    // foo2 -> cookies -> b, foo3 -> cookies -> c,d,e
549    // dbhost1 -> database -> db1, dbhost2 -> database -> db2,
550    // host1 -> localstorage -> http://host1:1/,
551    // host2 -> localstorage -> http://host2:2/.
552    // host1 -> sessionstorage -> http://host1:1/,
553    // host2 -> sessionstorage -> http://host2:2/,
554    // idbhost1 -> sessionstorage -> http://idbhost1:1/,
555    // idbhost2 -> sessionstorage -> http://idbhost2:2/.
556    EXPECT_EQ(34, cookies_model.GetRoot()->GetTotalNodeCount());
557    EXPECT_STREQ("A,B,C,D,E", GetMonsterCookies(monster).c_str());
558    EXPECT_STREQ("A,B,C,D,E", GetDisplayedCookies(&cookies_model).c_str());
559    EXPECT_EQ("db1,db2", GetDisplayedDatabases(&cookies_model));
560    EXPECT_EQ("http://host1:1/,http://host2:2/",
561              GetDisplayedLocalStorages(&cookies_model));
562    EXPECT_EQ("http://host1:1/,http://host2:2/",
563              GetDisplayedSessionStorages(&cookies_model));
564    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
565              GetDisplayedIndexedDBs(&cookies_model));
566  }
567  DeleteStoredObjects(cookies_model.GetRoot()->GetChild(2)->GetChild(0)->
568      GetChild(1));
569  {
570    SCOPED_TRACE("Middle cookie in third origin removed");
571    EXPECT_STREQ("A,B,C,E", GetMonsterCookies(monster).c_str());
572    EXPECT_STREQ("A,B,C,E", GetDisplayedCookies(&cookies_model).c_str());
573    EXPECT_EQ(33, cookies_model.GetRoot()->GetTotalNodeCount());
574    EXPECT_EQ("db1,db2", GetDisplayedDatabases(&cookies_model));
575    EXPECT_EQ("http://host1:1/,http://host2:2/",
576              GetDisplayedLocalStorages(&cookies_model));
577    EXPECT_EQ("http://host1:1/,http://host2:2/",
578              GetDisplayedSessionStorages(&cookies_model));
579    EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
580              GetDisplayedIndexedDBs(&cookies_model));
581  }
582}
583
584TEST_F(CookiesTreeModelTest, RemoveSecondOrigin) {
585  net::CookieMonster* monster = profile_->GetCookieMonster();
586  monster->SetCookie(GURL("http://foo1"), "A=1");
587  monster->SetCookie(GURL("http://foo2"), "B=1");
588  monster->SetCookie(GURL("http://foo3"), "C=1");
589  monster->SetCookie(GURL("http://foo3"), "D=1");
590  monster->SetCookie(GURL("http://foo3"), "E=1");
591  CookiesTreeModel cookies_model(monster,
592                                 mock_browsing_data_database_helper_,
593                                 mock_browsing_data_local_storage_helper_,
594                                 mock_browsing_data_session_storage_helper_,
595                                 mock_browsing_data_appcache_helper_,
596                                 mock_browsing_data_indexed_db_helper_,
597                                 false);
598  {
599    SCOPED_TRACE("Initial State 5 cookies");
600    // 11 because there's the root, then foo1 -> cookies -> a,
601    // foo2 -> cookies -> b, foo3 -> cookies -> c,d,e
602    EXPECT_EQ(12, cookies_model.GetRoot()->GetTotalNodeCount());
603    EXPECT_STREQ("A,B,C,D,E", GetMonsterCookies(monster).c_str());
604    EXPECT_STREQ("A,B,C,D,E", GetDisplayedCookies(&cookies_model).c_str());
605  }
606  DeleteStoredObjects(cookies_model.GetRoot()->GetChild(1));
607  {
608    SCOPED_TRACE("Second origin removed");
609    EXPECT_STREQ("A,C,D,E", GetMonsterCookies(monster).c_str());
610    EXPECT_STREQ("A,C,D,E", GetDisplayedCookies(&cookies_model).c_str());
611    // Left with root -> foo1 -> cookies -> a, foo3 -> cookies -> c,d,e
612    EXPECT_EQ(9, cookies_model.GetRoot()->GetTotalNodeCount());
613  }
614}
615
616TEST_F(CookiesTreeModelTest, OriginOrdering) {
617  net::CookieMonster* monster = profile_->GetCookieMonster();
618  monster->SetCookie(GURL("http://a.foo2.com"), "A=1");
619  monster->SetCookie(GURL("http://foo2.com"), "B=1");
620  monster->SetCookie(GURL("http://b.foo1.com"), "C=1");
621  monster->SetCookie(GURL("http://foo4.com"), "D=1; domain=.foo4.com;"
622      " path=/;");  // Leading dot on the foo4
623  monster->SetCookie(GURL("http://a.foo1.com"), "E=1");
624  monster->SetCookie(GURL("http://foo1.com"), "F=1");
625  monster->SetCookie(GURL("http://foo3.com"), "G=1");
626  monster->SetCookie(GURL("http://foo4.com"), "H=1");
627
628  CookiesTreeModel cookies_model(monster,
629      new MockBrowsingDataDatabaseHelper(profile_.get()),
630      new MockBrowsingDataLocalStorageHelper(profile_.get()),
631      new MockBrowsingDataLocalStorageHelper(profile_.get()),
632      new MockBrowsingDataAppCacheHelper(profile_.get()),
633      new MockBrowsingDataIndexedDBHelper(profile_.get()),
634      false);
635
636  {
637    SCOPED_TRACE("Initial State 8 cookies");
638    // CookieMonster orders cookies by pathlength, then by creation time.
639    // All paths are length 1.
640    EXPECT_STREQ("A,B,C,D,E,F,G,H", GetMonsterCookies(monster).c_str());
641    EXPECT_STREQ("F,E,C,B,A,G,D,H",
642        GetDisplayedCookies(&cookies_model).c_str());
643  }
644  DeleteStoredObjects(cookies_model.GetRoot()->GetChild(1));  // Delete "E"
645  {
646    EXPECT_STREQ("A,B,C,D,F,G,H", GetMonsterCookies(monster).c_str());
647    EXPECT_STREQ("F,C,B,A,G,D,H", GetDisplayedCookies(&cookies_model).c_str());
648  }
649}
650
651TEST_F(CookiesTreeModelTest, ContentSettings) {
652  GURL host("http://example.com/");
653  ContentSettingsPattern pattern("[*.]example.com");
654  net::CookieMonster* monster = profile_->GetCookieMonster();
655  monster->SetCookie(host, "A=1");
656
657  CookiesTreeModel cookies_model(monster,
658      new MockBrowsingDataDatabaseHelper(profile_.get()),
659      new MockBrowsingDataLocalStorageHelper(profile_.get()),
660      new MockBrowsingDataLocalStorageHelper(profile_.get()),
661      new MockBrowsingDataAppCacheHelper(profile_.get()),
662      new MockBrowsingDataIndexedDBHelper(profile_.get()),
663      false);
664
665  TestingProfile profile;
666  HostContentSettingsMap* content_settings =
667      profile.GetHostContentSettingsMap();
668  StubSettingsObserver observer;
669
670  CookieTreeRootNode* root =
671      static_cast<CookieTreeRootNode*>(cookies_model.GetRoot());
672  CookieTreeOriginNode* origin = root->GetOrCreateOriginNode(host);
673
674  EXPECT_EQ(1, origin->child_count());
675  EXPECT_TRUE(origin->CanCreateContentException());
676  origin->CreateContentException(
677      content_settings, CONTENT_SETTING_SESSION_ONLY);
678
679  EXPECT_EQ(2, observer.counter);
680  EXPECT_EQ(pattern, observer.last_pattern);
681  EXPECT_EQ(CONTENT_SETTING_SESSION_ONLY,
682      content_settings->GetContentSetting(
683          host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
684}
685
686}  // namespace
687