OLD | NEW |
---|---|
(Empty) | |
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/callback_helpers.h" | |
8 #include "base/logging.h" | |
9 #include "media/base/bind_to_loop.h" | |
10 | |
11 namespace media { | |
12 | |
13 #define FILE_IO_DVLOG(level) DVLOG(level) << "File IO Test: " | |
ddorwin
2013/12/16 18:16:52
I think you'll need to replace DVLOG and probably
xhwang
2013/12/16 23:04:29
This is in ClearKeyCdm code, where it's okay to us
| |
14 | |
15 const uint8_t kData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | |
16 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; | |
17 const int kDataSize = arraysize(kData); | |
18 | |
19 const uint8_t 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 }; | |
24 const int kBigDataSize = arraysize(kBigData); | |
25 | |
26 const int kLargeDataSize = 9 * 1024 + 7; // > kReadSize in cdm_file_io_impl.cc. | |
27 | |
28 // Macros to help add test cases/steps. | |
29 #define START_TEST_CASE(test_name) \ | |
30 do { \ | |
31 FileIOTest test_case(create_file_io_cb_, "FileIOTest." test_name); \ | |
32 CREATE_FILE_IO // Create FileIO for each test case. | |
33 | |
34 #define ADD_TEST_STEP(type, status, data, data_size) \ | |
35 test_case.AddTestStep(FileIOTest::type, cdm::FileIOClient::status, \ | |
ddorwin
2013/12/16 18:16:52
Does this really need to be a macro? Can you just
xhwang
2013/12/16 23:04:29
Using can only be used for class type. So I can't
| |
36 (data), (data_size)); | |
37 | |
38 #define END_TEST_CASE \ | |
39 tests_.push_back(test_case); \ | |
40 } while(0); | |
41 | |
42 #define CREATE_FILE_IO \ | |
ddorwin
2013/12/16 18:16:52
Could these all be functions? (If they were functi
xhwang
2013/12/16 23:04:29
To use function, I have to use real types. So the
| |
43 ADD_TEST_STEP(ACTION_CREATE, kSuccess, NULL, 0) | |
44 | |
45 #define OPEN_FILE \ | |
46 ADD_TEST_STEP(ACTION_OPEN, kSuccess, NULL, 0) | |
47 | |
48 #define EXPECT_FILE_OPENED(status) \ | |
49 ADD_TEST_STEP(RESULT_OPEN, status, NULL, 0) | |
50 | |
51 #define READ_FILE \ | |
52 ADD_TEST_STEP(ACTION_READ, kSuccess, NULL, 0) | |
53 | |
54 #define EXPECT_FILE_READ(status, data, data_size) \ | |
55 ADD_TEST_STEP(RESULT_READ, status, data, data_size) | |
56 | |
57 #define WRITE_FILE(data, data_size) \ | |
58 ADD_TEST_STEP(ACTION_WRITE, kSuccess, data, data_size) | |
59 | |
60 #define EXPECT_FILE_WRITTEN(status) \ | |
61 ADD_TEST_STEP(RESULT_WRITE, status, NULL, 0) | |
62 | |
63 #define CLOSE_FILE \ | |
64 ADD_TEST_STEP(ACTION_CLOSE, kSuccess, NULL, 0) | |
65 | |
66 // FileIOTestRunner implementation. | |
67 | |
68 FileIOTestRunner::FileIOTestRunner(const CreateFileIOCB& create_file_io_cb) | |
69 : create_file_io_cb_(create_file_io_cb), | |
70 num_tests_(0), | |
71 num_passed_tests_(0) { | |
72 // Generate |large_data_|. | |
73 large_data_.resize(kLargeDataSize); | |
74 for (size_t i = 0; i < kLargeDataSize; ++i) | |
75 large_data_[i] = i % kuint8max; | |
76 | |
77 AddTests(); | |
78 } | |
79 | |
80 FileIOTestRunner::~FileIOTestRunner() { | |
81 if (tests_.empty()) | |
82 return; | |
83 | |
84 DCHECK_LT(num_passed_tests_, num_tests_); | |
85 FILE_IO_DVLOG(1) << "Not Finished (probably due to timeout). " | |
ddorwin
2013/12/16 18:16:52
Does a timeout really get here vs. killing the pro
xhwang
2013/12/16 23:04:29
It doesn't crash the process. Instead, it tears do
| |
86 << num_passed_tests_ << " passed and " | |
87 << (num_tests_ - num_passed_tests_) << " failed in " | |
ddorwin
2013/12/16 18:16:52
failed or not run, right?
Do we need to do the mat
xhwang
2013/12/16 23:04:29
Done.
| |
88 << num_tests_ << " tests."; | |
89 } | |
90 | |
91 // Note: Consecutive expectations (EXPECT*) can happen in any order. | |
92 void 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_READ(kError, NULL, 0) | |
ddorwin
2013/12/16 18:16:52
This seems to contradict Note above - you will get
xhwang
2013/12/16 23:04:29
Done.
| |
107 EXPECT_FILE_OPENED(kSuccess) | |
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") | |
ddorwin
2013/12/16 18:16:52
Are empty and non-existent the same thing?
xhwang
2013/12/16 23:04:29
The result is the same since we specify PP_FILEOPE
ddorwin
2013/12/17 00:17:04
Okay, maybe we should note in the interface that o
| |
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 // TODO(xhwang): This test should fail. But pp::FileIO doesn't support locking | |
245 // of opened files. We need to either workaround this or fix pp::FileIO | |
246 // implementation. | |
247 START_TEST_CASE("ReopenFileInSeparateFileIO") | |
248 OPEN_FILE | |
249 EXPECT_FILE_OPENED(kSuccess) | |
250 WRITE_FILE(kData, kDataSize) | |
251 EXPECT_FILE_WRITTEN(kSuccess) | |
252 CREATE_FILE_IO // Create a second FileIO without closing the first one. | |
253 OPEN_FILE | |
254 EXPECT_FILE_OPENED(kSuccess) | |
255 READ_FILE | |
256 EXPECT_FILE_READ(kSuccess, kData, kDataSize) | |
257 WRITE_FILE(kBigData, kBigDataSize) | |
258 EXPECT_FILE_WRITTEN(kSuccess) | |
259 END_TEST_CASE | |
260 } | |
261 | |
262 void FileIOTestRunner::RunAllTests(const CompletionCB& completion_cb) { | |
263 completion_cb_ = BindToCurrentLoop(completion_cb); | |
264 num_tests_ = tests_.size(); | |
265 RunNextTest(); | |
266 } | |
267 | |
268 void FileIOTestRunner::RunNextTest() { | |
269 if (tests_.empty()) { | |
270 FILE_IO_DVLOG(1) << num_passed_tests_ << " passed and " | |
271 << (num_tests_ - num_passed_tests_) << " failed in " | |
272 << num_tests_ << " tests."; | |
273 bool success = (num_passed_tests_ == num_tests_); | |
274 base::ResetAndReturn(&completion_cb_).Run(success); | |
275 return; | |
276 } | |
277 | |
278 tests_.front().Run( | |
279 base::Bind(&FileIOTestRunner::OnTestComplete, base::Unretained(this))); | |
280 } | |
281 | |
282 void FileIOTestRunner::OnTestComplete(bool success) { | |
283 if (success) | |
284 num_passed_tests_++; | |
285 tests_.pop_front(); | |
286 RunNextTest(); | |
287 } | |
288 | |
289 // FileIOTest implementation. | |
290 | |
291 FileIOTest::FileIOTest(const CreateFileIOCB& create_file_io_cb, | |
292 const std::string& test_name) | |
293 : create_file_io_cb_(create_file_io_cb), | |
294 test_name_(test_name), | |
295 file_io_(NULL), | |
296 old_file_io_(NULL) {} | |
297 | |
298 FileIOTest::~FileIOTest() {} | |
299 | |
300 void FileIOTest::AddTestStep(StepType type, | |
301 Status status, | |
302 const uint8* data, | |
303 uint32 data_size) { | |
304 test_steps_.push_back(TestStep(type, status, data, data_size)); | |
305 } | |
306 | |
307 void FileIOTest::Run(const CompletionCB& completion_cb) { | |
308 FILE_IO_DVLOG(3) << "Run " << test_name_; | |
309 completion_cb_ = BindToCurrentLoop(completion_cb); | |
310 RunNextStep(); | |
311 } | |
312 | |
313 void FileIOTest::OnOpenComplete(Status status) { | |
314 OnResult(TestStep(RESULT_OPEN, status, NULL, 0)); | |
315 } | |
316 | |
317 void FileIOTest::OnReadComplete(Status status, | |
318 const uint8_t* data, | |
319 uint32_t data_size) { | |
320 OnResult(TestStep(RESULT_READ, status, data, data_size)); | |
321 } | |
322 | |
323 void FileIOTest::OnWriteComplete(Status status) { | |
324 OnResult(TestStep(RESULT_WRITE, status, NULL, 0)); | |
325 } | |
326 | |
327 bool FileIOTest::IsResult(const TestStep& test_step) { | |
328 return test_step.type == RESULT_OPEN || test_step.type == RESULT_READ || | |
ddorwin
2013/12/16 18:16:52
Use a switch statement instead? (Including all cas
xhwang
2013/12/16 23:04:29
Done.
| |
329 test_step.type == RESULT_WRITE; | |
330 } | |
331 | |
332 bool FileIOTest::MatchesResult(const TestStep& a, const TestStep& b) { | |
333 DCHECK(IsResult(a) && IsResult(b)); | |
334 if (a.type != b.type || a.status != b.status) | |
335 return false; | |
336 | |
337 if (a.type != RESULT_READ || a.status != cdm::FileIOClient::kSuccess) | |
338 return true; | |
339 | |
340 return (a.data_size == a.data_size && | |
341 std::equal(a.data, a.data + a.data_size, b.data)); | |
342 } | |
343 | |
344 void FileIOTest::RunNextStep() { | |
345 while (!test_steps_.empty()) { | |
346 if (IsResult(test_steps_.front())) | |
347 return; | |
ddorwin
2013/12/16 18:16:52
This being first seems to assume this was called f
xhwang
2013/12/16 23:04:29
Added comments.
| |
348 | |
349 TestStep test_step = test_steps_.front(); | |
350 test_steps_.pop_front(); | |
351 | |
352 switch (test_step.type) { | |
353 case ACTION_CREATE: | |
354 if (file_io_) { | |
355 if (old_file_io_) | |
ddorwin
2013/12/16 18:16:52
Please explain. Does this retire the oldest of 3 F
xhwang
2013/12/16 23:04:29
Done.
| |
356 old_file_io_->Close(); | |
357 old_file_io_ = file_io_; | |
358 } | |
359 file_io_ = create_file_io_cb_.Run(this); | |
360 if (!file_io_) { | |
361 FILE_IO_DVLOG(3) << "Cannot create FileIO object."; | |
362 OnTestComplete(false); | |
363 return; | |
364 } | |
365 break; | |
366 case ACTION_OPEN: | |
367 // Use test name as the test file name. | |
ddorwin
2013/12/16 18:16:52
It might be good to mention this in a higher-level
xhwang
2013/12/16 23:04:29
Done.
| |
368 file_io_->Open(test_name_.data(), test_name_.size()); | |
369 break; | |
370 case ACTION_READ: | |
371 file_io_->Read(); | |
372 break; | |
373 case ACTION_WRITE: | |
374 file_io_->Write(test_step.data, test_step.data_size); | |
375 break; | |
376 case ACTION_CLOSE: | |
377 file_io_->Close(); | |
378 file_io_ = NULL; | |
379 break; | |
380 default: | |
381 NOTREACHED(); | |
382 } | |
383 } | |
384 | |
385 OnTestComplete(true); | |
386 } | |
387 | |
388 void FileIOTest::OnResult(const TestStep& result) { | |
389 DCHECK(IsResult(result)); | |
390 if (!CheckResult(result)) { | |
391 OnTestComplete(false); | |
392 return; | |
393 } | |
394 | |
395 RunNextStep(); | |
396 } | |
397 | |
398 bool FileIOTest::CheckResult(const TestStep& result) { | |
399 if (test_steps_.empty() || !IsResult(test_steps_.front())) | |
400 return false; | |
401 | |
402 // If there are multiple results expected, the order does not matter. | |
403 std::list<TestStep>::iterator iter = test_steps_.begin(); | |
404 for (; iter != test_steps_.end(); ++iter) { | |
405 if (!IsResult(*iter)) | |
406 return false; | |
407 | |
408 if (!MatchesResult(*iter, result)) | |
409 continue; | |
410 | |
411 test_steps_.erase(iter); | |
412 return true; | |
413 } | |
414 | |
415 return false; | |
416 } | |
417 | |
418 void FileIOTest::OnTestComplete(bool success) { | |
419 FILE_IO_DVLOG(3) << test_name_ << (success ? " PASSED" : " FAILED"); | |
420 base::ResetAndReturn(&completion_cb_).Run(success); | |
421 if (old_file_io_) { | |
422 old_file_io_->Close(); | |
423 old_file_io_ = NULL; | |
424 } | |
425 if (file_io_) { | |
426 file_io_->Close(); | |
427 file_io_ = NULL; | |
428 } | |
429 } | |
430 | |
431 } // namespace media | |
OLD | NEW |