Merge "Add SPOID Unit Tests"

This commit is contained in:
John Bruce
2017-07-14 22:37:43 +00:00
committed by Android (Google) Code Review

View File

@@ -13,6 +13,7 @@
#include <ostream>
#include <string>
#include <list>
#include <vector>
#include "cdm_client_property_set.h"
#include "gmock/gmock.h"
@@ -116,16 +117,19 @@ const std::string kAppId("com.unittest.mock.app.id");
const uint8_t* const kUnprovisionResponse =
reinterpret_cast<const uint8_t*>("unprovision");
const size_t kUnprovisionResponseSize = 11;
const std::string kDeviceId = "0123456789ABCDEF";
const std::string kDeviceId("0123456789\0ABCDEF", 17);
// This is a serialized MetricsGroup message containing a small amount of
// sample data. This ensures we're able to extract it via a property.
const char kSerializedMetrics[] = {
0x0a, 0x0a, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74, 0x12, 0x02, 0x08, 0x00,
0x0a, 0x12, 0x0a, 0x05, 0x74, 0x65, 0x73, 0x74, 0x32, 0x12, 0x09, 0x11,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x15, 0x0a, 0x05,
0x74, 0x65, 0x73, 0x74, 0x33, 0x12, 0x0c, 0x1a, 0x0a, 0x74, 0x65, 0x73,
0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65};
0x0a, 0x0a, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74, 0x12, 0x02, 0x08, 0x00,
0x0a, 0x12, 0x0a, 0x05, 0x74, 0x65, 0x73, 0x74, 0x32, 0x12, 0x09, 0x11,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x15, 0x0a, 0x05,
0x74, 0x65, 0x73, 0x74, 0x33, 0x12, 0x0c, 0x1a, 0x0a, 0x74, 0x65, 0x73,
0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65
};
#define N_ELEM(a) (sizeof(a)/sizeof(a[0]))
} // anonymous namespace
class MockCDM : public WvContentDecryptionModule {
@@ -433,7 +437,7 @@ TEST_F(WVDrmPluginTest, DISABLED_GeneratesKeyRequests) {
{kIsoBmffMimeType, initData, cdmPsshBox}, // ISO-BMFF, old passing style
{kWebmMimeType, initData, cdmInitData} // WebM
};
size_t testSetCount = sizeof(testSets) / sizeof(TestSet);
size_t testSetCount = N_ELEM(testSets);
// Set up the expected calls. Per gMock rules, this must be done for all test
// sets prior to testing any of them.
@@ -842,8 +846,6 @@ TEST_F(WVDrmPluginTest, UnprovisionsOrigin) {
StrictMock<MockCrypto> crypto;
std::string appPackageName;
std::vector<uint8_t> cert;
std::vector<uint8_t> key;
std::vector<uint8_t> specialResponse;
specialResponse.assign(
kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize);
@@ -867,16 +869,38 @@ TEST_F(WVDrmPluginTest, UnprovisionsOrigin) {
});
}
TEST_F(WVDrmPluginTest, WillNotUnprovisionWithoutOrigin) {
// This test is only valid on SPOID-free devices. SPOID devices can
// unprovision without an origin because the empty-origin provisioning is
// not global.
TEST_F(WVDrmPluginTest, UnprovisionsGloballyWithSpoid) {
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
StrictMock<MockCrypto> crypto;
std::string appPackageName;
std::vector<uint8_t> specialResponse;
specialResponse.assign(
kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize);
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_DEVICE_ID, _))
.WillRepeatedly(DoAll(SetArgPointee<2>(kDeviceId),
testing::Return(wvcdm::NO_ERROR)));
EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL1, HasOrigin(EMPTY_ORIGIN)))
.Times(1);
EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL3, HasOrigin(EMPTY_ORIGIN)))
.Times(1);
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, true);
plugin.provideProvisionResponse(
toHidlVec(specialResponse),
[&](Status status, hidl_vec<uint8_t> /* cert */,
hidl_vec<uint8_t> /* key */) {
EXPECT_EQ(Status::OK, status);
});
}
TEST_F(WVDrmPluginTest, WillNotUnprovisionWithoutOriginOrSpoid) {
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
StrictMock<MockCrypto> crypto;
std::string appPackageName;
std::vector<uint8_t> cert;
std::vector<uint8_t> key;
std::vector<uint8_t> specialResponse;
specialResponse.assign(
kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize);
@@ -898,8 +922,6 @@ TEST_F(WVDrmPluginTest, MuxesOriginUnprovisioningErrors) {
StrictMock<MockCrypto> crypto;
std::string appPackageName;
std::vector<uint8_t> cert;
std::vector<uint8_t> key;
std::vector<uint8_t> specialResponse;
specialResponse.assign(
kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize);
@@ -1052,7 +1074,6 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
CdmQueryMap l3Map;
l3Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3;
static const std::string deviceId("0123456789\0ABCDEF", 17);
static const std::string systemId = "The Universe";
static const std::string provisioningId("Life\0&Everything", 16);
static const std::string openSessions = "42";
@@ -1069,7 +1090,7 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
testing::Return(wvcdm::NO_ERROR)));
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_DEVICE_ID, _))
.WillOnce(DoAll(SetArgPointee<2>(deviceId),
.WillOnce(DoAll(SetArgPointee<2>(kDeviceId),
testing::Return(wvcdm::NO_ERROR)));
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SYSTEM_ID, _))
@@ -1133,36 +1154,36 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
plugin.getPropertyString(
hidl_string("securityLevel"),
[&](Status status, hidl_string stringResult) {
[&](Status status, hidl_string stringResult) {
ASSERT_EQ(Status::OK, status);
EXPECT_STREQ(QUERY_VALUE_SECURITY_LEVEL_L1.c_str(), stringResult.c_str());
});
plugin.getPropertyString(
hidl_string("securityLevel"),
[&](Status status, hidl_string stringResult) {
[&](Status status, hidl_string stringResult) {
ASSERT_EQ(Status::OK, status);
EXPECT_STREQ(QUERY_VALUE_SECURITY_LEVEL_L3.c_str(), stringResult.c_str());
});
plugin.getPropertyByteArray(
hidl_string("deviceUniqueId"),
[&](Status status, hidl_vec<uint8_t> vectorResult) {
[&](Status status, hidl_vec<uint8_t> vectorResult) {
ASSERT_EQ(Status::OK, status);
std::vector<uint8_t> id(vectorResult);
EXPECT_THAT(id, ElementsAreArray(deviceId.data(), deviceId.size()));
EXPECT_THAT(id, ElementsAreArray(kDeviceId.data(), kDeviceId.size()));
});
plugin.getPropertyString(
hidl_string("systemId"),
[&](Status status, hidl_string stringResult) {
[&](Status status, hidl_string stringResult) {
ASSERT_EQ(Status::OK, status);
EXPECT_STREQ(systemId.c_str(), stringResult.c_str());
});
plugin.getPropertyByteArray(
hidl_string("provisioningUniqueId"),
[&](Status status, hidl_vec<uint8_t> vectorResult) {
[&](Status status, hidl_vec<uint8_t> vectorResult) {
ASSERT_EQ(Status::OK, status);
std::vector<uint8_t> id(vectorResult);
EXPECT_THAT(id, ElementsAreArray(provisioningId.data(),
@@ -1171,21 +1192,21 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
plugin.getPropertyString(
hidl_string("numberOfOpenSessions"),
[&](Status status, hidl_string stringResult) {
[&](Status status, hidl_string stringResult) {
ASSERT_EQ(Status::OK, status);
EXPECT_EQ(openSessions, stringResult.c_str());
});
plugin.getPropertyString(
hidl_string("maxNumberOfSessions"),
[&](Status status, hidl_string stringResult) {
[&](Status status, hidl_string stringResult) {
ASSERT_EQ(Status::OK, status);
EXPECT_EQ(maxSessions, stringResult.c_str());
});
plugin.getPropertyString(
hidl_string("oemCryptoApiVersion"),
[&](Status status, hidl_string stringResult) {
[&](Status status, hidl_string stringResult) {
ASSERT_EQ(Status::OK, status);
EXPECT_STREQ(oemCryptoApiVersion.c_str(), stringResult.c_str());
});
@@ -1206,7 +1227,7 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
plugin.getPropertyByteArray(
hidl_string("metrics"),
[&](Status status, hidl_vec<uint8_t> vectorResult) {
[&](Status status, hidl_vec<uint8_t> vectorResult) {
ASSERT_EQ(Status::OK, status);
std::vector<uint8_t> id(vectorResult);
EXPECT_THAT(id, ElementsAreArray(serializedMetrics.data(),
@@ -1262,6 +1283,117 @@ TEST_F(WVDrmPluginTest, DoesNotSetUnknownProperties) {
ASSERT_NE(Status::OK, status);
}
TEST_F(WVDrmPluginTest, CompliesWithSpoidVariability) {
StrictMock<MockCrypto> crypto;
const std::string kDeviceIds[] = {
kDeviceId,
kDeviceId + " the Second",
};
const size_t kDeviceCount = N_ELEM(kDeviceIds);
const std::string kAppNames[] = {
std::string("com.google.widevine"),
std::string("com.youtube"),
};
const size_t kAppCount = N_ELEM(kAppNames);
const std::string kOrigins[] = {
kOrigin,
kOrigin + " but not that one, the other one.",
std::string(/* Intentionally Empty */),
};
const size_t kOriginCount = N_ELEM(kOrigins);
const size_t kPluginCount = 2;
const size_t kPluginsPerCdm = kAppCount * kOriginCount * kPluginCount;
// We will get kPluginCount SPOIDs for every app package name + device id +
// origin combination.
std::vector<uint8_t>
spoids[kDeviceCount][kAppCount][kOriginCount][kPluginCount];
for (size_t deviceIndex = 0; deviceIndex < kDeviceCount; ++deviceIndex) {
const std::string& deviceId = kDeviceIds[deviceIndex];
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_DEVICE_ID, _))
.Times(AtLeast(kPluginsPerCdm))
.WillRepeatedly(DoAll(SetArgPointee<2>(deviceId),
testing::Return(wvcdm::NO_ERROR)));
for (size_t appIndex = 0; appIndex < kAppCount; ++appIndex) {
const std::string& appPackageName = kAppNames[appIndex];
for (size_t originIndex = 0; originIndex < kOriginCount; ++originIndex) {
const std::string& origin = kOrigins[originIndex];
for (size_t pluginIndex = 0;
pluginIndex < kPluginCount;
++pluginIndex) {
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, true);
if (!origin.empty()) {
ASSERT_EQ(Status::OK,
plugin.setPropertyString(hidl_string("origin"),
hidl_string(origin)));
}
plugin.getPropertyByteArray(
hidl_string("deviceUniqueId"),
[&](Status status, hidl_vec<uint8_t> vectorResult) {
ASSERT_EQ(Status::OK, status);
spoids[deviceIndex][appIndex][originIndex][pluginIndex] =
vectorResult;
});
}
}
}
}
// This nest of loops makes sure all the SPOIDs we retrieved above are
// identical if their parameters were identical and dissimilar otherwise.
for (size_t deviceIndex = 0; deviceIndex < kDeviceCount; ++deviceIndex) {
for (size_t appIndex = 0; appIndex < kAppCount; ++appIndex) {
for (size_t originIndex = 0; originIndex < kOriginCount; ++originIndex) {
for (size_t pluginIndex = 0;
pluginIndex < kPluginCount;
++pluginIndex) {
const std::vector<uint8_t>& firstSpoid =
spoids[deviceIndex][appIndex][originIndex][pluginIndex];
for (size_t deviceIndex2 = 0;
deviceIndex2 < kDeviceCount;
++deviceIndex2) {
for (size_t appIndex2 = 0; appIndex2 < kAppCount; ++appIndex2) {
for (size_t originIndex2 = 0;
originIndex2 < kOriginCount;
++originIndex2) {
for (size_t pluginIndex2 = 0;
pluginIndex2 < kPluginCount;
++pluginIndex2) {
const std::vector<uint8_t>& secondSpoid =
spoids[deviceIndex2][appIndex2][originIndex2][pluginIndex2];
if (deviceIndex == deviceIndex2 &&
appIndex == appIndex2 &&
originIndex == originIndex2) {
EXPECT_EQ(firstSpoid, secondSpoid);
} else {
EXPECT_NE(firstSpoid, secondSpoid);
}
}
}
}
}
}
}
}
}
}
TEST_F(WVDrmPluginTest, FailsGenericMethodsWithoutAnAlgorithmSet) {
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
StrictMock<MockCrypto> crypto;