void GraphInvalidator:: test() { // It should invalidate caches and wakeup workers { // create Dag::ptr dag(new Dag); Bedroom::ptr bedroom(new Bedroom); INotifier::ptr notifier(new BedroomNotifier(bedroom)); Step::ptr step(new Step(Signal::OperationDesc::ptr())); WaitForWakeupMock sleeper(bedroom); // wire up sleeper.start (); dag.write ()->appendStep(step); Signal::Intervals initial_valid(-20,60); int taskid = Step::registerTask(step.write (), initial_valid.spannedInterval ()); (void)taskid; // discard EXCEPTION_ASSERT_EQUALS(step.read ()->not_started(), ~initial_valid); EXCEPTION_ASSERT(sleeper.isRunning ()); EXCEPTION_ASSERT_EQUALS(sleeper.wait (1), false); EXCEPTION_ASSERT_EQUALS(bedroom->sleepers (), 1); // test GraphInvalidator graphInvalidator(dag, notifier, step); Signal::Intervals deprecated(40,50); graphInvalidator.deprecateCache (deprecated); EXCEPTION_ASSERT_EQUALS(step.read ()->not_started(), ~initial_valid | deprecated); sleeper.wait (1); EXCEPTION_ASSERT_EQUALS(bedroom->sleepers (), 0); EXCEPTION_ASSERT(sleeper.isFinished ()); } }
void RenderOperationDesc:: test() { // The RenderOperationDesc class should keep the filter operation used by a // render target and notify the render target about processing events. { RenderOperationDesc* rod; RenderOperationDescMockTarget* target; OperationDesc::ptr operation( new Test::TransparentOperationDesc() ); RenderTarget::ptr rtp(target = new RenderOperationDescMockTarget()); Signal::OperationDesc::ptr ro(rod = new RenderOperationDesc(operation, rtp)); Signal::Operation::ptr o = ro.write ()->createOperation(0); // Operations are processed through a Processing::Step Processing::Step step(ro); step.deprecateCache (Interval(4,9)); o->process (pBuffer()); EXCEPTION_ASSERT_EQUALS( Interval(4,9), target->I ); EXCEPTION_ASSERT_EQUALS( 1, target->processed_count ); EXCEPTION_ASSERT_EQUALS( (void*)0, rod->transform_desc ().get () ); } }
void BufferSource:: test() { pBuffer b(new Buffer(Interval(60,70), 40, 7)); for (int c=0; c<b->number_of_channels (); ++c) { float *p = b->getChannel (c)->waveform_data ()->getCpuMemory (); for (int i=0; i<b->number_of_samples (); ++i) p[i] = c + i/(float)b->number_of_samples (); } BufferSource s(b); Operation::ptr o = s.createOperation (0); Operation::test (o, &s); pBuffer r(new Buffer(Interval(60,70), 40, 7)); pBuffer d = o->process (r); EXCEPTION_ASSERT( *d == *b ); r = pBuffer(new Buffer(Interval(61,71), 1, 1)); d = o->process (r); EXCEPTION_ASSERT_EQUALS (b->number_of_channels (), d->number_of_channels ()); EXCEPTION_ASSERT_EQUALS (b->number_of_samples (), d->number_of_samples ()); EXCEPTION_ASSERT_EQUALS (r->getInterval (), d->getInterval ()); for (int c=0; c<b->number_of_channels (); ++c) { float *bp = b->getChannel (c)->waveform_data ()->getCpuMemory (); float *dp = d->getChannel (c)->waveform_data ()->getCpuMemory (); for (int i=0; i<b->number_of_samples ()-1; ++i) EXCEPTION_ASSERT_EQUALS (bp[1+i], dp[i]); EXCEPTION_ASSERT_EQUALS (dp[9], 0); } }
void QtEventWorkerFactory:: test() { std::string name = "QtEventWorkers"; int argc = 1; char * argv = &name[0]; QApplication a(argc,&argv); // takes 0.4 s if this is the first instantiation of QApplication Workers::test ([](ISchedule::ptr schedule){ Bedroom::ptr bedroom(new Bedroom); return IWorkerFactory::ptr(new QtEventWorkerFactory(schedule, bedroom)); }); { UNITTEST_STEPS TaskInfo("It should terminate all threads when it's closed"); ISchedule::ptr schedule[] = { ISchedule::ptr(new SleepScheduleMock), ISchedule::ptr(new LockScheduleMock), ISchedule::ptr(new BusyScheduleMock) }; for (unsigned i=0; i<sizeof(schedule)/sizeof(schedule[0]); i++) { Timer t; { ISchedule::ptr s = schedule[i]; //TaskInfo ti(boost::format("%s") % vartype(*s)); Bedroom::ptr bedroom(new Bedroom); Processing::Workers workers(IWorkerFactory::ptr(new QtEventWorkerFactory(s, bedroom))); Bedroom::Bed bed = dynamic_cast<BlockScheduleMock*>(s.get ())->bedroom.getBed(); workers.addComputingEngine(Signal::ComputingEngine::ptr()); // Wait until the schedule has been called (Bedroom supports // that the wakeup in schedule is called even before this sleep call // as long as 'bed' is allocated before the wakeup call) bed.sleep (); EXCEPTION_ASSERT_EQUALS(false, workers.remove_all_engines (10)); EXCEPTION_ASSERT_EQUALS(true, QtEventWorkerFactory::terminate_workers (workers, 0)); EXCEPTION_ASSERT_EQUALS(workers.n_workers(), 0u); EXPECT_EXCEPTION(QtEventWorker::TerminatedException, workers.rethrow_any_worker_exception ()); workers.clean_dead_workers (); } float elapsed = t.elapsed (); float n = (i+1)*0.00001; EXCEPTION_ASSERT_LESS(0.01+n, elapsed); EXCEPTION_ASSERT_LESS(elapsed, 0.04+n); // +n makes it possible to see in the test log which iteration that failed } } // It should wake up sleeping workers when any work is done to see if they can // help out on what's left. { } }
void Step:: test() { // It should keep a cache for a signal processing step (defined by an OpertionDesc). // // The cache description should contain information about what's out_of_date // and what's currently being updated. { // Create an OperationDesc pBuffer b(new Buffer(Interval(60,70), 40, 7)); for (unsigned c=0; c<b->number_of_channels (); ++c) { float *p = b->getChannel (c)->waveform_data ()->getCpuMemory (); for (int i=0; i<b->number_of_samples (); ++i) p[i] = c + 1+i/(float)b->number_of_samples (); } // Create a Step Step::ptr s2( new Step(OperationDesc::ptr())); shared_state<Step>::weak_ptr ws = s2; Step::ptr s = ws.lock (); // It should contain information about what's out_of_date and what's currently being updated. int taskid = s->registerTask(b->getInterval ()); EXCEPTION_ASSERT_EQUALS(s->not_started (), ~Intervals(b->getInterval ())); EXCEPTION_ASSERT_EQUALS(s->out_of_date(), Intervals::Intervals_ALL); Step::finishTask(s, taskid, b); EXCEPTION_ASSERT_EQUALS(s->out_of_date(), ~Intervals(b->getInterval ())); EXCEPTION_ASSERT( *b == *Step::readFixedLengthFromCache (s, b->getInterval ()) ); } // A crashed signal processing step should behave as a transparent operation. { OperationDesc::ptr silence(new Signal::OperationSetSilent(Signal::Interval(2,3))); Step s(silence); EXCEPTION_ASSERT(!s.get_crashed ()); EXCEPTION_ASSERT(s.operation_desc ()); EXCEPTION_ASSERT(s.operation_desc ().read ()->createOperation (0)); EXCEPTION_ASSERT(!dynamic_cast<Test::TransparentOperationDesc*>(s.operation_desc ().raw ())); EXCEPTION_ASSERT(!dynamic_cast<Test::TransparentOperation*>(s.operation_desc ().read ()->createOperation (0).get ())); s.mark_as_crashed_and_get_invalidator (); EXCEPTION_ASSERT(s.get_crashed ()); EXCEPTION_ASSERT(s.operation_desc ()); EXCEPTION_ASSERT(s.operation_desc ().read ()->createOperation (0)); EXCEPTION_ASSERT(dynamic_cast<Test::TransparentOperationDesc*>(s.operation_desc ().raw ())); EXCEPTION_ASSERT(dynamic_cast<Test::TransparentOperation*>(s.operation_desc ().read ()->createOperation (0).get ())); } }
void PrintBuffer:: test() { // It should print buffer contents for debugging purposes. { Signal::pBuffer b = RandomBuffer::smallBuffer(); std::string s = PrintBuffer::printBuffer(b); std::string expected = "[4, 9)5#, 2 channels\n[0] = { -3, 7, -8, 5, 3 }\n[1] = { 1, -9, -3, 6, -2 }\n"; EXCEPTION_ASSERT_EQUALS(s, expected); std::string stats = PrintBuffer::printBufferStats(b); expected = "[4, 9)5#, 2 channels\n[0]: max = 7, min = -8, mean = 0.8, std = 5.52811\n[1]: max = 6, min = -9, mean = -1.4, std = 4.92341\n"; EXCEPTION_ASSERT_EQUALS(stats, expected); } }
void BlockCache:: test() { // It should store allocated blocks readily available { Reference r1; Reference r2 = r1.right (); BlockLayout bl(2,2,1); VisualizationParams::ptr vp; pBlock b1(new Block(r1, bl, vp)); pBlock b2(new Block(r2, bl, vp)); BlockCache c; c.insert (b1); c.insert (b2); pBlock b3 = c.find(r1); pBlock b4 = c.find(r2); pBlock b5 = c.find (r2.parentHorizontal ()); pBlock b6 = c.find (r1.left ()); EXCEPTION_ASSERT( b1 == b3 ); EXCEPTION_ASSERT( b2 == b4 ); EXCEPTION_ASSERT( r2 == r1.right () ); EXCEPTION_ASSERT_EQUALS( r2.parentHorizontal (), r1 ); EXCEPTION_ASSERT( b1 == b5 ); EXCEPTION_ASSERT( b6 == pBlock() ); } }
void Step:: finishTask(Step::ptr step, int taskid, pBuffer result) { Interval result_interval; if (result) result_interval = result->getInterval (); TASKINFO TaskInfo ti(format("Step::finishTask %2% on %1%") % step.raw ()->operation_name() % result_interval); if (result) { // Result must have the same number of channels and sample rate as previous cache. // Call deprecateCache(Interval::Interval_ALL) to erase the cache when chainging number of channels or sample rate. step.raw ()->cache_->put (result); } auto self = step.write (); int matched_task = self->running_tasks.count (taskid); if (1 != matched_task) { Log("C = %d, taskid = %x on %s") % matched_task % taskid % self->operation_name (); EXCEPTION_ASSERT_EQUALS( 1, matched_task ); } Intervals expected_output = self->running_tasks[ taskid ]; Intervals update_miss = expected_output - result_interval; self->not_started_ |= update_miss; if (!result) { TASKINFO TaskInfo(format("The task was cancelled. Restoring %1% for %2%") % update_miss % self->operation_name()); } else { if (update_miss) { TaskInfo(format("These samples were supposed to be updated by the task but missed: %1% by %2%") % update_miss % self->operation_name()); } if (result_interval - expected_output) { // These samples were not supposed to be updated by the task but were calculated anyway TaskInfo(format("Unexpected extras: %1% = (%2%) - (%3%) from %4%") % (result_interval - expected_output) % result_interval % expected_output % self->operation_name()); // The samples are still marked as invalid. Would need to remove the // extra calculated samples from not_started_ but that would fail // in a situation where deprecatedCache is called after the task has // been created. So not_started_ can't be modified here (unless calls // to deprecatedCache were tracked). } } self->running_tasks.erase ( taskid ); self.unlock (); step.raw ()->wait_for_tasks_.notify_all (); }
void DataStorageString:: test() { // It should print contents of a DataStorage for debugging purposes. { float srcdata[] = { 1, 2, 3, 4 }; DataStorage<float>::ptr data; { data = CpuMemoryStorage::BorrowPtr( DataStorageSize(2,2), srcdata, false ); std::string s = DataStorageString::printDataStorage (data); std::string expected = "[2, 2]\n[y:0] = { 1, 2 }\n[y:1] = { 3, 4 }"; EXCEPTION_ASSERT_EQUALS(s, expected); std::string stats = DataStorageString::printDataStorageStats (data); expected = "size = [2, 2], min = 1, max = 4, mean = 2.5, std = 1.11803"; EXCEPTION_ASSERT_EQUALS(stats, expected); } { data = CpuMemoryStorage::BorrowPtr( DataStorageSize(3), srcdata, false ); std::string s = DataStorageString::printDataStorage (data); std::string expected = "[3] = { 1, 2, 3 }"; EXCEPTION_ASSERT_EQUALS(s, expected); std::string stats = DataStorageString::printDataStorageStats (data); expected = "size = [3], min = 1, max = 3, mean = 2, std = 0.816497"; EXCEPTION_ASSERT_EQUALS(stats, expected); } { data = CpuMemoryStorage::BorrowPtr( DataStorageSize(2,1,2), srcdata, false ); std::string s = DataStorageString::printDataStorage (data); std::string expected = "[2, 1, 2]\n[z:0, y:0] = { 1, 2 }\n[z:1, y:0] = { 3, 4 }"; EXCEPTION_ASSERT_EQUALS(s, expected); std::string stats = DataStorageString::printDataStorageStats (data); expected = "size = [2, 1, 2], min = 1, max = 4, mean = 2.5, std = 1.11803"; EXCEPTION_ASSERT_EQUALS(stats, expected); } { data = CpuMemoryStorage::BorrowPtr( DataStorageSize(1,2,2), srcdata, false ); std::string s = DataStorageString::printDataStorage (data); std::string expected = "[1, 2, 2]\n[z:0, y:0] = { 1 }\n[z:0, y:1] = { 2 }\n[z:1, y:0] = { 3 }\n[z:1, y:1] = { 4 }"; EXCEPTION_ASSERT_EQUALS(s, expected); std::string stats = DataStorageString::printDataStorageStats (data); expected = "size = [1, 2, 2], min = 1, max = 4, mean = 2.5, std = 1.11803"; EXCEPTION_ASSERT_EQUALS(stats, expected); } } }
GlTexture::GlTexture(unsigned int textureId) : width( 0 ), height( 0 ), textureId( textureId ), ownTextureId( 0 ) { EXCEPTION_ASSERT_LESS(0u, textureId); int width=0, height=0; glBindTexture (GL_TEXTURE_2D, textureId); GlException_SAFE_CALL( glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width) ); GlException_SAFE_CALL( glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height) ); glBindTexture (GL_TEXTURE_2D, 0); this->width = width; this->height = height; EXCEPTION_ASSERT_LESS(0, width); EXCEPTION_ASSERT_LESS(0, height); EXCEPTION_ASSERT_EQUALS(this->width, width); EXCEPTION_ASSERT_EQUALS(this->height, height); }
pBuffer SourceBase:: readChecked( const Interval& I ) { TIME_SOURCEBASE TaskTimer tt("%s::readChecked( %s )", vartype(*this).c_str(), I.toString().c_str()); EXCEPTION_ASSERT( I.count() ); pBuffer r = read(I); // Check if read returned the first sample in interval I Interval i(I.first, I.first + 1); if ((i & r->getInterval()) != i) { TaskTimer tt("%s::readChecked( %s ) got %s", vartype(*this).c_str(), I.toString().c_str(), r->getInterval ().toString ().c_str ()); EXCEPTION_ASSERT_EQUALS( i & r->getInterval(), i ); } return r; }
void DummyTransform:: test () { // It should transform a buffer into a dummy state and back. for (int i=0; i<2; i++) { TRACE_PERF(i==0 ? "It should init dummytransform" : "It should transform a buffer into a dummy state and back"); DummyTransform t; Signal::pBuffer b = Test::RandomBuffer::smallBuffer((int)hash<string>()("DummyTransform")); pChunk c = t(b->getChannel (0)); EXCEPTION_ASSERT(c); Signal::pMonoBuffer b2 = t.inverse (c); EXCEPTION_ASSERT(b->getChannel (0) == b2); EXCEPTION_ASSERT_EQUALS(c->getCoveredInterval (), b->getInterval ()); } }
void WaveformBlockFilterDesc:: test() { // It should instantiate CwtBlockFilter for different engines. { Heightmap::MergeChunkDesc::ptr mcd(new WaveformBlockFilterDesc); MergeChunk::ptr mc = mcd.read ()->createMergeChunk (0); EXCEPTION_ASSERT( !mc ); Signal::ComputingCpu cpu; mc = mcd.read ()->createMergeChunk (&cpu); EXCEPTION_ASSERT( mc ); EXCEPTION_ASSERT_EQUALS( vartype(*mc.get ()), "Heightmap::TfrMappings::WaveformBlockFilter" ); Signal::ComputingCuda cuda; mc = mcd.read ()->createMergeChunk (&cuda); EXCEPTION_ASSERT( !mc ); Signal::ComputingOpenCL opencl; mc = mcd.read ()->createMergeChunk (&opencl); EXCEPTION_ASSERT( !mc ); } }
void QtEventWorker:: test() { std::string name = "Worker"; int argc = 1; char * argv = &name[0]; QApplication a(argc,&argv); // It should start and stop automatically { UNITTEST_STEPS TaskTimer tt("It should start and stop automatically"); ISchedule::ptr gettask(new GetTaskMock()); QtEventWorker worker(Signal::ComputingEngine::ptr(), gettask); QThread::yieldCurrentThread (); EXCEPTION_ASSERT( worker.isRunning () ); } // It should run tasks as given by the scheduler { UNITTEST_STEPS TaskTimer tt("It should run tasks as given by the scheduler"); ISchedule::ptr gettask(new GetTaskMock()); QtEventWorker worker(Signal::ComputingEngine::ptr(), gettask); worker.wait (1); EXCEPTION_ASSERT_EQUALS( 1, dynamic_cast<GetTaskMock*>(&*gettask)->get_task_count ); // Verify that tasks execute properly in Task::test. EXCEPTION_ASSERT( worker.isRunning () ); worker.abort (); EXCEPTION_ASSERT( worker.wait (2) ); EXCEPTION_ASSERT( !worker.isRunning () ); } // It should wait to be awaken if there are no tasks { UNITTEST_STEPS TaskTimer tt("It should run tasks as given by the scheduler"); ISchedule::ptr gettask(new GetTaskMock()); QtEventWorker worker(Signal::ComputingEngine::ptr(), gettask); EXCEPTION_ASSERT( !worker.wait (1) ); EXCEPTION_ASSERT_EQUALS( 1, dynamic_cast<GetTaskMock*>(&*gettask)->get_task_count ); QThread::msleep (1); EXCEPTION_ASSERT_EQUALS( 1, dynamic_cast<GetTaskMock*>(&*gettask)->get_task_count ); worker.wakeup (); worker.wait (1); EXCEPTION_ASSERT_EQUALS( 2, dynamic_cast<GetTaskMock*>(&*gettask)->get_task_count ); } // It should store information about a crashed task (segfault) and stop execution. if (!DetectGdb::is_running_through_gdb() && !DetectGdb::was_started_through_gdb ()) { UNITTEST_STEPS TaskTimer tt("It should store information about a crashed task (segfault) and stop execution"); PrettifySegfault::EnableDirectPrint (false); ISchedule::ptr gettask(new GetTaskSegFaultMock()); QtEventWorker worker(Signal::ComputingEngine::ptr(), gettask); worker.wait (1); worker.abort (); EXCEPTION_ASSERT( worker.wait (1) ); EXCEPTION_ASSERT( worker.caught_exception () ); EXPECT_EXCEPTION(segfault_sigill_exception, rethrow_exception(worker.caught_exception ())); PrettifySegfault::EnableDirectPrint (true); } // It should store information about a crashed task (std::exception) and stop execution. (1) { UNITTEST_STEPS TaskTimer tt("It should store information about a crashed task (std::exception) and stop execution (1)"); ISchedule::ptr gettask(new GetTaskExceptionMock()); QtEventWorker worker(Signal::ComputingEngine::ptr(), gettask); QThread::yieldCurrentThread (); } // It should store information about a crashed task (std::exception) and stop execution. (2) { UNITTEST_STEPS TaskTimer tt("It should store information about a crashed task (std::exception) and stop execution (2)"); ISchedule::ptr gettask(new GetTaskExceptionMock()); QtEventWorker worker(Signal::ComputingEngine::ptr(), gettask); worker.wait (1); worker.abort (); worker.wait (1); worker.abort (); EXCEPTION_ASSERT( worker.caught_exception () ); try { rethrow_exception(worker.caught_exception ()); BOOST_THROW_EXCEPTION(boost::unknown_exception()); } catch (const ExceptionAssert& x) { const std::string* message = boost::get_error_info<ExceptionAssert::ExceptionAssert_message>(x); EXCEPTION_ASSERT_EQUALS( "testing that worker catches exceptions from a scheduler", message?*message:"" ); } } #if !defined SHARED_STATE_NO_TIMEOUT // It should store information about a crashed task (LockFailed) and stop execution. { UNITTEST_STEPS TaskTimer tt("It should store information about a crashed task (LockFailed) and stop execution."); ISchedule::ptr gettask(new ImmediateDeadLockMock()); QtEventWorker worker(Signal::ComputingEngine::ptr(), gettask); worker.wait (2); worker.abort (); EXCEPTION_ASSERT( worker.wait (10) ); EXCEPTION_ASSERT( worker.caught_exception () ); EXPECT_EXCEPTION(lock_failed, rethrow_exception(worker.caught_exception ())); EXCEPTION_ASSERT_EQUALS( 1, dynamic_cast<GetTaskMock*>(&*gettask)->get_task_count ); } #endif // It should not hang if it causes a deadlock (1) { UNITTEST_STEPS TaskTimer tt("It should not hang if it causes a deadlock (1)"); ISchedule::ptr gettask(new DeadLockMock()); QtEventWorker worker(Signal::ComputingEngine::ptr(), gettask); EXCEPTION_ASSERT( worker.isRunning () ); worker.terminate (); worker.terminate (); worker.terminate (); worker.terminate (); worker.abort (); worker.abort (); worker.abort (); worker.abort (); EXCEPTION_ASSERT( worker.wait (1) ); } // It should not hang if it causes a deadlock (2) { UNITTEST_STEPS TaskTimer tt("It should not hang if it causes a deadlock (2)"); ISchedule::ptr gettask(new DeadLockMock()); QtEventWorker worker(Signal::ComputingEngine::ptr(), gettask); EXCEPTION_ASSERT( !worker.wait (1) ); worker.terminate (); EXCEPTION_ASSERT( worker.wait (2) ); // Finish within 2 ms after terminate EXPECT_EXCEPTION( TerminatedException, rethrow_exception(worker.caught_exception ()) ); } // It should announce when tasks are finished. { UNITTEST_STEPS TaskTimer tt("It should announce when tasks are finished."); ISchedule::ptr gettask(new DummySchedule()); QtEventWorker worker(Signal::ComputingEngine::ptr(), gettask, false); QTimer t; t.setSingleShot( true ); t.setInterval( 100 ); QEventLoop e; connect (&t, SIGNAL(timeout()), &e, SLOT(quit())); connect (&worker, SIGNAL(oneTaskDone()), &e, SLOT(quit()), Qt::DirectConnection); worker.wakeup (); t.start(); e.exec (); bool aborted_from_timeout = !t.isActive(); EXCEPTION_ASSERT(!aborted_from_timeout); } }
void WorkerCrashLogger:: test() { // It should fetch information asynchronously of crashed workers. { DEBUG TaskInfo ti("Catch info from a previously crashed worker"); std::string name = "WorkerCrashLogger1"; int argc = 1; char * argv = &name[0]; QApplication a(argc,&argv); //for (int consume=0; consume<2; consume++) ISchedule::ptr schedule(new DummyScheduler); Bedroom::ptr bedroom(new Bedroom); Workers::ptr workers(new Workers(IWorkerFactory::ptr(new QtEventWorkerFactory(schedule, bedroom)))); { WorkerCrashLogger wcl(workers); } // Catch info from a previously crashed worker addAndWaitForStop(workers); addAndWaitForStop(workers); { TRACE_PERF("Init"); WorkerCrashLogger wcl(workers); a.processEvents (); // Init new thread before telling it to quit // When the thread quits. Wait for the beautifier to log everything. } // Should have consumed all workers Workers::DeadEngines de = workers.write ()->clean_dead_workers(); EXCEPTION_ASSERT_EQUALS(de.size (), 0u); } { DEBUG TaskInfo ti("Catch info from a crashed worker as it happens"); std::string name = "WorkerCrashLogger2"; int argc = 1; char * argv = &name[0]; QApplication a(argc,&argv); ISchedule::ptr schedule(new DummyScheduler); Bedroom::ptr bedroom(new Bedroom); Workers::ptr workers(new Workers(IWorkerFactory::ptr(new QtEventWorkerFactory(schedule, bedroom)))); { TRACE_PERF("Catch info from a crashed worker as it happens"); WorkerCrashLogger wcl(workers); // Catch info from a crashed worker as it happens addAndWaitForStop(workers); addAndWaitForStop(workers); } Workers::DeadEngines de = workers.write ()->clean_dead_workers(); EXCEPTION_ASSERT_EQUALS(de.size (), 0u); } { DEBUG TaskInfo ti("Support not consuming workers"); std::string name = "WorkerCrashLogger3"; int argc = 1; char * argv = &name[0]; QApplication a(argc,&argv); ISchedule::ptr schedule(new DummyScheduler); Bedroom::ptr bedroom(new Bedroom); Workers::ptr workers(new Workers(IWorkerFactory::ptr(new QtEventWorkerFactory(schedule, bedroom)))); // Catch info from a previously crashed worker addAndWaitForStop(workers); { TRACE_PERF("Support not consuming workers"); WorkerCrashLogger wcl(workers, false); a.processEvents (); // Catch info from a crashed worker as it happens addAndWaitForStop(workers); } // Should not have consumed any workers Workers::DeadEngines de = workers.write ()->clean_dead_workers(); EXCEPTION_ASSERT_EQUALS(de.size (), 2u); } }
void blocking_queue_test:: test () { // It should provide a thread safe solution to the multiple consumer-multiple producer pattern. { typedef blocking_queue<function<int()>> queue; queue q; auto producer = [&q](int a, int b) { for (int i=a; i<b; i++) q.push ([i]() { return i; }); }; auto consumer = [&q]() { int S = 0; try { while (true) S += q.pop ()(); } catch (queue::abort_exception) {} return S; }; vector<thread> producers; vector<future<int>> consumers; for (int i=0; i<10; i++) { producers.push_back (thread(producer, 100*i, 100*i + 100)); consumers.push_back (async(launch::async, consumer)); } for (thread& t : producers) t.join (); q.close (); int S = 0; for (future<int>& f : consumers) { int v = f.get (); EXCEPTION_ASSERT_LESS(1000, v); S += v; } EXCEPTION_ASSERT_EQUALS(S, (999-0)/2.0 * 1000); } // pop_for { typedef blocking_queue<int> queue; queue q; auto a = async(launch::async, [&q]() { EXCEPTION_ASSERT_EQUALS(q.pop_for (chrono::duration<double>(0.0001)), 0); EXCEPTION_ASSERT_EQUALS(q.pop_for (chrono::duration<double>(0.1)), 2); EXCEPTION_ASSERT_EQUALS(q.pop_for (chrono::duration<double>(0.0001)), 0); }); this_thread::sleep_for (chrono::duration<double>(0.001)); q.push (2); a.get(); } // clear { typedef blocking_queue<int> queue; queue q; q.push (2); q.push (4); EXCEPTION_ASSERT(!q.empty ()); auto q2 = q.clear (); EXCEPTION_ASSERT(q.empty ()); EXCEPTION_ASSERT_EQUALS(q2.size (), 2u); } }
void ChainInfo:: test() { std::string name = "ChainInfo"; int argc = 1; char * argv = &name[0]; QApplication a(argc,&argv); // It should provide info about the running state of a signal processing chain { Chain::ptr cp = Chain::createDefaultChain (); ChainInfo c(cp); EXCEPTION_ASSERT( !c.hasWork () ); EXCEPTION_ASSERT_EQUALS( QThread::idealThreadCount () + 1, c.n_workers () ); EXCEPTION_ASSERT_EQUALS( 0, c.dead_workers () ); } Signal::OperationDesc::ptr transparent(new Test::TransparentOperationDesc); Signal::OperationDesc::ptr buffersource(new Signal::BufferSource(Test::RandomBuffer::smallBuffer ())); // It should say that there is no work if a step has crashed (no crash). { UNITTEST_STEPS TaskInfo("It should say that there is no work if a step has crashed (no crash)"); Chain::ptr cp = Chain::createDefaultChain (); ChainInfo c(cp); TargetMarker::ptr at = cp.write ()->addTarget(transparent); TargetNeeds::ptr n = at->target_needs(); cp.write ()->addOperationAt(buffersource,at); EXCEPTION_ASSERT( !c.hasWork () ); n->updateNeeds(Signal::Interval(0,10)); EXCEPTION_ASSERT( c.hasWork () ); QThread::msleep (10); EXCEPTION_ASSERT( !c.hasWork () ); EXCEPTION_ASSERT_EQUALS( 0, c.dead_workers () ); } // It should say that there is no work if a step has crashed (requiredIntervalCrash). { UNITTEST_STEPS TaskInfo("It should say that there is no work if a step has crashed (requiredIntervalCrash)"); Chain::ptr cp = Chain::createDefaultChain (); ChainInfo c(cp); TargetMarker::ptr at = cp.write ()->addTarget(Signal::OperationDesc::ptr(new RequiredIntervalCrash)); TargetNeeds::ptr n = at->target_needs(); cp.write ()->addOperationAt(buffersource,at); EXCEPTION_ASSERT( !c.hasWork () ); EXCEPTION_ASSERT_EQUALS( 0, c.dead_workers () ); n->updateNeeds(Signal::Interval(0,10)); EXCEPTION_ASSERT( n->sleep (12) ); EXCEPTION_ASSERT( !c.hasWork () ); QThread::msleep (1); EXCEPTION_ASSERT_EQUALS( 1, c.dead_workers () ); } // It should say that there is no work if a step has crashed (process). { UNITTEST_STEPS TaskInfo("It should say that there is no work if a step has crashed (process)"); Chain::ptr cp = Chain::createDefaultChain (); ChainInfo c(cp); TargetMarker::ptr at = cp.write ()->addTarget(Signal::OperationDesc::ptr(new ProcessCrashOperationDesc)); TargetNeeds::ptr n = at->target_needs(); cp.write ()->addOperationAt(buffersource,at); EXCEPTION_ASSERT( !c.hasWork () ); n->updateNeeds(Signal::Interval(0,10)); EXCEPTION_ASSERT( c.hasWork () ); QThread::msleep (10); a.processEvents (); // a crashed worker announces 'wakeup' to the others through the application eventloop EXCEPTION_ASSERT( n->sleep (10) ); EXCEPTION_ASSERT( !c.hasWork () ); EXCEPTION_ASSERT_EQUALS( 1, c.dead_workers () ); } }
void Bedroom:: test() { // It should allow different threads to sleep on this object until another thread calls wakeup() for (int j=0;j<2; j++) { Bedroom::ptr bedroom(new Bedroom); int snoozes = 10; SleepyFaceMock sleepyface1(bedroom, snoozes); SleepyFaceMock sleepyface2(bedroom, snoozes); sleepyface1.start (); sleepyface2.start (); for (int i=snoozes; i>=0; i--) { EXCEPTION_ASSERT_EQUALS(sleepyface1.wait (1), i>0?false:true); EXCEPTION_ASSERT_EQUALS(sleepyface2.wait (1), i>0?false:true); // sleepyface1 and sleepyface2 shoule be sleeping now EXCEPTION_ASSERT_EQUALS(bedroom->sleepers(), i>0?2:0); // they should have 'i' times left to snooze EXCEPTION_ASSERTX(sleepyface1.snooze () == i && sleepyface2.snooze () == i, (boost::format("sleepyface1=%d, sleepyface2=%d, i=%d") % sleepyface1.snooze () % sleepyface2.snooze () % i)); // should wake up both bedroom->wakeup(); } EXCEPTION_ASSERT(sleepyface1.isFinished ()); EXCEPTION_ASSERT(sleepyface2.isFinished ()); EXCEPTION_ASSERT_EQUALS(bedroom->sleepers(), 0); } // It should throw a BedroomClosed exception if someone tries to go to // sleep when the bedroom is closed. { Bedroom b; b.close (); EXPECT_EXCEPTION(BedroomClosed, b.getBed().sleep ()); } // It should just sleep until the given timeout has elapsed { Bedroom b; Timer t; bool woken_up_by_wakeup_call = b.getBed ().sleep (2); // The thread was sleeping in its bed for 2 ms. So the elapsed 'Timer' // time should be more than 2 ms but less than 3 ms. EXCEPTION_ASSERT_LESS(t.elapsed (), 3e-3); EXCEPTION_ASSERT_LESS(2e-3, t.elapsed ()); EXCEPTION_ASSERT(!woken_up_by_wakeup_call); // timeout } // It should just sleep until the given timeout has elapsed for (int i=0; i<40; i++) { //TaskTimer tt("It should just sleep until the given timeout has elapsed"); Bedroom::ptr bedroom(new Bedroom); SleepingBeautyMock sbm(bedroom, 1); EXCEPTION_ASSERT_EQUALS(0,bedroom->sleepers ()); sbm.start (); // wait for the thread to go to sleep and then timeout for (int j=0; j<100 && 0==sbm.timeoutCount (); j++) EXCEPTION_ASSERT( !sbm.wait (1) ); // wakeup bedroom->wakeup(); // the thread should finish soon EXCEPTION_ASSERT( sbm.wait (128) ); EXCEPTION_ASSERT_EQUALS(0,bedroom->sleepers ()); } // It should just sleep until the given timeout has elapsed for (int i=0; i<40; i++) { //TaskTimer tt("It should just sleep until the given timeout has elapsed"); Bedroom::ptr bedroom(new Bedroom); SleepingBeautyMock sbm(bedroom, 1000); EXCEPTION_ASSERT_EQUALS(0,bedroom->sleepers ()); sbm.start (); // wait for the thread to go to sleep for (int j=0; j<100 && 0==bedroom->sleepers (); j++) EXCEPTION_ASSERT( !sbm.wait (1) ); EXCEPTION_ASSERT_EQUALS(1,bedroom->sleepers ()); // wakeup bedroom->wakeup(); // the thread should finish soon EXCEPTION_ASSERT( sbm.wait (128) ); EXCEPTION_ASSERT_EQUALS(0,bedroom->sleepers ()); // with such a long timeout the number of timeouts should be 0 EXCEPTION_ASSERT_EQUALS(0,sbm.timeoutCount ()); } }