Bug 1305780 - P2. Testcase for update fail. r?gcp draft
authordimi <dlee@mozilla.com>
Mon, 24 Oct 2016 08:43:54 +0800
changeset 428478 a9550b939404dbdb9cfabc74941d3943aa5d0906
parent 428477 2f2c5ba16311628f89bec4553ae2ce0cc5f6b23b
child 534733 c16ee08439bcf7664d4ac245207233d2aa28f880
push id33308
push userdlee@mozilla.com
push dateMon, 24 Oct 2016 00:44:22 +0000
reviewersgcp
bugs1305780
milestone52.0a1
Bug 1305780 - P2. Testcase for update fail. r?gcp MozReview-Commit-ID: CopsfRuawdm
toolkit/components/url-classifier/tests/gtest/Common.cpp
toolkit/components/url-classifier/tests/gtest/Common.h
toolkit/components/url-classifier/tests/gtest/TestFailUpdate.cpp
toolkit/components/url-classifier/tests/gtest/TestPerProviderDirectory.cpp
toolkit/components/url-classifier/tests/gtest/moz.build
new file mode 100644
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/gtest/Common.cpp
@@ -0,0 +1,53 @@
+#include "Common.h"
+#include "HashStore.h"
+#include "Classifier.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsTArray.h"
+#include "nsIThread.h"
+#include "nsThreadUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::safebrowsing;
+
+template<typename Function>
+void RunTestInNewThread(Function&& aFunction) {
+  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(mozilla::Forward<Function>(aFunction));
+  nsCOMPtr<nsIThread> testingThread;
+  nsresult rv = NS_NewThread(getter_AddRefs(testingThread), r);
+  ASSERT_EQ(rv, NS_OK);
+  testingThread->Shutdown();
+}
+
+already_AddRefed<nsIFile>
+GetFile(const nsTArray<nsString>& path)
+{
+  nsCOMPtr<nsIFile> file;
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  for (uint32_t i = 0; i < path.Length(); i++) {
+    file->Append(path[i]);
+  }
+  return file.forget();
+}
+
+void ApplyUpdate(nsTArray<TableUpdate*>& updates)
+{
+  nsCOMPtr<nsIFile> file;
+  NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(file));
+
+  UniquePtr<Classifier> classifier(new Classifier());
+  classifier->Open(*file);
+
+  RunTestInNewThread([&] () -> void {
+    classifier->ApplyUpdates(&updates);
+  });
+}
+
+void ApplyUpdate(TableUpdate* update)
+{
+  nsTArray<TableUpdate*> updates = { update };
+  ApplyUpdate(updates);
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/gtest/Common.h
@@ -0,0 +1,21 @@
+#include "HashStore.h"
+#include "nsIFile.h"
+#include "nsTArray.h"
+#include "gtest/gtest.h"
+
+using namespace mozilla;
+using namespace mozilla::safebrowsing;
+
+template<typename Function>
+void RunTestInNewThread(Function&& aFunction);
+
+// Return nsIFile with root directory - NS_APP_USER_PROFILE_50_DIR
+// Sub-directories are passed in path argument.
+already_AddRefed<nsIFile>
+GetFile(const nsTArray<nsString>& path);
+
+// ApplyUpdate will call |ApplyUpdates| of Classifier within a new thread
+void ApplyUpdate(nsTArray<TableUpdate*>& updates);
+
+void ApplyUpdate(TableUpdate* update);
+
new file mode 100644
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/gtest/TestFailUpdate.cpp
@@ -0,0 +1,97 @@
+#include "HashStore.h"
+#include "nsPrintfCString.h"
+#include "string.h"
+#include "gtest/gtest.h"
+#include "mozilla/Unused.h"
+
+using namespace mozilla;
+using namespace mozilla::safebrowsing;
+
+static const char* kFilesInV2[] = {".pset", ".sbstore"};
+static const char* kFilesInV4[] = {".pset", ".metadata"};
+
+#define V2_TABLE  "gtest-malware-simple"
+#define V4_TABLE1 "goog-malware-proto"
+#define V4_TABLE2 "goog-phish-proto"
+
+#define ROOT_DIR        NS_LITERAL_STRING("safebrowsing")
+#define SB_FILE(x, y)   NS_ConvertUTF8toUTF16(nsPrintfCString("%s%s",x, y))
+
+template<typename T, size_t N>
+void CheckFileExist(const char* table, const T (&files)[N], bool expectExists)
+{
+  for (uint32_t i = 0; i < N; i++) {
+    // This is just a quick way to know if this is v4 table
+    NS_ConvertUTF8toUTF16 SUB_DIR(strstr(table, "-proto") ? "google4" : "");
+    nsCOMPtr<nsIFile> file =
+      GetFile(nsTArray<nsString> { ROOT_DIR, SUB_DIR, SB_FILE(table, files[i]) });
+
+    bool exists;
+    file->Exists(&exists);
+
+    nsAutoCString path;
+    file->GetNativePath(path);
+    ASSERT_EQ(expectExists, exists) << path.get();
+  }
+}
+
+TEST(FailUpdate, CheckTableReset)
+{
+  const bool FULL_UPDATE = true;
+  const bool PARTIAL_UPDATE = false;
+
+  // Apply V2 update
+  {
+    auto update = new TableUpdateV2(NS_LITERAL_CSTRING(V2_TABLE));
+    Unused << update->NewAddChunk(1);
+
+    ApplyUpdate(update);
+
+    // A successful V2 update should create .pset & .sbstore files
+    CheckFileExist(V2_TABLE, kFilesInV2, true);
+  }
+
+  // Helper function to generate table update data
+  auto func = [](TableUpdateV4* update, bool full, const char* str) {
+    update->SetFullUpdate(full);
+    std::string prefix(str);
+    update->NewPrefixes(prefix.length(), prefix);
+  };
+
+  // Apply V4 update for table1
+  {
+    auto update = new TableUpdateV4(NS_LITERAL_CSTRING(V4_TABLE1));
+    func(update, FULL_UPDATE, "test_prefix");
+
+    ApplyUpdate(update);
+
+    // A successful V4 update should create .pset & .metadata files
+    CheckFileExist(V4_TABLE1, kFilesInV4, true);
+  }
+
+  // Apply V4 update for table2
+  {
+    auto update = new TableUpdateV4(NS_LITERAL_CSTRING(V4_TABLE2));
+    func(update, FULL_UPDATE, "test_prefix");
+
+    ApplyUpdate(update);
+
+    CheckFileExist(V4_TABLE2, kFilesInV4, true);
+  }
+
+  // Apply V4 update with the same prefix in previous full udpate
+  // This should cause an update error.
+  {
+    auto update = new TableUpdateV4(NS_LITERAL_CSTRING(V4_TABLE1));
+    func(update, PARTIAL_UPDATE, "test_prefix");
+
+    ApplyUpdate(update);
+
+    // A fail update should remove files for that table
+    CheckFileExist(V4_TABLE1, kFilesInV4, false);
+
+    // A fail update should NOT remove files for the other tables
+    CheckFileExist(V2_TABLE, kFilesInV2, true);
+    CheckFileExist(V4_TABLE2, kFilesInV4, true);
+  }
+}
--- a/toolkit/components/url-classifier/tests/gtest/TestPerProviderDirectory.cpp
+++ b/toolkit/components/url-classifier/tests/gtest/TestPerProviderDirectory.cpp
@@ -19,25 +19,16 @@ public:
 };
 
 } // end of namespace safebrowsing
 } // end of namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::safebrowsing;
 
