Bug 1120295 - test case for "Clear Recent History" command. r=cpearce. a=lmandel
authorJW Wang <jwwang@mozilla.com>
Tue, 13 Jan 2015 00:32:00 +0100
changeset 250172 3c5c3aa669f6
parent 250171 74d72da474f9
child 250173 589dc8554797
push id4521
push usercpearce@mozilla.com
push date2015-03-04 01:22 +0000
treeherdermozilla-beta@8abdbdecd2d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, lmandel
bugs1120295
milestone37.0
Bug 1120295 - test case for "Clear Recent History" command. r=cpearce. a=lmandel
dom/media/gtest/TestGMPCrossOrigin.cpp
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp
+++ b/dom/media/gtest/TestGMPCrossOrigin.cpp
@@ -115,50 +115,72 @@ GetGMPThread()
 {
   nsRefPtr<GeckoMediaPluginService> service =
     GeckoMediaPluginService::GetGeckoMediaPluginService();
   nsCOMPtr<nsIThread> thread;
   EXPECT_TRUE(NS_SUCCEEDED(service->GetThread(getter_AddRefs(thread))));
   return thread.forget();
 }
 
+/**
+ * Enumerate files under |aPath| (non-recursive).
+ */
 template<typename T>
 static nsresult
-EnumerateDir(const nsACString& aDir, T&& aDirIter)
+EnumerateDir(nsIFile* aPath, T&& aDirIter)
+{
+  nsCOMPtr<nsISimpleEnumerator> iter;
+  nsresult rv = aPath->GetDirectoryEntries(getter_AddRefs(iter));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  bool hasMore = false;
+  while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
+    nsCOMPtr<nsISupports> supports;
+    rv = iter->GetNext(getter_AddRefs(supports));
+    if (NS_FAILED(rv)) {
+      continue;
+    }
+
+    nsCOMPtr<nsIFile> entry(do_QueryInterface(supports, &rv));
+    if (NS_FAILED(rv)) {
+      continue;
+    }
+
+    aDirIter(entry);
+  }
+  return NS_OK;
+}
+
+/**
+ * Enumerate files under $profileDir/gmp/$aDir/ (non-recursive).
+ */
+template<typename T>
+static nsresult
+EnumerateGMPStorageDir(const nsACString& aDir, T&& aDirIter)
 {
   nsRefPtr<GeckoMediaPluginService> service =
     GeckoMediaPluginService::GetGeckoMediaPluginService();
   MOZ_ASSERT(service);
 
   // $profileDir/gmp/
   nsCOMPtr<nsIFile> path;
   nsresult rv = service->GetStorageDir(getter_AddRefs(path));
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
   // $profileDir/gmp/$aDir/
   rv = path->AppendNative(aDir);
-  NS_ENSURE_SUCCESS(rv, rv);
-  // Iterate all sub-folders of $profileDir/gmp/$aDir/
-  nsCOMPtr<nsISimpleEnumerator> iter;
-  rv = path->GetDirectoryEntries(getter_AddRefs(iter));
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
-  bool hasMore = false;
-  while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
-    nsCOMPtr<nsISupports> supports;
-    rv = iter->GetNext(getter_AddRefs(supports));
-    if (NS_FAILED(rv)) {
-      continue;
-    }
-    nsCOMPtr<nsIFile> entry(do_QueryInterface(supports, &rv));
-    if (NS_FAILED(rv)) {
-      continue;
-    }
-    aDirIter(entry);
-  }
-  return NS_OK;
+  return EnumerateDir(path, aDirIter);
 }
 
 class GMPShutdownObserver : public nsIRunnable
                           , public nsIObserver {
 public:
   GMPShutdownObserver(nsIRunnable* aShutdownTask,
                       nsIRunnable* Continuation,
                       const nsACString& aNodeId)
@@ -222,31 +244,37 @@ public:
   }
   const char* mTopic;
 };
 
 class ClearGMPStorageTask : public nsIRunnable
                           , public nsIObserver {
 public:
   ClearGMPStorageTask(nsIRunnable* Continuation,
-                      nsIThread* aTarget)
+                      nsIThread* aTarget, PRTime aSince)
     : mContinuation(Continuation)
     , mTarget(aTarget)
+    , mSince(aSince)
   {}
 
   NS_DECL_THREADSAFE_ISUPPORTS
 
   NS_IMETHOD Run() MOZ_OVERRIDE {
     MOZ_ASSERT(NS_IsMainThread());
     nsCOMPtr<nsIObserverService> observerService =
         mozilla::services::GetObserverService();
     EXPECT_TRUE(observerService);
     observerService->AddObserver(this, "gmp-clear-storage-complete", false);
     if (observerService) {
-      observerService->NotifyObservers(nullptr, "browser:purge-session-history", nullptr);
+      nsAutoString str;
+      if (mSince >= 0) {
+        str.AppendInt(static_cast<int64_t>(mSince));
+      }
+      observerService->NotifyObservers(
+          nullptr, "browser:purge-session-history", str.Data());
     }
     return NS_OK;
   }
 
   NS_IMETHOD Observe(nsISupports* aSubject,
                      const char* aTopic,
                      const char16_t* aSomeData) MOZ_OVERRIDE
   {
@@ -259,25 +287,27 @@ public:
     }
     return NS_OK;
   }
 
 private:
   virtual ~ClearGMPStorageTask() {}
   nsRefPtr<nsIRunnable> mContinuation;
   nsCOMPtr<nsIThread> mTarget;
