forked from mirrors/gecko-dev
		
	 acc75d964c
			
		
	
	
		acc75d964c
		
	
	
	
	
		
			
			Depends on D174432 Differential Revision: https://phabricator.services.mozilla.com/D174433
		
			
				
	
	
		
			785 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			785 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "Classifier.h"
 | |
| #include "HashStore.h"
 | |
| #include "mozilla/Components.h"
 | |
| #include "mozilla/Unused.h"
 | |
| #include "nsAppDirectoryServiceDefs.h"
 | |
| #include "nsIFile.h"
 | |
| #include "nsThreadUtils.h"
 | |
| #include "string.h"
 | |
| #include "LookupCacheV4.h"
 | |
| #include "nsUrlClassifierUtils.h"
 | |
| 
 | |
| #include "Common.h"
 | |
| 
 | |
| #define GTEST_SAFEBROWSING_DIR "safebrowsing"_ns
 | |
| #define GTEST_TABLE "gtest-malware-proto"_ns
 | |
| #define GTEST_PREFIXFILE "gtest-malware-proto.vlpset"_ns
 | |
| 
 | |
| // This function removes common elements of inArray and outArray from
 | |
| // outArray. This is used by partial update testcase to ensure partial update
 | |
| // data won't contain prefixes we already have.
 | |