-template<typename Function>
-void RunTestInNewThread(Function&& aFunction) {
-  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(mozilla::Forward<Function>(aFunction));
-  nsCOMPtr<nsIThread> testingThread;
-  nsresult rv = NS_NewThread(getter_AddRefs(testingThread), r);
-  ASSERT_EQ(rv, NS_OK);
-  testingThread->Shutdown();
-}
-
 template<typename T>
 void VerifyPrivateStorePath(const char* aTableName,
                             const char* aProvider,
                             nsIFile* aRootDir,
                             bool aUsePerProviderStore)
 {
   nsString rootStorePath;
   nsresult rv = aRootDir->GetPath(rootStorePath);
--- a/toolkit/components/url-classifier/tests/gtest/moz.build
+++ b/toolkit/components/url-classifier/tests/gtest/moz.build
@@ -4,17 +4,19 @@
 # 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/.
 
 LOCAL_INCLUDES += [
     '../..',
 ]
 
 UNIFIED_SOURCES += [
+    'Common.cpp',
     'TestChunkSet.cpp',
+    'TestFailUpdate.cpp',
     'TestPerProviderDirectory.cpp',
     'TestProtocolParser.cpp',
     'TestRiceDeltaDecoder.cpp',
     'TestSafebrowsingHash.cpp',
     'TestSafeBrowsingProtobuf.cpp',
     'TestTable.cpp',
     'TestUrlClassifierTableUpdateV4.cpp',
     'TestUrlClassifierUtils.cpp',