+  const PRTime mSince;
 };
 
 NS_IMPL_ISUPPORTS(ClearGMPStorageTask, nsIRunnable, nsIObserver)
 
 static void
 ClearGMPStorage(nsIRunnable* aContinuation,
-                nsIThread* aTarget)
+                nsIThread* aTarget, PRTime aSince = -1)
 {
-  nsRefPtr<ClearGMPStorageTask> task(new ClearGMPStorageTask(aContinuation, aTarget));
+  nsRefPtr<ClearGMPStorageTask> task(
+      new ClearGMPStorageTask(aContinuation, aTarget, aSince));
   NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL);
 }
 
 static void
 SimulatePBModeExit()
 {
   NS_DispatchToMainThread(new NotifyObserversTask("last-pb-context-exited"), NS_DISPATCH_SYNC);
 }
@@ -503,17 +533,17 @@ class GMPStorageTest : public GMPDecrypt
   private:
     NodeInfo* mNodeInfo;
   };
 
   void TestForgetThisSite_CollectSiteInfo() {
     nsAutoPtr<NodeInfo> siteInfo(
         new NodeInfo(NS_LITERAL_CSTRING("example1.com")));
     // Collect nodeIds that are expected to remain for later comparison.
-    EnumerateDir(NS_LITERAL_CSTRING("id"), NodeIdCollector(siteInfo));
+    EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), NodeIdCollector(siteInfo));
     // Invoke "Forget this site" on the main thread.
     NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<nsAutoPtr<NodeInfo>>(
         this, &GMPStorageTest::TestForgetThisSite_Forget, siteInfo));
   }
 
   void TestForgetThisSite_Forget(nsAutoPtr<NodeInfo> aSiteInfo) {
     nsRefPtr<GeckoMediaPluginService> service =
         GeckoMediaPluginService::GetGeckoMediaPluginService();
@@ -566,25 +596,186 @@ class GMPStorageTest : public GMPDecrypt
     ~StorageVerifier() {
       EXPECT_TRUE(mExpectedRemainingNodeIds.IsEmpty());
     }
   private:
     nsTArray<nsCString> mExpectedRemainingNodeIds;
   };
 
   void TestForgetThisSite_Verify(nsAutoPtr<NodeInfo> aSiteInfo) {
-    nsresult rv = EnumerateDir(
+    nsresult rv = EnumerateGMPStorageDir(
         NS_LITERAL_CSTRING("id"), NodeIdVerifier(aSiteInfo));
     EXPECT_TRUE(NS_SUCCEEDED(rv));
 
-    rv = EnumerateDir(
+    rv = EnumerateGMPStorageDir(
         NS_LITERAL_CSTRING("storage"), StorageVerifier(aSiteInfo));
     EXPECT_TRUE(NS_SUCCEEDED(rv));
   }
 
+  /**
+   * 1. Generate some storage data.
+   * 2. Find the max mtime |t| in $profileDir/gmp/id/.
+   * 3. Pass |t| to clear recent history.
+   * 4. Check if all directories in $profileDir/gmp/id/ and
+   *    $profileDir/gmp/storage are removed.
+   */
+  void TestClearRecentHistory1() {
+    AssertIsOnGMPThread();
+    EXPECT_TRUE(IsGMPStorageIsEmpty());
+
+    // Generate storage data for some site.
+    CreateDecryptor(NS_LITERAL_STRING("example1.com"),
+                    NS_LITERAL_STRING("example2.com"),
+                    false);
+
+    nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
+        this, &GMPStorageTest::TestClearRecentHistory1_Clear);
+    Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
+    Update(NS_LITERAL_CSTRING("test-storage"));
+
+  }
+
+  /**
+   * 1. Generate some storage data.
+   * 2. Find the max mtime |t| in $profileDir/gmp/storage/.
+   * 3. Pass |t| to clear recent history.
+   * 4. Check if all directories in $profileDir/gmp/id/ and
+   *    $profileDir/gmp/storage are removed.
+   */
+  void TestClearRecentHistory2() {
+    AssertIsOnGMPThread();
+    EXPECT_TRUE(IsGMPStorageIsEmpty());
+
+    // Generate storage data for some site.
+    CreateDecryptor(NS_LITERAL_STRING("example1.com"),
+                    NS_LITERAL_STRING("example2.com"),
+                    false);
+
+    nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
+        this, &GMPStorageTest::TestClearRecentHistory2_Clear);
+    Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
+    Update(NS_LITERAL_CSTRING("test-storage"));
+
+  }
+
+  /**
+   * 1. Generate some storage data.
+   * 2. Find the max mtime |t| in $profileDir/gmp/storage/.
+   * 3. Pass |t+1| to clear recent history.
+   * 4. Check if all directories in $profileDir/gmp/id/ and
+   *    $profileDir/gmp/storage remain unchanged.
+   */
+  void TestClearRecentHistory3() {
+    AssertIsOnGMPThread();
+    EXPECT_TRUE(IsGMPStorageIsEmpty());
+
+    // Generate storage data for some site.
+    CreateDecryptor(NS_LITERAL_STRING("example1.com"),
+                    NS_LITERAL_STRING("example2.com"),
+                    false);
+
+    nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
+        this, &GMPStorageTest::TestClearRecentHistory3_Clear);
+    Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
+    Update(NS_LITERAL_CSTRING("test-storage"));
+
+  }
+
+  class MaxMTimeFinder {
+  public:
+    MaxMTimeFinder() : mMaxTime(0) {}
+    void operator()(nsIFile* aFile) {
+      PRTime lastModified;
+      nsresult rv = aFile->GetLastModifiedTime(&lastModified);
+      if (NS_SUCCEEDED(rv) && lastModified > mMaxTime) {
+        mMaxTime = lastModified;
+      }
+      EnumerateDir(aFile, *this);
+    }
+    PRTime GetResult() const { return mMaxTime; }
+  private:
+    PRTime mMaxTime;
+  };
+
+  void TestClearRecentHistory1_Clear() {
+    MaxMTimeFinder f;
+    nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), f);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+    nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
+        this, &GMPStorageTest::TestClearRecentHistory_CheckEmpty);
+    nsCOMPtr<nsIThread> t(GetGMPThread());
+    ClearGMPStorage(r, t, f.GetResult());
+  }
+
+  void TestClearRecentHistory2_Clear() {
+    MaxMTimeFinder f;
+    nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), f);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+    nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
+        this, &GMPStorageTest::TestClearRecentHistory_CheckEmpty);
+    nsCOMPtr<nsIThread> t(GetGMPThread());
+    ClearGMPStorage(r, t, f.GetResult());
+  }
+
+  void TestClearRecentHistory3_Clear() {
+    MaxMTimeFinder f;
+    nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), f);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+    nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
+        this, &GMPStorageTest::TestClearRecentHistory_CheckNonEmpty);
+    nsCOMPtr<nsIThread> t(GetGMPThread());
+    ClearGMPStorage(r, t, f.GetResult() + 1);
+  }
+
+  class FileCounter {
+  public:
+    FileCounter() : mCount(0) {}
+    void operator()(nsIFile* aFile) {
+      ++mCount;
+    }
+    int GetCount() const { return mCount; }
+  private:
+    int mCount;
+  };
+
+  void TestClearRecentHistory_CheckEmpty() {
+    FileCounter c1;
+    nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), c1);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+    // There should be no files under $profileDir/gmp/id/
+    EXPECT_EQ(c1.GetCount(), 0);
+
+    FileCounter c2;
+    rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), c2);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+    // There should be no files under $profileDir/gmp/storage/
+    EXPECT_EQ(c2.GetCount(), 0);
+
+    SetFinished();
+  }
+
+  void TestClearRecentHistory_CheckNonEmpty() {
+    FileCounter c1;
+    nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), c1);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+    // There should be one directory under $profileDir/gmp/id/
+    EXPECT_EQ(c1.GetCount(), 1);
+
+    FileCounter c2;
+    rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), c2);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+    // There should be one directory under $profileDir/gmp/storage/
+    EXPECT_EQ(c2.GetCount(), 1);
+
+    SetFinished();
+  }
+
   void TestCrossOriginStorage() {
     EXPECT_TRUE(!mDecryptor);
 
     // Open decryptor on one, origin, write a record, and test that that
     // record can't be read on another origin.
     CreateDecryptor(NS_LITERAL_STRING("example3.com"),
                     NS_LITERAL_STRING("example4.com"),
                     false);
@@ -986,16 +1177,31 @@ TEST(GeckoMediaPlugins, GMPStorageBasic)
   runner->DoTest(&GMPStorageTest::TestBasicStorage);
 }
 
 TEST(GeckoMediaPlugins, GMPStorageForgetThisSite) {
   nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
   runner->DoTest(&GMPStorageTest::TestForgetThisSite);
 }
 
+TEST(GeckoMediaPlugins, GMPStorageClearRecentHistory1) {
+  nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
+  runner->DoTest(&GMPStorageTest::TestClearRecentHistory1);
+}
+
+TEST(GeckoMediaPlugins, GMPStorageClearRecentHistory2) {
+  nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
+  runner->DoTest(&GMPStorageTest::TestClearRecentHistory2);
+}
+
+TEST(GeckoMediaPlugins, GMPStorageClearRecentHistory3) {
+  nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
+  runner->DoTest(&GMPStorageTest::TestClearRecentHistory3);
+}
+
 TEST(GeckoMediaPlugins, GMPStorageCrossOrigin) {
   nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
   runner->DoTest(&GMPStorageTest::TestCrossOriginStorage);
 }
 
 TEST(GeckoMediaPlugins, GMPStoragePrivateBrowsing) {
   nsRefPtr<GMPStorageTest> runner = new GMPStorageTest();
   runner->DoTest(&GMPStorageTest::TestPBStorage);