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