Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: media/cdm/cdm_adapter_unittest.cc

Issue 1447943002: Revert of Add unit tests for CdmAdapter (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/cdm/aes_decryptor.cc ('k') | media/cdm/ppapi/external_clear_key/clear_key_cdm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/bind.h"
6 #include "base/files/file_path.h"
7 #include "base/files/file_util.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/path_service.h"
11 #include "base/run_loop.h"
12 #include "base/scoped_native_library.h"
13 #include "media/base/cdm_callback_promise.h"
14 #include "media/base/cdm_key_information.h"
15 #include "media/base/media_keys.h"
16 #include "media/cdm/api/content_decryption_module.h"
17 #include "media/cdm/cdm_adapter.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 using ::testing::_;
22 using ::testing::SaveArg;
23 MATCHER(IsNotEmpty, "") {
24 return !arg.empty();
25 }
26
27 // TODO(jrummell): These tests are a subset of those in aes_decryptor_unittest.
28 // Refactor aes_decryptor_unittest.cc to handle AesDecryptor directly and
29 // via CdmAdapter once CdmAdapter supports decrypting functionality. There
30 // will also be tests that only CdmAdapter supports, like file IO, which
31 // will need to be handled separately.
32
33 namespace media {
34
35 // INITIALIZE_CDM_MODULE is a macro in api/content_decryption_module.h.
36 // However, we need to pass it as a string to GetFunctionPointer() once it
37 // is expanded.
38 #define STRINGIFY(X) #X
39 #define MAKE_STRING(X) STRINGIFY(X)
40
41 const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey";
42
43 // File name of the External ClearKey CDM on different platforms.
44 const base::FilePath::CharType kExternalClearKeyCdmFileName[] =
45 #if defined(OS_MACOSX)
46 FILE_PATH_LITERAL("libclearkeycdm.dylib");
47 #elif defined(OS_WIN)
48 FILE_PATH_LITERAL("clearkeycdm.dll");
49 #else // OS_LINUX, etc.
50 FILE_PATH_LITERAL("libclearkeycdm.so");
51 #endif
52
53 // Random key ID used to create a session.
54 const uint8 kKeyId[] = {
55 // base64 equivalent is AQIDBAUGBwgJCgsMDQ4PEA
56 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
57 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
58 };
59
60 const char kKeyIdAsJWK[] = "{\"kids\": [\"AQIDBAUGBwgJCgsMDQ4PEA\"]}";
61
62 const uint8 kKeyIdAsPssh[] = {
63 0x00, 0x00, 0x00, 0x00, 'p', 's', 's', 'h', // size = 0
64 0x01, // version = 1
65 0x00, 0x00, 0x00, // flags
66 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02, // Common SystemID
67 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B,
68 0x00, 0x00, 0x00, 0x01, // key count
69 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // key
70 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
71 0x00, 0x00, 0x00, 0x00, // datasize
72 };
73
74 // Key is 0x0405060708090a0b0c0d0e0f10111213,
75 // base64 equivalent is BAUGBwgJCgsMDQ4PEBESEw.
76 const char kKeyAsJWK[] =
77 "{"
78 " \"keys\": ["
79 " {"
80 " \"kty\": \"oct\","
81 " \"alg\": \"A128KW\","
82 " \"kid\": \"AQIDBAUGBwgJCgsMDQ4PEA\","
83 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
84 " }"
85 " ],"
86 " \"type\": \"temporary\""
87 "}";
88
89 class CdmAdapterTest : public testing::Test {
90 public:
91 enum ExpectedResult { SUCCESS, FAILURE };
92
93 CdmAdapterTest() {}
94 ~CdmAdapterTest() override {}
95
96 protected:
97 // Initializes the adapter. |expected_result| tests that the call succeeds
98 // or generates an error.
99 void InitializeAndExpect(base::FilePath library_path,
100 ExpectedResult expected_result) {
101 CdmConfig cdm_config; // default settings of false are sufficient.
102
103 CdmAdapter::Create(
104 kExternalClearKeyKeySystem, library_path, cdm_config,
105 base::Bind(&CdmAdapterTest::OnSessionMessage, base::Unretained(this)),
106 base::Bind(&CdmAdapterTest::OnSessionClosed, base::Unretained(this)),
107 base::Bind(&CdmAdapterTest::OnLegacySessionError,
108 base::Unretained(this)),
109 base::Bind(&CdmAdapterTest::OnSessionKeysChange,
110 base::Unretained(this)),
111 base::Bind(&CdmAdapterTest::OnSessionExpirationUpdate,
112 base::Unretained(this)),
113 base::Bind(&CdmAdapterTest::OnCdmCreated, base::Unretained(this),
114 expected_result));
115 RunUntilIdle();
116 }
117
118 // Creates a new session using |key_id|. |session_id_| will be set
119 // when the promise is resolved. |expected_result| tests that
120 // CreateSessionAndGenerateRequest() succeeds or generates an error.
121 void CreateSessionAndExpect(EmeInitDataType data_type,
122 const std::vector<uint8>& key_id,
123 ExpectedResult expected_result) {
124 DCHECK(!key_id.empty());
125
126 if (expected_result == SUCCESS) {
127 EXPECT_CALL(*this,
128 OnSessionMessage(IsNotEmpty(), _, _, GURL::EmptyGURL()));
129 }
130
131 adapter_->CreateSessionAndGenerateRequest(
132 MediaKeys::TEMPORARY_SESSION, data_type, key_id,
133 CreateSessionPromise(expected_result));
134 RunUntilIdle();
135 }
136
137 // Loads the session specified by |session_id|. |expected_result| tests
138 // that LoadSession() succeeds or generates an error.
139 void LoadSessionAndExpect(const std::string& session_id,
140 ExpectedResult expected_result) {
141 DCHECK(!session_id.empty());
142 ASSERT_EQ(expected_result, FAILURE) << "LoadSession not supported.";
143
144 adapter_->LoadSession(MediaKeys::TEMPORARY_SESSION, session_id,
145 CreateSessionPromise(expected_result));
146 RunUntilIdle();
147 }
148
149 // Updates the session specified by |session_id| with |key|. |expected_result|
150 // tests that the update succeeds or generates an error. |new_key_expected|
151 // is the expected parameter when the SessionKeysChange event happens.
152 void UpdateSessionAndExpect(std::string session_id,
153 const std::string& key,
154 ExpectedResult expected_result,
155 bool new_key_expected) {
156 DCHECK(!key.empty());
157
158 if (expected_result == SUCCESS) {
159 EXPECT_CALL(*this,
160 OnSessionKeysChangeCalled(session_id, new_key_expected));
161 } else {
162 EXPECT_CALL(*this, OnSessionKeysChangeCalled(_, _)).Times(0);
163 }
164
165 adapter_->UpdateSession(session_id,
166 std::vector<uint8>(key.begin(), key.end()),
167 CreatePromise(expected_result));
168 RunUntilIdle();
169 }
170
171 base::FilePath ExternalClearKeyLibrary() { return library_path_; }
172
173 std::string SessionId() { return session_id_; }
174
175 private:
176 void SetUp() override {
177 // Determine the location of the CDM. It is expected to be in the same
178 // directory as the current module.
179 base::FilePath current_module_dir;
180 ASSERT_TRUE(PathService::Get(base::DIR_MODULE, &current_module_dir));
181 library_path_ =
182 current_module_dir.Append(base::FilePath(kExternalClearKeyCdmFileName));
183 ASSERT_TRUE(base::PathExists(library_path_)) << library_path_.value();
184
185 // Now load the CDM library.
186 base::NativeLibraryLoadError error;
187 library_.Reset(base::LoadNativeLibrary(library_path_, &error));
188 ASSERT_TRUE(library_.is_valid()) << error.ToString();
189
190 // Call INITIALIZE_CDM_MODULE()
191 typedef void (*InitializeCdmFunc)();
192 InitializeCdmFunc initialize_cdm_func = reinterpret_cast<InitializeCdmFunc>(
193 library_.GetFunctionPointer(MAKE_STRING(INITIALIZE_CDM_MODULE)));
194 ASSERT_TRUE(initialize_cdm_func) << "No INITIALIZE_CDM_MODULE in library";
195 initialize_cdm_func();
196 }
197
198 void TearDown() override {
199 // Call DeinitializeCdmModule()
200 typedef void (*DeinitializeCdmFunc)();
201 DeinitializeCdmFunc deinitialize_cdm_func =
202 reinterpret_cast<DeinitializeCdmFunc>(
203 library_.GetFunctionPointer("DeinitializeCdmModule"));
204 ASSERT_TRUE(deinitialize_cdm_func)
205 << "No DeinitializeCdmModule() in library";
206 deinitialize_cdm_func();
207 }
208
209 void OnCdmCreated(ExpectedResult expected_result,
210 const scoped_refptr<MediaKeys>& cdm,
211 const std::string& error_message) {
212 if (cdm) {
213 EXPECT_EQ(expected_result, SUCCESS) << "CDM should not have loaded.";
214 adapter_ = cdm;
215 } else {
216 EXPECT_EQ(expected_result, FAILURE) << error_message;
217 }
218 }
219
220 // Create a promise. |expected_result| is used to indicate how the promise
221 // should be fulfilled.
222 scoped_ptr<SimpleCdmPromise> CreatePromise(ExpectedResult expected_result) {
223 if (expected_result == SUCCESS) {
224 EXPECT_CALL(*this, OnResolve());
225 } else {
226 EXPECT_CALL(*this, OnReject(_, _, IsNotEmpty()));
227 }
228
229 scoped_ptr<SimpleCdmPromise> promise(new CdmCallbackPromise<>(
230 base::Bind(&CdmAdapterTest::OnResolve, base::Unretained(this)),
231 base::Bind(&CdmAdapterTest::OnReject, base::Unretained(this))));
232 return promise.Pass();
233 }
234
235 // Create a promise to be used when a new session is created.
236 // |expected_result| is used to indicate how the promise should be fulfilled.
237 scoped_ptr<NewSessionCdmPromise> CreateSessionPromise(
238 ExpectedResult expected_result) {
239 if (expected_result == SUCCESS) {
240 EXPECT_CALL(*this, OnResolveWithSession(_))
241 .WillOnce(SaveArg<0>(&session_id_));
242 } else {
243 EXPECT_CALL(*this, OnReject(_, _, IsNotEmpty()));
244 }
245
246 scoped_ptr<NewSessionCdmPromise> promise(
247 new CdmCallbackPromise<std::string>(
248 base::Bind(&CdmAdapterTest::OnResolveWithSession,
249 base::Unretained(this)),
250 base::Bind(&CdmAdapterTest::OnReject, base::Unretained(this))));
251 return promise.Pass();
252 }
253
254 void RunUntilIdle() { message_loop_.RunUntilIdle(); }
255
256 // Methods used for promise resolved/rejected.
257 MOCK_METHOD0(OnResolve, void());
258 MOCK_METHOD1(OnResolveWithSession, void(const std::string& session_id));
259 MOCK_METHOD3(OnReject,
260 void(MediaKeys::Exception exception_code,
261 uint32 system_code,
262 const std::string& error_message));
263
264 // Methods used for the events possibly generated by CdmAdapater.
265 MOCK_METHOD4(OnSessionMessage,
266 void(const std::string& session_id,
267 MediaKeys::MessageType message_type,
268 const std::vector<uint8_t>& message,
269 const GURL& legacy_destination_url));
270 MOCK_METHOD1(OnSessionClosed, void(const std::string& session_id));
271 MOCK_METHOD4(OnLegacySessionError,
272 void(const std::string& session_id,
273 MediaKeys::Exception exception,
274 uint32_t system_code,
275 const std::string& error_message));
276 MOCK_METHOD2(OnSessionKeysChangeCalled,
277 void(const std::string& session_id,
278 bool has_additional_usable_key));
279 void OnSessionKeysChange(const std::string& session_id,
280 bool has_additional_usable_key,
281 CdmKeysInfo keys_info) {
282 // MOCK methods don't like CdmKeysInfo.
283 OnSessionKeysChangeCalled(session_id, has_additional_usable_key);
284 }
285 MOCK_METHOD2(OnSessionExpirationUpdate,
286 void(const std::string& session_id,
287 const base::Time& new_expiry_time));
288
289 // Keep a reference to the CDM.
290 base::FilePath library_path_;
291 base::ScopedNativeLibrary library_;
292
293 scoped_refptr<MediaKeys> adapter_;
294
295 // |session_id_| is the latest result of calling CreateSession().
296 std::string session_id_;
297
298 base::MessageLoop message_loop_;
299
300 DISALLOW_COPY_AND_ASSIGN(CdmAdapterTest);
301 };
302
303 TEST_F(CdmAdapterTest, Initialize) {
304 InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
305 }
306
307 TEST_F(CdmAdapterTest, BadLibraryPath) {
308 InitializeAndExpect(base::FilePath(FILE_PATH_LITERAL("no_library_here")),
309 FAILURE);
310 }
311
312 TEST_F(CdmAdapterTest, CreateWebmSession) {
313 InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
314
315 std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
316 CreateSessionAndExpect(EmeInitDataType::WEBM, key_id, SUCCESS);
317 }
318
319 TEST_F(CdmAdapterTest, CreateKeyIdsSession) {
320 InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
321
322 // Don't include the trailing /0 from the string in the data passed in.
323 std::vector<uint8> key_id(kKeyIdAsJWK,
324 kKeyIdAsJWK + arraysize(kKeyIdAsJWK) - 1);
325 CreateSessionAndExpect(EmeInitDataType::KEYIDS, key_id, SUCCESS);
326 }
327
328 TEST_F(CdmAdapterTest, CreateCencSession) {
329 InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
330
331 std::vector<uint8> key_id(kKeyIdAsPssh,
332 kKeyIdAsPssh + arraysize(kKeyIdAsPssh));
333 #if defined(USE_PROPRIETARY_CODECS)
334 CreateSessionAndExpect(EmeInitDataType::CENC, key_id, SUCCESS);
335 #else
336 CreateSessionAndExpect(EmeInitDataType::CENC, key_id, FAILURE);
337 #endif
338 }
339
340 TEST_F(CdmAdapterTest, CreateSessionWithBadData) {
341 InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
342
343 // Use |kKeyId| but specify KEYIDS format.
344 std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
345 CreateSessionAndExpect(EmeInitDataType::KEYIDS, key_id, FAILURE);
346 }
347
348 TEST_F(CdmAdapterTest, LoadSession) {
349 InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
350
351 // LoadSession() is not supported by AesDecryptor.
352 std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
353 CreateSessionAndExpect(EmeInitDataType::KEYIDS, key_id, FAILURE);
354 }
355
356 TEST_F(CdmAdapterTest, UpdateSession) {
357 InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
358
359 std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
360 CreateSessionAndExpect(EmeInitDataType::WEBM, key_id, SUCCESS);
361
362 UpdateSessionAndExpect(SessionId(), kKeyAsJWK, SUCCESS, true);
363 }
364
365 TEST_F(CdmAdapterTest, UpdateSessionWithBadData) {
366 InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
367
368 std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
369 CreateSessionAndExpect(EmeInitDataType::WEBM, key_id, SUCCESS);
370
371 UpdateSessionAndExpect(SessionId(), "random data", FAILURE, true);
372 }
373
374 } // namespace media
OLDNEW
« no previous file with comments | « media/cdm/aes_decryptor.cc ('k') | media/cdm/ppapi/external_clear_key/clear_key_cdm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698