OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include <algorithm> | |
12 #include <map> | |
13 #include <tuple> | |
14 #include <vector> | |
15 | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 #include "webrtc/common_audio/swap_queue.h" | |
18 #include "webrtc/modules/interface/module_common_types.h" | |
19 #include "webrtc/system_wrappers/interface/event_wrapper.h" | |
20 #include "webrtc/system_wrappers/interface/sleep.h" | |
21 #include "webrtc/system_wrappers/interface/thread_wrapper.h" | |
22 | |
23 namespace webrtc { | |
24 | |
25 namespace { | |
26 | |
27 // Provides thread_safe random numbers. | |
kwiberg-webrtc
2015/10/14 14:10:16
The comment says nothing that the class name doesn
peah-webrtc
2015/10/15 07:35:00
Good point! I removed the comment.
peah-webrtc
2015/10/15 07:35:00
Done.
| |
28 class ThreadSafeRandomNumberGenerator { | |
29 public: | |
30 ThreadSafeRandomNumberGenerator() : ThreadSafeRandomNumberGenerator(42) {} | |
31 | |
32 explicit ThreadSafeRandomNumberGenerator(int seed) { srand(seed); } | |
33 | |
34 int operator()() { | |
35 rtc::CritScope cs(&crit_); | |
36 return rand(); | |
37 } | |
38 | |
39 private: | |
40 rtc::CriticalSection crit_; | |
41 }; | |
42 | |
43 // The type for a message. | |
44 class SwapQueueTestMessage { | |
45 public: | |
46 SwapQueueTestMessage() { | |
47 id_ = -1; | |
48 info_ = -1; | |
49 } | |
50 | |
51 SwapQueueTestMessage(const SwapQueueTestMessage& m) | |
52 : id_(m.id_), info_(m.info_) {} | |
53 | |
54 SwapQueueTestMessage(int id, int info) { | |
55 id_ = id; | |
56 info_ = info; | |
57 } | |
58 | |
59 bool Compare(const SwapQueueTestMessage& m) { | |
60 return ((id_ == m.id_) && (info_ == m.info_)); | |
61 } | |
62 | |
63 void swap(SwapQueueTestMessage& m) { | |
64 std::swap(id_, m.id_); | |
65 std::swap(info_, m.info_); | |
66 } | |
67 | |
68 private: | |
69 int id_; | |
70 int info_; | |
71 }; | |
72 | |
73 // Implements the tests for the sample queue. | |
74 class SwapQueueMessageTest | |
75 : public ::testing::TestWithParam<::testing::tuple<size_t, size_t>> { | |
76 public: | |
77 SwapQueueMessageTest() | |
78 : test_complete_(EventWrapper::Create()), | |
79 reader_thread_( | |
80 ThreadWrapper::CreateThread(CbReaderThread, this, "reader")), | |
81 writer_thread_( | |
82 ThreadWrapper::CreateThread(CbWriterThread, this, "writer")) {} | |
83 | |
84 // Run the test with a timeout. | |
85 EventTypeWrapper RunTest() { | |
86 StartThreads(); | |
87 return test_complete_->Wait(kTestTimeOutLimit); | |
88 } | |
89 | |
90 virtual void SetUp() { | |
91 // Read test parameter | |
92 size_t queue_size = static_cast<size_t>(testing::get<0>(GetParam())); | |
93 size_t messages_size = static_cast<size_t>(testing::get<1>(GetParam())); | |
94 | |
95 // Create queues. | |
96 queue_.reset(new SwapQueue<SwapQueueTestMessage>(queue_size)); | |
97 | |
98 // Create and populate message vector. | |
99 messages_ = std::vector<SwapQueueTestMessage>(); | |
100 CreateTestData(messages_size); | |
101 } | |
102 | |
103 virtual void TearDown() { | |
104 reader_thread_->Stop(); | |
105 writer_thread_->Stop(); | |
106 } | |
107 | |
108 private: | |
109 const int kTestTimeOutLimit = 10 * 1000; | |
110 | |
111 // Populates the data vectors with random values. | |
112 void CreateTestData(int messages_size) { | |
113 messages_.resize(messages_size); | |
114 for (size_t k = 0; k < messages_.size(); k++) | |
115 messages_[k] = SwapQueueTestMessage(random_generator_() % 10000, | |
116 random_generator_() % 10000); | |
117 } | |
118 | |
119 // Thread callback for the reader thread. | |
120 static bool CbReaderThread(void* context) { | |
121 return reinterpret_cast<SwapQueueMessageTest*>(context)->CbReaderImpl(); | |
122 } | |
123 | |
124 // Thread callback for the writer thread. | |
125 static bool CbWriterThread(void* context) { | |
126 return reinterpret_cast<SwapQueueMessageTest*>(context)->CbWriterImpl(); | |
127 } | |
128 | |
129 // Tests in a threadsafe manner whether all the samples have been | |
130 // written and read. | |
131 bool TestDone() { return (GetNumMessagesRead() == messages_.size()); } | |
132 | |
133 // Returns in a threadsafe manner the number of frames read from the queue. | |
134 size_t GetNumMessagesRead() const { | |
135 rtc::CritScope cs(&crit_); | |
136 return num_messages_read_; | |
137 } | |
138 | |
139 // Increases in a threadsafe manner the number of messages | |
140 // read from the queue. | |
141 void IncreaseMessageReadCounter() { | |
142 rtc::CritScope cs(&crit_); | |
143 num_messages_read_++; | |
144 } | |
145 | |
146 // Implements the callback functionality for the reader thread. | |
147 bool CbReaderImpl() { | |
148 SleepRandomTime(3); | |
149 | |
150 // Read the message and verify bitexactness. | |
151 SwapQueueTestMessage m; | |
152 if (queue_->Remove(&m)) { | |
153 EXPECT_TRUE(m.Compare(messages_[GetNumMessagesRead()])); | |
154 IncreaseMessageReadCounter(); | |
155 } | |
156 | |
157 // End the test if the test is done or an assert has occurred. | |
158 if (TestDone() || HasFatalFailure()) { | |
159 test_complete_->Set(); | |
160 } | |
161 | |
162 return true; | |
163 } | |
164 | |
165 // Implements the callback functionality for the writer thread. | |
166 bool CbWriterImpl() { | |
167 SleepRandomTime(3); | |
168 | |
169 if (num_messages_written_ < messages_.size()) { | |
170 // Attempt to put the message in the queue. | |
171 SwapQueueTestMessage m(messages_[num_messages_written_]); | |
172 if (queue_->Insert(&m)) | |
173 num_messages_written_++; | |
174 } | |
175 | |
176 // End the test early if a fatal failure (ASSERT_*) has occurred. | |
177 if (HasFatalFailure()) | |
178 test_complete_->Set(); | |
179 | |
180 return true; | |
181 } | |
182 | |
183 // Sleeps a random time. | |
184 void SleepRandomTime(int max_sleep) { | |
185 SleepMs(random_generator_() % (max_sleep + 1)); | |
186 } | |
187 | |
188 // Start the threads used in the test. | |
189 void StartThreads() { | |
190 ASSERT_TRUE(reader_thread_->Start()); | |
191 reader_thread_->SetPriority(kRealtimePriority); | |
192 ASSERT_TRUE(writer_thread_->Start()); | |
193 writer_thread_->SetPriority(kRealtimePriority); | |
194 } | |
195 | |
196 // Test parameters. | |
197 rtc::scoped_ptr<SwapQueue<SwapQueueTestMessage>> queue_; | |
198 mutable rtc::CriticalSection crit_; | |
199 ThreadSafeRandomNumberGenerator random_generator_; | |
200 const rtc::scoped_ptr<EventWrapper> test_complete_; | |
201 rtc::scoped_ptr<ThreadWrapper> reader_thread_; | |
202 rtc::scoped_ptr<ThreadWrapper> writer_thread_; | |
203 std::vector<SwapQueueTestMessage> messages_; | |
204 size_t num_messages_written_ = 0; | |
205 size_t num_messages_read_ GUARDED_BY(crit_) = 0; | |
206 }; | |
207 | |
208 // Implements the tests sample queue. | |
209 class SwapQueueSampleTest : public ::testing::TestWithParam< | |
210 ::testing::tuple<size_t, size_t, size_t>> { | |
211 public: | |
212 SwapQueueSampleTest() | |
213 : queue_size_(static_cast<size_t>(testing::get<0>(GetParam()))), | |
214 max_frame_length_(static_cast<size_t>(testing::get<1>(GetParam()))), | |
215 data_length_(static_cast<size_t>(testing::get<2>(GetParam()))), | |
216 test_complete_(EventWrapper::Create()), | |
217 reader_thread_( | |
218 ThreadWrapper::CreateThread(CbReaderThread, this, "reader")), | |
219 writer_thread_( | |
220 ThreadWrapper::CreateThread(CbWriterThread, this, "writer")) {} | |
221 | |
222 // Run the test with a timeout. | |
223 EventTypeWrapper RunTest() { | |
224 StartThreads(); | |
225 return test_complete_->Wait(kTestTimeOutLimit); | |
226 } | |
227 | |
228 virtual void SetUp() { | |
229 // Allocate read and write buffers. | |
230 buffer_reader_ = std::vector<int16_t>(max_frame_length_, 0); | |
231 buffer_writer_ = std::vector<int16_t>(max_frame_length_, 0); | |
232 | |
233 // Create queue. | |
234 std::vector<int16_t> template_queue_element(buffer_reader_.size()); | |
235 sample_queue_.reset(new SwapQueue<std::vector<int16_t>>( | |
236 queue_size_, template_queue_element)); | |
237 | |
238 // Create and populate data vectors. | |
239 CreateTestData(data_length_); | |
240 } | |
241 | |
242 virtual void TearDown() { | |
243 reader_thread_->Stop(); | |
244 writer_thread_->Stop(); | |
245 } | |
246 | |
247 private: | |
248 const int kTestTimeOutLimit = 10 * 1000; | |
249 | |
250 // Populates the data vectors with random values. | |
251 void CreateTestData(size_t data_length) { | |
252 samples_.resize(data_length); | |
253 for (size_t k = 0; k < data_length; k++) { | |
254 samples_[k] = ((random_generator_() % (32767 + 32768)) - 32768); | |
255 } | |
256 } | |
257 | |
258 // Thread callback for the reader thread. | |
259 static bool CbReaderThread(void* context) { | |
260 return reinterpret_cast<SwapQueueSampleTest*>(context)->CbReaderImpl(); | |
261 } | |
262 | |
263 // Thread callback for the writer thread. | |
264 static bool CbWriterThread(void* context) { | |
265 return reinterpret_cast<SwapQueueSampleTest*>(context)->CbWriterImpl(); | |
266 } | |
267 | |
268 // Tests in a threadsafe manner whether all the samples have been | |
269 // written and read. | |
270 bool TestDone() { return (GetNumSamplesRead() == data_length_); } | |
271 | |
272 // Returns in a threadsafe manner the number of frames read from the queue. | |
273 size_t GetNumFramesRead() { | |
274 rtc::CritScope cs(&crit_); | |
275 return num_frames_read_; | |
276 } | |
277 | |
278 // Returns in a threadsafe manner the number of samples read from the queue. | |
279 size_t GetNumSamplesRead() { | |
280 rtc::CritScope cs(&crit_); | |
281 return num_samples_read_; | |
282 } | |
283 | |
284 // Increases in a threadsafe manner the number of frames and samples | |
285 // read from the queue. | |
286 void IncreaseReadCounters(size_t num_samples_read) { | |
287 rtc::CritScope cs(&crit_); | |
288 num_frames_read_++; | |
289 num_samples_read_ += num_samples_read; | |
290 } | |
291 | |
292 // Implements the callback functionality for the reader thread. | |
293 bool CbReaderImpl() { | |
294 SleepRandomTime(3); | |
295 | |
296 // Read the samples and verify bitexactness. | |
297 const size_t num_samples_read = GetNumSamplesRead(); | |
298 if (sample_queue_->Remove(&buffer_reader_)) { | |
299 for (size_t k = 0; k < buffer_reader_.size(); k++) | |
300 EXPECT_EQ(buffer_reader_[k], samples_[num_samples_read + k]); | |
301 | |
302 IncreaseReadCounters(buffer_reader_.size()); | |
303 } | |
304 | |
305 // End the test if the test is done or an assert has occurred. | |
306 if (TestDone() || HasFatalFailure()) { | |
307 test_complete_->Set(); | |
308 } | |
309 | |
310 return true; | |
311 } | |
312 | |
313 // Implements the callback functionality for the writer thread. | |
314 bool CbWriterImpl() { | |
315 SleepRandomTime(3); | |
316 | |
317 // Choose number of samples to write. | |
318 const size_t num_samples_to_write = | |
319 std::min(random_generator_() % max_frame_length_, | |
320 data_length_ - num_samples_written_); | |
321 | |
322 // Write the data. | |
323 bool data_written = false; | |
324 if (num_samples_to_write > 0) { | |
325 if (buffer_writer_.size() != num_samples_to_write) | |
326 buffer_writer_.resize(num_samples_to_write); | |
327 | |
328 memcpy(&buffer_writer_[0], &samples_[num_samples_written_], | |
329 num_samples_to_write * sizeof(samples_[0])); | |
330 | |
331 data_written = sample_queue_->Insert(&buffer_writer_); | |
332 } | |
333 | |
334 // Update the number of samples left to write | |
335 if (data_written) { | |
336 num_samples_written_ += num_samples_to_write; | |
337 num_frames_written_++; | |
338 } | |
339 | |
340 // End the test early if a fatal failure (ASSERT_*) has occurred. | |
341 if (HasFatalFailure()) | |
342 test_complete_->Set(); | |
343 | |
344 return true; | |
345 } | |
346 | |
347 // Sleeps a random time. | |
348 void SleepRandomTime(int max_sleep) { | |
349 SleepMs(random_generator_() % (max_sleep + 1)); | |
350 } | |
351 | |
352 // Start the threads used in the test. | |
353 void StartThreads() { | |
354 ASSERT_TRUE(reader_thread_->Start()); | |
355 reader_thread_->SetPriority(kRealtimePriority); | |
356 ASSERT_TRUE(writer_thread_->Start()); | |
357 writer_thread_->SetPriority(kRealtimePriority); | |
358 } | |
359 | |
360 // Test parameters. | |
361 const size_t queue_size_; | |
362 const size_t max_frame_length_; | |
363 const size_t data_length_; | |
364 | |
365 rtc::scoped_ptr<SwapQueue<std::vector<int16_t>>> sample_queue_; | |
366 rtc::CriticalSection crit_; | |
367 ThreadSafeRandomNumberGenerator random_generator_; | |
368 const rtc::scoped_ptr<EventWrapper> test_complete_; | |
369 rtc::scoped_ptr<ThreadWrapper> reader_thread_; | |
370 rtc::scoped_ptr<ThreadWrapper> writer_thread_; | |
371 std::vector<int16_t> samples_; | |
372 size_t num_samples_read_ GUARDED_BY(crit_) = 0; | |
373 size_t num_samples_written_ = 0; | |
374 std::vector<int16_t> buffer_reader_; | |
375 std::vector<int16_t> buffer_writer_; | |
376 size_t num_frames_written_ = 0; | |
377 size_t num_frames_read_ GUARDED_BY(crit_) = 0; | |
378 }; | |
379 | |
380 // Test parameter for the basic sample based SwapQueue Tests. | |
381 const size_t kChunkSize = 3; | |
382 | |
383 // Test parameters for the message queue tests. | |
384 const size_t kMessageQueueSizes[] = {2, 7, 20}; | |
385 const size_t kMessageQueueDataLengths[] = {100}; | |
386 | |
387 // Test parameters for the sample queue tests. | |
388 const size_t kSampleQueueSizes[] = {7, 100}; | |
389 const size_t kMaxFrameLengths[] = {77, 160}; | |
390 const size_t kSampleQueueDataLengths[] = {200, 500}; | |
391 | |
392 // Item invariance check function for the InvarianceVerification | |
393 // test. | |
394 bool InvarianceVerifier(const std::vector<int>& v) { | |
395 RTC_CHECK(v.size() == kChunkSize); | |
396 return true; | |
397 } | |
398 | |
399 } // anonymous namespace | |
400 | |
401 TEST(SwapQueueTest, SuccessfulInvarianceVerification) { | |
402 std::vector<int> template_element(kChunkSize); | |
403 SwapQueue<std::vector<int>, &InvarianceVerifier> queue(2, template_element); | |
404 std::vector<int> valid_chunk(kChunkSize, 0); | |
405 | |
406 EXPECT_TRUE(queue.Insert(&valid_chunk)); | |
407 EXPECT_EQ(valid_chunk.size(), kChunkSize); | |
408 EXPECT_TRUE(queue.Remove(&valid_chunk)); | |
409 EXPECT_EQ(valid_chunk.size(), kChunkSize); | |
410 } | |
411 | |
412 #if defined(GTEST_HAS_DEATH_TEST) | |
413 TEST(SwapQueueTest, UnSuccessfulInvarianceVerification1) { | |
414 std::vector<int> template_element(kChunkSize); | |
415 SwapQueue<std::vector<int>, &InvarianceVerifier> queue(2, template_element); | |
416 std::vector<int> invalid_chunk(kChunkSize - 1, 0); | |
417 EXPECT_DEATH(queue.Insert(&invalid_chunk), ""); | |
418 EXPECT_DEATH(queue.Insert(&invalid_chunk), ""); | |
kwiberg-webrtc
2015/10/14 14:10:16
Unless your employee ID is 007, you don't get to l
peah-webrtc
2015/10/15 07:35:00
:-)
peah-webrtc
2015/10/15 07:35:00
Done.
| |
419 } | |
420 | |
421 TEST(SwapQueueTest, UnSuccessfulInvarianceVerification2) { | |
422 std::vector<int> template_element(kChunkSize); | |
423 SwapQueue<std::vector<int>, &InvarianceVerifier> queue(2, template_element); | |
424 std::vector<int> invalid_chunk(kChunkSize - 1, 0); | |
425 std::vector<int> valid_chunk(kChunkSize, 0); | |
426 | |
427 EXPECT_TRUE(queue.Insert(&valid_chunk)); | |
428 EXPECT_EQ(valid_chunk.size(), kChunkSize); | |
429 EXPECT_DEATH(queue.Remove(&invalid_chunk), ""); | |
430 } | |
431 #endif | |
432 | |
433 TEST(SwapQueueTest, FullQueue) { | |
434 SwapQueue<int> queue(2); | |
435 int i = 0; | |
436 EXPECT_TRUE(queue.Insert(&i)); | |
437 EXPECT_TRUE(queue.Insert(&i)); | |
438 EXPECT_FALSE(queue.Insert(&i)); | |
439 EXPECT_TRUE(queue.Remove(&i)); | |
440 EXPECT_TRUE(queue.Insert(&i)); | |
441 EXPECT_FALSE(queue.Insert(&i)); | |
442 } | |
443 | |
444 TEST(SwapQueueTest, EmptyQueue) { | |
445 SwapQueue<int> queue(2); | |
446 int i = 0; | |
447 EXPECT_FALSE(queue.Remove(&i)); | |
448 EXPECT_TRUE(queue.Insert(&i)); | |
449 EXPECT_TRUE(queue.Remove(&i)); | |
450 EXPECT_FALSE(queue.Remove(&i)); | |
451 } | |
452 | |
453 TEST(SwapQueueTest, InitializeTest) { | |
454 std::vector<int> i(kChunkSize, 0); | |
455 SwapQueue<std::vector<int>> queue(2, i); | |
456 | |
457 EXPECT_TRUE(queue.Insert(&i)); | |
458 EXPECT_EQ(i.size(), kChunkSize); | |
459 EXPECT_TRUE(queue.Insert(&i)); | |
460 EXPECT_EQ(i.size(), kChunkSize); | |
461 EXPECT_TRUE(queue.Remove(&i)); | |
462 EXPECT_EQ(i.size(), kChunkSize); | |
463 EXPECT_TRUE(queue.Remove(&i)); | |
464 EXPECT_EQ(i.size(), kChunkSize); | |
465 } | |
466 | |
467 TEST_P(SwapQueueSampleTest, BitExactness) { | |
468 // Run test and verify that it did not time out. | |
469 EXPECT_EQ(kEventSignaled, RunTest()); | |
470 } | |
471 | |
472 TEST_P(SwapQueueMessageTest, BitExactness) { | |
473 // Run test and verify that it did not time out. | |
474 EXPECT_EQ(kEventSignaled, RunTest()); | |
475 } | |
476 | |
477 INSTANTIATE_TEST_CASE_P( | |
478 SwapQueueMessageTestAllCombinations, | |
479 SwapQueueMessageTest, | |
480 testing::Combine(::testing::ValuesIn(kMessageQueueSizes), | |
481 ::testing::ValuesIn(kMessageQueueDataLengths))); | |
482 | |
483 INSTANTIATE_TEST_CASE_P( | |
484 SwapQueueSampleTestAllCombinations, | |
485 SwapQueueSampleTest, | |
486 testing::Combine(::testing::ValuesIn(kSampleQueueSizes), | |
487 ::testing::ValuesIn(kMaxFrameLengths), | |
488 ::testing::ValuesIn(kSampleQueueDataLengths))); | |
489 | |
490 } // namespace webrtc | |
OLD | NEW |