summaryrefslogtreecommitdiffstats
path: root/media/cdm/ppapi
diff options
context:
space:
mode:
authorxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-20 07:26:18 +0000
committerxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-20 07:26:18 +0000
commit34afd587d396b13defb7cf900caf3b67769d0b1e (patch)
tree33cd6c505b3ed7732c64f74cd1731d88c60c1c73 /media/cdm/ppapi
parent19d068c3f5a0ea6385cb4cd228ce8be1f135cd3d (diff)
downloadchromium_src-34afd587d396b13defb7cf900caf3b67769d0b1e.zip
chromium_src-34afd587d396b13defb7cf900caf3b67769d0b1e.tar.gz
chromium_src-34afd587d396b13defb7cf900caf3b67769d0b1e.tar.bz2
Add CDM FileIO tests.
- Add CdmFileIOTest, which tests CdmFileIO in ClearKeyCdm. - Update EncryptedMediaTest to check the result of CdmFileIOTest. BUG=324134 TEST=Tests added pass on Linux. Review URL: https://codereview.chromium.org/93243003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@242027 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/cdm/ppapi')
-rw-r--r--media/cdm/ppapi/cdm_file_io_test.cc437
-rw-r--r--media/cdm/ppapi/cdm_file_io_test.h157
-rw-r--r--media/cdm/ppapi/clear_key_cdm.cc49
-rw-r--r--media/cdm/ppapi/clear_key_cdm.h15
4 files changed, 649 insertions, 9 deletions
diff --git a/media/cdm/ppapi/cdm_file_io_test.cc b/media/cdm/ppapi/cdm_file_io_test.cc
new file mode 100644
index 0000000..5bbcd8e
--- /dev/null
+++ b/media/cdm/ppapi/cdm_file_io_test.cc
@@ -0,0 +1,437 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/cdm/ppapi/cdm_file_io_test.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+
+namespace media {
+
+#define FILE_IO_DVLOG(level) DVLOG(level) << "File IO Test: "
+
+const uint8 kData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
+const uint32 kDataSize = arraysize(kData);
+
+const uint8 kBigData[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00 };
+const uint32 kBigDataSize = arraysize(kBigData);
+
+// Must be > kReadSize in cdm_file_io_impl.cc.
+const uint32 kLargeDataSize = 9 * 1024 + 7;
+
+// Macros to help add test cases/steps.
+#define START_TEST_CASE(test_name) \
+ do { \
+ FileIOTest test_case(create_file_io_cb_, "FileIOTest." test_name); \
+ CREATE_FILE_IO // Create FileIO for each test case.
+
+#define ADD_TEST_STEP(type, status, data, data_size) \
+ test_case.AddTestStep(FileIOTest::type, cdm::FileIOClient::status, \
+ (data), (data_size));
+
+#define END_TEST_CASE \
+ remaining_tests_.push_back(test_case); \
+ } while(0);
+
+#define CREATE_FILE_IO \
+ ADD_TEST_STEP(ACTION_CREATE, kSuccess, NULL, 0)
+
+#define OPEN_FILE \
+ ADD_TEST_STEP(ACTION_OPEN, kSuccess, NULL, 0)
+
+#define EXPECT_FILE_OPENED(status) \
+ ADD_TEST_STEP(RESULT_OPEN, status, NULL, 0)
+
+#define READ_FILE \
+ ADD_TEST_STEP(ACTION_READ, kSuccess, NULL, 0)
+
+#define EXPECT_FILE_READ(status, data, data_size) \
+ ADD_TEST_STEP(RESULT_READ, status, data, data_size)
+
+#define WRITE_FILE(data, data_size) \
+ ADD_TEST_STEP(ACTION_WRITE, kSuccess, data, data_size)
+
+#define EXPECT_FILE_WRITTEN(status) \
+ ADD_TEST_STEP(RESULT_WRITE, status, NULL, 0)
+
+#define CLOSE_FILE \
+ ADD_TEST_STEP(ACTION_CLOSE, kSuccess, NULL, 0)
+
+// FileIOTestRunner implementation.
+
+FileIOTestRunner::FileIOTestRunner(const CreateFileIOCB& create_file_io_cb)
+ : create_file_io_cb_(create_file_io_cb),
+ total_num_tests_(0),
+ num_passed_tests_(0) {
+ // Generate |large_data_|.
+ large_data_.resize(kLargeDataSize);
+ for (size_t i = 0; i < kLargeDataSize; ++i)
+ large_data_[i] = i % kuint8max;
+
+ AddTests();
+}
+
+FileIOTestRunner::~FileIOTestRunner() {
+ if (remaining_tests_.empty())
+ return;
+
+ DCHECK_LT(num_passed_tests_, total_num_tests_);
+ FILE_IO_DVLOG(1) << "Not Finished (probably due to timeout). "
+ << num_passed_tests_ << " passed in "
+ << total_num_tests_ << " tests.";
+}
+
+// Note: Consecutive expectations (EXPECT*) can happen in any order.
+void FileIOTestRunner::AddTests() {
+ START_TEST_CASE("ReadBeforeOpeningFile")
+ READ_FILE
+ EXPECT_FILE_READ(kError, NULL, 0)
+ END_TEST_CASE
+
+ START_TEST_CASE("WriteBeforeOpeningFile")
+ WRITE_FILE(kData, kDataSize)
+ EXPECT_FILE_WRITTEN(kError)
+ END_TEST_CASE
+
+ START_TEST_CASE("ReadBeforeFileOpened")
+ OPEN_FILE
+ READ_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ EXPECT_FILE_READ(kError, NULL, 0)
+ END_TEST_CASE
+
+ START_TEST_CASE("WriteBeforeFileOpened")
+ OPEN_FILE
+ WRITE_FILE(kData, kDataSize)
+ EXPECT_FILE_WRITTEN(kError)
+ EXPECT_FILE_OPENED(kSuccess)
+ END_TEST_CASE
+
+ START_TEST_CASE("ReadDuringPendingRead")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ WRITE_FILE(kData, kDataSize)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ READ_FILE
+ READ_FILE
+ EXPECT_FILE_READ(kInUse, NULL, 0)
+ EXPECT_FILE_READ(kSuccess, kData, kDataSize)
+ END_TEST_CASE
+
+ START_TEST_CASE("ReadDuringPendingWrite")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ WRITE_FILE(kData, kDataSize)
+ READ_FILE
+ EXPECT_FILE_READ(kInUse, NULL, 0)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ END_TEST_CASE
+
+ START_TEST_CASE("WriteDuringPendingRead")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ READ_FILE
+ WRITE_FILE(kData, kDataSize)
+ EXPECT_FILE_WRITTEN(kInUse)
+ EXPECT_FILE_READ(kSuccess, NULL, 0)
+ END_TEST_CASE
+
+ START_TEST_CASE("WriteDuringPendingWrite")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ WRITE_FILE(kData, kDataSize)
+ WRITE_FILE(kBigData, kBigDataSize)
+ EXPECT_FILE_WRITTEN(kInUse)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ END_TEST_CASE
+
+ START_TEST_CASE("ReadEmptyFile")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ READ_FILE
+ EXPECT_FILE_READ(kSuccess, NULL, 0)
+ END_TEST_CASE
+
+ START_TEST_CASE("WriteAndRead")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ WRITE_FILE(kData, kDataSize)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ READ_FILE
+ EXPECT_FILE_READ(kSuccess, kData, kDataSize)
+ END_TEST_CASE
+
+ START_TEST_CASE("WriteZeroBytes")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ WRITE_FILE(NULL, 0)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ READ_FILE
+ EXPECT_FILE_READ(kSuccess, NULL, 0)
+ END_TEST_CASE
+
+ START_TEST_CASE("WriteAndReadLargeData")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ WRITE_FILE(&large_data_[0], kLargeDataSize)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ READ_FILE
+ EXPECT_FILE_READ(kSuccess, &large_data_[0], kLargeDataSize)
+ END_TEST_CASE
+
+ START_TEST_CASE("OverwriteZeroBytes")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ WRITE_FILE(kData, kDataSize)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ READ_FILE
+ EXPECT_FILE_READ(kSuccess, kData, kDataSize)
+ WRITE_FILE(NULL, 0)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ READ_FILE
+ EXPECT_FILE_READ(kSuccess, NULL, 0)
+ END_TEST_CASE
+
+ START_TEST_CASE("OverwriteWithSmallerData")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ WRITE_FILE(kBigData, kBigDataSize)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ WRITE_FILE(kData, kDataSize)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ READ_FILE
+ EXPECT_FILE_READ(kSuccess, kData, kDataSize)
+ END_TEST_CASE
+
+ START_TEST_CASE("OverwriteWithLargerData")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ WRITE_FILE(kData, kDataSize)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ WRITE_FILE(kBigData, kBigDataSize)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ READ_FILE
+ EXPECT_FILE_READ(kSuccess, kBigData, kBigDataSize)
+ END_TEST_CASE
+
+ START_TEST_CASE("ReadExistingFile")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ WRITE_FILE(kData, kDataSize)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ CLOSE_FILE
+ CREATE_FILE_IO
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ READ_FILE
+ EXPECT_FILE_READ(kSuccess, kData, kDataSize)
+ END_TEST_CASE
+
+ START_TEST_CASE("ReopenFileInTheSameFileIO")
+ OPEN_FILE
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kError) // The second Open() failed.
+ EXPECT_FILE_OPENED(kSuccess) // The first Open() succeeded.
+ END_TEST_CASE
+
+ // TODO(xhwang): This test should fail. But pp::FileIO doesn't support locking
+ // of opened files. We need to either workaround this or fix pp::FileIO
+ // implementation.
+ START_TEST_CASE("ReopenFileInSeparateFileIO")
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ WRITE_FILE(kData, kDataSize)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ CREATE_FILE_IO // Create a second FileIO without closing the first one.
+ OPEN_FILE
+ EXPECT_FILE_OPENED(kSuccess)
+ READ_FILE
+ EXPECT_FILE_READ(kSuccess, kData, kDataSize)
+ WRITE_FILE(kBigData, kBigDataSize)
+ EXPECT_FILE_WRITTEN(kSuccess)
+ END_TEST_CASE
+}
+
+void FileIOTestRunner::RunAllTests(const CompletionCB& completion_cb) {
+ completion_cb_ = completion_cb;
+ total_num_tests_ = remaining_tests_.size();
+ RunNextTest();
+}
+
+void FileIOTestRunner::RunNextTest() {
+ if (remaining_tests_.empty()) {
+ FILE_IO_DVLOG(1) << num_passed_tests_ << " passed and "
+ << (total_num_tests_ - num_passed_tests_) << " failed in "
+ << total_num_tests_ << " tests.";
+ bool success = (num_passed_tests_ == total_num_tests_);
+ base::ResetAndReturn(&completion_cb_).Run(success);
+ return;
+ }
+
+ remaining_tests_.front().Run(
+ base::Bind(&FileIOTestRunner::OnTestComplete, base::Unretained(this)));
+}
+
+void FileIOTestRunner::OnTestComplete(bool success) {
+ if (success)
+ num_passed_tests_++;
+ remaining_tests_.pop_front();
+ RunNextTest();
+}
+
+// FileIOTest implementation.
+
+FileIOTest::FileIOTest(const CreateFileIOCB& create_file_io_cb,
+ const std::string& test_name)
+ : create_file_io_cb_(create_file_io_cb),
+ test_name_(test_name) {}
+
+FileIOTest::~FileIOTest() {}
+
+void FileIOTest::AddTestStep(
+ StepType type, Status status, const uint8* data, uint32 data_size) {
+ test_steps_.push_back(TestStep(type, status, data, data_size));
+}
+
+void FileIOTest::Run(const CompletionCB& completion_cb) {
+ FILE_IO_DVLOG(3) << "Run " << test_name_;
+ completion_cb_ = completion_cb;
+ DCHECK(!test_steps_.empty() && !IsResult(test_steps_.front()));
+ RunNextStep();
+}
+
+void FileIOTest::OnOpenComplete(Status status) {
+ OnResult(TestStep(RESULT_OPEN, status, NULL, 0));
+}
+
+void FileIOTest::OnReadComplete(Status status,
+ const uint8_t* data,
+ uint32_t data_size) {
+ OnResult(TestStep(RESULT_READ, status, data, data_size));
+}
+
+void FileIOTest::OnWriteComplete(Status status) {
+ OnResult(TestStep(RESULT_WRITE, status, NULL, 0));
+}
+
+bool FileIOTest::IsResult(const TestStep& test_step) {
+ switch (test_step.type) {
+ case RESULT_OPEN:
+ case RESULT_READ:
+ case RESULT_WRITE:
+ return true;
+ case ACTION_CREATE:
+ case ACTION_OPEN:
+ case ACTION_READ:
+ case ACTION_WRITE:
+ case ACTION_CLOSE:
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool FileIOTest::MatchesResult(const TestStep& a, const TestStep& b) {
+ DCHECK(IsResult(a) && IsResult(b));
+ if (a.type != b.type || a.status != b.status)
+ return false;
+
+ if (a.type != RESULT_READ || a.status != cdm::FileIOClient::kSuccess)
+ return true;
+
+ return (a.data_size == a.data_size &&
+ std::equal(a.data, a.data + a.data_size, b.data));
+}
+
+void FileIOTest::RunNextStep() {
+ // Run all actions in the current action group.
+ while (!test_steps_.empty()) {
+ // Start to wait for test results when the next step is a test result.
+ if (IsResult(test_steps_.front()))
+ return;
+
+ TestStep test_step = test_steps_.front();
+ test_steps_.pop_front();
+
+ cdm::FileIO* file_io = file_io_stack_.empty()? NULL : file_io_stack_.top();
+
+ switch (test_step.type) {
+ case ACTION_CREATE:
+ file_io = create_file_io_cb_.Run(this);
+ if (!file_io) {
+ FILE_IO_DVLOG(3) << "Cannot create FileIO object.";
+ OnTestComplete(false);
+ return;
+ }
+ file_io_stack_.push(file_io);
+ break;
+ case ACTION_OPEN:
+ // Use test name as the test file name.
+ file_io->Open(test_name_.data(), test_name_.size());
+ break;
+ case ACTION_READ:
+ file_io->Read();
+ break;
+ case ACTION_WRITE:
+ file_io->Write(test_step.data, test_step.data_size);
+ break;
+ case ACTION_CLOSE:
+ file_io->Close();
+ file_io_stack_.pop();
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ OnTestComplete(true);
+}
+
+void FileIOTest::OnResult(const TestStep& result) {
+ DCHECK(IsResult(result));
+ if (!CheckResult(result)) {
+ OnTestComplete(false);
+ return;
+ }
+
+ RunNextStep();
+}
+
+bool FileIOTest::CheckResult(const TestStep& result) {
+ if (test_steps_.empty() || !IsResult(test_steps_.front()))
+ return false;
+
+ // If there are multiple results expected, the order does not matter.
+ std::list<TestStep>::iterator iter = test_steps_.begin();
+ for (; iter != test_steps_.end(); ++iter) {
+ if (!IsResult(*iter))
+ return false;
+
+ if (!MatchesResult(*iter, result))
+ continue;
+
+ test_steps_.erase(iter);
+ return true;
+ }
+
+ return false;
+}
+
+void FileIOTest::OnTestComplete(bool success) {
+ while (!file_io_stack_.empty()) {
+ cdm::FileIO* file_io = file_io_stack_.top();
+ file_io->Close();
+ file_io_stack_.pop();
+ }
+ FILE_IO_DVLOG(3) << test_name_ << (success ? " PASSED" : " FAILED");
+ base::ResetAndReturn(&completion_cb_).Run(success);
+}
+
+} // namespace media
diff --git a/media/cdm/ppapi/cdm_file_io_test.h b/media/cdm/ppapi/cdm_file_io_test.h
new file mode 100644
index 0000000..3e0060c
--- /dev/null
+++ b/media/cdm/ppapi/cdm_file_io_test.h
@@ -0,0 +1,157 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_CDM_PPAPI_CDM_FILE_IO_TEST_H_
+#define MEDIA_CDM_PPAPI_CDM_FILE_IO_TEST_H_
+
+#include <list>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "media/cdm/ppapi/api/content_decryption_module.h"
+
+namespace media {
+
+typedef base::Callback<void(bool success)> CompletionCB;
+typedef base::Callback<cdm::FileIO*(cdm::FileIOClient* client)> CreateFileIOCB;
+
+// A customizable test class that tests cdm::FileIO implementation.
+// - To create a test, call AddTestStep() to add a test step. A test step can be
+// either an action to make (use ACTION_* types), or a result to verify (use
+// RESULT_* types).
+// - To run the test, simply call Run() with a completion callback. The result
+// will be reported in the completion callback when the test is finished.
+//
+// The following rules apply to the test steps:
+// - Test steps are ordered (with the exception that results in a result group
+// is not ordered).
+// - Consecutive action steps form an "action group". Consecutively result
+// steps form a "result group". An action group is followed by a result
+// group and vice versa.
+// - A test must start with an action group.
+// - To process an action group, the test runner runs (and clears) all steps
+// in the group in the order they were added. Then it waits for test
+// results.
+// - When a cdm::FileIOClient method is called, the test runner compares the
+// result with all results in the current result group. If no result in that
+// group matches the test result, the test fails. Otherwise, the matching
+// result is cleared from the group. If the group is empty, the test runner
+// starts to process the next action group. Otherwise, the test runner keeps
+// waiting for the next test result.
+// - After all steps are cleared, the test passes.
+class FileIOTest : public cdm::FileIOClient {
+ public:
+ // Types of allowed test steps:
+ // - ACTION_* specifies the next step to test.
+ // - RESULT_* specifies the expected result of the previous step(s).
+ enum StepType {
+ ACTION_CREATE,
+ ACTION_OPEN, // |test_name_| will be used used as the file name to open.
+ RESULT_OPEN,
+ ACTION_READ,
+ RESULT_READ,
+ ACTION_WRITE,
+ RESULT_WRITE,
+ ACTION_CLOSE // If ACTION_CLOSE is not specified, FileIO::Close() will be
+ // automatically called at the end of the test.
+ };
+
+ FileIOTest(const CreateFileIOCB& create_file_io_cb,
+ const std::string& test_name);
+ ~FileIOTest();
+
+ // Adds a test step in this test. |this| object doesn't take the ownership of
+ // |data|, which should be valid throughout the lifetime of |this| object.
+ void AddTestStep(
+ StepType type, Status status, const uint8* data, uint32 data_size);
+
+ // Runs this test case and returns the test result through |completion_cb|.
+ void Run(const CompletionCB& completion_cb);
+
+ private:
+ struct TestStep {
+ // |this| object doesn't take the ownership of |data|, which should be valid
+ // throughout the lifetime of |this| object.
+ TestStep(StepType type, Status status, const uint8* data, uint32 data_size)
+ : type(type), status(status), data(data), data_size(data_size) {}
+
+ StepType type;
+
+ // Expected status for RESULT* steps.
+ Status status;
+
+ // Data to write in ACTION_WRITE, or read data in RESULT_READ.
+ const uint8* data;
+ uint32 data_size;
+ };
+
+ // Returns whether |test_step| is a RESULT_* step.
+ static bool IsResult(const TestStep& test_step);
+
+ // Returns whether two results match.
+ static bool MatchesResult(const TestStep& a, const TestStep& b);
+
+ // cdm::FileIOClient implementation.
+ virtual void OnOpenComplete(Status status) OVERRIDE;
+ virtual void OnReadComplete(Status status,
+ const uint8_t* data,
+ uint32_t data_size) OVERRIDE;
+ virtual void OnWriteComplete(Status status) OVERRIDE;
+
+ // Runs the next step in this test case.
+ void RunNextStep();
+
+ void OnResult(const TestStep& result);
+
+ // Checks whether the test result matches this step. This can only be called
+ // when this step is a RESULT_* step.
+ bool CheckResult(const TestStep& result);
+
+ void OnTestComplete(bool success);
+
+ CreateFileIOCB create_file_io_cb_;
+ CompletionCB completion_cb_;
+
+ std::string test_name_;
+ std::list<TestStep> test_steps_;
+
+ // All opened cdm::FileIO objects. We keep multiple cdm::FileIO objects open
+ // so that we can test multiple cdm::FileIO objects accessing the same file.
+ // In the current implementation, all ACTION_* are performed on the latest
+ // opened cdm::FileIO object, hence the stack.
+ std::stack<cdm::FileIO*> file_io_stack_;
+};
+
+// Tests cdm::FileIO implementation.
+class FileIOTestRunner {
+ public:
+ explicit FileIOTestRunner(const CreateFileIOCB& create_file_io_cb);
+ ~FileIOTestRunner();
+
+ void AddTests();
+
+ // Run all tests. When tests are completed, the result will be reported in the
+ // |completion_cb|.
+ void RunAllTests(const CompletionCB& completion_cb);
+
+ private:
+ void OnTestComplete(bool success);
+ void RunNextTest();
+
+ CreateFileIOCB create_file_io_cb_;
+ CompletionCB completion_cb_;
+ std::list<FileIOTest> remaining_tests_;
+ std::vector<uint8> large_data_;
+ size_t total_num_tests_; // Total number of tests.
+ size_t num_passed_tests_; // Number of passed tests.
+
+ DISALLOW_COPY_AND_ASSIGN (FileIOTestRunner);
+};
+
+} // namespace media
+
+#endif // MEDIA_CDM_PPAPI_CDM_FILE_IO_TEST_H_
diff --git a/media/cdm/ppapi/clear_key_cdm.cc b/media/cdm/ppapi/clear_key_cdm.cc
index 16a00a5..ea89e82 100644
--- a/media/cdm/ppapi/clear_key_cdm.cc
+++ b/media/cdm/ppapi/clear_key_cdm.cc
@@ -15,6 +15,7 @@
#include "base/time/time.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
+#include "media/cdm/ppapi/cdm_file_io_test.h"
#include "media/cdm/ppapi/cdm_video_decoder.h"
#if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
@@ -63,6 +64,8 @@ const char kClearKeyCdmVersion[] = "0.1.0.1";
const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey";
const char kExternalClearKeyDecryptOnlyKeySystem[] =
"org.chromium.externalclearkey.decryptonly";
+const char kExternalClearKeyFileIOTestKeySystem[] =
+ "org.chromium.externalclearkey.fileiotest";
const int64 kSecondsPerMinute = 60;
const int64 kMsPerSecond = 1000;
const int64 kInitialTimerDelayMs = 200;
@@ -70,6 +73,8 @@ const int64 kMaxTimerDelayMs = 1 * kSecondsPerMinute * kMsPerSecond;
// Heart beat message header. If a key message starts with |kHeartBeatHeader|,
// it's a heart beat message. Otherwise, it's a key request.
const char kHeartBeatHeader[] = "HEARTBEAT";
+// CDM file IO test result header.
+const char kFileIOTestResultHeader[] = "FILEIOTESTRESULT";
// Copies |input_buffer| into a media::DecoderBuffer. If the |input_buffer| is
// empty, an empty (end-of-stream) media::DecoderBuffer is returned.
@@ -107,6 +112,12 @@ static scoped_refptr<media::DecoderBuffer> CopyDecoderBufferFrom(
return output_buffer;
}
+static std::string GetFileIOTestResultMessage(bool success) {
+ std::string message(kFileIOTestResultHeader);
+ message += success ? '1' : '0';
+ return message;
+}
+
template<typename Type>
class ScopedResetter {
public:
@@ -135,7 +146,8 @@ void* CreateCdmInstance(int cdm_interface_version,
std::string key_system_string(key_system, key_system_size);
if (key_system_string != kExternalClearKeyKeySystem &&
- key_system_string != kExternalClearKeyDecryptOnlyKeySystem) {
+ key_system_string != kExternalClearKeyDecryptOnlyKeySystem &&
+ key_system_string != kExternalClearKeyFileIOTestKeySystem) {
DVLOG(1) << "Unsupported key system:" << key_system_string;
return NULL;
}
@@ -149,7 +161,9 @@ void* CreateCdmInstance(int cdm_interface_version,
return NULL;
return new media::ClearKeyCdm(
- host, key_system_string == kExternalClearKeyDecryptOnlyKeySystem);
+ host,
+ key_system_string == kExternalClearKeyDecryptOnlyKeySystem,
+ key_system_string == kExternalClearKeyFileIOTestKeySystem);
}
const char* GetCdmVersion() {
@@ -158,7 +172,9 @@ const char* GetCdmVersion() {
namespace media {
-ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, bool is_decrypt_only)
+ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host,
+ bool is_decrypt_only,
+ bool should_test_file_io)
: decryptor_(
base::Bind(&ClearKeyCdm::OnSessionCreated, base::Unretained(this)),
base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)),
@@ -167,7 +183,8 @@ ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, bool is_decrypt_only)
base::Bind(&ClearKeyCdm::OnSessionError, base::Unretained(this))),
host_(host),
is_decrypt_only_(is_decrypt_only),
- heartbeat_session_id_(0),
+ should_test_file_io_(should_test_file_io),
+ last_session_id_(MediaKeys::kInvalidSessionId),
timer_delay_ms_(kInitialTimerDelayMs),
timer_set_(false) {
#if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
@@ -190,8 +207,11 @@ void ClearKeyCdm::CreateSession(uint32 session_id,
decryptor_.CreateSession(
session_id, std::string(type, type_size), init_data, init_data_size);
- // Only save the latest session ID for heartbeat messages.
- heartbeat_session_id_ = session_id;
+ // Save the latest session ID for heartbeat and file IO test messages.
+ last_session_id_ = session_id;
+
+ if (should_test_file_io_)
+ StartFileIOTest();
}
void ClearKeyCdm::UpdateSession(uint32 session_id,
@@ -224,7 +244,7 @@ void ClearKeyCdm::TimerExpired(void* context) {
// There is no service at this URL, so applications should ignore it.
const char url[] = "http://test.externalclearkey.chromium.org";
- host_->OnSessionMessage(heartbeat_session_id_,
+ host_->OnSessionMessage(last_session_id_,
heartbeat_message.data(),
heartbeat_message.size(),
url,
@@ -556,4 +576,19 @@ cdm::Status ClearKeyCdm::GenerateFakeAudioFrames(
}
#endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER
+void ClearKeyCdm::StartFileIOTest() {
+ file_io_test_runner_.reset(new FileIOTestRunner(
+ base::Bind(&ClearKeyCdmHost::CreateFileIO, base::Unretained(host_))));
+ file_io_test_runner_->RunAllTests(
+ base::Bind(&ClearKeyCdm::OnFileIOTestComplete, base::Unretained(this)));
+}
+
+void ClearKeyCdm::OnFileIOTestComplete(bool success) {
+ DVLOG(1) << __FUNCTION__ << ": " << success;
+ std::string message = GetFileIOTestResultMessage(success);
+ host_->OnSessionMessage(
+ last_session_id_, message.data(), message.size(), NULL, 0);
+ file_io_test_runner_.reset();
+}
+
} // namespace media
diff --git a/media/cdm/ppapi/clear_key_cdm.h b/media/cdm/ppapi/clear_key_cdm.h
index 87f45e1..79c8af0 100644
--- a/media/cdm/ppapi/clear_key_cdm.h
+++ b/media/cdm/ppapi/clear_key_cdm.h
@@ -23,6 +23,7 @@
#endif
namespace media {
+class FileIOTestRunner;
class CdmVideoDecoder;
class DecoderBuffer;
class FFmpegCdmAudioDecoder;
@@ -30,7 +31,9 @@ class FFmpegCdmAudioDecoder;
// Clear key implementation of the cdm::ContentDecryptionModule interface.
class ClearKeyCdm : public ClearKeyCdmInterface {
public:
- explicit ClearKeyCdm(Host* host, bool is_decrypt_only);
+ explicit ClearKeyCdm(Host* host,
+ bool is_decrypt_only,
+ bool should_test_file_io);
virtual ~ClearKeyCdm();
// ContentDecryptionModule implementation.
@@ -104,13 +107,19 @@ class ClearKeyCdm : public ClearKeyCdmInterface {
cdm::AudioFrames* audio_frames);
#endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER
+ void StartFileIOTest();
+
+ // Callback for CDM File IO test.
+ void OnFileIOTestComplete(bool success);
+
AesDecryptor decryptor_;
ClearKeyCdmHost* host_;
const bool is_decrypt_only_;
+ const bool should_test_file_io_;
- uint32 heartbeat_session_id_;
+ uint32 last_session_id_;
std::string next_heartbeat_message_;
// Timer delay in milliseconds for the next host_->SetTimer() call.
@@ -134,6 +143,8 @@ class ClearKeyCdm : public ClearKeyCdmInterface {
scoped_ptr<CdmVideoDecoder> video_decoder_;
+ scoped_ptr<FileIOTestRunner> file_io_test_runner_;
+
DISALLOW_COPY_AND_ASSIGN(ClearKeyCdm);
};