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 #include "base/strings/string_number_conversions.h" 6 #include "base/strings/utf_string_conversions.h" 7 #include "content/public/browser/browser_context.h" 8 #include "content/public/browser/download_manager.h" 9 #include "content/public/browser/notification_service.h" 10 #include "content/public/browser/notification_types.h" 11 #include "content/public/browser/web_contents.h" 12 #include "content/public/test/browser_test_utils.h" 13 #include "content/public/test/test_utils.h" 14 #include "content/shell/shell.h" 15 #include "content/test/content_browser_test.h" 16 #include "content/test/content_browser_test_utils.h" 17 #include "content/test/net/url_request_mock_http_job.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 namespace content { 21 22 class DatabaseTest : public ContentBrowserTest { 23 public: 24 DatabaseTest() {} 25 26 void RunScriptAndCheckResult(Shell* shell, 27 const std::string& script, 28 const std::string& result) { 29 std::string data; 30 ASSERT_TRUE(ExecuteScriptAndExtractString( 31 shell->web_contents(), 32 script, 33 &data)); 34 ASSERT_EQ(data, result); 35 } 36 37 void Navigate(Shell* shell) { 38 NavigateToURL(shell, GetTestUrl("", "simple_database.html")); 39 } 40 41 void CreateTable(Shell* shell) { 42 RunScriptAndCheckResult(shell, "createTable()", "done"); 43 } 44 45 void InsertRecord(Shell* shell, const std::string& data) { 46 RunScriptAndCheckResult(shell, "insertRecord('" + data + "')", "done"); 47 } 48 49 void UpdateRecord(Shell* shell, int index, const std::string& data) { 50 RunScriptAndCheckResult( 51 shell, 52 "updateRecord(" + base::IntToString(index) + ", '" + data + "')", 53 "done"); 54 } 55 56 void DeleteRecord(Shell* shell, int index) { 57 RunScriptAndCheckResult( 58 shell, "deleteRecord(" + base::IntToString(index) + ")", "done"); 59 } 60 61 void CompareRecords(Shell* shell, const std::string& expected) { 62 RunScriptAndCheckResult(shell, "getRecords()", expected); 63 } 64 65 bool HasTable(Shell* shell) { 66 std::string data; 67 CHECK(ExecuteScriptAndExtractString( 68 shell->web_contents(), 69 "getRecords()", 70 &data)); 71 return data != "getRecords error: [object SQLError]"; 72 } 73 }; 74 75 // Insert records to the database. 76 IN_PROC_BROWSER_TEST_F(DatabaseTest, InsertRecord) { 77 Navigate(shell()); 78 CreateTable(shell()); 79 InsertRecord(shell(), "text"); 80 CompareRecords(shell(), "text"); 81 InsertRecord(shell(), "text2"); 82 CompareRecords(shell(), "text, text2"); 83 } 84 85 // Update records in the database. 86 IN_PROC_BROWSER_TEST_F(DatabaseTest, UpdateRecord) { 87 Navigate(shell()); 88 CreateTable(shell()); 89 InsertRecord(shell(), "text"); 90 UpdateRecord(shell(), 0, "0"); 91 CompareRecords(shell(), "0"); 92 93 InsertRecord(shell(), "1"); 94 InsertRecord(shell(), "2"); 95 UpdateRecord(shell(), 1, "1000"); 96 CompareRecords(shell(), "0, 1000, 2"); 97 } 98 99 // Delete records in the database. 100 IN_PROC_BROWSER_TEST_F(DatabaseTest, DeleteRecord) { 101 Navigate(shell()); 102 CreateTable(shell()); 103 InsertRecord(shell(), "text"); 104 DeleteRecord(shell(), 0); 105 CompareRecords(shell(), std::string()); 106 107 InsertRecord(shell(), "0"); 108 InsertRecord(shell(), "1"); 109 InsertRecord(shell(), "2"); 110 DeleteRecord(shell(), 1); 111 CompareRecords(shell(), "0, 2"); 112 } 113 114 // Attempts to delete a nonexistent row in the table. 115 IN_PROC_BROWSER_TEST_F(DatabaseTest, DeleteNonexistentRow) { 116 Navigate(shell()); 117 CreateTable(shell()); 118 InsertRecord(shell(), "text"); 119 120 RunScriptAndCheckResult( 121 shell(), "deleteRecord(1)", "could not find row with index: 1"); 122 123 CompareRecords(shell(), "text"); 124 } 125 126 // Insert, update, and delete records in the database. 127 IN_PROC_BROWSER_TEST_F(DatabaseTest, DatabaseOperations) { 128 Navigate(shell()); 129 CreateTable(shell()); 130 131 std::string expected; 132 for (int i = 0; i < 10; ++i) { 133 std::string item = base::IntToString(i); 134 InsertRecord(shell(), item); 135 if (!expected.empty()) 136 expected += ", "; 137 expected += item; 138 } 139 CompareRecords(shell(), expected); 140 141 expected.clear(); 142 for (int i = 0; i < 10; ++i) { 143 std::string item = base::IntToString(i * i); 144 UpdateRecord(shell(), i, item); 145 if (!expected.empty()) 146 expected += ", "; 147 expected += item; 148 } 149 CompareRecords(shell(), expected); 150 151 for (int i = 0; i < 10; ++i) 152 DeleteRecord(shell(), 0); 153 154 CompareRecords(shell(), std::string()); 155 156 RunScriptAndCheckResult( 157 shell(), "deleteRecord(1)", "could not find row with index: 1"); 158 159 CompareRecords(shell(), std::string()); 160 } 161 162 // Create records in the database and verify they persist after reload. 163 IN_PROC_BROWSER_TEST_F(DatabaseTest, ReloadPage) { 164 Navigate(shell()); 165 CreateTable(shell()); 166 InsertRecord(shell(), "text"); 167 168 WindowedNotificationObserver load_stop_observer( 169 NOTIFICATION_LOAD_STOP, 170 NotificationService::AllSources()); 171 shell()->Reload(); 172 load_stop_observer.Wait(); 173 174 CompareRecords(shell(), "text"); 175 } 176 177 // Attempt to read a database created in a regular browser from an off the 178 // record browser. 179 IN_PROC_BROWSER_TEST_F(DatabaseTest, OffTheRecordCannotReadRegularDatabase) { 180 Navigate(shell()); 181 CreateTable(shell()); 182 InsertRecord(shell(), "text"); 183 184 Shell* otr = CreateOffTheRecordBrowser(); 185 Navigate(otr); 186 ASSERT_FALSE(HasTable(otr)); 187 188 CreateTable(otr); 189 CompareRecords(otr, std::string()); 190 } 191 192 // Attempt to read a database created in an off the record browser from a 193 // regular browser. 194 IN_PROC_BROWSER_TEST_F(DatabaseTest, RegularCannotReadOffTheRecordDatabase) { 195 Shell* otr = CreateOffTheRecordBrowser(); 196 Navigate(otr); 197 CreateTable(otr); 198 InsertRecord(otr, "text"); 199 200 Navigate(shell()); 201 ASSERT_FALSE(HasTable(shell())); 202 CreateTable(shell()); 203 CompareRecords(shell(), std::string()); 204 } 205 206 // Verify DB changes within first window are present in the second window. 207 IN_PROC_BROWSER_TEST_F(DatabaseTest, ModificationPersistInSecondTab) { 208 Navigate(shell()); 209 CreateTable(shell()); 210 InsertRecord(shell(), "text"); 211 212 Shell* shell2 = CreateBrowser(); 213 Navigate(shell2); 214 UpdateRecord(shell2, 0, "0"); 215 216 CompareRecords(shell(), "0"); 217 CompareRecords(shell2, "0"); 218 } 219 220 // Verify database modifications persist after restarting browser. 221 IN_PROC_BROWSER_TEST_F(DatabaseTest, PRE_DatabasePersistsAfterRelaunch) { 222 Navigate(shell()); 223 CreateTable(shell()); 224 InsertRecord(shell(), "text"); 225 } 226 227 IN_PROC_BROWSER_TEST_F(DatabaseTest, DatabasePersistsAfterRelaunch) { 228 Navigate(shell()); 229 CompareRecords(shell(), "text"); 230 } 231 232 // Verify OTR database is removed after OTR window closes. 233 IN_PROC_BROWSER_TEST_F(DatabaseTest, PRE_OffTheRecordDatabaseNotPersistent) { 234 Shell* otr = CreateOffTheRecordBrowser(); 235 Navigate(otr); 236 CreateTable(otr); 237 InsertRecord(otr, "text"); 238 } 239 240 IN_PROC_BROWSER_TEST_F(DatabaseTest, OffTheRecordDatabaseNotPersistent) { 241 Shell* otr = CreateOffTheRecordBrowser(); 242 Navigate(otr); 243 ASSERT_FALSE(HasTable(otr)); 244 } 245 246 // Verify database modifications persist after crashing window. 247 IN_PROC_BROWSER_TEST_F(DatabaseTest, ModificationsPersistAfterRendererCrash) { 248 Navigate(shell()); 249 CreateTable(shell()); 250 InsertRecord(shell(), "1"); 251 252 CrashTab(shell()->web_contents()); 253 Navigate(shell()); 254 CompareRecords(shell(), "1"); 255 } 256 257 // Test to check if database modifications are persistent across windows in 258 // off the record window. 259 IN_PROC_BROWSER_TEST_F(DatabaseTest, OffTheRecordDBPersistentAcrossWindows) { 260 Shell* otr1 = CreateOffTheRecordBrowser(); 261 Navigate(otr1); 262 CreateTable(otr1); 263 InsertRecord(otr1, "text"); 264 265 Shell* otr2 = CreateOffTheRecordBrowser(); 266 Navigate(otr2); 267 CompareRecords(otr2, "text"); 268 } 269 270 } // namespace content 271