OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/notifications/notification_database.h" | 5 #include "content/browser/notifications/notification_database.h" |
6 | 6 |
7 #include "base/files/scoped_temp_dir.h" | 7 #include "base/files/scoped_temp_dir.h" |
| 8 #include "base/strings/string_number_conversions.h" |
| 9 #include "base/strings/utf_string_conversions.h" |
| 10 #include "content/browser/notifications/notification_database_data.h" |
| 11 #include "content/public/common/platform_notification_data.h" |
8 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
9 #include "third_party/leveldatabase/src/include/leveldb/db.h" | 13 #include "third_party/leveldatabase/src/include/leveldb/db.h" |
10 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" | 14 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
| 15 #include "url/gurl.h" |
11 | 16 |
12 namespace content { | 17 namespace content { |
13 | 18 |
14 class NotificationDatabaseTest : public ::testing::Test { | 19 class NotificationDatabaseTest : public ::testing::Test { |
15 protected: | 20 protected: |
16 // Creates a new NotificationDatabase instance in memory. | 21 // Creates a new NotificationDatabase instance in memory. |
17 NotificationDatabase* CreateDatabaseInMemory() { | 22 NotificationDatabase* CreateDatabaseInMemory() { |
18 return new NotificationDatabase(base::FilePath()); | 23 return new NotificationDatabase(base::FilePath()); |
19 } | 24 } |
20 | 25 |
(...skipping 15 matching lines...) Expand all Loading... |
36 | 41 |
37 // Writes a LevelDB key-value pair directly to the LevelDB backing the | 42 // Writes a LevelDB key-value pair directly to the LevelDB backing the |
38 // notification database in |database|. | 43 // notification database in |database|. |
39 void WriteLevelDBKeyValuePair(NotificationDatabase* database, | 44 void WriteLevelDBKeyValuePair(NotificationDatabase* database, |
40 const std::string& key, | 45 const std::string& key, |
41 const std::string& value) { | 46 const std::string& value) { |
42 leveldb::Status status = | 47 leveldb::Status status = |
43 database->GetDBForTesting()->Put(leveldb::WriteOptions(), key, value); | 48 database->GetDBForTesting()->Put(leveldb::WriteOptions(), key, value); |
44 ASSERT_TRUE(status.ok()); | 49 ASSERT_TRUE(status.ok()); |
45 } | 50 } |
46 | |
47 // Increments the next notification id value in the database. Normally this | |
48 // is managed by the NotificationDatabase when writing notification data. | |
49 // | |
50 // TODO(peter): Stop doing this manually when writing notification data will | |
51 // do this for us, except for tests verifying corruption behavior. | |
52 void IncrementNextNotificationId(NotificationDatabase* database) { | |
53 int64_t next_notification_id; | |
54 ASSERT_EQ(NotificationDatabase::STATUS_OK, | |
55 database->GetNextNotificationId(&next_notification_id)); | |
56 | |
57 leveldb::WriteBatch batch; | |
58 database->WriteNextNotificationId(&batch, next_notification_id + 1); | |
59 | |
60 leveldb::Status status = | |
61 database->GetDBForTesting()->Write(leveldb::WriteOptions(), &batch); | |
62 | |
63 ASSERT_TRUE(status.ok()); | |
64 } | |
65 }; | 51 }; |
66 | 52 |
67 TEST_F(NotificationDatabaseTest, OpenCloseMemory) { | 53 TEST_F(NotificationDatabaseTest, OpenCloseMemory) { |
68 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); | 54 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
69 | 55 |
70 // Should return false because the database does not exist in memory. | 56 // Should return false because the database does not exist in memory. |
71 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, | 57 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, |
72 database->Open(false /* create_if_missing */)); | 58 database->Open(false /* create_if_missing */)); |
73 | 59 |
74 // Should return true, indicating that the database could be created. | 60 // Should return true, indicating that the database could be created. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 ASSERT_EQ(NotificationDatabase::STATUS_OK, database->Destroy()); | 111 ASSERT_EQ(NotificationDatabase::STATUS_OK, database->Destroy()); |
126 EXPECT_FALSE(IsDatabaseOpen(database.get())); | 112 EXPECT_FALSE(IsDatabaseOpen(database.get())); |
127 | 113 |
128 // Try to re-open the database (but not re-create it). This should fail as | 114 // Try to re-open the database (but not re-create it). This should fail as |
129 // the files associated with the database should have been blown away. | 115 // the files associated with the database should have been blown away. |
130 database.reset(CreateDatabaseOnFileSystem(database_dir.path())); | 116 database.reset(CreateDatabaseOnFileSystem(database_dir.path())); |
131 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, | 117 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, |
132 database->Open(false /* create_if_missing */)); | 118 database->Open(false /* create_if_missing */)); |
133 } | 119 } |
134 | 120 |
135 TEST_F(NotificationDatabaseTest, GetNextNotificationIdIncrements) { | 121 TEST_F(NotificationDatabaseTest, NotificationIdIncrements) { |
136 base::ScopedTempDir database_dir; | 122 base::ScopedTempDir database_dir; |
137 ASSERT_TRUE(database_dir.CreateUniqueTempDir()); | 123 ASSERT_TRUE(database_dir.CreateUniqueTempDir()); |
138 | 124 |
139 scoped_ptr<NotificationDatabase> database( | 125 scoped_ptr<NotificationDatabase> database( |
140 CreateDatabaseOnFileSystem(database_dir.path())); | 126 CreateDatabaseOnFileSystem(database_dir.path())); |
141 | 127 |
142 ASSERT_EQ(NotificationDatabase::STATUS_OK, | 128 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
143 database->Open(true /* create_if_missing */)); | 129 database->Open(true /* create_if_missing */)); |
144 | 130 |
| 131 GURL origin("https://example.com"); |
| 132 |
| 133 NotificationDatabaseData database_data; |
145 int64_t notification_id = 0; | 134 int64_t notification_id = 0; |
146 | 135 |
147 // Verify that getting two ids on the same database instance results in | 136 // Verify that getting two ids on the same database instance results in |
148 // incrementing values. Notification ids will start at 1. | 137 // incrementing values. Notification ids will start at 1. |
149 ASSERT_EQ(NotificationDatabase::STATUS_OK, | 138 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
150 database->GetNextNotificationId(¬ification_id)); | 139 database->WriteNotificationData(origin, |
151 EXPECT_EQ(1, notification_id); | 140 database_data, |
152 | 141 ¬ification_id)); |
153 ASSERT_NO_FATAL_FAILURE(IncrementNextNotificationId(database.get())); | 142 EXPECT_EQ(notification_id, 1); |
154 | 143 |
155 ASSERT_EQ(NotificationDatabase::STATUS_OK, | 144 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
156 database->GetNextNotificationId(¬ification_id)); | 145 database->WriteNotificationData(origin, |
157 EXPECT_EQ(2, notification_id); | 146 database_data, |
158 | 147 ¬ification_id)); |
159 ASSERT_NO_FATAL_FAILURE(IncrementNextNotificationId(database.get())); | 148 EXPECT_EQ(notification_id, 2); |
160 | 149 |
161 database.reset(CreateDatabaseOnFileSystem(database_dir.path())); | 150 database.reset(CreateDatabaseOnFileSystem(database_dir.path())); |
162 ASSERT_EQ(NotificationDatabase::STATUS_OK, | 151 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
163 database->Open(false /* create_if_missing */)); | 152 database->Open(false /* create_if_missing */)); |
164 | 153 |
165 // Verify that the next notification id was stored in the database, and | 154 // Verify that the next notification id was stored in the database, and |
166 // continues where we expect it to be, even after closing and opening it. | 155 // continues where we expect it to be, even after closing and opening it. |
167 ASSERT_EQ(NotificationDatabase::STATUS_OK, | 156 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
168 database->GetNextNotificationId(¬ification_id)); | 157 database->WriteNotificationData(origin, |
169 EXPECT_EQ(3, notification_id); | 158 database_data, |
170 } | 159 ¬ification_id)); |
171 | 160 EXPECT_EQ(notification_id, 3); |
172 TEST_F(NotificationDatabaseTest, GetNextNotificationIdCorruption) { | 161 } |
173 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); | 162 |
174 ASSERT_EQ(NotificationDatabase::STATUS_OK, | 163 TEST_F(NotificationDatabaseTest, NotificationIdCorruption) { |
175 database->Open(true /* create_if_missing */)); | 164 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
176 | 165 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
177 int64_t notification_id = 0; | 166 database->Open(true /* create_if_missing */)); |
178 | 167 |
179 ASSERT_EQ(NotificationDatabase::STATUS_OK, | 168 GURL origin("https://example.com"); |
180 database->GetNextNotificationId(¬ification_id)); | 169 |
181 EXPECT_EQ(1, notification_id); | 170 NotificationDatabaseData database_data; |
| 171 int64_t notification_id = 0; |
| 172 |
| 173 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 174 database->WriteNotificationData(origin, |
| 175 database_data, |
| 176 ¬ification_id)); |
| 177 EXPECT_EQ(notification_id, 1); |
182 | 178 |
183 // Deliberately write an invalid value as the next notification id to the | 179 // Deliberately write an invalid value as the next notification id to the |
184 // database, which should cause GetNextNotificationId to realize that | 180 // database, which should cause GetAndIncrementNextNotificationId to realize |
185 // something is wrong with the data it's reading. | 181 // that something is wrong with the data it's reading. |
186 ASSERT_NO_FATAL_FAILURE(WriteLevelDBKeyValuePair(database.get(), | 182 ASSERT_NO_FATAL_FAILURE(WriteLevelDBKeyValuePair(database.get(), |
187 "NEXT_NOTIFICATION_ID", | 183 "NEXT_NOTIFICATION_ID", |
188 "-42")); | 184 "-42")); |
189 | 185 |
190 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_CORRUPTED, | 186 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_CORRUPTED, |
191 database->GetNextNotificationId(¬ification_id)); | 187 database->WriteNotificationData(origin, |
| 188 database_data, |
| 189 ¬ification_id)); |
| 190 } |
| 191 |
| 192 TEST_F(NotificationDatabaseTest, ReadInvalidNotificationData) { |
| 193 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 194 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 195 database->Open(true /* create_if_missing */)); |
| 196 |
| 197 NotificationDatabaseData database_data; |
| 198 |
| 199 // Reading the notification data for a notification that does not exist should |
| 200 // return the ERROR_NOT_FOUND status code. |
| 201 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, |
| 202 database->ReadNotificationData(9001, |
| 203 GURL("https://chrome.com"), |
| 204 &database_data)); |
| 205 } |
| 206 |
| 207 TEST_F(NotificationDatabaseTest, ReadNotificationDataDifferentOrigin) { |
| 208 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 209 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 210 database->Open(true /* create_if_missing */)); |
| 211 |
| 212 int64_t notification_id = 0; |
| 213 GURL origin("https://example.com"); |
| 214 |
| 215 NotificationDatabaseData database_data, read_database_data; |
| 216 database_data.notification_data.title = base::UTF8ToUTF16("My Notification"); |
| 217 |
| 218 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 219 database->WriteNotificationData(origin, |
| 220 database_data, |
| 221 ¬ification_id)); |
| 222 |
| 223 // Reading the notification from the database when given a different origin |
| 224 // should return the ERROR_NOT_FOUND status code. |
| 225 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, |
| 226 database->ReadNotificationData(notification_id, |
| 227 GURL("https://chrome.com"), |
| 228 &read_database_data)); |
| 229 |
| 230 // However, reading the notification from the database with the same origin |
| 231 // should return STATUS_OK and the associated notification data. |
| 232 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 233 database->ReadNotificationData(notification_id, |
| 234 origin, |
| 235 &read_database_data)); |
| 236 |
| 237 EXPECT_EQ(database_data.notification_data.title, |
| 238 read_database_data.notification_data.title); |
| 239 } |
| 240 |
| 241 TEST_F(NotificationDatabaseTest, ReadNotificationDataReflection) { |
| 242 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 243 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 244 database->Open(true /* create_if_missing */)); |
| 245 |
| 246 int64_t notification_id = 0; |
| 247 |
| 248 GURL origin("https://example.com"); |
| 249 |
| 250 PlatformNotificationData notification_data; |
| 251 notification_data.title = base::UTF8ToUTF16("My Notification"); |
| 252 notification_data.direction = |
| 253 PlatformNotificationData::NotificationDirectionRightToLeft; |
| 254 notification_data.lang = "nl-NL"; |
| 255 notification_data.body = base::UTF8ToUTF16("Hello, world!"); |
| 256 notification_data.tag = "replace id"; |
| 257 notification_data.icon = GURL("https://example.com/icon.png"); |
| 258 notification_data.silent = true; |
| 259 |
| 260 NotificationDatabaseData database_data; |
| 261 database_data.notification_id = notification_id; |
| 262 database_data.origin = origin; |
| 263 database_data.service_worker_registration_id = 42; |
| 264 database_data.notification_data = notification_data; |
| 265 |
| 266 // Write the constructed notification to the database, and then immediately |
| 267 // read it back from the database again as well. |
| 268 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 269 database->WriteNotificationData(origin, |
| 270 database_data, |
| 271 ¬ification_id)); |
| 272 |
| 273 NotificationDatabaseData read_database_data; |
| 274 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 275 database->ReadNotificationData(notification_id, |
| 276 origin, |
| 277 &read_database_data)); |
| 278 |
| 279 // Verify that all members retrieved from the database are exactly the same |
| 280 // as the ones that were written to it. This tests the serialization behavior. |
| 281 |
| 282 EXPECT_EQ(database_data.notification_id, read_database_data.notification_id); |
| 283 EXPECT_EQ(database_data.origin, read_database_data.origin); |
| 284 EXPECT_EQ(database_data.service_worker_registration_id, |
| 285 read_database_data.service_worker_registration_id); |
| 286 |
| 287 const PlatformNotificationData& read_notification_data = |
| 288 read_database_data.notification_data; |
| 289 |
| 290 EXPECT_EQ(notification_data.title, read_notification_data.title); |
| 291 EXPECT_EQ(notification_data.direction, read_notification_data.direction); |
| 292 EXPECT_EQ(notification_data.lang, read_notification_data.lang); |
| 293 EXPECT_EQ(notification_data.body, read_notification_data.body); |
| 294 EXPECT_EQ(notification_data.tag, read_notification_data.tag); |
| 295 EXPECT_EQ(notification_data.icon, read_notification_data.icon); |
| 296 EXPECT_EQ(notification_data.silent, read_notification_data.silent); |
| 297 } |
| 298 |
| 299 TEST_F(NotificationDatabaseTest, ReadWriteMultipleNotificationData) { |
| 300 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 301 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 302 database->Open(true /* create_if_missing */)); |
| 303 |
| 304 NotificationDatabaseData database_data; |
| 305 GURL origin("https://example.com"); |
| 306 |
| 307 // Write ten notifications to the database, each with a unique title and |
| 308 // notification id (it is the responsibility of the user to increment this). |
| 309 for (int i = 1; i <= 10; ++i) { |
| 310 database_data.notification_id = i; |
| 311 database_data.notification_data.title = base::IntToString16(i); |
| 312 |
| 313 int64_t notification_id = 0; |
| 314 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 315 database->WriteNotificationData(origin, |
| 316 database_data, |
| 317 ¬ification_id)); |
| 318 EXPECT_EQ(notification_id, i); |
| 319 } |
| 320 |
| 321 // Read the ten notifications from the database, and verify that the titles |
| 322 // of each of them matches with how they were created. |
| 323 for (int i = 1; i <= 10; ++i) { |
| 324 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 325 database->ReadNotificationData(i /* notification_id */, |
| 326 origin, |
| 327 &database_data)); |
| 328 |
| 329 EXPECT_EQ(base::IntToString16(i), database_data.notification_data.title); |
| 330 } |
| 331 } |
| 332 |
| 333 TEST_F(NotificationDatabaseTest, DeleteInvalidNotificationData) { |
| 334 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 335 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 336 database->Open(true /* create_if_missing */)); |
| 337 |
| 338 // Deleting non-existing notifications should return an error status. |
| 339 ASSERT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, |
| 340 database->DeleteNotificationData(9001, |
| 341 GURL("https://chrome.com"))); |
| 342 } |
| 343 |
| 344 TEST_F(NotificationDatabaseTest, DeleteNotificationDataSameOrigin) { |
| 345 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 346 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 347 database->Open(true /* create_if_missing */)); |
| 348 |
| 349 int64_t notification_id = 0; |
| 350 |
| 351 NotificationDatabaseData database_data; |
| 352 GURL origin("https://example.com"); |
| 353 |
| 354 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 355 database->WriteNotificationData(origin, |
| 356 database_data, |
| 357 ¬ification_id)); |
| 358 |
| 359 // Reading a notification after writing one should succeed. |
| 360 EXPECT_EQ(NotificationDatabase::STATUS_OK, |
| 361 database->ReadNotificationData(notification_id, |
| 362 origin, |
| 363 &database_data)); |
| 364 |
| 365 // Delete the notification which was just written to the database, and verify |
| 366 // that reading it again will fail. |
| 367 EXPECT_EQ(NotificationDatabase::STATUS_OK, |
| 368 database->DeleteNotificationData(notification_id, origin)); |
| 369 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, |
| 370 database->ReadNotificationData(notification_id, |
| 371 origin, |
| 372 &database_data)); |
| 373 } |
| 374 |
| 375 TEST_F(NotificationDatabaseTest, DeleteNotificationDataDifferentOrigin) { |
| 376 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 377 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 378 database->Open(true /* create_if_missing */)); |
| 379 |
| 380 int64_t notification_id = 0; |
| 381 |
| 382 NotificationDatabaseData database_data; |
| 383 database_data.notification_id = notification_id; |
| 384 |
| 385 GURL origin("https://example.com"); |
| 386 |
| 387 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 388 database->WriteNotificationData(origin, |
| 389 database_data, |
| 390 ¬ification_id)); |
| 391 |
| 392 // Attempting to delete the database with a different origin, but with the |
| 393 // same |notification_id|, should return a not found error status code. |
| 394 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, |
| 395 database->DeleteNotificationData(notification_id, |
| 396 GURL("https://chrome.com"))); |
192 } | 397 } |
193 | 398 |
194 } // namespace content | 399 } // namespace content |
OLD | NEW |