/src/mozilla-central/toolkit/components/url-classifier/tests/gtest/TestUrlClassifierTableUpdateV4.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* Any copyright is dedicated to the Public Domain. |
2 | | * http://creativecommons.org/publicdomain/zero/1.0/ */ |
3 | | |
4 | | #include "Common.h" |
5 | | #include "Classifier.h" |
6 | | #include "HashStore.h" |
7 | | #include "nsAppDirectoryServiceDefs.h" |
8 | | #include "nsIFile.h" |
9 | | #include "nsIThread.h" |
10 | | #include "string.h" |
11 | | #include "gtest/gtest.h" |
12 | | #include "nsThreadUtils.h" |
13 | | |
14 | | using namespace mozilla; |
15 | | using namespace mozilla::safebrowsing; |
16 | | |
17 | | typedef nsCString _Prefix; |
18 | | typedef nsTArray<_Prefix> _PrefixArray; |
19 | | |
20 | 0 | #define GTEST_SAFEBROWSING_DIR NS_LITERAL_CSTRING("safebrowsing") |
21 | 0 | #define GTEST_TABLE NS_LITERAL_CSTRING("gtest-malware-proto") |
22 | 0 | #define GTEST_PREFIXFILE NS_LITERAL_CSTRING("gtest-malware-proto.pset") |
23 | | |
24 | | // This function removes common elements of inArray and outArray from |
25 | | // outArray. This is used by partial update testcase to ensure partial update |
26 | | // data won't contain prefixes we already have. |
27 | | static void |
28 | | RemoveIntersection(const _PrefixArray& inArray, _PrefixArray& outArray) |
29 | 0 | { |
30 | 0 | for (uint32_t i = 0; i < inArray.Length(); i++) { |
31 | 0 | int32_t idx = outArray.BinaryIndexOf(inArray[i]); |
32 | 0 | if (idx >= 0) { |
33 | 0 | outArray.RemoveElementAt(idx); |
34 | 0 | } |
35 | 0 | } |
36 | 0 | } |
37 | | |
38 | | // This fucntion removes elements from outArray by index specified in |
39 | | // removal array. |
40 | | static void |
41 | | RemoveElements(const nsTArray<uint32_t>& removal, _PrefixArray& outArray) |
42 | 0 | { |
43 | 0 | for (int32_t i = removal.Length() - 1; i >= 0; i--) { |
44 | 0 | outArray.RemoveElementAt(removal[i]); |
45 | 0 | } |
46 | 0 | } |
47 | | |
48 | | static void |
49 | | MergeAndSortArray(const _PrefixArray& array1, |
50 | | const _PrefixArray& array2, |
51 | | _PrefixArray& output) |
52 | 0 | { |
53 | 0 | output.Clear(); |
54 | 0 | output.AppendElements(array1); |
55 | 0 | output.AppendElements(array2); |
56 | 0 | output.Sort(); |
57 | 0 | } |
58 | | |
59 | | static void |
60 | | CalculateCheckSum(_PrefixArray& prefixArray, nsCString& checksum) |
61 | 0 | { |
62 | 0 | prefixArray.Sort(); |
63 | 0 |
|
64 | 0 | nsresult rv; |
65 | 0 | nsCOMPtr<nsICryptoHash> cryptoHash = |
66 | 0 | do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); |
67 | 0 |
|
68 | 0 | cryptoHash->Init(nsICryptoHash::SHA256); |
69 | 0 | for (uint32_t i = 0; i < prefixArray.Length(); i++) { |
70 | 0 | const _Prefix& prefix = prefixArray[i]; |
71 | 0 | cryptoHash->Update(reinterpret_cast<uint8_t*>( |
72 | 0 | const_cast<char*>(prefix.get())), prefix.Length()); |
73 | 0 | } |
74 | 0 | cryptoHash->Finish(false, checksum); |
75 | 0 | } |
76 | | |
77 | | // N: Number of prefixes, MIN/MAX: minimum/maximum prefix size |
78 | | // This function will append generated prefixes to outArray. |
79 | | static void |
80 | | CreateRandomSortedPrefixArray(uint32_t N, |
81 | | uint32_t MIN, |
82 | | uint32_t MAX, |
83 | | _PrefixArray& outArray) |
84 | 0 | { |
85 | 0 | outArray.SetCapacity(outArray.Length() + N); |
86 | 0 |
|
87 | 0 | const uint32_t range = (MAX - MIN + 1); |
88 | 0 |
|
89 | 0 | for (uint32_t i = 0; i < N; i++) { |
90 | 0 | uint32_t prefixSize = (rand() % range) + MIN; |
91 | 0 | _Prefix prefix; |
92 | 0 | prefix.SetLength(prefixSize); |
93 | 0 |
|
94 | 0 | while (true) { |
95 | 0 | char* dst = prefix.BeginWriting(); |
96 | 0 | for (uint32_t j = 0; j < prefixSize; j++) { |
97 | 0 | dst[j] = rand() % 256; |
98 | 0 | } |
99 | 0 |
|
100 | 0 | if (!outArray.Contains(prefix)) { |
101 | 0 | outArray.AppendElement(prefix); |
102 | 0 | break; |
103 | 0 | } |
104 | 0 | } |
105 | 0 | } |
106 | 0 |
|
107 | 0 | outArray.Sort(); |
108 | 0 | } |
109 | | |
110 | | // N: Number of removal indices, MAX: maximum index |
111 | | static void |
112 | | CreateRandomRemovalIndices(uint32_t N, |
113 | | uint32_t MAX, |
114 | | nsTArray<uint32_t>& outArray) |
115 | 0 | { |
116 | 0 | for (uint32_t i = 0; i < N; i++) { |
117 | 0 | uint32_t idx = rand() % MAX; |
118 | 0 | if (!outArray.Contains(idx)) { |
119 | 0 | outArray.InsertElementSorted(idx); |
120 | 0 | } |
121 | 0 | } |
122 | 0 | } |
123 | | |
124 | | // Function to generate TableUpdateV4. |
125 | | static void |
126 | | GenerateUpdateData(bool fullUpdate, |
127 | | PrefixStringMap& add, |
128 | | nsTArray<uint32_t>* removal, |
129 | | nsCString* checksum, |
130 | | TableUpdateArray& tableUpdates) |
131 | 0 | { |
132 | 0 | RefPtr<TableUpdateV4> tableUpdate = new TableUpdateV4(GTEST_TABLE); |
133 | 0 | tableUpdate->SetFullUpdate(fullUpdate); |
134 | 0 |
|
135 | 0 | for (auto iter = add.ConstIter(); !iter.Done(); iter.Next()) { |
136 | 0 | nsCString* pstring = iter.Data(); |
137 | 0 | tableUpdate->NewPrefixes(iter.Key(), *pstring); |
138 | 0 | } |
139 | 0 |
|
140 | 0 | if (removal) { |
141 | 0 | tableUpdate->NewRemovalIndices(removal->Elements(), removal->Length()); |
142 | 0 | } |
143 | 0 |
|
144 | 0 | if (checksum) { |
145 | 0 | std::string stdChecksum; |
146 | 0 | stdChecksum.assign(const_cast<char*>(checksum->BeginReading()), checksum->Length()); |
147 | 0 |
|
148 | 0 | tableUpdate->NewChecksum(stdChecksum); |
149 | 0 | } |
150 | 0 |
|
151 | 0 | tableUpdates.AppendElement(tableUpdate); |
152 | 0 | } |
153 | | |
154 | | static void |
155 | | VerifyPrefixSet(PrefixStringMap& expected) |
156 | 0 | { |
157 | 0 | // Verify the prefix set is written to disk. |
158 | 0 | nsCOMPtr<nsIFile> file; |
159 | 0 | NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file)); |
160 | 0 |
|
161 | 0 | file->AppendNative(GTEST_SAFEBROWSING_DIR); |
162 | 0 | file->AppendNative(GTEST_PREFIXFILE); |
163 | 0 |
|
164 | 0 | RefPtr<VariableLengthPrefixSet> load = new VariableLengthPrefixSet; |
165 | 0 | load->Init(GTEST_TABLE); |
166 | 0 |
|
167 | 0 | PrefixStringMap prefixesInFile; |
168 | 0 | load->LoadFromFile(file); |
169 | 0 | load->GetPrefixes(prefixesInFile); |
170 | 0 |
|
171 | 0 | for (auto iter = expected.ConstIter(); !iter.Done(); iter.Next()) { |
172 | 0 | nsCString* expectedPrefix = iter.Data(); |
173 | 0 | nsCString* resultPrefix = prefixesInFile.Get(iter.Key()); |
174 | 0 |
|
175 | 0 | ASSERT_TRUE(*resultPrefix == *expectedPrefix); |
176 | 0 | } |
177 | 0 | } |
178 | | |
179 | | static void |
180 | | Clear() |
181 | 0 | { |
182 | 0 | nsCOMPtr<nsIFile> file; |
183 | 0 | NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file)); |
184 | 0 |
|
185 | 0 | RefPtr<Classifier> classifier = new Classifier(); |
186 | 0 | classifier->Open(*file); |
187 | 0 | classifier->Reset(); |
188 | 0 | } |
189 | | |
190 | | static void |
191 | | testUpdateFail(TableUpdateArray& tableUpdates) |
192 | 0 | { |
193 | 0 | nsCOMPtr<nsIFile> file; |
194 | 0 | NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file)); |
195 | 0 |
|
196 | 0 | RefPtr<Classifier> classifier = new Classifier(); |
197 | 0 | classifier->Open(*file); |
198 | 0 |
|
199 | 0 | nsresult rv = SyncApplyUpdates(classifier, tableUpdates); |
200 | 0 | ASSERT_TRUE(NS_FAILED(rv)); |
201 | 0 | } |
202 | | |
203 | | static void |
204 | | testUpdate(TableUpdateArray& tableUpdates, |
205 | | PrefixStringMap& expected) |
206 | 0 | { |
207 | 0 | nsCOMPtr<nsIFile> file; |
208 | 0 | NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file)); |
209 | 0 |
|
210 | 0 | { |
211 | 0 | // Force nsIUrlClassifierUtils loading on main thread |
212 | 0 | // because nsIUrlClassifierDBService will not run in advance |
213 | 0 | // in gtest. |
214 | 0 | nsresult rv; |
215 | 0 | nsCOMPtr<nsIUrlClassifierUtils> dummy = |
216 | 0 | do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID, &rv); |
217 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
218 | 0 | } |
219 | 0 |
|
220 | 0 | RefPtr<Classifier> classifier = new Classifier(); |
221 | 0 | classifier->Open(*file); |
222 | 0 |
|
223 | 0 | nsresult rv = SyncApplyUpdates(classifier, tableUpdates); |
224 | 0 | ASSERT_TRUE(rv == NS_OK); |
225 | 0 | VerifyPrefixSet(expected); |
226 | 0 | } |
227 | | |
228 | | static void |
229 | | testFullUpdate(PrefixStringMap& add, nsCString* checksum) |
230 | 0 | { |
231 | 0 | TableUpdateArray tableUpdates; |
232 | 0 |
|
233 | 0 | GenerateUpdateData(true, add, nullptr, checksum, tableUpdates); |
234 | 0 |
|
235 | 0 | testUpdate(tableUpdates, add); |
236 | 0 | } |
237 | | |
238 | | static void |
239 | | testPartialUpdate(PrefixStringMap& add, |
240 | | nsTArray<uint32_t>* removal, |
241 | | nsCString* checksum, |
242 | | PrefixStringMap& expected) |
243 | 0 | { |
244 | 0 | TableUpdateArray tableUpdates; |
245 | 0 | GenerateUpdateData(false, add, removal, checksum, tableUpdates); |
246 | 0 |
|
247 | 0 | testUpdate(tableUpdates, expected); |
248 | 0 | } |
249 | | |
250 | | static void |
251 | | testOpenLookupCache() |
252 | 0 | { |
253 | 0 | nsCOMPtr<nsIFile> file; |
254 | 0 | NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file)); |
255 | 0 | file->AppendNative(GTEST_SAFEBROWSING_DIR); |
256 | 0 |
|
257 | 0 | RunTestInNewThread([&] () -> void { |
258 | 0 | RefPtr<LookupCacheV4> cache = new LookupCacheV4(nsCString(GTEST_TABLE), |
259 | 0 | EmptyCString(), file); |
260 | 0 | nsresult rv = cache->Init(); |
261 | 0 | ASSERT_EQ(rv, NS_OK); |
262 | 0 |
|
263 | 0 | rv = cache->Open(); |
264 | 0 | ASSERT_EQ(rv, NS_OK); |
265 | 0 | }); |
266 | 0 | } |
267 | | |
268 | | // Tests start from here. |
269 | | TEST(UrlClassifierTableUpdateV4, FixLenghtPSetFullUpdate) |
270 | 0 | { |
271 | 0 | srand(time(NULL)); |
272 | 0 |
|
273 | 0 | _PrefixArray array; |
274 | 0 | PrefixStringMap map; |
275 | 0 | nsCString checksum; |
276 | 0 |
|
277 | 0 | CreateRandomSortedPrefixArray(5000, 4, 4, array); |
278 | 0 | PrefixArrayToPrefixStringMap(array, map); |
279 | 0 | CalculateCheckSum(array, checksum); |
280 | 0 |
|
281 | 0 | testFullUpdate(map, &checksum); |
282 | 0 |
|
283 | 0 | Clear(); |
284 | 0 | } |
285 | | |
286 | | TEST(UrlClassifierTableUpdateV4, VariableLenghtPSetFullUpdate) |
287 | 0 | { |
288 | 0 | _PrefixArray array; |
289 | 0 | PrefixStringMap map; |
290 | 0 | nsCString checksum; |
291 | 0 |
|
292 | 0 | CreateRandomSortedPrefixArray(5000, 5, 32, array); |
293 | 0 | PrefixArrayToPrefixStringMap(array, map); |
294 | 0 | CalculateCheckSum(array, checksum); |
295 | 0 |
|
296 | 0 | testFullUpdate(map, &checksum); |
297 | 0 |
|
298 | 0 | Clear(); |
299 | 0 | } |
300 | | |
301 | | // This test contain both variable length prefix set and fixed-length prefix set |
302 | | TEST(UrlClassifierTableUpdateV4, MixedPSetFullUpdate) |
303 | 0 | { |
304 | 0 | _PrefixArray array; |
305 | 0 | PrefixStringMap map; |
306 | 0 | nsCString checksum; |
307 | 0 |
|
308 | 0 | CreateRandomSortedPrefixArray(5000, 4, 4, array); |
309 | 0 | CreateRandomSortedPrefixArray(1000, 5, 32, array); |
310 | 0 | PrefixArrayToPrefixStringMap(array, map); |
311 | 0 | CalculateCheckSum(array, checksum); |
312 | 0 |
|
313 | 0 | testFullUpdate(map, &checksum); |
314 | 0 |
|
315 | 0 | Clear(); |
316 | 0 | } |
317 | | |
318 | | TEST(UrlClassifierTableUpdateV4, PartialUpdateWithRemoval) |
319 | 0 | { |
320 | 0 | _PrefixArray fArray; |
321 | 0 |
|
322 | 0 | // Apply a full update first. |
323 | 0 | { |
324 | 0 | PrefixStringMap fMap; |
325 | 0 | nsCString checksum; |
326 | 0 |
|
327 | 0 | CreateRandomSortedPrefixArray(10000, 4, 4, fArray); |
328 | 0 | CreateRandomSortedPrefixArray(2000, 5, 32, fArray); |
329 | 0 | PrefixArrayToPrefixStringMap(fArray, fMap); |
330 | 0 | CalculateCheckSum(fArray, checksum); |
331 | 0 |
|
332 | 0 | testFullUpdate(fMap, &checksum); |
333 | 0 | } |
334 | 0 |
|
335 | 0 | // Apply a partial update with removal. |
336 | 0 | { |
337 | 0 | _PrefixArray pArray, mergedArray; |
338 | 0 | PrefixStringMap pMap, mergedMap; |
339 | 0 | nsCString checksum; |
340 | 0 |
|
341 | 0 | CreateRandomSortedPrefixArray(5000, 4, 4, pArray); |
342 | 0 | CreateRandomSortedPrefixArray(1000, 5, 32, pArray); |
343 | 0 | RemoveIntersection(fArray, pArray); |
344 | 0 | PrefixArrayToPrefixStringMap(pArray, pMap); |
345 | 0 |
|
346 | 0 | // Remove 1/5 of elements of original prefix set. |
347 | 0 | nsTArray<uint32_t> removal; |
348 | 0 | CreateRandomRemovalIndices(fArray.Length() / 5, fArray.Length(), removal); |
349 | 0 | RemoveElements(removal, fArray); |
350 | 0 |
|
351 | 0 | // Calculate the expected prefix map. |
352 | 0 | MergeAndSortArray(fArray, pArray, mergedArray); |
353 | 0 | PrefixArrayToPrefixStringMap(mergedArray, mergedMap); |
354 | 0 | CalculateCheckSum(mergedArray, checksum); |
355 | 0 |
|
356 | 0 | testPartialUpdate(pMap, &removal, &checksum, mergedMap); |
357 | 0 | } |
358 | 0 |
|
359 | 0 | Clear(); |
360 | 0 | } |
361 | | |
362 | | TEST(UrlClassifierTableUpdateV4, PartialUpdateWithoutRemoval) |
363 | 0 | { |
364 | 0 | _PrefixArray fArray; |
365 | 0 |
|
366 | 0 | // Apply a full update first. |
367 | 0 | { |
368 | 0 | PrefixStringMap fMap; |
369 | 0 | nsCString checksum; |
370 | 0 |
|
371 | 0 | CreateRandomSortedPrefixArray(10000, 4, 4, fArray); |
372 | 0 | CreateRandomSortedPrefixArray(2000, 5, 32, fArray); |
373 | 0 | PrefixArrayToPrefixStringMap(fArray, fMap); |
374 | 0 | CalculateCheckSum(fArray, checksum); |
375 | 0 |
|
376 | 0 | testFullUpdate(fMap, &checksum); |
377 | 0 | } |
378 | 0 |
|
379 | 0 | // Apply a partial update without removal |
380 | 0 | { |
381 | 0 | _PrefixArray pArray, mergedArray; |
382 | 0 | PrefixStringMap pMap, mergedMap; |
383 | 0 | nsCString checksum; |
384 | 0 |
|
385 | 0 | CreateRandomSortedPrefixArray(5000, 4, 4, pArray); |
386 | 0 | CreateRandomSortedPrefixArray(1000, 5, 32, pArray); |
387 | 0 | RemoveIntersection(fArray, pArray); |
388 | 0 | PrefixArrayToPrefixStringMap(pArray, pMap); |
389 | 0 |
|
390 | 0 | // Calculate the expected prefix map. |
391 | 0 | MergeAndSortArray(fArray, pArray, mergedArray); |
392 | 0 | PrefixArrayToPrefixStringMap(mergedArray, mergedMap); |
393 | 0 | CalculateCheckSum(mergedArray, checksum); |
394 | 0 |
|
395 | 0 | testPartialUpdate(pMap, nullptr, &checksum, mergedMap); |
396 | 0 | } |
397 | 0 |
|
398 | 0 | Clear(); |
399 | 0 | } |
400 | | |
401 | | // Expect failure because partial update contains prefix already |
402 | | // in old prefix set. |
403 | | TEST(UrlClassifierTableUpdateV4, PartialUpdatePrefixAlreadyExist) |
404 | 0 | { |
405 | 0 | _PrefixArray fArray; |
406 | 0 |
|
407 | 0 | // Apply a full update fist. |
408 | 0 | { |
409 | 0 | PrefixStringMap fMap; |
410 | 0 | nsCString checksum; |
411 | 0 |
|
412 | 0 | CreateRandomSortedPrefixArray(1000, 4, 32, fArray); |
413 | 0 | PrefixArrayToPrefixStringMap(fArray, fMap); |
414 | 0 | CalculateCheckSum(fArray, checksum); |
415 | 0 |
|
416 | 0 | testFullUpdate(fMap, &checksum); |
417 | 0 | } |
418 | 0 |
|
419 | 0 | // Apply a partial update which contains a prefix in previous full update. |
420 | 0 | // This should cause an update error. |
421 | 0 | { |
422 | 0 | _PrefixArray pArray; |
423 | 0 | PrefixStringMap pMap; |
424 | 0 | TableUpdateArray tableUpdates; |
425 | 0 |
|
426 | 0 | // Pick one prefix from full update prefix and add it to partial update. |
427 | 0 | // This should result a failure when call ApplyUpdates. |
428 | 0 | pArray.AppendElement(fArray[rand() % fArray.Length()]); |
429 | 0 | CreateRandomSortedPrefixArray(200, 4, 32, pArray); |
430 | 0 | PrefixArrayToPrefixStringMap(pArray, pMap); |
431 | 0 |
|
432 | 0 | GenerateUpdateData(false, pMap, nullptr, nullptr, tableUpdates); |
433 | 0 | testUpdateFail(tableUpdates); |
434 | 0 | } |
435 | 0 |
|
436 | 0 | Clear(); |
437 | 0 | } |
438 | | |
439 | | // Test apply partial update directly without applying an full update first. |
440 | | TEST(UrlClassifierTableUpdateV4, OnlyPartialUpdate) |
441 | 0 | { |
442 | 0 | _PrefixArray pArray; |
443 | 0 | PrefixStringMap pMap; |
444 | 0 | nsCString checksum; |
445 | 0 |
|
446 | 0 | CreateRandomSortedPrefixArray(5000, 4, 4, pArray); |
447 | 0 | CreateRandomSortedPrefixArray(1000, 5, 32, pArray); |
448 | 0 | PrefixArrayToPrefixStringMap(pArray, pMap); |
449 | 0 | CalculateCheckSum(pArray, checksum); |
450 | 0 |
|
451 | 0 | testPartialUpdate(pMap, nullptr, &checksum, pMap); |
452 | 0 |
|
453 | 0 | Clear(); |
454 | 0 | } |
455 | | |
456 | | // Test partial update without any ADD prefixes, only removalIndices. |
457 | | TEST(UrlClassifierTableUpdateV4, PartialUpdateOnlyRemoval) |
458 | 0 | { |
459 | 0 | _PrefixArray fArray; |
460 | 0 |
|
461 | 0 | // Apply a full update first. |
462 | 0 | { |
463 | 0 | PrefixStringMap fMap; |
464 | 0 | nsCString checksum; |
465 | 0 |
|
466 | 0 | CreateRandomSortedPrefixArray(5000, 4, 4, fArray); |
467 | 0 | CreateRandomSortedPrefixArray(1000, 5, 32, fArray); |
468 | 0 | PrefixArrayToPrefixStringMap(fArray, fMap); |
469 | 0 | CalculateCheckSum(fArray, checksum); |
470 | 0 |
|
471 | 0 | testFullUpdate(fMap, &checksum); |
472 | 0 | } |
473 | 0 |
|
474 | 0 | // Apply a partial update without add prefix, only contain removal indices. |
475 | 0 | { |
476 | 0 | _PrefixArray pArray; |
477 | 0 | PrefixStringMap pMap, mergedMap; |
478 | 0 | nsCString checksum; |
479 | 0 |
|
480 | 0 | // Remove 1/5 of elements of original prefix set. |
481 | 0 | nsTArray<uint32_t> removal; |
482 | 0 | CreateRandomRemovalIndices(fArray.Length() / 5, fArray.Length(), removal); |
483 | 0 | RemoveElements(removal, fArray); |
484 | 0 |
|
485 | 0 | PrefixArrayToPrefixStringMap(fArray, mergedMap); |
486 | 0 | CalculateCheckSum(fArray, checksum); |
487 | 0 |
|
488 | 0 | testPartialUpdate(pMap, &removal, &checksum, mergedMap); |
489 | 0 | } |
490 | 0 |
|
491 | 0 | Clear(); |
492 | 0 | } |
493 | | |
494 | | // Test one tableupdate array contains full update and multiple partial updates. |
495 | | TEST(UrlClassifierTableUpdateV4, MultipleTableUpdates) |
496 | 0 | { |
497 | 0 | _PrefixArray fArray, pArray, mergedArray; |
498 | 0 | PrefixStringMap fMap, pMap, mergedMap; |
499 | 0 | nsCString checksum; |
500 | 0 |
|
501 | 0 | TableUpdateArray tableUpdates; |
502 | 0 |
|
503 | 0 | // Generate first full udpate |
504 | 0 | CreateRandomSortedPrefixArray(10000, 4, 4, fArray); |
505 | 0 | CreateRandomSortedPrefixArray(2000, 5, 32, fArray); |
506 | 0 | PrefixArrayToPrefixStringMap(fArray, fMap); |
507 | 0 | CalculateCheckSum(fArray, checksum); |
508 | 0 |
|
509 | 0 | GenerateUpdateData(true, fMap, nullptr, &checksum, tableUpdates); |
510 | 0 |
|
511 | 0 | // Generate second partial update |
512 | 0 | CreateRandomSortedPrefixArray(3000, 4, 4, pArray); |
513 | 0 | CreateRandomSortedPrefixArray(1000, 5, 32, pArray); |
514 | 0 | RemoveIntersection(fArray, pArray); |
515 | 0 | PrefixArrayToPrefixStringMap(pArray, pMap); |
516 | 0 |
|
517 | 0 | MergeAndSortArray(fArray, pArray, mergedArray); |
518 | 0 | CalculateCheckSum(mergedArray, checksum); |
519 | 0 |
|
520 | 0 | GenerateUpdateData(false, pMap, nullptr, &checksum, tableUpdates); |
521 | 0 |
|
522 | 0 | // Generate thrid partial update |
523 | 0 | fArray.AppendElements(pArray); |
524 | 0 | fArray.Sort(); |
525 | 0 | pArray.Clear(); |
526 | 0 | CreateRandomSortedPrefixArray(3000, 4, 4, pArray); |
527 | 0 | CreateRandomSortedPrefixArray(1000, 5, 32, pArray); |
528 | 0 | RemoveIntersection(fArray, pArray); |
529 | 0 | PrefixArrayToPrefixStringMap(pArray, pMap); |
530 | 0 |
|
531 | 0 | // Remove 1/5 of elements of original prefix set. |
532 | 0 | nsTArray<uint32_t> removal; |
533 | 0 | CreateRandomRemovalIndices(fArray.Length() / 5, fArray.Length(), removal); |
534 | 0 | RemoveElements(removal, fArray); |
535 | 0 |
|
536 | 0 | MergeAndSortArray(fArray, pArray, mergedArray); |
537 | 0 | PrefixArrayToPrefixStringMap(mergedArray, mergedMap); |
538 | 0 | CalculateCheckSum(mergedArray, checksum); |
539 | 0 |
|
540 | 0 | GenerateUpdateData(false, pMap, &removal, &checksum, tableUpdates); |
541 | 0 |
|
542 | 0 | testUpdate(tableUpdates, mergedMap); |
543 | 0 |
|
544 | 0 | Clear(); |
545 | 0 | } |
546 | | |
547 | | // Test apply full update first, and then apply multiple partial updates |
548 | | // in one tableupdate array. |
549 | | TEST(UrlClassifierTableUpdateV4, MultiplePartialUpdateTableUpdates) |
550 | 0 | { |
551 | 0 | _PrefixArray fArray; |
552 | 0 |
|
553 | 0 | // Apply a full update first |
554 | 0 | { |
555 | 0 | PrefixStringMap fMap; |
556 | 0 | nsCString checksum; |
557 | 0 |
|
558 | 0 | // Generate first full udpate |
559 | 0 | CreateRandomSortedPrefixArray(10000, 4, 4, fArray); |
560 | 0 | CreateRandomSortedPrefixArray(3000, 5, 32, fArray); |
561 | 0 | PrefixArrayToPrefixStringMap(fArray, fMap); |
562 | 0 | CalculateCheckSum(fArray, checksum); |
563 | 0 |
|
564 | 0 | testFullUpdate(fMap, &checksum); |
565 | 0 | } |
566 | 0 |
|
567 | 0 | // Apply multiple partial updates in one table update |
568 | 0 | { |
569 | 0 | _PrefixArray pArray, mergedArray; |
570 | 0 | PrefixStringMap pMap, mergedMap; |
571 | 0 | nsCString checksum; |
572 | 0 | nsTArray<uint32_t> removal; |
573 | 0 | TableUpdateArray tableUpdates; |
574 | 0 |
|
575 | 0 | // Generate first partial update |
576 | 0 | CreateRandomSortedPrefixArray(3000, 4, 4, pArray); |
577 | 0 | CreateRandomSortedPrefixArray(1000, 5, 32, pArray); |
578 | 0 | RemoveIntersection(fArray, pArray); |
579 | 0 | PrefixArrayToPrefixStringMap(pArray, pMap); |
580 | 0 |
|
581 | 0 | // Remove 1/5 of elements of original prefix set. |
582 | 0 | CreateRandomRemovalIndices(fArray.Length() / 5, fArray.Length(), removal); |
583 | 0 | RemoveElements(removal, fArray); |
584 | 0 |
|
585 | 0 | MergeAndSortArray(fArray, pArray, mergedArray); |
586 | 0 | CalculateCheckSum(mergedArray, checksum); |
587 | 0 |
|
588 | 0 | GenerateUpdateData(false, pMap, &removal, &checksum, tableUpdates); |
589 | 0 |
|
590 | 0 | fArray.AppendElements(pArray); |
591 | 0 | fArray.Sort(); |
592 | 0 | pArray.Clear(); |
593 | 0 | removal.Clear(); |
594 | 0 |
|
595 | 0 | // Generate second partial update. |
596 | 0 | CreateRandomSortedPrefixArray(2000, 4, 4, pArray); |
597 | 0 | CreateRandomSortedPrefixArray(1000, 5, 32, pArray); |
598 | 0 | RemoveIntersection(fArray, pArray); |
599 | 0 | PrefixArrayToPrefixStringMap(pArray, pMap); |
600 | 0 |
|
601 | 0 | // Remove 1/5 of elements of original prefix set. |
602 | 0 | CreateRandomRemovalIndices(fArray.Length() / 5, fArray.Length(), removal); |
603 | 0 | RemoveElements(removal, fArray); |
604 | 0 |
|
605 | 0 | MergeAndSortArray(fArray, pArray, mergedArray); |
606 | 0 | PrefixArrayToPrefixStringMap(mergedArray, mergedMap); |
607 | 0 | CalculateCheckSum(mergedArray, checksum); |
608 | 0 |
|
609 | 0 | GenerateUpdateData(false, pMap, &removal, &checksum, tableUpdates); |
610 | 0 |
|
611 | 0 | testUpdate(tableUpdates, mergedMap); |
612 | 0 | } |
613 | 0 |
|
614 | 0 | Clear(); |
615 | 0 | } |
616 | | |
617 | | // Test removal indices are larger than the original prefix set. |
618 | | TEST(UrlClassifierTableUpdateV4, RemovalIndexTooLarge) |
619 | 0 | { |
620 | 0 | _PrefixArray fArray; |
621 | 0 |
|
622 | 0 | // Apply a full update first |
623 | 0 | { |
624 | 0 | PrefixStringMap fMap; |
625 | 0 | nsCString checksum; |
626 | 0 |
|
627 | 0 | CreateRandomSortedPrefixArray(1000, 4, 32, fArray); |
628 | 0 | PrefixArrayToPrefixStringMap(fArray, fMap); |
629 | 0 | CalculateCheckSum(fArray, checksum); |
630 | 0 |
|
631 | 0 | testFullUpdate(fMap, &checksum); |
632 | 0 | } |
633 | 0 |
|
634 | 0 | // Apply a partial update with removal indice array larger than |
635 | 0 | // old prefix set(fArray). This should cause an error. |
636 | 0 | { |
637 | 0 | _PrefixArray pArray; |
638 | 0 | PrefixStringMap pMap; |
639 | 0 | nsTArray<uint32_t> removal; |
640 | 0 | TableUpdateArray tableUpdates; |
641 | 0 |
|
642 | 0 | CreateRandomSortedPrefixArray(200, 4, 32, pArray); |
643 | 0 | RemoveIntersection(fArray, pArray); |
644 | 0 | PrefixArrayToPrefixStringMap(pArray, pMap); |
645 | 0 |
|
646 | 0 | for (uint32_t i = 0; i < fArray.Length() + 1 ;i++) { |
647 | 0 | removal.AppendElement(i); |
648 | 0 | } |
649 | 0 |
|
650 | 0 | GenerateUpdateData(false, pMap, &removal, nullptr, tableUpdates); |
651 | 0 | testUpdateFail(tableUpdates); |
652 | 0 | } |
653 | 0 |
|
654 | 0 | Clear(); |
655 | 0 | } |
656 | | |
657 | | TEST(UrlClassifierTableUpdateV4, ChecksumMismatch) |
658 | 0 | { |
659 | 0 | // Apply a full update first |
660 | 0 | { |
661 | 0 | _PrefixArray fArray; |
662 | 0 | PrefixStringMap fMap; |
663 | 0 | nsCString checksum; |
664 | 0 |
|
665 | 0 | CreateRandomSortedPrefixArray(1000, 4, 32, fArray); |
666 | 0 | PrefixArrayToPrefixStringMap(fArray, fMap); |
667 | 0 | CalculateCheckSum(fArray, checksum); |
668 | 0 |
|
669 | 0 | testFullUpdate(fMap, &checksum); |
670 | 0 | } |
671 | 0 |
|
672 | 0 | // Apply a partial update with incorrect checksum |
673 | 0 | { |
674 | 0 | _PrefixArray pArray; |
675 | 0 | PrefixStringMap pMap; |
676 | 0 | nsCString checksum; |
677 | 0 | TableUpdateArray tableUpdates; |
678 | 0 |
|
679 | 0 | CreateRandomSortedPrefixArray(200, 4, 32, pArray); |
680 | 0 | PrefixArrayToPrefixStringMap(pArray, pMap); |
681 | 0 |
|
682 | 0 | // Checksum should be calculated with both old prefix set and add prefix set, |
683 | 0 | // here we only calculate checksum with add prefix set to check if applyUpdate |
684 | 0 | // will return failure. |
685 | 0 | CalculateCheckSum(pArray, checksum); |
686 | 0 |
|
687 | 0 | GenerateUpdateData(false, pMap, nullptr, &checksum, tableUpdates); |
688 | 0 | testUpdateFail(tableUpdates); |
689 | 0 | } |
690 | 0 |
|
691 | 0 | Clear(); |
692 | 0 | } |
693 | | |
694 | | TEST(UrlClassifierTableUpdateV4, ApplyUpdateThenLoad) |
695 | 0 | { |
696 | 0 | // Apply update with checksum |
697 | 0 | { |
698 | 0 | _PrefixArray fArray; |
699 | 0 | PrefixStringMap fMap; |
700 | 0 | nsCString checksum; |
701 | 0 |
|
702 | 0 | CreateRandomSortedPrefixArray(1000, 4, 32, fArray); |
703 | 0 | PrefixArrayToPrefixStringMap(fArray, fMap); |
704 | 0 | CalculateCheckSum(fArray, checksum); |
705 | 0 |
|
706 | 0 | testFullUpdate(fMap, &checksum); |
707 | 0 |
|
708 | 0 | // Open lookup cache will load prefix set and verify the checksum |
709 | 0 | testOpenLookupCache(); |
710 | 0 | } |
711 | 0 |
|
712 | 0 | Clear(); |
713 | 0 |
|
714 | 0 | // Apply update without checksum |
715 | 0 | { |
716 | 0 | _PrefixArray fArray; |
717 | 0 | PrefixStringMap fMap; |
718 | 0 |
|
719 | 0 | CreateRandomSortedPrefixArray(1000, 4, 32, fArray); |
720 | 0 | PrefixArrayToPrefixStringMap(fArray, fMap); |
721 | 0 |
|
722 | 0 | testFullUpdate(fMap, nullptr); |
723 | 0 |
|
724 | 0 | testOpenLookupCache(); |
725 | 0 | } |
726 | 0 |
|
727 | 0 | Clear(); |
728 | 0 | } |
729 | | |
730 | | // This test is used to avoid an eror from nsICryptoHash |
731 | | TEST(UrlClassifierTableUpdateV4, ApplyUpdateWithFixedChecksum) |
732 | 0 | { |
733 | 0 | _PrefixArray fArray = { _Prefix("enus"), _Prefix("apollo"), _Prefix("mars"), |
734 | 0 | _Prefix("Hecatonchires cyclopes"), |
735 | 0 | _Prefix("vesta"), _Prefix("neptunus"), _Prefix("jupiter"), |
736 | 0 | _Prefix("diana"), _Prefix("minerva"), _Prefix("ceres"), |
737 | 0 | _Prefix("Aidos,Adephagia,Adikia,Aletheia"), |
738 | 0 | _Prefix("hecatonchires"), _Prefix("alcyoneus"), _Prefix("hades"), |
739 | 0 | _Prefix("vulcanus"), _Prefix("juno"), _Prefix("mercury"), |
740 | 0 | _Prefix("Stheno, Euryale and Medusa") |
741 | 0 | }; |
742 | 0 | fArray.Sort(); |
743 | 0 |
|
744 | 0 | PrefixStringMap fMap; |
745 | 0 | PrefixArrayToPrefixStringMap(fArray, fMap); |
746 | 0 |
|
747 | 0 | nsCString checksum("\xae\x18\x94\xd7\xd0\x83\x5f\xc1" |
748 | 0 | "\x58\x59\x5c\x2c\x72\xb9\x6e\x5e" |
749 | 0 | "\xf4\xe8\x0a\x6b\xff\x5e\x6b\x81" |
750 | 0 | "\x65\x34\x06\x16\x06\x59\xa0\x67"); |
751 | 0 |
|
752 | 0 | testFullUpdate(fMap, &checksum); |
753 | 0 |
|
754 | 0 | // Open lookup cache will load prefix set and verify the checksum |
755 | 0 | testOpenLookupCache(); |
756 | 0 |
|
757 | 0 | Clear(); |
758 | 0 | } |
759 | | |
760 | | // This test ensure that an empty update works correctly. Empty update |
761 | | // should be skipped by CheckValidUpdate in Classifier::UpdateTableV4. |
762 | | TEST(UrlClassifierTableUpdateV4, EmptyUpdate) |
763 | 0 | { |
764 | 0 | PrefixStringMap emptyAddition; |
765 | 0 | nsTArray<uint32_t> emptyRemoval; |
766 | 0 |
|
767 | 0 | _PrefixArray array; |
768 | 0 | PrefixStringMap map; |
769 | 0 | nsCString checksum; |
770 | 0 |
|
771 | 0 | CalculateCheckSum(array, checksum); |
772 | 0 |
|
773 | 0 | // Test apply empty full/partial update before we already |
774 | 0 | // have data in DB. |
775 | 0 | testFullUpdate(emptyAddition, &checksum); |
776 | 0 | testPartialUpdate(emptyAddition, &emptyRemoval, &checksum, map); |
777 | 0 |
|
778 | 0 | // Apply an full update. |
779 | 0 | CreateRandomSortedPrefixArray(100, 4, 4, array); |
780 | 0 | CreateRandomSortedPrefixArray(10, 5, 32, array); |
781 | 0 | PrefixArrayToPrefixStringMap(array, map); |
782 | 0 | CalculateCheckSum(array, checksum); |
783 | 0 |
|
784 | 0 | testFullUpdate(map, &checksum); |
785 | 0 |
|
786 | 0 | // Test apply empty full/partial update when we already |
787 | 0 | // have data in DB |
788 | 0 | testPartialUpdate(emptyAddition, &emptyRemoval, &checksum, map); |
789 | 0 | testFullUpdate(emptyAddition, &checksum); |
790 | 0 |
|
791 | 0 | Clear(); |
792 | 0 | } |
793 | | |
794 | | // This test ensure applying an empty update directly through update algorithm |
795 | | // should be correct. |
796 | | TEST(UrlClassifierTableUpdateV4, EmptyUpdate2) |
797 | 0 | { |
798 | 0 | // Setup LookupCache with initial data |
799 | 0 | _PrefixArray array; |
800 | 0 | CreateRandomSortedPrefixArray(100, 4, 4, array); |
801 | 0 | CreateRandomSortedPrefixArray(10, 5, 32, array); |
802 | 0 | RefPtr<LookupCacheV4> cache = SetupLookupCache<LookupCacheV4>(array); |
803 | 0 |
|
804 | 0 | // Setup TableUpdate object with only checksum from previous update(initial data). |
805 | 0 | nsCString checksum; |
806 | 0 | CalculateCheckSum(array, checksum); |
807 | 0 | std::string stdChecksum; |
808 | 0 | stdChecksum.assign(const_cast<char*>(checksum.BeginReading()), checksum.Length()); |
809 | 0 |
|
810 | 0 | RefPtr<TableUpdateV4> tableUpdate = new TableUpdateV4(GTEST_TABLE); |
811 | 0 | tableUpdate->NewChecksum(stdChecksum); |
812 | 0 |
|
813 | 0 | // Apply update directly through LookupCache interface |
814 | 0 | PrefixStringMap input, output; |
815 | 0 | PrefixArrayToPrefixStringMap(array, input); |
816 | 0 | nsresult rv = cache->ApplyUpdate(tableUpdate.get(), input, output); |
817 | 0 |
|
818 | 0 | ASSERT_TRUE(rv == NS_OK); |
819 | 0 |
|
820 | 0 | Clear(); |
821 | 0 | } |