| static void RemoveIntersection(const _PrefixArray& inArray,
 | |
|                                _PrefixArray& outArray) {
 | |
|   for (uint32_t i = 0; i < inArray.Length(); i++) {
 | |
|     int32_t idx = outArray.BinaryIndexOf(inArray[i]);
 | |
|     if (idx >= 0) {
 | |
|       outArray.RemoveElementAt(idx);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| // This fucntion removes elements from outArray by index specified in
 | |
| // removal array.
 | |
| static void RemoveElements(const nsTArray<uint32_t>& removal,
 | |
|                            _PrefixArray& outArray) {
 | |
|   for (int32_t i = removal.Length() - 1; i >= 0; i--) {
 | |
|     outArray.RemoveElementAt(removal[i]);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void MergeAndSortArray(const _PrefixArray& array1,
 | |
|                               const _PrefixArray& array2,
 | |
|                               _PrefixArray& output) {
 | |
|   output.Clear();
 | |
|   output.AppendElements(array1);
 | |
|   output.AppendElements(array2);
 | |
|   output.Sort();
 | |
| }
 | |
| 
 | |
| static void CalculateSHA256(_PrefixArray& prefixArray, nsCString& sha256) {
 | |
|   prefixArray.Sort();
 | |
| 
 | |
|   nsresult rv;
 | |
|   nsCOMPtr<nsICryptoHash> cryptoHash =
 | |
|       do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
 | |
| 
 | |
|   cryptoHash->Init(nsICryptoHash::SHA256);
 | |
|   for (uint32_t i = 0; i < prefixArray.Length(); i++) {
 | |
|     const _Prefix& prefix = prefixArray[i];
 | |
|     cryptoHash->Update(
 | |
|         reinterpret_cast<uint8_t*>(const_cast<char*>(prefix.get())),
 | |
|         prefix.Length());
 | |
|   }
 | |
|   cryptoHash->Finish(false, sha256);
 | |
| }
 | |
| 
 | |
| // N: Number of prefixes, MIN/MAX: minimum/maximum prefix size
 | |
| // This function will append generated prefixes to outArray.
 | |
| static void CreateRandomSortedPrefixArray(uint32_t N, uint32_t MIN,
 | |
|                                           uint32_t MAX,
 | |
|                                           _PrefixArray& outArray) {
 | |
|   outArray.SetCapacity(outArray.Length() + N);
 | |
| 
 | |
|   const uint32_t range = (MAX - MIN + 1);
 | |
| 
 | |
|   for (uint32_t i = 0; i < N; i++) {
 | |
|     uint32_t prefixSize = (rand() % range) + MIN;
 | |
|     _Prefix prefix;
 | |
|     prefix.SetLength(prefixSize);
 | |
| 
 | |
|     while (true) {
 | |
|       char* dst = prefix.BeginWriting();
 | |
|       for (uint32_t j = 0; j < prefixSize; j++) {
 | |
|         dst[j] = rand() % 256;
 | |
|       }
 | |
| 
 | |
|       if (!outArray.Contains(prefix)) {
 | |
|         outArray.AppendElement(prefix);
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   outArray.Sort();
 | |
| }
 | |
| 
 | |
| // N: Number of removal indices, MAX: maximum index
 | |
| static void CreateRandomRemovalIndices(uint32_t N, uint32_t MAX,
 | |
|                                        nsTArray<uint32_t>& outArray) {
 | |
|   for (uint32_t i = 0; i < N; i++) {
 | |
|     uint32_t idx = rand() % MAX;
 | |
|     if (!outArray.Contains(idx)) {
 | |
|       outArray.InsertElementSorted(idx);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| // Function to generate TableUpdateV4.
 | |
| static void GenerateUpdateData(bool fullUpdate, PrefixStringMap& add,
 | |
|                                nsTArray<uint32_t>* removal, nsCString* sha256,
 | |
|                                TableUpdateArray& tableUpdates) {
 | |
|   RefPtr<TableUpdateV4> tableUpdate = new TableUpdateV4(GTEST_TABLE);
 | |
|   tableUpdate->SetFullUpdate(fullUpdate);
 | |
| 
 | |
|   for (const auto& entry : add) {
 | |
|     nsCString* pstring = entry.GetWeak();
 | |
|     tableUpdate->NewPrefixes(entry.GetKey(), *pstring);
 | |
|   }
 | |
| 
 | |
|   if (removal) {
 | |
|     tableUpdate->NewRemovalIndices(removal->Elements(), removal->Length());
 | |
|   }
 | |
| 
 | |
|   if (sha256) {
 | |
|     std::string stdSHA256;
 | |
|     stdSHA256.assign(const_cast<char*>(sha256->BeginReading()),
 | |
|                      sha256->Length());
 | |
| 
 | |
|     tableUpdate->SetSHA256(stdSHA256);
 | |
|   }
 | |
| 
 | |
|   tableUpdates.AppendElement(tableUpdate);
 | |
| }
 | |
| 
 | |
| static void VerifyPrefixSet(PrefixStringMap& expected) {
 | |
|   // Verify the prefix set is written to disk.
 | |
|   nsCOMPtr<nsIFile> file;
 | |
|   NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file));
 | |
|   file->AppendNative(GTEST_SAFEBROWSING_DIR);
 | |
| 
 | |
|   RefPtr<LookupCacheV4> lookup =
 | |
|       new LookupCacheV4(GTEST_TABLE, "test"_ns, file);
 | |
|   lookup->Init();
 | |
| 
 | |
|   file->AppendNative(GTEST_PREFIXFILE);
 | |
|   lookup->LoadFromFile(file);
 | |
| 
 | |
|   PrefixStringMap prefixesInFile;
 | |
|   lookup->GetPrefixes(prefixesInFile);
 | |
| 
 | |
|   for (const auto& entry : expected) {
 | |
|     nsCString* expectedPrefix = entry.GetWeak();
 | |
|     nsCString* resultPrefix = prefixesInFile.Get(entry.GetKey());
 | |
| 
 | |
|     ASSERT_TRUE(*resultPrefix == *expectedPrefix);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void Clear() {
 | |
|   nsCOMPtr<nsIFile> file;
 | |
|   NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file));
 | |
| 
 | |
|   RefPtr<Classifier> classifier = new Classifier();
 | |
|   classifier->Open(*file);
 | |
|   classifier->Reset();
 | |
| }
 | |
| 
 | |
| static void testUpdateFail(TableUpdateArray& tableUpdates) {
 | |
|   nsresult rv = SyncApplyUpdates(tableUpdates);
 | |
|   ASSERT_NS_FAILED(rv);
 | |
| }
 | |
| 
 | |
| static void testUpdate(TableUpdateArray& tableUpdates,
 | |
|                        PrefixStringMap& expected) {
 | |
|   // Force nsUrlClassifierUtils loading on main thread
 | |
|   // because nsIUrlClassifierDBService will not run in advance
 | |
|   // in gtest.
 | |
|   nsUrlClassifierUtils::GetInstance();
 | |
| 
 | |
|   nsresult rv = SyncApplyUpdates(tableUpdates);
 | |
|   ASSERT_TRUE(rv == NS_OK);
 | |
|   VerifyPrefixSet(expected);
 | |
| }
 | |
| 
 | |
| static void testFullUpdate(PrefixStringMap& add, nsCString* sha256) {
 | |
|   TableUpdateArray tableUpdates;
 | |
| 
 | |
|   GenerateUpdateData(true, add, nullptr, sha256, tableUpdates);
 | |
| 
 | |
|   testUpdate(tableUpdates, add);
 | |
| }
 | |
| 
 | |
| static void testPartialUpdate(PrefixStringMap& add, nsTArray<uint32_t>* removal,
 | |
|                               nsCString* sha256, PrefixStringMap& expected) {
 | |
|   TableUpdateArray tableUpdates;
 | |
|   GenerateUpdateData(false, add, removal, sha256, tableUpdates);
 | |
| 
 | |
|   testUpdate(tableUpdates, expected);
 | |
| }
 | |
| 
 | |
| static void testOpenLookupCache() {
 | |
|   nsCOMPtr<nsIFile> file;
 | |
|   NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file));
 | |
|   file->AppendNative(GTEST_SAFEBROWSING_DIR);
 | |
| 
 | |
|   RunTestInNewThread([&]() -> void {
 | |
|     RefPtr<LookupCacheV4> cache =
 | |
|         new LookupCacheV4(nsCString(GTEST_TABLE), ""_ns, file);
 | |
|     nsresult rv = cache->Init();
 | |
|     ASSERT_EQ(rv, NS_OK);
 | |
| 
 | |
|     rv = cache->Open();
 | |
|     ASSERT_EQ(rv, NS_OK);
 | |
|   });
 | |
| }
 | |
| 
 | |
| // Tests start from here.
 | |
| TEST(UrlClassifierTableUpdateV4, FixLengthPSetFullUpdate)
 | |
| {
 | |
|   srand(time(NULL));
 | |
| 
 | |
|   _PrefixArray array;
 | |
|   PrefixStringMap map;
 | |
|   nsCString sha256;
 | |
| 
 | |
|   CreateRandomSortedPrefixArray(5000, 4, 4, array);
 | |
|   PrefixArrayToPrefixStringMap(array, map);
 | |
|   CalculateSHA256(array, sha256);
 | |
| 
 | |
|   testFullUpdate(map, &sha256);
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| TEST(UrlClassifierTableUpdateV4, VariableLengthPSetFullUpdate)
 | |
| {
 | |
|   _PrefixArray array;
 | |
|   PrefixStringMap map;
 | |
|   nsCString sha256;
 | |
| 
 | |
|   CreateRandomSortedPrefixArray(5000, 5, 32, array);
 | |
|   PrefixArrayToPrefixStringMap(array, map);
 | |
|   CalculateSHA256(array, sha256);
 | |
| 
 | |
|   testFullUpdate(map, &sha256);
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| // This test contain both variable length prefix set and fixed-length prefix set
 | |
| TEST(UrlClassifierTableUpdateV4, MixedPSetFullUpdate)
 | |
| {
 | |
|   _PrefixArray array;
 | |
|   PrefixStringMap map;
 | |
|   nsCString sha256;
 | |
| 
 | |
|   CreateRandomSortedPrefixArray(5000, 4, 4, array);
 | |
|   CreateRandomSortedPrefixArray(1000, 5, 32, array);
 | |
|   PrefixArrayToPrefixStringMap(array, map);
 | |
|   CalculateSHA256(array, sha256);
 | |
| 
 | |
|   testFullUpdate(map, &sha256);
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| TEST(UrlClassifierTableUpdateV4, PartialUpdateWithRemoval)
 | |
| {
 | |
|   _PrefixArray fArray;
 | |
| 
 | |
|   // Apply a full update first.
 | |
|   {
 | |
|     PrefixStringMap fMap;
 | |
|     nsCString sha256;
 | |
| 
 | |
|     CreateRandomSortedPrefixArray(10000, 4, 4, fArray);
 | |
|     CreateRandomSortedPrefixArray(2000, 5, 32, fArray);
 | |
|     PrefixArrayToPrefixStringMap(fArray, fMap);
 | |
|     CalculateSHA256(fArray, sha256);
 | |
| 
 | |
|     testFullUpdate(fMap, &sha256);
 | |
|   }
 | |
| 
 | |
|   // Apply a partial update with removal.
 | |
|   {
 | |
|     _PrefixArray pArray, mergedArray;
 | |
|     PrefixStringMap pMap, mergedMap;
 | |
|     nsCString sha256;
 | |
| 
 | |
|     CreateRandomSortedPrefixArray(5000, 4, 4, pArray);
 | |
|     CreateRandomSortedPrefixArray(1000, 5, 32, pArray);
 | |
|     RemoveIntersection(fArray, pArray);
 | |
|     PrefixArrayToPrefixStringMap(pArray, pMap);
 | |
| 
 | |
|     // Remove 1/5 of elements of original prefix set.
 | |
|     nsTArray<uint32_t> removal;
 | |
|     CreateRandomRemovalIndices(fArray.Length() / 5, fArray.Length(), removal);
 | |
|     RemoveElements(removal, fArray);
 | |
| 
 | |
|     // Calculate the expected prefix map.
 | |
|     MergeAndSortArray(fArray, pArray, mergedArray);
 | |
|     PrefixArrayToPrefixStringMap(mergedArray, mergedMap);
 | |
|     CalculateSHA256(mergedArray, sha256);
 | |
| 
 | |
|     testPartialUpdate(pMap, &removal, &sha256, mergedMap);
 | |
|   }
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| TEST(UrlClassifierTableUpdateV4, PartialUpdateWithoutRemoval)
 | |
| {
 | |
|   _PrefixArray fArray;
 | |
| 
 | |
|   // Apply a full update first.
 | |
|   {
 | |
|     PrefixStringMap fMap;
 | |
|     nsCString sha256;
 | |
| 
 | |
|     CreateRandomSortedPrefixArray(10000, 4, 4, fArray);
 | |
|     CreateRandomSortedPrefixArray(2000, 5, 32, fArray);
 | |
|     PrefixArrayToPrefixStringMap(fArray, fMap);
 | |
|     CalculateSHA256(fArray, sha256);
 | |
| 
 | |
|     testFullUpdate(fMap, &sha256);
 | |
|   }
 | |
| 
 | |
|   // Apply a partial update without removal
 | |
|   {
 | |
|     _PrefixArray pArray, mergedArray;
 | |
|     PrefixStringMap pMap, mergedMap;
 | |
|     nsCString sha256;
 | |
| 
 | |
|     CreateRandomSortedPrefixArray(5000, 4, 4, pArray);
 | |
|     CreateRandomSortedPrefixArray(1000, 5, 32, pArray);
 | |
|     RemoveIntersection(fArray, pArray);
 | |
|     PrefixArrayToPrefixStringMap(pArray, pMap);
 | |
| 
 | |
|     // Calculate the expected prefix map.
 | |
|     MergeAndSortArray(fArray, pArray, mergedArray);
 | |
|     PrefixArrayToPrefixStringMap(mergedArray, mergedMap);
 | |
|     CalculateSHA256(mergedArray, sha256);
 | |
| 
 | |
|     testPartialUpdate(pMap, nullptr, &sha256, mergedMap);
 | |
|   }
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| // Expect failure because partial update contains prefix already
 | |
| // in old prefix set.
 | |
| TEST(UrlClassifierTableUpdateV4, PartialUpdatePrefixAlreadyExist)
 | |
| {
 | |
|   _PrefixArray fArray;
 | |
| 
 | |
|   // Apply a full update fist.
 | |
|   {
 | |
|     PrefixStringMap fMap;
 | |
|     nsCString sha256;
 | |
| 
 | |
|     CreateRandomSortedPrefixArray(1000, 4, 32, fArray);
 | |
|     PrefixArrayToPrefixStringMap(fArray, fMap);
 | |
|     CalculateSHA256(fArray, sha256);
 | |
| 
 | |
|     testFullUpdate(fMap, &sha256);
 | |
|   }
 | |
| 
 | |
|   // Apply a partial update which contains a prefix in previous full update.
 | |
|   // This should cause an update error.
 | |
|   {
 | |
|     _PrefixArray pArray;
 | |
|     PrefixStringMap pMap;
 | |
|     TableUpdateArray tableUpdates;
 | |
| 
 | |
|     // Pick one prefix from full update prefix and add it to partial update.
 | |
|     // This should result a failure when call ApplyUpdates.
 | |
|     pArray.AppendElement(fArray[rand() % fArray.Length()]);
 | |
|     CreateRandomSortedPrefixArray(200, 4, 32, pArray);
 | |
|     PrefixArrayToPrefixStringMap(pArray, pMap);
 | |
| 
 | |
|     GenerateUpdateData(false, pMap, nullptr, nullptr, tableUpdates);
 | |
|     testUpdateFail(tableUpdates);
 | |
|   }
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| // Test apply partial update directly without applying an full update first.
 | |
| TEST(UrlClassifierTableUpdateV4, OnlyPartialUpdate)
 | |
| {
 | |
|   _PrefixArray pArray;
 | |
|   PrefixStringMap pMap;
 | |
|   nsCString sha256;
 | |
| 
 | |
|   CreateRandomSortedPrefixArray(5000, 4, 4, pArray);
 | |
|   CreateRandomSortedPrefixArray(1000, 5, 32, pArray);
 | |
|   PrefixArrayToPrefixStringMap(pArray, pMap);
 | |
|   CalculateSHA256(pArray, sha256);
 | |
| 
 | |
|   testPartialUpdate(pMap, nullptr, &sha256, pMap);
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| // Test partial update without any ADD prefixes, only removalIndices.
 | |
| TEST(UrlClassifierTableUpdateV4, PartialUpdateOnlyRemoval)
 | |
| {
 | |
|   _PrefixArray fArray;
 | |
| 
 | |
|   // Apply a full update first.
 | |
|   {
 | |
|     PrefixStringMap fMap;
 | |
|     nsCString sha256;
 | |
| 
 | |
|     CreateRandomSortedPrefixArray(5000, 4, 4, fArray);
 | |
|     CreateRandomSortedPrefixArray(1000, 5, 32, fArray);
 | |
|     PrefixArrayToPrefixStringMap(fArray, fMap);
 | |
|     CalculateSHA256(fArray, sha256);
 | |
| 
 | |
|     testFullUpdate(fMap, &sha256);
 | |
|   }
 | |
| 
 | |
|   // Apply a partial update without add prefix, only contain removal indices.
 | |
|   {
 | |
|     _PrefixArray pArray;
 | |
|     PrefixStringMap pMap, mergedMap;
 | |
|     nsCString sha256;
 | |
| 
 | |
|     // Remove 1/5 of elements of original prefix set.
 | |
|     nsTArray<uint32_t> removal;
 | |
|     CreateRandomRemovalIndices(fArray.Length() / 5, fArray.Length(), removal);
 | |
|     RemoveElements(removal, fArray);
 | |
| 
 | |
|     PrefixArrayToPrefixStringMap(fArray, mergedMap);
 | |
|     CalculateSHA256(fArray, sha256);
 | |
| 
 | |
|     testPartialUpdate(pMap, &removal, &sha256, mergedMap);
 | |
|   }
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| // Test one tableupdate array contains full update and multiple partial updates.
 | |
| TEST(UrlClassifierTableUpdateV4, MultipleTableUpdates)
 | |
| {
 | |
|   _PrefixArray fArray, pArray, mergedArray;
 | |
|   PrefixStringMap fMap, pMap, mergedMap;
 | |
|   nsCString sha256;
 | |
| 
 | |
|   TableUpdateArray tableUpdates;
 | |
| 
 | |
|   // Generate first full udpate
 | |
|   CreateRandomSortedPrefixArray(10000, 4, 4, fArray);
 | |
|   CreateRandomSortedPrefixArray(2000, 5, 32, fArray);
 | |
|   PrefixArrayToPrefixStringMap(fArray, fMap);
 | |
|   CalculateSHA256(fArray, sha256);
 | |
| 
 | |
|   GenerateUpdateData(true, fMap, nullptr, &sha256, tableUpdates);
 | |
| 
 | |
|   // Generate second partial update
 | |
|   CreateRandomSortedPrefixArray(3000, 4, 4, pArray);
 | |
|   CreateRandomSortedPrefixArray(1000, 5, 32, pArray);
 | |
|   RemoveIntersection(fArray, pArray);
 | |
|   PrefixArrayToPrefixStringMap(pArray, pMap);
 | |
| 
 | |
|   MergeAndSortArray(fArray, pArray, mergedArray);
 | |
|   CalculateSHA256(mergedArray, sha256);
 | |
| 
 | |
|   GenerateUpdateData(false, pMap, nullptr, &sha256, tableUpdates);
 | |
| 
 | |
|   // Generate thrid partial update
 | |
|   fArray.AppendElements(pArray);
 | |
|   fArray.Sort();
 | |
|   pArray.Clear();
 | |
|   CreateRandomSortedPrefixArray(3000, 4, 4, pArray);
 | |
|   CreateRandomSortedPrefixArray(1000, 5, 32, pArray);
 | |
|   RemoveIntersection(fArray, pArray);
 | |
|   PrefixArrayToPrefixStringMap(pArray, pMap);
 | |
| 
 | |
|   // Remove 1/5 of elements of original prefix set.
 | |
|   nsTArray<uint32_t> removal;
 | |
|   CreateRandomRemovalIndices(fArray.Length() / 5, fArray.Length(), removal);
 | |
|   RemoveElements(removal, fArray);
 | |
| 
 | |
|   MergeAndSortArray(fArray, pArray, mergedArray);
 | |
|   PrefixArrayToPrefixStringMap(mergedArray, mergedMap);
 | |
|   CalculateSHA256(mergedArray, sha256);
 | |
| 
 | |
|   GenerateUpdateData(false, pMap, &removal, &sha256, tableUpdates);
 | |
| 
 | |
|   testUpdate(tableUpdates, mergedMap);
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| // Test apply full update first, and then apply multiple partial updates
 | |
| // in one tableupdate array.
 | |
| TEST(UrlClassifierTableUpdateV4, MultiplePartialUpdateTableUpdates)
 | |
| {
 | |
|   _PrefixArray fArray;
 | |
| 
 | |
|   // Apply a full update first
 | |
|   {
 | |
|     PrefixStringMap fMap;
 | |
|     nsCString sha256;
 | |
| 
 | |
|     // Generate first full udpate
 | |
|     CreateRandomSortedPrefixArray(10000, 4, 4, fArray);
 | |
|     CreateRandomSortedPrefixArray(3000, 5, 32, fArray);
 | |
|     PrefixArrayToPrefixStringMap(fArray, fMap);
 | |
|     CalculateSHA256(fArray, sha256);
 | |
| 
 | |
|     testFullUpdate(fMap, &sha256);
 | |
|   }
 | |
| 
 | |
|   // Apply multiple partial updates in one table update
 | |
|   {
 | |
|     _PrefixArray pArray, mergedArray;
 | |
|     PrefixStringMap pMap, mergedMap;
 | |
|     nsCString sha256;
 | |
|     nsTArray<uint32_t> removal;
 | |
|     TableUpdateArray tableUpdates;
 | |
| 
 | |
|     // Generate first partial update
 | |
|     CreateRandomSortedPrefixArray(3000, 4, 4, pArray);
 | |
|     CreateRandomSortedPrefixArray(1000, 5, 32, pArray);
 | |
|     RemoveIntersection(fArray, pArray);
 | |
|     PrefixArrayToPrefixStringMap(pArray, pMap);
 | |
| 
 | |
|     // Remove 1/5 of elements of original prefix set.
 | |
|     CreateRandomRemovalIndices(fArray.Length() / 5, fArray.Length(), removal);
 | |
|     RemoveElements(removal, fArray);
 | |
| 
 | |
|     MergeAndSortArray(fArray, pArray, mergedArray);
 | |
|     CalculateSHA256(mergedArray, sha256);
 | |
| 
 | |
|     GenerateUpdateData(false, pMap, &removal, &sha256, tableUpdates);
 | |
| 
 | |
|     fArray.AppendElements(pArray);
 | |
|     fArray.Sort();
 | |
|     pArray.Clear();
 | |
|     removal.Clear();
 | |
| 
 | |
|     // Generate second partial update.
 | |
|     CreateRandomSortedPrefixArray(2000, 4, 4, pArray);
 | |
|     CreateRandomSortedPrefixArray(1000, 5, 32, pArray);
 | |
|     RemoveIntersection(fArray, pArray);
 | |
|     PrefixArrayToPrefixStringMap(pArray, pMap);
 | |
| 
 | |
|     // Remove 1/5 of elements of original prefix set.
 | |
|     CreateRandomRemovalIndices(fArray.Length() / 5, fArray.Length(), removal);
 | |
|     RemoveElements(removal, fArray);
 | |
| 
 | |
|     MergeAndSortArray(fArray, pArray, mergedArray);
 | |
|     PrefixArrayToPrefixStringMap(mergedArray, mergedMap);
 | |
|     CalculateSHA256(mergedArray, sha256);
 | |
| 
 | |
|     GenerateUpdateData(false, pMap, &removal, &sha256, tableUpdates);
 | |
| 
 | |
|     testUpdate(tableUpdates, mergedMap);
 | |
|   }
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| // Test removal indices are larger than the original prefix set.
 | |
| TEST(UrlClassifierTableUpdateV4, RemovalIndexTooLarge)
 | |
| {
 | |
|   _PrefixArray fArray;
 | |
| 
 | |
|   // Apply a full update first
 | |
|   {
 | |
|     PrefixStringMap fMap;
 | |
|     nsCString sha256;
 | |
| 
 | |
|     CreateRandomSortedPrefixArray(1000, 4, 32, fArray);
 | |
|     PrefixArrayToPrefixStringMap(fArray, fMap);
 | |
|     CalculateSHA256(fArray, sha256);
 | |
| 
 | |
|     testFullUpdate(fMap, &sha256);
 | |
|   }
 | |
| 
 | |
|   // Apply a partial update with removal indice array larger than
 | |
|   // old prefix set(fArray). This should cause an error.
 | |
|   {
 | |
|     _PrefixArray pArray;
 | |
|     PrefixStringMap pMap;
 | |
|     nsTArray<uint32_t> removal;
 | |
|     TableUpdateArray tableUpdates;
 | |
| 
 | |
|     CreateRandomSortedPrefixArray(200, 4, 32, pArray);
 | |
|     RemoveIntersection(fArray, pArray);
 | |
|     PrefixArrayToPrefixStringMap(pArray, pMap);
 | |
| 
 | |
|     for (uint32_t i = 0; i < fArray.Length() + 1; i++) {
 | |
|       removal.AppendElement(i);
 | |
|     }
 | |
| 
 | |
|     GenerateUpdateData(false, pMap, &removal, nullptr, tableUpdates);
 | |
|     testUpdateFail(tableUpdates);
 | |
|   }
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| TEST(UrlClassifierTableUpdateV4, ChecksumMismatch)
 | |
| {
 | |
|   // Apply a full update first
 | |
|   {
 | |
|     _PrefixArray fArray;
 | |
|     PrefixStringMap fMap;
 | |
|     nsCString sha256;
 | |
| 
 | |
|     CreateRandomSortedPrefixArray(1000, 4, 32, fArray);
 | |
|     PrefixArrayToPrefixStringMap(fArray, fMap);
 | |
|     CalculateSHA256(fArray, sha256);
 | |
| 
 | |
|     testFullUpdate(fMap, &sha256);
 | |
|   }
 | |
| 
 | |
|   // Apply a partial update with incorrect sha256
 | |
|   {
 | |
|     _PrefixArray pArray;
 | |
|     PrefixStringMap pMap;
 | |
|     nsCString sha256;
 | |
|     TableUpdateArray tableUpdates;
 | |
| 
 | |
|     CreateRandomSortedPrefixArray(200, 4, 32, pArray);
 | |
|     PrefixArrayToPrefixStringMap(pArray, pMap);
 | |
| 
 | |
|     // sha256 should be calculated with both old prefix set and add prefix
 | |
|     // set, here we only calculate sha256 with add prefix set to check if
 | |
|     // applyUpdate will return failure.
 | |
|     CalculateSHA256(pArray, sha256);
 | |
| 
 | |
|     GenerateUpdateData(false, pMap, nullptr, &sha256, tableUpdates);
 | |
|     testUpdateFail(tableUpdates);
 | |
|   }
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| TEST(UrlClassifierTableUpdateV4, ApplyUpdateThenLoad)
 | |
| {
 | |
|   // Apply update with sha256
 | |
|   {
 | |
|     _PrefixArray fArray;
 | |
|     PrefixStringMap fMap;
 | |
|     nsCString sha256;
 | |
| 
 | |
|     CreateRandomSortedPrefixArray(1000, 4, 32, fArray);
 | |
|     PrefixArrayToPrefixStringMap(fArray, fMap);
 | |
|     CalculateSHA256(fArray, sha256);
 | |
| 
 | |
|     testFullUpdate(fMap, &sha256);
 | |
| 
 | |
|     // Open lookup cache will load prefix set and verify the sha256
 | |
|     testOpenLookupCache();
 | |
|   }
 | |
| 
 | |
|   Clear();
 | |
| 
 | |
|   // Apply update without sha256
 | |
|   {
 | |
|     _PrefixArray fArray;
 | |
|     PrefixStringMap fMap;
 | |
| 
 | |
|     CreateRandomSortedPrefixArray(1000, 4, 32, fArray);
 | |
|     PrefixArrayToPrefixStringMap(fArray, fMap);
 | |
| 
 | |
|     testFullUpdate(fMap, nullptr);
 | |
| 
 | |
|     testOpenLookupCache();
 | |
|   }
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| // This test is used to avoid an eror from nsICryptoHash
 | |
| TEST(UrlClassifierTableUpdateV4, ApplyUpdateWithFixedChecksum)
 | |
| {
 | |
|   _PrefixArray fArray = {_Prefix("enus"),
 | |
|                          _Prefix("apollo"),
 | |
|                          _Prefix("mars"),
 | |
|                          _Prefix("Hecatonchires cyclopes"),
 | |
|                          _Prefix("vesta"),
 | |
|                          _Prefix("neptunus"),
 | |
|                          _Prefix("jupiter"),
 | |
|                          _Prefix("diana"),
 | |
|                          _Prefix("minerva"),
 | |
|                          _Prefix("ceres"),
 | |
|                          _Prefix("Aidos,Adephagia,Adikia,Aletheia"),
 | |
|                          _Prefix("hecatonchires"),
 | |
|                          _Prefix("alcyoneus"),
 | |
|                          _Prefix("hades"),
 | |
|                          _Prefix("vulcanus"),
 | |
|                          _Prefix("juno"),
 | |
|                          _Prefix("mercury"),
 | |
|                          _Prefix("Stheno, Euryale and Medusa")};
 | |
|   fArray.Sort();
 | |
| 
 | |
|   PrefixStringMap fMap;
 | |
|   PrefixArrayToPrefixStringMap(fArray, fMap);
 | |
| 
 | |
|   nsCString sha256(
 | |
|       "\xae\x18\x94\xd7\xd0\x83\x5f\xc1"
 | |
|       "\x58\x59\x5c\x2c\x72\xb9\x6e\x5e"
 | |
|       "\xf4\xe8\x0a\x6b\xff\x5e\x6b\x81"
 | |
|       "\x65\x34\x06\x16\x06\x59\xa0\x67");
 | |
| 
 | |
|   testFullUpdate(fMap, &sha256);
 | |
| 
 | |
|   // Open lookup cache will load prefix set and verify the sha256
 | |
|   testOpenLookupCache();
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| // This test ensure that an empty update works correctly. Empty update
 | |
| // should be skipped by CheckValidUpdate in Classifier::UpdateTableV4.
 | |
| TEST(UrlClassifierTableUpdateV4, EmptyUpdate)
 | |
| {
 | |
|   PrefixStringMap emptyAddition;
 | |
|   nsTArray<uint32_t> emptyRemoval;
 | |
| 
 | |
|   _PrefixArray array;
 | |
|   PrefixStringMap map;
 | |
|   nsCString sha256;
 | |
| 
 | |
|   CalculateSHA256(array, sha256);
 | |
| 
 | |
|   // Test apply empty full/partial update before we already
 | |
|   // have data in DB.
 | |
|   testFullUpdate(emptyAddition, &sha256);
 | |
|   testPartialUpdate(emptyAddition, &emptyRemoval, &sha256, map);
 | |
| 
 | |
|   // Apply an full update.
 | |
|   CreateRandomSortedPrefixArray(100, 4, 4, array);
 | |
|   CreateRandomSortedPrefixArray(10, 5, 32, array);
 | |
|   PrefixArrayToPrefixStringMap(array, map);
 | |
|   CalculateSHA256(array, sha256);
 | |
| 
 | |
|   testFullUpdate(map, &sha256);
 | |
| 
 | |
|   // Test apply empty full/partial update when we already
 | |
|   // have data in DB
 | |
|   testPartialUpdate(emptyAddition, &emptyRemoval, &sha256, map);
 | |
|   testFullUpdate(emptyAddition, &sha256);
 | |
| 
 | |
|   Clear();
 | |
| }
 | |
| 
 | |
| // This test ensure applying an empty update directly through update algorithm
 | |
| // should be correct.
 | |
| TEST(UrlClassifierTableUpdateV4, EmptyUpdate2)
 | |
| {
 | |
|   // Setup LookupCache with initial data
 | |
|   _PrefixArray array;
 | |
|   CreateRandomSortedPrefixArray(100, 4, 4, array);
 | |
|   CreateRandomSortedPrefixArray(10, 5, 32, array);
 | |
|   RefPtr<LookupCacheV4> cache = SetupLookupCache<LookupCacheV4>(array);
 | |
| 
 | |
|   // Setup TableUpdate object with only sha256 from previous update(initial
 | |
|   // data).
 | |
|   nsCString sha256;
 | |
|   CalculateSHA256(array, sha256);
 | |
|   std::string stdSHA256;
 | |
|   stdSHA256.assign(const_cast<char*>(sha256.BeginReading()), sha256.Length());
 | |
| 
 | |
|   RefPtr<TableUpdateV4> tableUpdate = new TableUpdateV4(GTEST_TABLE);
 | |
|   tableUpdate->SetSHA256(stdSHA256);
 | |
| 
 | |
|   // Apply update directly through LookupCache interface
 | |
|   PrefixStringMap input, output;
 | |
|   PrefixArrayToPrefixStringMap(array, input);
 | |
|   nsresult rv = cache->ApplyUpdate(tableUpdate.get(), input, output);
 | |
| 
 | |
|   ASSERT_TRUE(rv == NS_OK);
 | |
| 
 | |
|   Clear();
 | |
| }
 |