cdm_file_io_test.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright 2013 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 "media/cdm/ppapi/cdm_file_io_test.h"
6
7#include "base/bind.h"
8#include "base/callback_helpers.h"
9#include "base/logging.h"
10
11namespace media {
12
13#define FILE_IO_DVLOG(level) DVLOG(level) << "File IO Test: "
14
15const uint8 kData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
16                        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
17const uint32 kDataSize = arraysize(kData);
18
19const uint8 kBigData[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
20                           0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
21                           0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
22                           0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
23                           0x00 };
24const uint32 kBigDataSize = arraysize(kBigData);
25
26// Must be > kReadSize in cdm_file_io_impl.cc.
27const uint32 kLargeDataSize = 9 * 1024 + 7;
28
29// Macros to help add test cases/steps.
30#define START_TEST_CASE(test_name)                                     \
31  do {                                                                 \
32    FileIOTest test_case(create_file_io_cb_, "FileIOTest." test_name); \
33    CREATE_FILE_IO  // Create FileIO for each test case.
34
35#define ADD_TEST_STEP(type, status, data, data_size)                   \
36    test_case.AddTestStep(FileIOTest::type, cdm::FileIOClient::status, \
37                          (data), (data_size));
38
39#define END_TEST_CASE                 \
40    remaining_tests_.push_back(test_case); \
41  } while(0);
42
43#define CREATE_FILE_IO \
44  ADD_TEST_STEP(ACTION_CREATE, kSuccess, NULL, 0)
45
46#define OPEN_FILE \
47  ADD_TEST_STEP(ACTION_OPEN, kSuccess, NULL, 0)
48
49#define EXPECT_FILE_OPENED(status) \
50  ADD_TEST_STEP(RESULT_OPEN, status, NULL, 0)
51
52#define READ_FILE \
53  ADD_TEST_STEP(ACTION_READ, kSuccess, NULL, 0)
54
55#define EXPECT_FILE_READ(status, data, data_size) \
56  ADD_TEST_STEP(RESULT_READ, status, data, data_size)
57
58#define WRITE_FILE(data, data_size) \
59  ADD_TEST_STEP(ACTION_WRITE, kSuccess, data, data_size)
60
61#define EXPECT_FILE_WRITTEN(status) \
62  ADD_TEST_STEP(RESULT_WRITE, status, NULL, 0)
63
64#define CLOSE_FILE \
65  ADD_TEST_STEP(ACTION_CLOSE, kSuccess, NULL, 0)
66
67// FileIOTestRunner implementation.
68
69FileIOTestRunner::FileIOTestRunner(const CreateFileIOCB& create_file_io_cb)
70    : create_file_io_cb_(create_file_io_cb),
71      total_num_tests_(0),
72      num_passed_tests_(0) {
73  // Generate |large_data_|.
74  large_data_.resize(kLargeDataSize);
75  for (size_t i = 0; i < kLargeDataSize; ++i)
76    large_data_[i] = i % kuint8max;
77
78  AddTests();
79}
80
81FileIOTestRunner::~FileIOTestRunner() {
82  if (remaining_tests_.empty())
83    return;
84
85  DCHECK_LT(num_passed_tests_, total_num_tests_);
86  FILE_IO_DVLOG(1) << "Not Finished (probably due to timeout). "
87                   << num_passed_tests_ << " passed in "
88                   << total_num_tests_ << " tests.";
89}
90
91// Note: Consecutive expectations (EXPECT*) can happen in any order.
92void FileIOTestRunner::AddTests() {
93  START_TEST_CASE("ReadBeforeOpeningFile")
94    READ_FILE
95    EXPECT_FILE_READ(kError, NULL, 0)
96  END_TEST_CASE
97
98  START_TEST_CASE("WriteBeforeOpeningFile")
99    WRITE_FILE(kData, kDataSize)
100    EXPECT_FILE_WRITTEN(kError)
101  END_TEST_CASE
102
103  START_TEST_CASE("ReadBeforeFileOpened")
104    OPEN_FILE
105    READ_FILE
106    EXPECT_FILE_OPENED(kSuccess)
107    EXPECT_FILE_READ(kError, NULL, 0)
108  END_TEST_CASE
109
110  START_TEST_CASE("WriteBeforeFileOpened")
111    OPEN_FILE
112    WRITE_FILE(kData, kDataSize)
113    EXPECT_FILE_WRITTEN(kError)
114    EXPECT_FILE_OPENED(kSuccess)
115  END_TEST_CASE
116
117  START_TEST_CASE("ReadDuringPendingRead")
118    OPEN_FILE
119    EXPECT_FILE_OPENED(kSuccess)
120    WRITE_FILE(kData, kDataSize)
121    EXPECT_FILE_WRITTEN(kSuccess)
122    READ_FILE
123    READ_FILE
124    EXPECT_FILE_READ(kInUse, NULL, 0)
125    EXPECT_FILE_READ(kSuccess, kData, kDataSize)
126  END_TEST_CASE
127
128  START_TEST_CASE("ReadDuringPendingWrite")
129    OPEN_FILE
130    EXPECT_FILE_OPENED(kSuccess)
131    WRITE_FILE(kData, kDataSize)
132    READ_FILE
133    EXPECT_FILE_READ(kInUse, NULL, 0)
134    EXPECT_FILE_WRITTEN(kSuccess)
135  END_TEST_CASE
136
137  START_TEST_CASE("WriteDuringPendingRead")
138    OPEN_FILE
139    EXPECT_FILE_OPENED(kSuccess)
140    READ_FILE
141    WRITE_FILE(kData, kDataSize)
142    EXPECT_FILE_WRITTEN(kInUse)
143    EXPECT_FILE_READ(kSuccess, NULL, 0)
144  END_TEST_CASE
145
146  START_TEST_CASE("WriteDuringPendingWrite")
147    OPEN_FILE
148    EXPECT_FILE_OPENED(kSuccess)
149    WRITE_FILE(kData, kDataSize)
150    WRITE_FILE(kBigData, kBigDataSize)
151    EXPECT_FILE_WRITTEN(kInUse)
152    EXPECT_FILE_WRITTEN(kSuccess)
153  END_TEST_CASE
154
155  START_TEST_CASE("ReadEmptyFile")
156    OPEN_FILE
157    EXPECT_FILE_OPENED(kSuccess)
158    READ_FILE
159    EXPECT_FILE_READ(kSuccess, NULL, 0)
160  END_TEST_CASE
161
162  START_TEST_CASE("WriteAndRead")
163    OPEN_FILE
164    EXPECT_FILE_OPENED(kSuccess)
165    WRITE_FILE(kData, kDataSize)
166    EXPECT_FILE_WRITTEN(kSuccess)
167    READ_FILE
168    EXPECT_FILE_READ(kSuccess, kData, kDataSize)
169  END_TEST_CASE
170
171  START_TEST_CASE("WriteZeroBytes")
172    OPEN_FILE
173    EXPECT_FILE_OPENED(kSuccess)
174    WRITE_FILE(NULL, 0)
175    EXPECT_FILE_WRITTEN(kSuccess)
176    READ_FILE
177    EXPECT_FILE_READ(kSuccess, NULL, 0)
178  END_TEST_CASE
179
180  START_TEST_CASE("WriteAndReadLargeData")
181    OPEN_FILE
182    EXPECT_FILE_OPENED(kSuccess)
183    WRITE_FILE(&large_data_[0], kLargeDataSize)
184    EXPECT_FILE_WRITTEN(kSuccess)
185    READ_FILE
186    EXPECT_FILE_READ(kSuccess, &large_data_[0], kLargeDataSize)
187  END_TEST_CASE
188
189  START_TEST_CASE("OverwriteZeroBytes")
190    OPEN_FILE
191    EXPECT_FILE_OPENED(kSuccess)
192    WRITE_FILE(kData, kDataSize)
193    EXPECT_FILE_WRITTEN(kSuccess)
194    READ_FILE
195    EXPECT_FILE_READ(kSuccess, kData, kDataSize)
196    WRITE_FILE(NULL, 0)
197    EXPECT_FILE_WRITTEN(kSuccess)
198    READ_FILE
199    EXPECT_FILE_READ(kSuccess, NULL, 0)
200  END_TEST_CASE
201
202  START_TEST_CASE("OverwriteWithSmallerData")
203    OPEN_FILE
204    EXPECT_FILE_OPENED(kSuccess)
205    WRITE_FILE(kBigData, kBigDataSize)
206    EXPECT_FILE_WRITTEN(kSuccess)
207    WRITE_FILE(kData, kDataSize)
208    EXPECT_FILE_WRITTEN(kSuccess)
209    READ_FILE
210    EXPECT_FILE_READ(kSuccess, kData, kDataSize)
211  END_TEST_CASE
212
213  START_TEST_CASE("OverwriteWithLargerData")
214    OPEN_FILE
215    EXPECT_FILE_OPENED(kSuccess)
216    WRITE_FILE(kData, kDataSize)
217    EXPECT_FILE_WRITTEN(kSuccess)
218    WRITE_FILE(kBigData, kBigDataSize)
219    EXPECT_FILE_WRITTEN(kSuccess)
220    READ_FILE
221    EXPECT_FILE_READ(kSuccess, kBigData, kBigDataSize)
222  END_TEST_CASE
223
224  START_TEST_CASE("ReadExistingFile")
225    OPEN_FILE
226    EXPECT_FILE_OPENED(kSuccess)
227    WRITE_FILE(kData, kDataSize)
228    EXPECT_FILE_WRITTEN(kSuccess)
229    CLOSE_FILE
230    CREATE_FILE_IO
231    OPEN_FILE
232    EXPECT_FILE_OPENED(kSuccess)
233    READ_FILE
234    EXPECT_FILE_READ(kSuccess, kData, kDataSize)
235  END_TEST_CASE
236
237  START_TEST_CASE("ReopenFileInTheSameFileIO")
238    OPEN_FILE
239    OPEN_FILE
240    EXPECT_FILE_OPENED(kError)  // The second Open() failed.
241    EXPECT_FILE_OPENED(kSuccess)  // The first Open() succeeded.
242  END_TEST_CASE
243
244  START_TEST_CASE("ReopenFileInSeparateFileIO")
245    OPEN_FILE
246    EXPECT_FILE_OPENED(kSuccess)
247    WRITE_FILE(kData, kDataSize)
248    EXPECT_FILE_WRITTEN(kSuccess)
249    CREATE_FILE_IO  // Create a second FileIO without closing the first one.
250    OPEN_FILE
251    EXPECT_FILE_OPENED(kInUse)
252  END_TEST_CASE
253
254  START_TEST_CASE("CloseAfterCreation")
255    CLOSE_FILE
256  END_TEST_CASE
257
258  START_TEST_CASE("CloseDuringPendingOpen")
259    OPEN_FILE
260    CLOSE_FILE
261  END_TEST_CASE
262
263  START_TEST_CASE("CloseDuringPendingWrite")
264    OPEN_FILE
265    EXPECT_FILE_OPENED(kSuccess)
266    WRITE_FILE(kData, kDataSize)
267    CLOSE_FILE
268  END_TEST_CASE
269
270  START_TEST_CASE("CloseDuringPendingRead")
271    OPEN_FILE
272    EXPECT_FILE_OPENED(kSuccess)
273    WRITE_FILE(kData, kDataSize)
274    EXPECT_FILE_WRITTEN(kSuccess)
275    READ_FILE
276    CLOSE_FILE
277  END_TEST_CASE
278}
279
280void FileIOTestRunner::RunAllTests(const CompletionCB& completion_cb) {
281  completion_cb_ = completion_cb;
282  total_num_tests_ = remaining_tests_.size();
283  RunNextTest();
284}
285
286void FileIOTestRunner::RunNextTest() {
287  if (remaining_tests_.empty()) {
288    FILE_IO_DVLOG(1) << num_passed_tests_ << " passed and "
289                     << (total_num_tests_ - num_passed_tests_) << " failed in "
290                     << total_num_tests_ << " tests.";
291    bool success = (num_passed_tests_ == total_num_tests_);
292    base::ResetAndReturn(&completion_cb_).Run(success);
293    return;
294  }
295
296  remaining_tests_.front().Run(
297      base::Bind(&FileIOTestRunner::OnTestComplete, base::Unretained(this)));
298}
299
300void FileIOTestRunner::OnTestComplete(bool success) {
301  if (success)
302    num_passed_tests_++;
303  remaining_tests_.pop_front();
304  RunNextTest();
305}
306
307// FileIOTest implementation.
308
309FileIOTest::FileIOTest(const CreateFileIOCB& create_file_io_cb,
310                       const std::string& test_name)
311    : create_file_io_cb_(create_file_io_cb),
312      test_name_(test_name) {}
313
314FileIOTest::~FileIOTest() {}
315
316void FileIOTest::AddTestStep(
317    StepType type, Status status, const uint8* data, uint32 data_size) {
318  test_steps_.push_back(TestStep(type, status, data, data_size));
319}
320
321void FileIOTest::Run(const CompletionCB& completion_cb) {
322  FILE_IO_DVLOG(3) << "Run " << test_name_;
323  completion_cb_ = completion_cb;
324  DCHECK(!test_steps_.empty() && !IsResult(test_steps_.front()));
325  RunNextStep();
326}
327
328void FileIOTest::OnOpenComplete(Status status) {
329  OnResult(TestStep(RESULT_OPEN, status, NULL, 0));
330}
331
332void FileIOTest::OnReadComplete(Status status,
333                                const uint8_t* data,
334                                uint32_t data_size) {
335  OnResult(TestStep(RESULT_READ, status, data, data_size));
336}
337
338void FileIOTest::OnWriteComplete(Status status) {
339  OnResult(TestStep(RESULT_WRITE, status, NULL, 0));
340}
341
342bool FileIOTest::IsResult(const TestStep& test_step) {
343  switch (test_step.type) {
344    case RESULT_OPEN:
345    case RESULT_READ:
346    case RESULT_WRITE:
347      return true;
348    case ACTION_CREATE:
349    case ACTION_OPEN:
350    case ACTION_READ:
351    case ACTION_WRITE:
352    case ACTION_CLOSE:
353      return false;
354  }
355  NOTREACHED();
356  return false;
357}
358
359bool FileIOTest::MatchesResult(const TestStep& a, const TestStep& b) {
360  DCHECK(IsResult(a) && IsResult(b));
361  if (a.type != b.type || a.status != b.status)
362    return false;
363
364  if (a.type != RESULT_READ || a.status != cdm::FileIOClient::kSuccess)
365    return true;
366
367  return (a.data_size == a.data_size &&
368          std::equal(a.data, a.data + a.data_size, b.data));
369}
370
371void FileIOTest::RunNextStep() {
372  // Run all actions in the current action group.
373  while (!test_steps_.empty()) {
374    // Start to wait for test results when the next step is a test result.
375    if (IsResult(test_steps_.front()))
376      return;
377
378    TestStep test_step = test_steps_.front();
379    test_steps_.pop_front();
380
381    cdm::FileIO* file_io = file_io_stack_.empty()? NULL : file_io_stack_.top();
382
383    switch (test_step.type) {
384      case ACTION_CREATE:
385        file_io = create_file_io_cb_.Run(this);
386        if (!file_io) {
387          FILE_IO_DVLOG(3) << "Cannot create FileIO object.";
388          OnTestComplete(false);
389          return;
390        }
391        file_io_stack_.push(file_io);
392        break;
393      case ACTION_OPEN:
394        // Use test name as the test file name.
395        file_io->Open(test_name_.data(), test_name_.size());
396        break;
397      case ACTION_READ:
398        file_io->Read();
399        break;
400      case ACTION_WRITE:
401        file_io->Write(test_step.data, test_step.data_size);
402        break;
403      case ACTION_CLOSE:
404        file_io->Close();
405        file_io_stack_.pop();
406        break;
407      default:
408        NOTREACHED();
409    }
410  }
411
412  OnTestComplete(true);
413}
414
415void FileIOTest::OnResult(const TestStep& result) {
416  DCHECK(IsResult(result));
417  if (!CheckResult(result)) {
418    OnTestComplete(false);
419    return;
420  }
421
422  RunNextStep();
423}
424
425bool FileIOTest::CheckResult(const TestStep& result) {
426  if (test_steps_.empty() || !IsResult(test_steps_.front()))
427    return false;
428
429  // If there are multiple results expected, the order does not matter.
430  std::list<TestStep>::iterator iter = test_steps_.begin();
431  for (; iter != test_steps_.end(); ++iter) {
432    if (!IsResult(*iter))
433      return false;
434
435    if (!MatchesResult(*iter, result))
436      continue;
437
438    test_steps_.erase(iter);
439    return true;
440  }
441
442  return false;
443}
444
445void FileIOTest::OnTestComplete(bool success) {
446  while (!file_io_stack_.empty()) {
447    file_io_stack_.top()->Close();
448    file_io_stack_.pop();
449  }
450  FILE_IO_DVLOG(3) << test_name_ << (success ? " PASSED" : " FAILED");
451  base::ResetAndReturn(&completion_cb_).Run(success);
452}
453
454}  // namespace media
455