From 4853871026a74bd58ccc472cebb3c215babcf8f1 Mon Sep 17 00:00:00 2001 From: "John W. Bruce" Date: Wed, 12 Jul 2017 16:21:19 -0700 Subject: [PATCH] Add SPOID Unit Tests (This is a merge of http://go/wvgerrit/29121) This commit adds unit tests for globally unprovisioning with a SPOID and to validate that SPOIDs vary in the expected ways depending on the inputs they are given. This change also fixes some indentation that was off and was getting copied around the file. Bug: 37179588 Test: libwvdrmdrmplugin_hidl_test Change-Id: Ie9604b974228d151e1b32680c42824a66412bad7 --- .../mediadrm/test/WVDrmPlugin_test.cpp | 190 +++++++++++++++--- 1 file changed, 161 insertions(+), 29 deletions(-) diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp index 080f7103..9e7fd272 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "cdm_client_property_set.h" #include "gmock/gmock.h" @@ -114,16 +115,19 @@ const std::string kAppId("com.unittest.mock.app.id"); const uint8_t* const kUnprovisionResponse = reinterpret_cast("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 { @@ -431,7 +435,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. @@ -840,8 +844,6 @@ TEST_F(WVDrmPluginTest, UnprovisionsOrigin) { StrictMock crypto; std::string appPackageName; - std::vector cert; - std::vector key; std::vector specialResponse; specialResponse.assign( kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize); @@ -865,16 +867,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> cdm = new StrictMock(); + StrictMock crypto; + std::string appPackageName; + + std::vector 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 /* cert */, + hidl_vec /* key */) { + EXPECT_EQ(Status::OK, status); + }); +} + +TEST_F(WVDrmPluginTest, WillNotUnprovisionWithoutOriginOrSpoid) { android::sp> cdm = new StrictMock(); StrictMock crypto; std::string appPackageName; - std::vector cert; - std::vector key; std::vector specialResponse; specialResponse.assign( kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize); @@ -896,8 +920,6 @@ TEST_F(WVDrmPluginTest, MuxesOriginUnprovisioningErrors) { StrictMock crypto; std::string appPackageName; - std::vector cert; - std::vector key; std::vector specialResponse; specialResponse.assign( kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize); @@ -1050,7 +1072,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"; @@ -1066,7 +1087,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, _)) @@ -1122,36 +1143,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 vectorResult) { + [&](Status status, hidl_vec vectorResult) { ASSERT_EQ(Status::OK, status); std::vector 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 vectorResult) { + [&](Status status, hidl_vec vectorResult) { ASSERT_EQ(Status::OK, status); std::vector id(vectorResult); EXPECT_THAT(id, ElementsAreArray(provisioningId.data(), @@ -1160,28 +1181,28 @@ 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_EQ(oemCryptoApiVersion, stringResult.c_str()); }); plugin.getPropertyByteArray( hidl_string("metrics"), - [&](Status status, hidl_vec vectorResult) { + [&](Status status, hidl_vec vectorResult) { ASSERT_EQ(Status::OK, status); std::vector id(vectorResult); EXPECT_THAT(id, ElementsAreArray(serializedMetrics.data(), @@ -1237,6 +1258,117 @@ TEST_F(WVDrmPluginTest, DoesNotSetUnknownProperties) { ASSERT_NE(Status::OK, status); } +TEST_F(WVDrmPluginTest, CompliesWithSpoidVariability) { + StrictMock 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 + spoids[kDeviceCount][kAppCount][kOriginCount][kPluginCount]; + + for (size_t deviceIndex = 0; deviceIndex < kDeviceCount; ++deviceIndex) { + const std::string& deviceId = kDeviceIds[deviceIndex]; + + android::sp> cdm = new StrictMock(); + + 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 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& 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& 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> cdm = new StrictMock(); StrictMock crypto;