Bug 1271169 - Add gtest to ensure EME device binding works. r=gerald draft
authorChris Pearce <cpearce@mozilla.com>
Tue, 10 May 2016 13:40:05 +1200
changeset 369949 bea5acc878a639fb819051e19e23533c14c19927
parent 369948 f60f1e68649fa90cbe1f2fe09f5f69948444b1df
child 521659 62bd555365887bc1fb19be21996428fedcd1f1fa
push id18959
push usercpearce@mozilla.com
push dateTue, 24 May 2016 01:20:09 +0000
reviewersgerald
bugs1271169
milestone49.0a1
Bug 1271169 - Add gtest to ensure EME device binding works. r=gerald Call the device binding code in gtests, and have a test GMP which returns the device ID it was passed in a message, so that we can verify that the id the GMP was passed is the same as the id generated in the parent. MozReview-Commit-ID: Gjqvo6dRK1D
dom/media/gmp-plugin/gmp-fake.cpp
dom/media/gmp-plugin/gmp-test-decryptor.cpp
dom/media/gmp-plugin/gmp-test-decryptor.h
dom/media/gtest/TestGMPCrossOrigin.cpp
--- a/dom/media/gmp-plugin/gmp-fake.cpp
+++ b/dom/media/gmp-plugin/gmp-fake.cpp
@@ -83,9 +83,16 @@ extern "C" {
     return GMPGenericErr;
   }
 
   PUBLIC_FUNC void
   GMPShutdown (void) {
     g_platform_api = NULL;
   }
 
+#if defined(GMP_FAKE_SUPPORT_DECRYPT)
+  PUBLIC_FUNC void
+  GMPSetNodeId(const char* aNodeId, uint32_t aLength) {
+    FakeDecryptor::SetNodeId(aNodeId, aLength);
+  }
+#endif
+
 } // extern "C"
--- a/dom/media/gmp-plugin/gmp-test-decryptor.cpp
+++ b/dom/media/gmp-plugin/gmp-test-decryptor.cpp
@@ -15,16 +15,18 @@
 #include <sstream>
 #include <set>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 
 using namespace std;
 
