1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "gtest/gtest.h"
8 
9 #include "mozilla/RefPtr.h"
10 #include "mozilla/SchedulerGroup.h"
11 
12 #include "ChromiumCDMCallback.h"
13 #include "GMPTestMonitor.h"
14 #include "GMPServiceParent.h"
15 #include "MediaResult.h"
16 #include "nsIFile.h"
17 #include "nsNSSComponent.h"  //For EnsureNSSInitializedChromeOrContent
18 #include "nsThreadUtils.h"
19 
20 using namespace mozilla;
21 using namespace mozilla::gmp;
22 
GetGMPThread()23 static already_AddRefed<nsIThread> GetGMPThread() {
24   RefPtr<GeckoMediaPluginService> service =
25       GeckoMediaPluginService::GetGeckoMediaPluginService();
26   nsCOMPtr<nsIThread> thread;
27   EXPECT_TRUE(NS_SUCCEEDED(service->GetThread(getter_AddRefs(thread))));
28   return thread.forget();
29 }
30 
GetAbstractGMPThread()31 static RefPtr<AbstractThread> GetAbstractGMPThread() {
32   RefPtr<GeckoMediaPluginService> service =
33       GeckoMediaPluginService::GetGeckoMediaPluginService();
34   return service->GetAbstractGMPThread();
35 }
36 /**
37  * Enumerate files under |aPath| (non-recursive).
38  */
39 template <typename T>
EnumerateDir(nsIFile * aPath,T && aDirIter)40 static nsresult EnumerateDir(nsIFile* aPath, T&& aDirIter) {
41   nsCOMPtr<nsIDirectoryEnumerator> iter;
42   nsresult rv = aPath->GetDirectoryEntries(getter_AddRefs(iter));
43   if (NS_FAILED(rv)) {
44     return rv;
45   }
46 
47   nsCOMPtr<nsIFile> entry;
48   while (NS_SUCCEEDED(iter->GetNextFile(getter_AddRefs(entry))) && entry) {
49     aDirIter(entry);
50   }
51   return NS_OK;
52 }
53 
54 /**
55  * Enumerate files under $profileDir/gmp/$platform/gmp-fake/$aDir/
56  * (non-recursive).
57  */
58 template <typename T>
EnumerateCDMStorageDir(const nsACString & aDir,T && aDirIter)59 static nsresult EnumerateCDMStorageDir(const nsACString& aDir, T&& aDirIter) {
60   RefPtr<GeckoMediaPluginServiceParent> service =
61       GeckoMediaPluginServiceParent::GetSingleton();
62   MOZ_ASSERT(service);
63 
64   // $profileDir/gmp/$platform/
65   nsCOMPtr<nsIFile> path;
66   nsresult rv = service->GetStorageDir(getter_AddRefs(path));
67   if (NS_FAILED(rv)) {
68     return rv;
69   }
70 
71   // $profileDir/gmp/$platform/gmp-fake/
72   rv = path->Append(NS_LITERAL_STRING("gmp-fake"));
73   if (NS_FAILED(rv)) {
74     return rv;
75   }
76 
77   // $profileDir/gmp/$platform/gmp-fake/$aDir/
78   rv = path->AppendNative(aDir);
79   if (NS_FAILED(rv)) {
80     return rv;
81   }
82 
83   return EnumerateDir(path, aDirIter);
84 }
85 
86 class GMPShutdownObserver : public nsIRunnable, public nsIObserver {
87  public:
GMPShutdownObserver(already_AddRefed<nsIRunnable> aShutdownTask,already_AddRefed<nsIRunnable> Continuation,const nsACString & aNodeId)88   GMPShutdownObserver(already_AddRefed<nsIRunnable> aShutdownTask,
89                       already_AddRefed<nsIRunnable> Continuation,
90                       const nsACString& aNodeId)
91       : mShutdownTask(aShutdownTask),
92         mContinuation(Continuation),
93         mNodeId(NS_ConvertUTF8toUTF16(aNodeId)) {}
94 
95   NS_DECL_THREADSAFE_ISUPPORTS
96 
Run()97   NS_IMETHOD Run() override {
98     MOZ_ASSERT(NS_IsMainThread());
99     nsCOMPtr<nsIObserverService> observerService =
100         mozilla::services::GetObserverService();
101     EXPECT_TRUE(observerService);
102     observerService->AddObserver(this, "gmp-shutdown", false);
103 
104     nsCOMPtr<nsIThread> thread(GetGMPThread());
105     thread->Dispatch(mShutdownTask, NS_DISPATCH_NORMAL);
106     return NS_OK;
107   }
108 
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aSomeData)109   NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
110                      const char16_t* aSomeData) override {
111     if (!strcmp(aTopic, "gmp-shutdown") &&
112         mNodeId.Equals(nsDependentString(aSomeData))) {
113       nsCOMPtr<nsIObserverService> observerService =
114           mozilla::services::GetObserverService();
115       EXPECT_TRUE(observerService);
116       observerService->RemoveObserver(this, "gmp-shutdown");
117       nsCOMPtr<nsIThread> thread(GetGMPThread());
118       thread->Dispatch(mContinuation, NS_DISPATCH_NORMAL);
119     }
120     return NS_OK;
121   }
122 
123  private:
124   virtual ~GMPShutdownObserver() = default;
125   nsCOMPtr<nsIRunnable> mShutdownTask;
126   nsCOMPtr<nsIRunnable> mContinuation;
127   const nsString mNodeId;
128 };
129 
130 NS_IMPL_ISUPPORTS(GMPShutdownObserver, nsIRunnable, nsIObserver)
131 
132 class NotifyObserversTask : public Runnable {
133  public:
NotifyObserversTask(const char * aTopic)134   explicit NotifyObserversTask(const char* aTopic)
135       : mozilla::Runnable("NotifyObserversTask"), mTopic(aTopic) {}
Run()136   NS_IMETHOD Run() override {
137     MOZ_ASSERT(NS_IsMainThread());
138     nsCOMPtr<nsIObserverService> observerService =
139         mozilla::services::GetObserverService();
140     if (observerService) {
141       observerService->NotifyObservers(nullptr, mTopic, nullptr);
142     }
143     return NS_OK;
144   }
145   const char* mTopic;
146 };
147 
148 class ClearCDMStorageTask : public nsIRunnable, public nsIObserver {
149  public:
ClearCDMStorageTask(already_AddRefed<nsIRunnable> Continuation,nsIThread * aTarget,PRTime aSince)150   ClearCDMStorageTask(already_AddRefed<nsIRunnable> Continuation,
151                       nsIThread* aTarget, PRTime aSince)
152       : mContinuation(Continuation), mTarget(aTarget), mSince(aSince) {}
153 
154   NS_DECL_THREADSAFE_ISUPPORTS
155 
Run()156   NS_IMETHOD Run() override {
157     MOZ_ASSERT(NS_IsMainThread());
158     nsCOMPtr<nsIObserverService> observerService =
159         mozilla::services::GetObserverService();
160     EXPECT_TRUE(observerService);
161     observerService->AddObserver(this, "gmp-clear-storage-complete", false);
162     if (observerService) {
163       nsAutoString str;
164       if (mSince >= 0) {
165         str.AppendInt(static_cast<int64_t>(mSince));
166       }
167       observerService->NotifyObservers(nullptr, "browser:purge-session-history",
168                                        str.Data());
169     }
170     return NS_OK;
171   }
172 
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aSomeData)173   NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
174                      const char16_t* aSomeData) override {
175     if (!strcmp(aTopic, "gmp-clear-storage-complete")) {
176       nsCOMPtr<nsIObserverService> observerService =
177           mozilla::services::GetObserverService();
178       EXPECT_TRUE(observerService);
179       observerService->RemoveObserver(this, "gmp-clear-storage-complete");
180       mTarget->Dispatch(mContinuation, NS_DISPATCH_NORMAL);
181     }
182     return NS_OK;
183   }
184 
185  private:
186   virtual ~ClearCDMStorageTask() = default;
187   nsCOMPtr<nsIRunnable> mContinuation;
188   nsCOMPtr<nsIThread> mTarget;
189   const PRTime mSince;
190 };
191 
NS_IMPL_ISUPPORTS(ClearCDMStorageTask,nsIRunnable,nsIObserver)192 NS_IMPL_ISUPPORTS(ClearCDMStorageTask, nsIRunnable, nsIObserver)
193 
194 static void ClearCDMStorage(already_AddRefed<nsIRunnable> aContinuation,
195                             nsIThread* aTarget, PRTime aSince = -1) {
196   RefPtr<ClearCDMStorageTask> task(
197       new ClearCDMStorageTask(std::move(aContinuation), aTarget, aSince));
198   SchedulerGroup::Dispatch(TaskCategory::Other, task.forget());
199 }
200 
SimulatePBModeExit()201 static void SimulatePBModeExit() {
202   NS_DispatchToMainThread(new NotifyObserversTask("last-pb-context-exited"),
203                           NS_DISPATCH_SYNC);
204 }
205 
206 class TestGetNodeIdCallback : public GetNodeIdCallback {
207  public:
TestGetNodeIdCallback(nsCString & aNodeId,nsresult & aResult)208   TestGetNodeIdCallback(nsCString& aNodeId, nsresult& aResult)
209       : mNodeId(aNodeId), mResult(aResult) {}
210 
Done(nsresult aResult,const nsACString & aNodeId)211   void Done(nsresult aResult, const nsACString& aNodeId) {
212     mResult = aResult;
213     mNodeId = aNodeId;
214   }
215 
216  private:
217   nsCString& mNodeId;
218   nsresult& mResult;
219 };
220 
GetNodeId(const nsAString & aOrigin,const nsAString & aTopLevelOrigin,const nsAString & aGmpName,bool aInPBMode)221 static NodeId GetNodeId(const nsAString& aOrigin,
222                         const nsAString& aTopLevelOrigin,
223                         const nsAString& aGmpName, bool aInPBMode) {
224   OriginAttributes attrs;
225   attrs.mPrivateBrowsingId = aInPBMode ? 1 : 0;
226 
227   nsAutoCString suffix;
228   attrs.CreateSuffix(suffix);
229 
230   nsAutoString origin;
231   origin.Assign(aOrigin);
232   origin.Append(NS_ConvertUTF8toUTF16(suffix));
233 
234   nsAutoString topLevelOrigin;
235   topLevelOrigin.Assign(aTopLevelOrigin);
236   topLevelOrigin.Append(NS_ConvertUTF8toUTF16(suffix));
237   return NodeId(origin, topLevelOrigin, aGmpName);
238 }
239 
GetNodeId(const nsAString & aOrigin,const nsAString & aTopLevelOrigin,bool aInPBMode)240 static nsCString GetNodeId(const nsAString& aOrigin,
241                            const nsAString& aTopLevelOrigin, bool aInPBMode) {
242   RefPtr<GeckoMediaPluginServiceParent> service =
243       GeckoMediaPluginServiceParent::GetSingleton();
244   EXPECT_TRUE(service);
245   nsCString nodeId;
246   nsresult result;
247   UniquePtr<GetNodeIdCallback> callback(
248       new TestGetNodeIdCallback(nodeId, result));
249 
250   OriginAttributes attrs;
251   attrs.mPrivateBrowsingId = aInPBMode ? 1 : 0;
252 
253   nsAutoCString suffix;
254   attrs.CreateSuffix(suffix);
255 
256   nsAutoString origin;
257   origin.Assign(aOrigin);
258   origin.Append(NS_ConvertUTF8toUTF16(suffix));
259 
260   nsAutoString topLevelOrigin;
261   topLevelOrigin.Assign(aTopLevelOrigin);
262   topLevelOrigin.Append(NS_ConvertUTF8toUTF16(suffix));
263 
264   // We rely on the fact that the GetNodeId implementation for
265   // GeckoMediaPluginServiceParent is synchronous.
266   nsresult rv =
267       service->GetNodeId(origin, topLevelOrigin, NS_LITERAL_STRING("gmp-fake"),
268                          std::move(callback));
269   EXPECT_TRUE(NS_SUCCEEDED(rv) && NS_SUCCEEDED(result));
270   return nodeId;
271 }
272 
IsCDMStorageIsEmpty()273 static bool IsCDMStorageIsEmpty() {
274   RefPtr<GeckoMediaPluginServiceParent> service =
275       GeckoMediaPluginServiceParent::GetSingleton();
276   MOZ_ASSERT(service);
277   nsCOMPtr<nsIFile> storage;
278   nsresult rv = service->GetStorageDir(getter_AddRefs(storage));
279   EXPECT_TRUE(NS_SUCCEEDED(rv));
280   bool exists = false;
281   if (storage) {
282     storage->Exists(&exists);
283   }
284   return !exists;
285 }
286 
AssertIsOnGMPThread()287 static void AssertIsOnGMPThread() {
288   RefPtr<GeckoMediaPluginService> service =
289       GeckoMediaPluginService::GetGeckoMediaPluginService();
290   MOZ_ASSERT(service);
291   nsCOMPtr<nsIThread> thread;
292   service->GetThread(getter_AddRefs(thread));
293   MOZ_ASSERT(thread);
294   nsCOMPtr<nsIThread> currentThread;
295   DebugOnly<nsresult> rv = NS_GetCurrentThread(getter_AddRefs(currentThread));
296   MOZ_ASSERT(NS_SUCCEEDED(rv));
297   MOZ_ASSERT(currentThread == thread);
298 }
299 
300 class CDMStorageTest {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CDMStorageTest)301   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CDMStorageTest)
302 
303   void DoTest(void (CDMStorageTest::*aTestMethod)()) {
304     EnsureNSSInitializedChromeOrContent();
305     nsCOMPtr<nsIThread> thread(GetGMPThread());
306     ClearCDMStorage(
307         NewRunnableMethod("CDMStorageTest::DoTest", this, aTestMethod), thread);
308     AwaitFinished();
309   }
310 
CDMStorageTest()311   CDMStorageTest() : mMonitor("CDMStorageTest"), mFinished(false) {}
312 
Update(const nsCString & aMessage)313   void Update(const nsCString& aMessage) {
314     nsTArray<uint8_t> msg;
315     msg.AppendElements(aMessage.get(), aMessage.Length());
316     mCDM->UpdateSession(NS_LITERAL_CSTRING("fake-session-id"), 1, msg);
317   }
318 
TestGetNodeId()319   void TestGetNodeId() {
320     AssertIsOnGMPThread();
321 
322     EXPECT_TRUE(IsCDMStorageIsEmpty());
323 
324     const nsString origin1 = NS_LITERAL_STRING("http://example1.com");
325     const nsString origin2 = NS_LITERAL_STRING("http://example2.org");
326 
327     nsCString PBnodeId1 = GetNodeId(origin1, origin2, true);
328     nsCString PBnodeId2 = GetNodeId(origin1, origin2, true);
329 
330     // Node ids for the same origins should be the same in PB mode.
331     EXPECT_TRUE(PBnodeId1.Equals(PBnodeId2));
332 
333     nsCString PBnodeId3 = GetNodeId(origin2, origin1, true);
334 
335     // Node ids with origin and top level origin swapped should be different.
336     EXPECT_TRUE(!PBnodeId3.Equals(PBnodeId1));
337 
338     // Getting node ids in PB mode should not result in the node id being
339     // stored.
340     EXPECT_TRUE(IsCDMStorageIsEmpty());
341 
342     nsCString nodeId1 = GetNodeId(origin1, origin2, false);
343     nsCString nodeId2 = GetNodeId(origin1, origin2, false);
344 
345     // NodeIds for the same origin pair in non-pb mode should be the same.
346     EXPECT_TRUE(nodeId1.Equals(nodeId2));
347 
348     // Node ids for a given origin pair should be different for the PB origins
349     // should be the same in PB mode.
350     EXPECT_TRUE(!PBnodeId1.Equals(nodeId1));
351     EXPECT_TRUE(!PBnodeId2.Equals(nodeId2));
352 
353     nsCOMPtr<nsIThread> thread(GetGMPThread());
354     ClearCDMStorage(NewRunnableMethod<nsCString>(
355                         "CDMStorageTest::TestGetNodeId_Continuation", this,
356                         &CDMStorageTest::TestGetNodeId_Continuation, nodeId1),
357                     thread);
358   }
359 
TestGetNodeId_Continuation(nsCString aNodeId1)360   void TestGetNodeId_Continuation(nsCString aNodeId1) {
361     EXPECT_TRUE(IsCDMStorageIsEmpty());
362 
363     // Once we clear storage, the node ids generated for the same origin-pair
364     // should be different.
365     const nsString origin1 = NS_LITERAL_STRING("http://example1.com");
366     const nsString origin2 = NS_LITERAL_STRING("http://example2.org");
367     nsCString nodeId3 = GetNodeId(origin1, origin2, false);
368     EXPECT_TRUE(!aNodeId1.Equals(nodeId3));
369 
370     SetFinished();
371   }
372 
CreateDecryptor(const nsAString & aOrigin,const nsAString & aTopLevelOrigin,bool aInPBMode,const nsCString & aUpdate)373   void CreateDecryptor(const nsAString& aOrigin,
374                        const nsAString& aTopLevelOrigin, bool aInPBMode,
375                        const nsCString& aUpdate) {
376     nsTArray<nsCString> updates;
377     updates.AppendElement(aUpdate);
378     CreateDecryptor(aOrigin, aTopLevelOrigin, aInPBMode, std::move(updates));
379   }
380 
CreateDecryptor(const nsAString & aOrigin,const nsAString & aTopLevelOrigin,bool aInPBMode,nsTArray<nsCString> && aUpdates)381   void CreateDecryptor(const nsAString& aOrigin,
382                        const nsAString& aTopLevelOrigin, bool aInPBMode,
383                        nsTArray<nsCString>&& aUpdates) {
384     CreateDecryptor(GetNodeId(aOrigin, aTopLevelOrigin,
385                               NS_LITERAL_STRING("gmp-fake"), aInPBMode),
386                     std::move(aUpdates));
387   }
388 
CreateDecryptor(const NodeId & aNodeId,nsTArray<nsCString> && aUpdates)389   void CreateDecryptor(const NodeId& aNodeId, nsTArray<nsCString>&& aUpdates) {
390     RefPtr<GeckoMediaPluginService> service =
391         GeckoMediaPluginService::GetGeckoMediaPluginService();
392     EXPECT_TRUE(service);
393 
394     nsTArray<nsCString> tags;
395     tags.AppendElement(NS_LITERAL_CSTRING("fake"));
396 
397     RefPtr<CDMStorageTest> self = this;
398     RefPtr<gmp::GetCDMParentPromise> promise =
399         service->GetCDM(aNodeId, std::move(tags), nullptr);
400     auto thread = GetAbstractGMPThread();
401     promise->Then(
402         thread, __func__,
403         [self, updates = std::move(aUpdates),
404          thread](RefPtr<gmp::ChromiumCDMParent> cdm) mutable {
405           self->mCDM = cdm;
406           EXPECT_TRUE(!!self->mCDM);
407           self->mCallback.reset(new CallbackProxy(self));
408           nsCString failureReason;
409           self->mCDM
410               ->Init(self->mCallback.get(), false, true,
411                      GetMainThreadEventTarget())
412               ->Then(
413                   thread, __func__,
414                   [self, updates = std::move(updates)] {
415                     for (const auto& update : updates) {
416                       self->Update(update);
417                     }
418                   },
419                   [](MediaResult rv) { EXPECT_TRUE(false); });
420         },
421         [](MediaResult rv) { EXPECT_TRUE(false); });
422   }
423 
TestBasicStorage()424   void TestBasicStorage() {
425     AssertIsOnGMPThread();
426     EXPECT_TRUE(IsCDMStorageIsEmpty());
427 
428     RefPtr<GeckoMediaPluginService> service =
429         GeckoMediaPluginService::GetGeckoMediaPluginService();
430 
431     // Send a message to the fake GMP for it to run its own tests internally.
432     // It sends us a "test-storage complete" message when its passed, or
433     // some other message if its tests fail.
434     Expect(NS_LITERAL_CSTRING("test-storage complete"),
435            NewRunnableMethod("CDMStorageTest::SetFinished", this,
436                              &CDMStorageTest::SetFinished));
437 
438     CreateDecryptor(NS_LITERAL_STRING("http://example1.com"),
439                     NS_LITERAL_STRING("http://example2.com"), false,
440                     NS_LITERAL_CSTRING("test-storage"));
441   }
442 
443   /**
444    * 1. Generate storage data for some sites.
445    * 2. Forget about one of the sites.
446    * 3. Check if the storage data for the forgotten site are erased correctly.
447    * 4. Check if the storage data for other sites remain unchanged.
448    */
TestForgetThisSite()449   void TestForgetThisSite() {
450     AssertIsOnGMPThread();
451     EXPECT_TRUE(IsCDMStorageIsEmpty());
452 
453     // Generate storage data for some site.
454     nsCOMPtr<nsIRunnable> r = NewRunnableMethod(
455         "CDMStorageTest::TestForgetThisSite_AnotherSite", this,
456         &CDMStorageTest::TestForgetThisSite_AnotherSite);
457     Expect(NS_LITERAL_CSTRING("test-storage complete"), r.forget());
458 
459     CreateDecryptor(NS_LITERAL_STRING("http://example1.com"),
460                     NS_LITERAL_STRING("http://example2.com"), false,
461                     NS_LITERAL_CSTRING("test-storage"));
462   }
463 
TestForgetThisSite_AnotherSite()464   void TestForgetThisSite_AnotherSite() {
465     Shutdown();
466 
467     // Generate storage data for another site.
468     nsCOMPtr<nsIRunnable> r = NewRunnableMethod(
469         "CDMStorageTest::TestForgetThisSite_CollectSiteInfo", this,
470         &CDMStorageTest::TestForgetThisSite_CollectSiteInfo);
471     Expect(NS_LITERAL_CSTRING("test-storage complete"), r.forget());
472 
473     CreateDecryptor(NS_LITERAL_STRING("http://example3.com"),
474                     NS_LITERAL_STRING("http://example4.com"), false,
475                     NS_LITERAL_CSTRING("test-storage"));
476   }
477 
478   struct NodeInfo {
NodeInfoCDMStorageTest::NodeInfo479     explicit NodeInfo(const nsACString& aSite,
480                       const mozilla::OriginAttributesPattern& aPattern)
481         : siteToForget(aSite), mPattern(aPattern) {}
482     nsCString siteToForget;
483     mozilla::OriginAttributesPattern mPattern;
484     nsTArray<nsCString> expectedRemainingNodeIds;
485   };
486 
487   class NodeIdCollector {
488    public:
NodeIdCollector(NodeInfo * aInfo)489     explicit NodeIdCollector(NodeInfo* aInfo) : mNodeInfo(aInfo) {}
operator ()(nsIFile * aFile)490     void operator()(nsIFile* aFile) {
491       nsCString salt;
492       nsresult rv = ReadSalt(aFile, salt);
493       ASSERT_TRUE(NS_SUCCEEDED(rv));
494       if (!MatchOrigin(aFile, mNodeInfo->siteToForget, mNodeInfo->mPattern)) {
495         mNodeInfo->expectedRemainingNodeIds.AppendElement(salt);
496       }
497     }
498 
499    private:
500     NodeInfo* mNodeInfo;
501   };
502 
TestForgetThisSite_CollectSiteInfo()503   void TestForgetThisSite_CollectSiteInfo() {
504     mozilla::OriginAttributesPattern pattern;
505 
506     UniquePtr<NodeInfo> siteInfo(
507         new NodeInfo(NS_LITERAL_CSTRING("http://example1.com"), pattern));
508     // Collect nodeIds that are expected to remain for later comparison.
509     EnumerateCDMStorageDir(NS_LITERAL_CSTRING("id"),
510                            NodeIdCollector(siteInfo.get()));
511     // Invoke "Forget this site" on the main thread.
512     SchedulerGroup::Dispatch(
513         TaskCategory::Other,
514         NewRunnableMethod<UniquePtr<NodeInfo>&&>(
515             "CDMStorageTest::TestForgetThisSite_Forget", this,
516             &CDMStorageTest::TestForgetThisSite_Forget, std::move(siteInfo)));
517   }
518 
TestForgetThisSite_Forget(UniquePtr<NodeInfo> && aSiteInfo)519   void TestForgetThisSite_Forget(UniquePtr<NodeInfo>&& aSiteInfo) {
520     RefPtr<GeckoMediaPluginServiceParent> service =
521         GeckoMediaPluginServiceParent::GetSingleton();
522     service->ForgetThisSiteNative(
523         NS_ConvertUTF8toUTF16(aSiteInfo->siteToForget), aSiteInfo->mPattern);
524 
525     nsCOMPtr<nsIThread> thread;
526     service->GetThread(getter_AddRefs(thread));
527 
528     nsCOMPtr<nsIRunnable> r = NewRunnableMethod<UniquePtr<NodeInfo>&&>(
529         "CDMStorageTest::TestForgetThisSite_Verify", this,
530         &CDMStorageTest::TestForgetThisSite_Verify, std::move(aSiteInfo));
531     thread->Dispatch(r, NS_DISPATCH_NORMAL);
532 
533     nsCOMPtr<nsIRunnable> f = NewRunnableMethod(
534         "CDMStorageTest::SetFinished", this, &CDMStorageTest::SetFinished);
535     thread->Dispatch(f, NS_DISPATCH_NORMAL);
536   }
537 
538   class NodeIdVerifier {
539    public:
NodeIdVerifier(const NodeInfo * aInfo)540     explicit NodeIdVerifier(const NodeInfo* aInfo)
541         : mNodeInfo(aInfo),
542           mExpectedRemainingNodeIds(aInfo->expectedRemainingNodeIds.Clone()) {}
operator ()(nsIFile * aFile)543     void operator()(nsIFile* aFile) {
544       nsCString salt;
545       nsresult rv = ReadSalt(aFile, salt);
546       ASSERT_TRUE(NS_SUCCEEDED(rv));
547       // Shouldn't match the origin if we clear correctly.
548       EXPECT_FALSE(
549           MatchOrigin(aFile, mNodeInfo->siteToForget, mNodeInfo->mPattern));
550       // Check if remaining nodeIDs are as expected.
551       EXPECT_TRUE(mExpectedRemainingNodeIds.RemoveElement(salt));
552     }
~NodeIdVerifier()553     ~NodeIdVerifier() { EXPECT_TRUE(mExpectedRemainingNodeIds.IsEmpty()); }
554 
555    private:
556     const NodeInfo* mNodeInfo;
557     nsTArray<nsCString> mExpectedRemainingNodeIds;
558   };
559 
560   class StorageVerifier {
561    public:
StorageVerifier(const NodeInfo * aInfo)562     explicit StorageVerifier(const NodeInfo* aInfo)
563         : mExpectedRemainingNodeIds(aInfo->expectedRemainingNodeIds.Clone()) {}
operator ()(nsIFile * aFile)564     void operator()(nsIFile* aFile) {
565       nsCString salt;
566       nsresult rv = aFile->GetNativeLeafName(salt);
567       ASSERT_TRUE(NS_SUCCEEDED(rv));
568       EXPECT_TRUE(mExpectedRemainingNodeIds.RemoveElement(salt));
569     }
~StorageVerifier()570     ~StorageVerifier() { EXPECT_TRUE(mExpectedRemainingNodeIds.IsEmpty()); }
571 
572    private:
573     nsTArray<nsCString> mExpectedRemainingNodeIds;
574   };
575 
TestForgetThisSite_Verify(UniquePtr<NodeInfo> && aSiteInfo)576   void TestForgetThisSite_Verify(UniquePtr<NodeInfo>&& aSiteInfo) {
577     nsresult rv = EnumerateCDMStorageDir(NS_LITERAL_CSTRING("id"),
578                                          NodeIdVerifier(aSiteInfo.get()));
579     EXPECT_TRUE(NS_SUCCEEDED(rv));
580 
581     rv = EnumerateCDMStorageDir(NS_LITERAL_CSTRING("storage"),
582                                 StorageVerifier(aSiteInfo.get()));
583     EXPECT_TRUE(NS_SUCCEEDED(rv));
584   }
585 
586   /**
587    * 1. Generate some storage data.
588    * 2. Find the max mtime |t| in $profileDir/gmp/$platform/gmp-fake/id/.
589    * 3. Pass |t| to clear recent history.
590    * 4. Check if all directories in $profileDir/gmp/$platform/gmp-fake/id/ and
591    *    $profileDir/gmp/$platform/gmp-fake/storage are removed.
592    */
TestClearRecentHistory1()593   void TestClearRecentHistory1() {
594     AssertIsOnGMPThread();
595     EXPECT_TRUE(IsCDMStorageIsEmpty());
596 
597     // Generate storage data for some site.
598     nsCOMPtr<nsIRunnable> r =
599         NewRunnableMethod("CDMStorageTest::TestClearRecentHistory1_Clear", this,
600                           &CDMStorageTest::TestClearRecentHistory1_Clear);
601     Expect(NS_LITERAL_CSTRING("test-storage complete"), r.forget());
602 
603     CreateDecryptor(NS_LITERAL_STRING("http://example1.com"),
604                     NS_LITERAL_STRING("http://example2.com"), false,
605                     NS_LITERAL_CSTRING("test-storage"));
606   }
607 
608   /**
609    * 1. Generate some storage data.
610    * 2. Find the max mtime |t| in $profileDir/gmp/$platform/gmp-fake/storage/.
611    * 3. Pass |t| to clear recent history.
612    * 4. Check if all directories in $profileDir/gmp/$platform/gmp-fake/id/ and
613    *    $profileDir/gmp/$platform/gmp-fake/storage are removed.
614    */
TestClearRecentHistory2()615   void TestClearRecentHistory2() {
616     AssertIsOnGMPThread();
617     EXPECT_TRUE(IsCDMStorageIsEmpty());
618 
619     // Generate storage data for some site.
620     nsCOMPtr<nsIRunnable> r =
621         NewRunnableMethod("CDMStorageTest::TestClearRecentHistory2_Clear", this,
622                           &CDMStorageTest::TestClearRecentHistory2_Clear);
623     Expect(NS_LITERAL_CSTRING("test-storage complete"), r.forget());
624 
625     CreateDecryptor(NS_LITERAL_STRING("http://example1.com"),
626                     NS_LITERAL_STRING("http://example2.com"), false,
627                     NS_LITERAL_CSTRING("test-storage"));
628   }
629 
630   /**
631    * 1. Generate some storage data.
632    * 2. Find the max mtime |t| in $profileDir/gmp/$platform/gmp-fake/storage/.
633    * 3. Pass |t+1| to clear recent history.
634    * 4. Check if all directories in $profileDir/gmp/$platform/gmp-fake/id/ and
635    *    $profileDir/gmp/$platform/gmp-fake/storage remain unchanged.
636    */
TestClearRecentHistory3()637   void TestClearRecentHistory3() {
638     AssertIsOnGMPThread();
639     EXPECT_TRUE(IsCDMStorageIsEmpty());
640 
641     // Generate storage data for some site.
642     nsCOMPtr<nsIRunnable> r =
643         NewRunnableMethod("CDMStorageTest::TestClearRecentHistory3_Clear", this,
644                           &CDMStorageTest::TestClearRecentHistory3_Clear);
645     Expect(NS_LITERAL_CSTRING("test-storage complete"), r.forget());
646 
647     CreateDecryptor(NS_LITERAL_STRING("http://example1.com"),
648                     NS_LITERAL_STRING("http://example2.com"), false,
649                     NS_LITERAL_CSTRING("test-storage"));
650   }
651 
652   class MaxMTimeFinder {
653    public:
MaxMTimeFinder()654     MaxMTimeFinder() : mMaxTime(0) {}
operator ()(nsIFile * aFile)655     void operator()(nsIFile* aFile) {
656       PRTime lastModified;
657       nsresult rv = aFile->GetLastModifiedTime(&lastModified);
658       if (NS_SUCCEEDED(rv) && lastModified > mMaxTime) {
659         mMaxTime = lastModified;
660       }
661       EnumerateDir(aFile, *this);
662     }
GetResult() const663     PRTime GetResult() const { return mMaxTime; }
664 
665    private:
666     PRTime mMaxTime;
667   };
668 
TestClearRecentHistory1_Clear()669   void TestClearRecentHistory1_Clear() {
670     MaxMTimeFinder f;
671     nsresult rv = EnumerateCDMStorageDir(NS_LITERAL_CSTRING("id"), f);
672     EXPECT_TRUE(NS_SUCCEEDED(rv));
673 
674     nsCOMPtr<nsIRunnable> r = NewRunnableMethod(
675         "CDMStorageTest::TestClearRecentHistory_CheckEmpty", this,
676         &CDMStorageTest::TestClearRecentHistory_CheckEmpty);
677     nsCOMPtr<nsIThread> t(GetGMPThread());
678     ClearCDMStorage(r.forget(), t, f.GetResult());
679   }
680 
TestClearRecentHistory2_Clear()681   void TestClearRecentHistory2_Clear() {
682     MaxMTimeFinder f;
683     nsresult rv = EnumerateCDMStorageDir(NS_LITERAL_CSTRING("storage"), f);
684     EXPECT_TRUE(NS_SUCCEEDED(rv));
685 
686     nsCOMPtr<nsIRunnable> r = NewRunnableMethod(
687         "CDMStorageTest::TestClearRecentHistory_CheckEmpty", this,
688         &CDMStorageTest::TestClearRecentHistory_CheckEmpty);
689     nsCOMPtr<nsIThread> t(GetGMPThread());
690     ClearCDMStorage(r.forget(), t, f.GetResult());
691   }
692 
TestClearRecentHistory3_Clear()693   void TestClearRecentHistory3_Clear() {
694     MaxMTimeFinder f;
695     nsresult rv = EnumerateCDMStorageDir(NS_LITERAL_CSTRING("storage"), f);
696     EXPECT_TRUE(NS_SUCCEEDED(rv));
697 
698     nsCOMPtr<nsIRunnable> r = NewRunnableMethod(
699         "CDMStorageTest::TestClearRecentHistory_CheckNonEmpty", this,
700         &CDMStorageTest::TestClearRecentHistory_CheckNonEmpty);
701     nsCOMPtr<nsIThread> t(GetGMPThread());
702     ClearCDMStorage(r.forget(), t, f.GetResult() + 1);
703   }
704 
705   class FileCounter {
706    public:
FileCounter()707     FileCounter() : mCount(0) {}
operator ()(nsIFile * aFile)708     void operator()(nsIFile* aFile) { ++mCount; }
GetCount() const709     int GetCount() const { return mCount; }
710 
711    private:
712     int mCount;
713   };
714 
TestClearRecentHistory_CheckEmpty()715   void TestClearRecentHistory_CheckEmpty() {
716     FileCounter c1;
717     nsresult rv = EnumerateCDMStorageDir(NS_LITERAL_CSTRING("id"), c1);
718     EXPECT_TRUE(NS_SUCCEEDED(rv));
719     // There should be no files under $profileDir/gmp/$platform/gmp-fake/id/
720     EXPECT_EQ(c1.GetCount(), 0);
721 
722     FileCounter c2;
723     rv = EnumerateCDMStorageDir(NS_LITERAL_CSTRING("storage"), c2);
724     EXPECT_TRUE(NS_SUCCEEDED(rv));
725     // There should be no files under
726     // $profileDir/gmp/$platform/gmp-fake/storage/
727     EXPECT_EQ(c2.GetCount(), 0);
728 
729     SetFinished();
730   }
731 
TestClearRecentHistory_CheckNonEmpty()732   void TestClearRecentHistory_CheckNonEmpty() {
733     FileCounter c1;
734     nsresult rv = EnumerateCDMStorageDir(NS_LITERAL_CSTRING("id"), c1);
735     EXPECT_TRUE(NS_SUCCEEDED(rv));
736     // There should be one directory under
737     // $profileDir/gmp/$platform/gmp-fake/id/
738     EXPECT_EQ(c1.GetCount(), 1);
739 
740     FileCounter c2;
741     rv = EnumerateCDMStorageDir(NS_LITERAL_CSTRING("storage"), c2);
742     EXPECT_TRUE(NS_SUCCEEDED(rv));
743     // There should be one directory under
744     // $profileDir/gmp/$platform/gmp-fake/storage/
745     EXPECT_EQ(c2.GetCount(), 1);
746 
747     SetFinished();
748   }
749 
TestCrossOriginStorage()750   void TestCrossOriginStorage() {
751     EXPECT_TRUE(!mCDM);
752 
753     // Send the decryptor the message "store recordid $time"
754     // Wait for the decrytor to send us "stored recordid $time"
755     auto t = time(0);
756     nsCString response("stored crossOriginTestRecordId ");
757     response.AppendInt((int64_t)t);
758     Expect(
759         response,
760         NewRunnableMethod(
761             "CDMStorageTest::TestCrossOriginStorage_RecordStoredContinuation",
762             this,
763             &CDMStorageTest::TestCrossOriginStorage_RecordStoredContinuation));
764 
765     nsCString update("store crossOriginTestRecordId ");
766     update.AppendInt((int64_t)t);
767 
768     // Open decryptor on one, origin, write a record, and test that that
769     // record can't be read on another origin.
770     CreateDecryptor(NS_LITERAL_STRING("http://example3.com"),
771                     NS_LITERAL_STRING("http://example4.com"), false, update);
772   }
773 
TestCrossOriginStorage_RecordStoredContinuation()774   void TestCrossOriginStorage_RecordStoredContinuation() {
775     // Close the old decryptor, and create a new one on a different origin,
776     // and try to read the record.
777     Shutdown();
778 
779     Expect(NS_LITERAL_CSTRING(
780                "retrieve crossOriginTestRecordId succeeded (length 0 bytes)"),
781            NewRunnableMethod("CDMStorageTest::SetFinished", this,
782                              &CDMStorageTest::SetFinished));
783 
784     CreateDecryptor(NS_LITERAL_STRING("http://example5.com"),
785                     NS_LITERAL_STRING("http://example6.com"), false,
786                     NS_LITERAL_CSTRING("retrieve crossOriginTestRecordId"));
787   }
788 
TestPBStorage()789   void TestPBStorage() {
790     // Send the decryptor the message "store recordid $time"
791     // Wait for the decrytor to send us "stored recordid $time"
792     nsCString response("stored pbdata test-pb-data");
793     Expect(response,
794            NewRunnableMethod(
795                "CDMStorageTest::TestPBStorage_RecordStoredContinuation", this,
796                &CDMStorageTest::TestPBStorage_RecordStoredContinuation));
797 
798     // Open decryptor on one, origin, write a record, close decryptor,
799     // open another, and test that record can be read, close decryptor,
800     // then send pb-last-context-closed notification, then open decryptor
801     // and check that it can't read that data; it should have been purged.
802     CreateDecryptor(NS_LITERAL_STRING("http://pb1.com"),
803                     NS_LITERAL_STRING("http://pb2.com"), true,
804                     NS_LITERAL_CSTRING("store pbdata test-pb-data"));
805   }
806 
TestPBStorage_RecordStoredContinuation()807   void TestPBStorage_RecordStoredContinuation() {
808     Shutdown();
809 
810     Expect(
811         NS_LITERAL_CSTRING("retrieve pbdata succeeded (length 12 bytes)"),
812         NewRunnableMethod(
813             "CDMStorageTest::TestPBStorage_RecordRetrievedContinuation", this,
814             &CDMStorageTest::TestPBStorage_RecordRetrievedContinuation));
815 
816     CreateDecryptor(NS_LITERAL_STRING("http://pb1.com"),
817                     NS_LITERAL_STRING("http://pb2.com"), true,
818                     NS_LITERAL_CSTRING("retrieve pbdata"));
819   }
820 
TestPBStorage_RecordRetrievedContinuation()821   void TestPBStorage_RecordRetrievedContinuation() {
822     Shutdown();
823     SimulatePBModeExit();
824 
825     Expect(NS_LITERAL_CSTRING("retrieve pbdata succeeded (length 0 bytes)"),
826            NewRunnableMethod("CDMStorageTest::SetFinished", this,
827                              &CDMStorageTest::SetFinished));
828 
829     CreateDecryptor(NS_LITERAL_STRING("http://pb1.com"),
830                     NS_LITERAL_STRING("http://pb2.com"), true,
831                     NS_LITERAL_CSTRING("retrieve pbdata"));
832   }
833 
834 #if defined(XP_WIN)
TestOutputProtection()835   void TestOutputProtection() {
836     Shutdown();
837 
838     Expect(NS_LITERAL_CSTRING("OP tests completed"),
839            NewRunnableMethod("CDMStorageTest::SetFinished", this,
840                              &CDMStorageTest::SetFinished));
841 
842     CreateDecryptor(NS_LITERAL_STRING("http://example15.com"),
843                     NS_LITERAL_STRING("http://example16.com"), false,
844                     NS_LITERAL_CSTRING("test-op-apis"));
845   }
846 #endif
847 
TestLongRecordNames()848   void TestLongRecordNames() {
849     NS_NAMED_LITERAL_CSTRING(longRecordName,
850                              "A_"
851                              "very_very_very_very_very_very_very_very_very_"
852                              "very_very_very_very_very_very_"
853                              "very_very_very_very_very_very_very_very_very_"
854                              "very_very_very_very_very_very_"
855                              "very_very_very_very_very_very_very_very_very_"
856                              "very_very_very_very_very_very_"
857                              "very_very_very_very_very_very_very_very_very_"
858                              "very_very_very_very_very_very_"
859                              "very_very_very_very_very_very_very_very_very_"
860                              "very_very_very_very_very_very_"
861                              "very_very_very_very_very_very_very_very_very_"
862                              "very_very_very_very_very_very_"
863                              "very_very_very_very_very_very_very_very_very_"
864                              "very_very_very_very_very_very_"
865                              "very_very_very_very_very_very_very_very_very_"
866                              "very_very_very_very_very_very_"
867                              "very_very_very_very_very_very_very_very_very_"
868                              "very_very_very_very_very_very_"
869                              "very_very_very_very_very_very_very_very_very_"
870                              "very_very_very_very_very_very_"
871                              "very_very_very_very_very_very_very_very_very_"
872                              "very_very_very_very_very_very_"
873                              "very_very_very_very_very_very_very_very_very_"
874                              "very_very_very_very_very_very_"
875                              "very_very_very_very_very_very_very_very_very_"
876                              "very_very_very_very_very_very_"
877                              "very_very_very_very_very_very_very_very_very_"
878                              "very_very_very_very_very_very_"
879                              "very_very_very_very_very_very_very_very_very_"
880                              "very_very_very_very_very_very_"
881                              "long_record_name");
882 
883     NS_NAMED_LITERAL_CSTRING(data, "Just_some_arbitrary_data.");
884 
885     MOZ_ASSERT(longRecordName.Length() < GMP_MAX_RECORD_NAME_SIZE);
886     MOZ_ASSERT(longRecordName.Length() > 260);  // Windows MAX_PATH
887 
888     nsCString response("stored ");
889     response.Append(longRecordName);
890     response.AppendLiteral(" ");
891     response.Append(data);
892     Expect(response, NewRunnableMethod("CDMStorageTest::SetFinished", this,
893                                        &CDMStorageTest::SetFinished));
894 
895     nsCString update("store ");
896     update.Append(longRecordName);
897     update.AppendLiteral(" ");
898     update.Append(data);
899     CreateDecryptor(NS_LITERAL_STRING("http://fuz.com"),
900                     NS_LITERAL_STRING("http://baz.com"), false, update);
901   }
902 
Expect(const nsCString & aMessage,already_AddRefed<nsIRunnable> aContinuation)903   void Expect(const nsCString& aMessage,
904               already_AddRefed<nsIRunnable> aContinuation) {
905     mExpected.AppendElement(
906         ExpectedMessage(aMessage, std::move(aContinuation)));
907   }
908 
AwaitFinished()909   void AwaitFinished() {
910     mozilla::SpinEventLoopUntil([&]() -> bool { return mFinished; });
911     mFinished = false;
912   }
913 
ShutdownThen(already_AddRefed<nsIRunnable> aContinuation)914   void ShutdownThen(already_AddRefed<nsIRunnable> aContinuation) {
915     EXPECT_TRUE(!!mCDM);
916     if (!mCDM) {
917       return;
918     }
919     EXPECT_FALSE(mNodeId.IsEmpty());
920     RefPtr<GMPShutdownObserver> task(new GMPShutdownObserver(
921         NewRunnableMethod("CDMStorageTest::Shutdown", this,
922                           &CDMStorageTest::Shutdown),
923         std::move(aContinuation), mNodeId));
924     SchedulerGroup::Dispatch(TaskCategory::Other, task.forget());
925   }
926 
Shutdown()927   void Shutdown() {
928     if (mCDM) {
929       mCDM->Shutdown();
930       mCDM = nullptr;
931       mNodeId = EmptyCString();
932     }
933   }
934 
Dummy()935   void Dummy() {}
936 
SetFinished()937   void SetFinished() {
938     mFinished = true;
939     Shutdown();
940     nsCOMPtr<nsIRunnable> task = NewRunnableMethod(
941         "CDMStorageTest::Dummy", this, &CDMStorageTest::Dummy);
942     SchedulerGroup::Dispatch(TaskCategory::Other, task.forget());
943   }
944 
SessionMessage(const nsACString & aSessionId,uint32_t aMessageType,const nsTArray<uint8_t> & aMessage)945   void SessionMessage(const nsACString& aSessionId, uint32_t aMessageType,
946                       const nsTArray<uint8_t>& aMessage) {
947     MonitorAutoLock mon(mMonitor);
948 
949     nsCString msg((const char*)aMessage.Elements(), aMessage.Length());
950     EXPECT_TRUE(mExpected.Length() > 0);
951     bool matches = mExpected[0].mMessage.Equals(msg);
952     EXPECT_STREQ(mExpected[0].mMessage.get(), msg.get());
953     if (mExpected.Length() > 0 && matches) {
954       nsCOMPtr<nsIRunnable> continuation = mExpected[0].mContinuation;
955       mExpected.RemoveElementAt(0);
956       if (continuation) {
957         NS_DispatchToCurrentThread(continuation);
958       }
959     }
960   }
961 
Terminated()962   void Terminated() {
963     if (mCDM) {
964       mCDM->Shutdown();
965       mCDM = nullptr;
966     }
967   }
968 
969  private:
970   ~CDMStorageTest() = default;
971 
972   struct ExpectedMessage {
ExpectedMessageCDMStorageTest::ExpectedMessage973     ExpectedMessage(const nsCString& aMessage,
974                     already_AddRefed<nsIRunnable> aContinuation)
975         : mMessage(aMessage), mContinuation(aContinuation) {}
976     nsCString mMessage;
977     nsCOMPtr<nsIRunnable> mContinuation;
978   };
979 
980   nsTArray<ExpectedMessage> mExpected;
981 
982   RefPtr<nsIRunnable> mSetDecryptorIdContinuation;
983 
984   RefPtr<gmp::ChromiumCDMParent> mCDM;
985   Monitor mMonitor;
986   Atomic<bool> mFinished;
987   nsCString mNodeId;
988 
989   class CallbackProxy : public ChromiumCDMCallback {
990    public:
CallbackProxy(CDMStorageTest * aRunner)991     explicit CallbackProxy(CDMStorageTest* aRunner) : mRunner(aRunner) {}
992 
SetSessionId(uint32_t aPromiseId,const nsCString & aSessionId)993     void SetSessionId(uint32_t aPromiseId,
994                       const nsCString& aSessionId) override {}
995 
ResolveLoadSessionPromise(uint32_t aPromiseId,bool aSuccessful)996     void ResolveLoadSessionPromise(uint32_t aPromiseId,
997                                    bool aSuccessful) override {}
998 
ResolvePromiseWithKeyStatus(uint32_t aPromiseId,uint32_t aKeyStatus)999     void ResolvePromiseWithKeyStatus(uint32_t aPromiseId,
1000                                      uint32_t aKeyStatus) override {}
1001 
ResolvePromise(uint32_t aPromiseId)1002     void ResolvePromise(uint32_t aPromiseId) override {}
1003 
RejectPromise(uint32_t aPromiseId,ErrorResult && aError,const nsCString & aErrorMessage)1004     void RejectPromise(uint32_t aPromiseId, ErrorResult&& aError,
1005                        const nsCString& aErrorMessage) override {}
1006 
SessionMessage(const nsACString & aSessionId,uint32_t aMessageType,nsTArray<uint8_t> && aMessage)1007     void SessionMessage(const nsACString& aSessionId, uint32_t aMessageType,
1008                         nsTArray<uint8_t>&& aMessage) override {
1009       mRunner->SessionMessage(aSessionId, aMessageType, std::move(aMessage));
1010     }
1011 
SessionKeysChange(const nsCString & aSessionId,nsTArray<mozilla::gmp::CDMKeyInformation> && aKeysInfo)1012     void SessionKeysChange(
1013         const nsCString& aSessionId,
1014         nsTArray<mozilla::gmp::CDMKeyInformation>&& aKeysInfo) override {}
1015 
ExpirationChange(const nsCString & aSessionId,double aSecondsSinceEpoch)1016     void ExpirationChange(const nsCString& aSessionId,
1017                           double aSecondsSinceEpoch) override {}
1018 
SessionClosed(const nsCString & aSessionId)1019     void SessionClosed(const nsCString& aSessionId) override {}
1020 
Terminated()1021     void Terminated() override { mRunner->Terminated(); }
1022 
Shutdown()1023     void Shutdown() override { mRunner->Shutdown(); }
1024 
1025    private:
1026     // Warning: Weak ref.
1027     CDMStorageTest* mRunner;
1028   };
1029 
1030   UniquePtr<CallbackProxy> mCallback;
1031 };  // class CDMStorageTest
1032 
TEST(GeckoMediaPlugins,CDMStorageGetNodeId)1033 TEST(GeckoMediaPlugins, CDMStorageGetNodeId)
1034 {
1035   RefPtr<CDMStorageTest> runner = new CDMStorageTest();
1036   runner->DoTest(&CDMStorageTest::TestGetNodeId);
1037 }
1038 
TEST(GeckoMediaPlugins,CDMStorageBasic)1039 TEST(GeckoMediaPlugins, CDMStorageBasic)
1040 {
1041   RefPtr<CDMStorageTest> runner = new CDMStorageTest();
1042   runner->DoTest(&CDMStorageTest::TestBasicStorage);
1043 }
1044 
TEST(GeckoMediaPlugins,CDMStorageForgetThisSite)1045 TEST(GeckoMediaPlugins, CDMStorageForgetThisSite)
1046 {
1047   RefPtr<CDMStorageTest> runner = new CDMStorageTest();
1048   runner->DoTest(&CDMStorageTest::TestForgetThisSite);
1049 }
1050 
TEST(GeckoMediaPlugins,CDMStorageClearRecentHistory1)1051 TEST(GeckoMediaPlugins, CDMStorageClearRecentHistory1)
1052 {
1053   RefPtr<CDMStorageTest> runner = new CDMStorageTest();
1054   runner->DoTest(&CDMStorageTest::TestClearRecentHistory1);
1055 }
1056 
TEST(GeckoMediaPlugins,CDMStorageClearRecentHistory2)1057 TEST(GeckoMediaPlugins, CDMStorageClearRecentHistory2)
1058 {
1059   RefPtr<CDMStorageTest> runner = new CDMStorageTest();
1060   runner->DoTest(&CDMStorageTest::TestClearRecentHistory2);
1061 }
1062 
TEST(GeckoMediaPlugins,CDMStorageClearRecentHistory3)1063 TEST(GeckoMediaPlugins, CDMStorageClearRecentHistory3)
1064 {
1065   RefPtr<CDMStorageTest> runner = new CDMStorageTest();
1066   runner->DoTest(&CDMStorageTest::TestClearRecentHistory3);
1067 }
1068 
TEST(GeckoMediaPlugins,CDMStorageCrossOrigin)1069 TEST(GeckoMediaPlugins, CDMStorageCrossOrigin)
1070 {
1071   RefPtr<CDMStorageTest> runner = new CDMStorageTest();
1072   runner->DoTest(&CDMStorageTest::TestCrossOriginStorage);
1073 }
1074 
TEST(GeckoMediaPlugins,CDMStoragePrivateBrowsing)1075 TEST(GeckoMediaPlugins, CDMStoragePrivateBrowsing)
1076 {
1077   RefPtr<CDMStorageTest> runner = new CDMStorageTest();
1078   runner->DoTest(&CDMStorageTest::TestPBStorage);
1079 }
1080 
1081 #if defined(XP_WIN)
TEST(GeckoMediaPlugins,GMPOutputProtection)1082 TEST(GeckoMediaPlugins, GMPOutputProtection)
1083 {
1084   RefPtr<CDMStorageTest> runner = new CDMStorageTest();
1085   runner->DoTest(&CDMStorageTest::TestOutputProtection);
1086 }
1087 #endif
1088 
TEST(GeckoMediaPlugins,CDMStorageLongRecordNames)1089 TEST(GeckoMediaPlugins, CDMStorageLongRecordNames)
1090 {
1091   RefPtr<CDMStorageTest> runner = new CDMStorageTest();
1092   runner->DoTest(&CDMStorageTest::TestLongRecordNames);
1093 }
1094