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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 TEST_F(NotificationDatabaseTest, GetNextNotificationIdIncrements) { | 121 TEST_F(NotificationDatabaseTest, GetNextNotificationIdIncrements) { |
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->GetNextNotificationId(¬ification_id)); |
151 EXPECT_EQ(1, notification_id); | 140 EXPECT_EQ(1, notification_id); |
152 | 141 |
153 ASSERT_NO_FATAL_FAILURE(IncrementNextNotificationId(database.get())); | 142 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 143 database->WriteNotificationData(notification_id, |
| 144 origin, |
| 145 database_data)); |
154 | 146 |
155 ASSERT_EQ(NotificationDatabase::STATUS_OK, | 147 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
156 database->GetNextNotificationId(¬ification_id)); | 148 database->GetNextNotificationId(¬ification_id)); |
157 EXPECT_EQ(2, notification_id); | 149 EXPECT_EQ(2, notification_id); |
158 | 150 |
159 ASSERT_NO_FATAL_FAILURE(IncrementNextNotificationId(database.get())); | 151 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 152 database->WriteNotificationData(notification_id, |
| 153 origin, |
| 154 database_data)); |
160 | 155 |
161 database.reset(CreateDatabaseOnFileSystem(database_dir.path())); | 156 database.reset(CreateDatabaseOnFileSystem(database_dir.path())); |
162 ASSERT_EQ(NotificationDatabase::STATUS_OK, | 157 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
163 database->Open(false /* create_if_missing */)); | 158 database->Open(false /* create_if_missing */)); |
164 | 159 |
165 // Verify that the next notification id was stored in the database, and | 160 // 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. | 161 // continues where we expect it to be, even after closing and opening it. |
167 ASSERT_EQ(NotificationDatabase::STATUS_OK, | 162 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
168 database->GetNextNotificationId(¬ification_id)); | 163 database->GetNextNotificationId(¬ification_id)); |
169 EXPECT_EQ(3, notification_id); | 164 EXPECT_EQ(3, notification_id); |
(...skipping 14 matching lines...) Expand all Loading... |
184 // database, which should cause GetNextNotificationId to realize that | 179 // database, which should cause GetNextNotificationId to realize that |
185 // something is wrong with the data it's reading. | 180 // something is wrong with the data it's reading. |
186 ASSERT_NO_FATAL_FAILURE(WriteLevelDBKeyValuePair(database.get(), | 181 ASSERT_NO_FATAL_FAILURE(WriteLevelDBKeyValuePair(database.get(), |
187 "NEXT_NOTIFICATION_ID", | 182 "NEXT_NOTIFICATION_ID", |
188 "-42")); | 183 "-42")); |
189 | 184 |
190 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_CORRUPTED, | 185 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_CORRUPTED, |
191 database->GetNextNotificationId(¬ification_id)); | 186 database->GetNextNotificationId(¬ification_id)); |
192 } | 187 } |
193 | 188 |
| 189 TEST_F(NotificationDatabaseTest, ReadInvalidNotificationData) { |
| 190 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 191 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 192 database->Open(true /* create_if_missing */)); |
| 193 |
| 194 NotificationDatabaseData database_data; |
| 195 |
| 196 // Reading the notification data for a notification that does not exist should |
| 197 // return the ERROR_NOT_FOUND status code. |
| 198 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, |
| 199 database->ReadNotificationData(9001, |
| 200 GURL("https://chrome.com"), |
| 201 &database_data)); |
| 202 } |
| 203 |
| 204 TEST_F(NotificationDatabaseTest, ReadNotificationDataDifferentOrigin) { |
| 205 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 206 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 207 database->Open(true /* create_if_missing */)); |
| 208 |
| 209 int64_t notification_id = 0; |
| 210 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 211 database->GetNextNotificationId(¬ification_id)); |
| 212 |
| 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(notification_id, |
| 220 origin, |
| 221 database_data)); |
| 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 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 248 database->GetNextNotificationId(¬ification_id)); |
| 249 |
| 250 GURL origin("https://example.com"); |
| 251 |
| 252 PlatformNotificationData notification_data; |
| 253 notification_data.title = base::UTF8ToUTF16("My Notification"); |
| 254 notification_data.direction = |
| 255 PlatformNotificationData::NotificationDirectionRightToLeft; |
| 256 notification_data.lang = "nl-NL"; |
| 257 notification_data.body = base::UTF8ToUTF16("Hello, world!"); |
| 258 notification_data.tag = "replace id"; |
| 259 notification_data.icon = GURL("https://example.com/icon.png"); |
| 260 notification_data.silent = true; |
| 261 |
| 262 NotificationDatabaseData database_data; |
| 263 database_data.notification_id = notification_id; |
| 264 database_data.origin = origin; |
| 265 database_data.service_worker_registration_id = 42; |
| 266 database_data.notification_data = notification_data; |
| 267 |
| 268 // Write the constructed notification to the database, and then immediately |
| 269 // read it back from the database again as well. |
| 270 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 271 database->WriteNotificationData(notification_id, |
| 272 origin, |
| 273 database_data)); |
| 274 |
| 275 NotificationDatabaseData read_database_data; |
| 276 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 277 database->ReadNotificationData(notification_id, |
| 278 origin, |
| 279 &read_database_data)); |
| 280 |
| 281 // Verify that all members retrieved from the database are exactly the same |
| 282 // as the ones that were written to it. This tests the serialization behavior. |
| 283 |
| 284 EXPECT_EQ(database_data.notification_id, read_database_data.notification_id); |
| 285 EXPECT_EQ(database_data.origin, read_database_data.origin); |
| 286 EXPECT_EQ(database_data.service_worker_registration_id, |
| 287 read_database_data.service_worker_registration_id); |
| 288 |
| 289 const PlatformNotificationData& read_notification_data = |
| 290 read_database_data.notification_data; |
| 291 |
| 292 EXPECT_EQ(notification_data.title, read_notification_data.title); |
| 293 EXPECT_EQ(notification_data.direction, read_notification_data.direction); |
| 294 EXPECT_EQ(notification_data.lang, read_notification_data.lang); |
| 295 EXPECT_EQ(notification_data.body, read_notification_data.body); |
| 296 EXPECT_EQ(notification_data.tag, read_notification_data.tag); |
| 297 EXPECT_EQ(notification_data.icon, read_notification_data.icon); |
| 298 EXPECT_EQ(notification_data.silent, read_notification_data.silent); |
| 299 } |
| 300 |
| 301 TEST_F(NotificationDatabaseTest, ReadWriteMultipleNotificationData) { |
| 302 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 303 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 304 database->Open(true /* create_if_missing */)); |
| 305 |
| 306 int64_t notification_id = 0; |
| 307 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 308 database->GetNextNotificationId(¬ification_id)); |
| 309 |
| 310 NotificationDatabaseData database_data; |
| 311 GURL origin("https://example.com"); |
| 312 |
| 313 // Write ten notifications to the database, each with a unique title and |
| 314 // notification id (it is the responsibility of the user to increment this). |
| 315 for (int i = 0; i < 10; ++i) { |
| 316 database_data.notification_id = notification_id + i; |
| 317 database_data.notification_data.title = base::IntToString16(i); |
| 318 |
| 319 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 320 database->WriteNotificationData(notification_id + i, |
| 321 origin, |
| 322 database_data)); |
| 323 } |
| 324 |
| 325 // Read the ten notifications from the database, and verify that the titles |
| 326 // of each of them matches with how they were created. |
| 327 for (int i = 0; i < 10; ++i) { |
| 328 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 329 database->ReadNotificationData(notification_id + i, |
| 330 origin, |
| 331 &database_data)); |
| 332 |
| 333 EXPECT_EQ(base::IntToString16(i), database_data.notification_data.title); |
| 334 } |
| 335 } |
| 336 |
| 337 TEST_F(NotificationDatabaseTest, DeleteInvalidNotificationData) { |
| 338 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 339 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 340 database->Open(true /* create_if_missing */)); |
| 341 |
| 342 // Deleting non-existing notifications should return an error status. |
| 343 ASSERT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, |
| 344 database->DeleteNotificationData(9001, |
| 345 GURL("https://chrome.com"))); |
| 346 } |
| 347 |
| 348 TEST_F(NotificationDatabaseTest, DeleteNotificationDataSameOrigin) { |
| 349 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 350 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 351 database->Open(true /* create_if_missing */)); |
| 352 |
| 353 int64_t notification_id = 0; |
| 354 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 355 database->GetNextNotificationId(¬ification_id)); |
| 356 |
| 357 NotificationDatabaseData database_data; |
| 358 database_data.notification_id = notification_id; |
| 359 |
| 360 GURL origin("https://example.com"); |
| 361 |
| 362 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 363 database->WriteNotificationData(notification_id, |
| 364 origin, |
| 365 database_data)); |
| 366 |
| 367 // Reading a notification after writing one should succeed. |
| 368 EXPECT_EQ(NotificationDatabase::STATUS_OK, |
| 369 database->ReadNotificationData(notification_id, |
| 370 origin, |
| 371 &database_data)); |
| 372 |
| 373 // Delete the notification which was just written to the database, and verify |
| 374 // that reading it again will fail. |
| 375 EXPECT_EQ(NotificationDatabase::STATUS_OK, |
| 376 database->DeleteNotificationData(notification_id, origin)); |
| 377 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, |
| 378 database->ReadNotificationData(notification_id, |
| 379 origin, |
| 380 &database_data)); |
| 381 } |
| 382 |
| 383 TEST_F(NotificationDatabaseTest, DeleteNotificationDataDifferentOrigin) { |
| 384 scoped_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); |
| 385 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 386 database->Open(true /* create_if_missing */)); |
| 387 |
| 388 int64_t notification_id = 0; |
| 389 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 390 database->GetNextNotificationId(¬ification_id)); |
| 391 |
| 392 NotificationDatabaseData database_data; |
| 393 database_data.notification_id = notification_id; |
| 394 |
| 395 GURL origin("https://example.com"); |
| 396 |
| 397 ASSERT_EQ(NotificationDatabase::STATUS_OK, |
| 398 database->WriteNotificationData(notification_id, |
| 399 origin, |
| 400 database_data)); |
| 401 |
| 402 // Attempting to delete the database with a different origin, but with the |
| 403 // same |notification_id|, should return a not found error status code. |
| 404 EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND, |
| 405 database->DeleteNotificationData(notification_id, |
| 406 GURL("https://chrome.com"))); |
| 407 } |
| 408 |
194 } // namespace content | 409 } // namespace content |
OLD | NEW |