+std::string FakeDecryptor::sNodeId;
+
 FakeDecryptor* FakeDecryptor::sInstance = nullptr;
 extern GMPPlatformAPI* g_platform_api; // Defined in gmp-fake.cpp
 
 class GMPMutexAutoLock
 {
 public:
   explicit GMPMutexAutoLock(GMPMutex* aMutex) : mMutex(aMutex) {
     mMutex->Acquire();
@@ -562,16 +564,18 @@ FakeDecryptor::UpdateSession(uint32_t aP
   } else if (task == "retrieve-plugin-voucher") {
     const uint8_t* rawVoucher = nullptr;
     uint32_t length = 0;
     mHost->GetPluginVoucher(&rawVoucher, &length);
     std::string voucher((const char*)rawVoucher, (const char*)(rawVoucher + length));
     Message("retrieved plugin-voucher: " + voucher);
   } else if (task == "retrieve-record-names") {
     GMPEnumRecordNames(&RecvGMPRecordIterator, this);
+  } else if (task == "retrieve-node-id") {
+    Message("node-id " + sNodeId);
   }
 }
 
 class CompleteShutdownTask : public GMPTask {
 public:
   explicit CompleteShutdownTask(GMPAsyncShutdownHost* aHost)
     : mHost(aHost)
   {
--- a/dom/media/gmp-plugin/gmp-test-decryptor.h
+++ b/dom/media/gmp-plugin/gmp-test-decryptor.h
@@ -67,20 +67,25 @@ public:
 
   void DecryptingComplete() override;
 
   static void Message(const std::string& aMessage);
 
   void ProcessRecordNames(GMPRecordIterator* aRecordIterator,
                           GMPErr aStatus);
 
+  static void SetNodeId(const char* aNodeId, uint32_t aLength) {
+    sNodeId = std::string(aNodeId, aNodeId + aLength);
+  }
+
 private:
 
   virtual ~FakeDecryptor() {}
   static FakeDecryptor* sInstance;
+  static std::string sNodeId;
 
   void TestStorage();
 
   GMPDecryptorCallback* mCallback;
   GMPDecryptorHost* mHost;
 };
 
 class TestAsyncShutdown : public GMPAsyncShutdown {
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp
+++ b/dom/media/gtest/TestGMPCrossOrigin.cpp
@@ -15,16 +15,17 @@
 #include "GMPServiceParent.h"
 #include "MediaPrefs.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsIFile.h"
 #include "nsISimpleEnumerator.h"
 #include "mozilla/Atomics.h"
 #include "nsNSSComponent.h"
 #include "mozilla/DebugOnly.h"
+#include "GMPDeviceBinding.h"
 
 #if defined(XP_WIN)
 #include "mozilla/WindowsVersion.h"
 #endif
 
 using namespace std;
 
 using namespace mozilla;
@@ -609,31 +610,40 @@ class GMPStorageTest : public GMPDecrypt
       thread->Dispatch(mContinuation, NS_DISPATCH_NORMAL);
     }
 
   private:
     RefPtr<GMPStorageTest> mRunner;
     nsCOMPtr<nsIRunnable> mContinuation;
   };
 
+  void CreateDecryptor(const nsCString& aNodeId,
+                       const nsCString& aUpdate)
+  {
+    nsTArray<nsCString> updates;
+    updates.AppendElement(aUpdate);
+    nsCOMPtr<nsIRunnable> continuation(new Updates(this, Move(updates)));
+    CreateDecryptor(aNodeId, continuation);
+  }
+
   void CreateDecryptor(const nsAString& aOrigin,
                        const nsAString& aTopLevelOrigin,
                        bool aInPBMode,
                        const nsCString& aUpdate)
   {
     nsTArray<nsCString> updates;
     updates.AppendElement(aUpdate);
     CreateDecryptor(aOrigin, aTopLevelOrigin, aInPBMode, Move(updates));
   }
   class Updates : public Runnable
   {
   public:
     Updates(GMPStorageTest* aRunner, nsTArray<nsCString>&& aUpdates)
       : mRunner(aRunner),
-        mUpdates(aUpdates)
+        mUpdates(Move(aUpdates))
     {
     }
 
     NS_IMETHOD Run()
     {
       for (auto& update : mUpdates) {
         mRunner->Update(update);
       }
@@ -644,27 +654,26 @@ class GMPStorageTest : public GMPDecrypt
     RefPtr<GMPStorageTest> mRunner;
     nsTArray<nsCString> mUpdates;
   };
   void CreateDecryptor(const nsAString& aOrigin,
                        const nsAString& aTopLevelOrigin,
                        bool aInPBMode,
                        nsTArray<nsCString>&& aUpdates) {
     nsCOMPtr<nsIRunnable> updates(new Updates(this, Move(aUpdates)));
-    CreateDecryptor(aOrigin, aTopLevelOrigin, aInPBMode, updates);
+    CreateDecryptor(GetNodeId(aOrigin, aTopLevelOrigin, aInPBMode), updates);
   }
-  void CreateDecryptor(const nsAString& aOrigin,
-                       const nsAString& aTopLevelOrigin,
-                       bool aInPBMode,
+
+  void CreateDecryptor(const nsCString& aNodeId,
                        nsIRunnable* aContinuation) {
     RefPtr<GeckoMediaPluginService> service =
       GeckoMediaPluginService::GetGeckoMediaPluginService();
     EXPECT_TRUE(service);
 
-    mNodeId = GetNodeId(aOrigin, aTopLevelOrigin, aInPBMode);
+    mNodeId = aNodeId;
     EXPECT_TRUE(!mNodeId.IsEmpty());
 
     nsTArray<nsCString> tags;
     tags.AppendElement(NS_LITERAL_CSTRING("fake"));
 
     UniquePtr<GetGMPDecryptorCallback> callback(
       new CreateDecryptorDone(this, aContinuation));
     nsresult rv =
@@ -1075,17 +1084,17 @@ class GMPStorageTest : public GMPDecrypt
                                      const nsAString& aOrigin2,
                                      void (GMPStorageTest::*aCallback)()) {
     nsCOMPtr<nsIRunnable> continuation(
       NewRunnableMethod<nsCOMPtr<nsIRunnable>>(
         this,
         &GMPStorageTest::NextAsyncShutdownTimeoutTest,
         NewRunnableMethod(this, aCallback)));
 
-    CreateDecryptor(aOrigin1, aOrigin2, false, continuation);
+    CreateDecryptor(GetNodeId(aOrigin1, aOrigin2, false), continuation);
   }
 
   void TestAsyncShutdownTimeout() {
     // Create decryptors that timeout in their async shutdown.
     // If the gtest hangs on shutdown, test fails!
     CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("http://example7.com"),
                                   NS_LITERAL_STRING("http://example8.com"),
                                   &GMPStorageTest::TestAsyncShutdownTimeout2);
@@ -1269,16 +1278,34 @@ class GMPStorageTest : public GMPDecrypt
     update.AppendLiteral(" ");
     update.Append(data);
     CreateDecryptor(NS_LITERAL_STRING("http://fuz.com"),
                     NS_LITERAL_STRING("http://baz.com"),
                     false,
                     update);
   }
 
+  void TestNodeId() {
+    // Calculate the nodeId, and the device bound nodeId. Start a GMP, and
+    // have it return the device bound nodeId that it's been passed. Assert
+    // they have the same value.
+    const nsString origin = NS_LITERAL_STRING("http://example-fuz-baz.com");
+    nsCString originSalt1 = GetNodeId(origin, origin, false);
+
+    nsCString salt = originSalt1;
+    std::string nodeId;
+    EXPECT_TRUE(CalculateGMPDeviceId(salt.BeginWriting(), salt.Length(), nodeId));
+
+    std::string expected = "node-id " + nodeId;
+    Expect(nsDependentCString(expected.c_str()), NewRunnableMethod(this, &GMPStorageTest::SetFinished));
+
+    CreateDecryptor(originSalt1,
+                    NS_LITERAL_CSTRING("retrieve-node-id"));
+  }
+
   void Expect(const nsCString& aMessage, already_AddRefed<nsIRunnable> aContinuation) {
     mExpected.AppendElement(ExpectedMessage(aMessage, Move(aContinuation)));
   }
 
   void AwaitFinished() {
     while (!mFinished) {
       NS_ProcessNextEvent(nullptr, true);
     }
@@ -1485,8 +1512,13 @@ TEST(GeckoMediaPlugins, GMPStorageGetRec
   RefPtr<GMPStorageTest> runner = new GMPStorageTest();
   runner->DoTest(&GMPStorageTest::GetRecordNamesPersistentStorage);
 }
 
 TEST(GeckoMediaPlugins, GMPStorageLongRecordNames) {
   RefPtr<GMPStorageTest> runner = new GMPStorageTest();
   runner->DoTest(&GMPStorageTest::TestLongRecordNames);
 }
+
+TEST(GeckoMediaPlugins, GMPNodeId) {
+  RefPtr<GMPStorageTest> runner = new GMPStorageTest();
+  runner->DoTest(&GMPStorageTest::TestNodeId);
+}