Coverage Report

Created: 2018-09-25 14:53

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