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
--- 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);
+}