| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "na64dp/pipeline.hh" | ||
| 2 | #include "na64dp/abstractHandler.hh" | ||
| 3 | #include "na64dp/abstractEventSource.hh" | ||
| 4 | #include "na64event/data/event.hh" | ||
| 5 | //#include "na64dp/abstractHitHandler.hh" | ||
| 6 | //#include "na64dp/abstractEventSource.hh" | ||
| 7 | //#include "na64detID/TBName.hh" | ||
| 8 | //#include "na64dp/pipeline.hh" | ||
| 9 | |||
| 10 | #include <gtest/gtest.h> | ||
| 11 | |||
| 12 | /**\file tests/PipelineBasic.cc | ||
| 13 | * | ||
| 14 | * Testing unit processing basic pipeline's discrimination logic as well as | ||
| 15 | * construction of basic structures. | ||
| 16 | * Creates two handlers within pipeline over a mocking source. The source | ||
| 17 | * sets only the event identifier and yields fixed number of events. The | ||
| 18 | * handlers discriminates each 2nd and 3rd event and records event ids passed | ||
| 19 | * by. | ||
| 20 | * Then the unit verifies that all the events supposed to be passed were passed | ||
| 21 | * indeed. | ||
| 22 | * | ||
| 23 | * Other suite tests full stack of pipeline API with mock classes of event source, event | ||
| 24 | * handler and calibration handle. | ||
| 25 | * */ | ||
| 26 | |||
| 27 | namespace na64dp { | ||
| 28 | namespace test { | ||
| 29 | |||
| 30 | // Mock handler used for testing purposes; discriminates events by their IDs | ||
| 31 | class MockHandler : public AbstractHandler { | ||
| 32 | public: | ||
| 33 | std::vector<EventID> idsPassed; | ||
| 34 | private: | ||
| 35 | int _evIDDiv; | ||
| 36 | public: | ||
| 37 | 2 | MockHandler( int evIDDiv ) | |
| 38 | 2 | : AbstractHandler(log4cpp::Category::getInstance("testing")) | |
| 39 |
3/3✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
|
6 | , _evIDDiv(evIDDiv) {} |
| 40 | 27 | virtual ProcRes process_event(event::Event & event) override { | |
| 41 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 12 times.
|
27 | if( event.id % _evIDDiv ) { |
| 42 | 15 | idsPassed.push_back( event.id ); | |
| 43 | 15 | return kOk; | |
| 44 | } | ||
| 45 | 12 | return kDiscriminateEvent; | |
| 46 | } | ||
| 47 | }; | ||
| 48 | |||
| 49 | // Mock events source | ||
| 50 | class MockSource : public AbstractEventSource { | ||
| 51 | private: | ||
| 52 | size_t _evCounter | ||
| 53 | , _evMaxCount; | ||
| 54 | public: | ||
| 55 | 1 | MockSource( size_t max ) | |
| 56 | 1 | : AbstractEventSource() | |
| 57 | 1 | , _evCounter(0) | |
| 58 | 1 | , _evMaxCount(max) {} | |
| 59 | 19 | virtual bool read(event::Event & e, event::LocalMemory &) override { | |
| 60 | 19 | ++_evCounter; | |
| 61 | 19 | e.id = EventID(_evCounter); | |
| 62 | 19 | return _evCounter < _evMaxCount; | |
| 63 | } | ||
| 64 | }; | ||
| 65 | |||
| 66 | // Builds pipeline of two mock handlers over mock source, checks the basic | ||
| 67 | // discrimination logic | ||
| 68 | 8 | TEST(Pipeline, EventDiscriminationLogic) { | |
| 69 |
2/3✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 7 not taken.
|
2 | MockHandler * h1 = new MockHandler(2) // discriminate each 2nd event |
| 70 |
2/3✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 7 not taken.
|
2 | , * h2 = new MockHandler(3) // discriminate each 3rd event |
| 71 | ; | ||
| 72 |
1/1✓ Branch 1 taken 1 times.
|
2 | Pipeline p; |
| 73 |
1/1✓ Branch 1 taken 1 times.
|
2 | p.push_back(h1); |
| 74 |
1/1✓ Branch 1 taken 1 times.
|
2 | p.push_back(h2); |
| 75 |
1/1✓ Branch 1 taken 1 times.
|
2 | MockSource src(19); |
| 76 | |||
| 77 | // TODO: since some important use cases of allocators lifecycle are not | ||
| 78 | // clear yet, the block below will most probably change at some point. | ||
| 79 | #if 0 | ||
| 80 | auto lmem = LocalMemory::instantiate(); | ||
| 81 | bool hasRead = false; | ||
| 82 | do { | ||
| 83 | auto evRef = lmem.new_event(); | ||
| 84 | if( hasRead = src.read(*evRef) ) { | ||
| 85 | p.process(evRef); | ||
| 86 | } | ||
| 87 | } while( hasRead ); | ||
| 88 | #else | ||
| 89 | { | ||
| 90 | // Physical memory block holding the event data created | ||
| 91 | char buffer[1024]; | ||
| 92 | // ^^^ TODO: this must be enlarged sometimes, when we are changing | ||
| 93 | // event size... We have to foresee some adaptive mechanism here. | ||
| 94 | |||
| 95 | // Memory management strategy | ||
| 96 | // TODO: handle cases other than `PlainBlock` | ||
| 97 | // (will vary depending on the NA64SW_EVMALLOC_STRATEGY) | ||
| 98 | 2 | mem::PlainBlock block(buffer, sizeof(buffer)); | |
| 99 | // Reentrant memory access API | ||
| 100 |
1/1✓ Branch 1 taken 1 times.
|
2 | LocalMemory lmem(block); |
| 101 | |||
| 102 | for(;;) { | ||
| 103 | // Create event for current iteration | ||
| 104 |
1/1✓ Branch 1 taken 19 times.
|
38 | auto evRef = lmem.create<event::Event>(lmem); |
| 105 | |||
| 106 |
1/1✓ Branch 2 taken 19 times.
|
38 | util::reset(*evRef); |
| 107 |
2/2✓ Branch 2 taken 18 times.
✓ Branch 3 taken 1 times.
|
38 | if( src.read(*evRef, lmem) ) |
| 108 |
1/1✓ Branch 2 taken 18 times.
|
36 | p.process(*evRef, lmem); |
| 109 | else | ||
| 110 | 2 | break; | |
| 111 |
1/1✓ Branch 1 taken 18 times.
|
36 | lmem.reset(); |
| 112 | 36 | block.reset(); | |
| 113 | 74 | } | |
| 114 | 2 | } | |
| 115 | #endif | ||
| 116 | // h1 has contain increasing odd numbers: 1, 3, 5 ... 17 | ||
| 117 | 2 | int nC = -1; | |
| 118 |
2/3✓ Branch 2 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
|
2 | EXPECT_EQ( h1->idsPassed.size(), 9 ); |
| 119 |
2/2✓ Branch 5 taken 9 times.
✓ Branch 6 taken 1 times.
|
20 | for( auto n : h1->idsPassed ) { |
| 120 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
|
18 | EXPECT_TRUE( n%2 ); |
| 121 |
2/3✓ Branch 1 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
|
18 | EXPECT_EQ( nC += 2, n ); |
| 122 | } | ||
| 123 | // h1 has contain 1, 5, 7, 11, 13, 17 | ||
| 124 | 2 | const int checkArr[] = { 1, 5, 7, 11, 13, 17 }; | |
| 125 | 2 | const int * nCPtr = checkArr; | |
| 126 |
2/3✓ Branch 2 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
|
2 | EXPECT_EQ( h2->idsPassed.size(), 6 ); |
| 127 |
2/2✓ Branch 5 taken 6 times.
✓ Branch 6 taken 1 times.
|
14 | for(auto n : h2->idsPassed) { |
| 128 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
|
12 | EXPECT_TRUE( n%3 ); |
| 129 |
2/3✓ Branch 1 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
|
12 | EXPECT_EQ( *(nCPtr++), n ); |
| 130 | } | ||
| 131 | 2 | } | |
| 132 | |||
| 133 | #if 0 | ||
| 134 | |||
| 135 | /**\brief A mock detector naming | ||
| 136 | * | ||
| 137 | * Represents a mock calibration data source: applies distinct naming schemata for | ||
| 138 | * run #1 and run #2. | ||
| 139 | **/ | ||
| 140 | class MockCalibHandle : public iCalibHandle { | ||
| 141 | private: | ||
| 142 | int _cRunNo; | ||
| 143 | utils::TBNameMappings _nameMappings; | ||
| 144 | protected: | ||
| 145 | // This mock implementation considers only run #1 and #2 and changes name | ||
| 146 | // mappings between them. | ||
| 147 | virtual bool _new_run_no( na64ee::runNo_t rNo ) override { | ||
| 148 | bool doRecache = (rNo != _cRunNo); | ||
| 149 | if(doRecache) { | ||
| 150 | utils::TBNameMappings & m = _nameMappings; | ||
| 151 | m.clear_mappings(); | ||
| 152 | if( 1 == rNo ) { | ||
| 153 | m.add_chip( "SADCT", 0x1 | ||
| 154 | , "A mock chip for SADC hits, v#1." | ||
| 155 | , "{kin}{statNum2}/{hist}" ); | ||
| 156 | m.add_chip( "APVT", 0x2 | ||
| 157 | , "A mock chip for APV hits, v#1." | ||
| 158 | , "{kin}{statNum2}/{hist}" ); | ||
| 159 | |||
| 160 | m.define_kin( "NCAL", 0x1, "Non-existing SADC detector #1" | ||
| 161 | , "SADCT", "{kin}{statNum}" ); | ||
| 162 | m.define_kin( "NCBL", 0x2, "Non-existing SADC detector #2" | ||
| 163 | , "SADCT", "{kin}{statNum}" ); | ||
| 164 | m.define_kin( "TRCK", 0x1, "Non-existing APV detector #1" | ||
| 165 | , "APVT", "{kin}{statNum2}__" ); | ||
| 166 | } else if( 2 == rNo ) { | ||
| 167 | m.add_chip( "SADCT", 0x3, "A mock chip for SADC hits, v#2.", "{kin}{statNum2}/{hist}" ); | ||
| 168 | m.add_chip( "APVT", 0x1, "A mock chip for APV hits, v#2.", "{kin}{statNum2}/{hist}" ); | ||
| 169 | |||
| 170 | m.define_kin( "NCAL", 0x1, "Non-existing SADC detector #1" | ||
| 171 | , "SADCT", "{kin}{statNum2}" ); | ||
| 172 | m.define_kin( "TRCK", 0x4, "Non-existing APV detector #1" | ||
| 173 | , "APVT", "{kin}{statNum2}__" ); | ||
| 174 | m.define_kin( "TRDK", 0x3, "Non-existing APV detector #2" | ||
| 175 | , "APVT", "{kin}{statNum2}__" ); | ||
| 176 | } else { | ||
| 177 | throw std::runtime_error("Invalid run number provided."); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | _cRunNo = rNo; | ||
| 181 | return doRecache; | ||
| 182 | } | ||
| 183 | virtual bool _has_calib_info( const std::string &, DetID_t ) const override { return false; } | ||
| 184 | virtual const CalibBuffer & _get_calib_info( const std::string &, DetID_t ) override { throw std::runtime_error("forbidden call"); } | ||
| 185 | virtual void _set_calib_info( const std::string &, DetID_t, const CalibBuffer & ) override {} | ||
| 186 | public: | ||
| 187 | MockCalibHandle() {} | ||
| 188 | virtual const utils::TBNameMappings & naming() override { | ||
| 189 | return _nameMappings; | ||
| 190 | } | ||
| 191 | }; | ||
| 192 | |||
| 193 | class MockIndex : public iCalibRunIndex { | ||
| 194 | public: | ||
| 195 | const int n; | ||
| 196 | MockIndex(int n_) : n(n_) {} | ||
| 197 | virtual void updates( EventID oldEventID | ||
| 198 | , EventID newEventID | ||
| 199 | , UpdatesList & ul ) { | ||
| 200 | uint8_t ctrlOctet = newEventID.run_no(); | ||
| 201 | if( 1 == n ) { | ||
| 202 | ctrlOctet &= 0xf; | ||
| 203 | } else { | ||
| 204 | ctrlOctet >>= 4; | ||
| 205 | } | ||
| 206 | if( ! (ctrlOctet & 0x1) ) return; | ||
| 207 | oldEventID.event_no(n - 1); | ||
| 208 | std::string loaderName = (0x2 & ctrlOctet) ? "loader1" : "loader2" | ||
| 209 | , calibTypeName = (0x4 & ctrlOctet) ? "foo" : "bar" | ||
| 210 | ; | ||
| 211 | if( 0x8 & ctrlOctet ) { | ||
| 212 | ul.enqueue_update_of_type<int>( calibTypeName | ||
| 213 | , loaderName | ||
| 214 | , oldEventID ); | ||
| 215 | } else { | ||
| 216 | ul.enqueue_update_of_type<float>( calibTypeName | ||
| 217 | , loaderName | ||
| 218 | , oldEventID ); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | }; | ||
| 222 | |||
| 223 | class MockLoader : public iCalibDataLoader { | ||
| 224 | public: | ||
| 225 | const int n; | ||
| 226 | uint8_t & ctrlByte; | ||
| 227 | MockLoader( int n_, uint8_t & ctrlByte_ ) : n(n_), ctrlByte(ctrlByte_) {} | ||
| 228 | /// Loads calibration data into given dispatcher instance | ||
| 229 | virtual void load_data( EventID eventID | ||
| 230 | , Dispatcher::CIDataID cidID | ||
| 231 | , Dispatcher & ) override { | ||
| 232 | std::string calibName = cidID.second; | ||
| 233 | std::type_index calibTypeIndex = cidID.first; | ||
| 234 | uint8_t ctrlSeq = 0x0; | ||
| 235 | if( calibName == "foo" ) { | ||
| 236 | ctrlSeq |= 0x4; | ||
| 237 | } else { | ||
| 238 | ASSERT_STREQ( calibName.c_str(), "bar" ); | ||
| 239 | } | ||
| 240 | if( std::type_index(typeid(int)) == calibTypeIndex ) { | ||
| 241 | ctrlSeq |= 0x8; | ||
| 242 | } else { | ||
| 243 | ASSERT_EQ(std::type_index(typeid(float)), calibTypeIndex); | ||
| 244 | } | ||
| 245 | if( 1 == n ) { | ||
| 246 | ctrlSeq |= 0x2; | ||
| 247 | } | ||
| 248 | ctrlSeq |= 0x1; // unconditionally set, indicating that index has emitted update | ||
| 249 | ctrlByte |= (ctrlSeq << (eventID.event_no() ? 4 : 0) ); | ||
| 250 | } | ||
| 251 | /// Shall return whether the specified calibration is available | ||
| 252 | virtual bool has( EventID | ||
| 253 | , Dispatcher::CIDataID ) { | ||
| 254 | return true; | ||
| 255 | } | ||
| 256 | }; | ||
| 257 | |||
| 258 | //template<typename HitT> | ||
| 259 | //struct MockSourceTraits; | ||
| 260 | |||
| 261 | /// Mock event source, producing distinct types of events dor two runs | ||
| 262 | class MockEventSource : public AbstractEventSource { | ||
| 263 | public: | ||
| 264 | std::map<std::string, size_t> nHitsByName; | ||
| 265 | private: | ||
| 266 | int _eventCounter; | ||
| 267 | //MockCalibHandle & _ch; //? | ||
| 268 | |||
| 269 | template<typename HitT> | ||
| 270 | void _fill_hits( event::Event & e, int count, const char * tbn ) { | ||
| 271 | if( count < 1 ) return; // no fill for false counts | ||
| 272 | char * postfix = NULL; | ||
| 273 | const utils::TBNameMappings & m = _ch.naming(); | ||
| 274 | DetID did = m.detector_id_by_ddd_name( tbn, postfix ); | ||
| 275 | _log.debug( "Name mappings for event %d yielded detector ID %#x for" | ||
| 276 | " name \"%s\" (filling with %d hits).", e.id, did.id, tbn, count ); | ||
| 277 | //EXPECT_EQ('\0', *postfix); | ||
| 278 | if( nHitsByName.end() != nHitsByName.find(tbn) ) { | ||
| 279 | nHitsByName[tbn] += count; | ||
| 280 | } else { | ||
| 281 | nHitsByName[tbn] = count; | ||
| 282 | } | ||
| 283 | for( int i = 0; i < count; ++i ) { | ||
| 284 | DetID thisDid(did); // we copy did (chip + kin + station number) to | ||
| 285 | thisDid.payload(i+1); // modify the payload | ||
| 286 | try { | ||
| 287 | HitT & newHit = *EvFieldTraits<HitT>::inserter(*this)( e, thisDid, _ch.naming() ); | ||
| 288 | // ... | ||
| 289 | } catch( std::exception & e ) { | ||
| 290 | _log.error( "Error occured while imposing new hit entry for" | ||
| 291 | " detector id %#x (chip = %#x \"%s\", kin = %#x," | ||
| 292 | " stat.num.=%d, payload=%#x, name=\"%s\"/\"%s\")" | ||
| 293 | , thisDid.id | ||
| 294 | , thisDid.chip(), m.chip_name( thisDid.chip() ) | ||
| 295 | , thisDid.kin() | ||
| 296 | , thisDid.number() | ||
| 297 | , thisDid.payload() | ||
| 298 | , tbn | ||
| 299 | , m.detector_ddd_name_by_id( thisDid ).c_str() ); | ||
| 300 | throw; | ||
| 301 | } | ||
| 302 | _log.debug( "Put hit in map; banks sizes: SADC - %zu, APV - %zu," | ||
| 303 | " maps sizes: SADC - %zu, APV - %zu." | ||
| 304 | , _banks.bankSADC.size() | ||
| 305 | , _banks.bankAPV.size() | ||
| 306 | , e.sadcHits.size() | ||
| 307 | , e.apvHits.size() ); | ||
| 308 | } | ||
| 309 | } | ||
| 310 | public: | ||
| 311 | MockEventSource( calib::Manager & mgr ) : AbstractEventSource(banks) | ||
| 312 | , _eventCounter(0) | ||
| 313 | {} | ||
| 314 | |||
| 315 | virtual bool read( event::Event & e ) override { | ||
| 316 | na64ee::UEventID euID = { .numeric = na64ee::assemble_event_id( _eventCounter > 70 ? 1 : 2 | ||
| 317 | , _eventCounter/10 | ||
| 318 | , _eventCounter%10 ) }; | ||
| 319 | e.id = euID.chunklessLayout; | ||
| 320 | // For series below the following summation formulae takes place: | ||
| 321 | // * number of hits per event (negative must be zeroed): | ||
| 322 | // n := c % D - B | ||
| 323 | // * number of events where hits of these type are present: | ||
| 324 | // E := floor(N/D)*(D - B - 1) | ||
| 325 | // May be understood as numer of passed events (D - B - 1) of on | ||
| 326 | // interval of length D multiplied by numer of intervals. | ||
| 327 | // * overall number of hits "generated" for certain detector type: | ||
| 328 | // k = D - B - 1 | ||
| 329 | // S := floor(N/D)*(n*(n-1)/2) | ||
| 330 | // May be derived from previous takin into account that whithin each | ||
| 331 | // interval, n-th triangular number of hits is generated -- a | ||
| 332 | // binomial coefficient (n-2, 2) which is (n^2 - n)/2. | ||
| 333 | if( _eventCounter < 50 ) { | ||
| 334 | // run #1 | ||
| 335 | _ch.set_run_no(1); // has to cause re-caching of all subscribers | ||
| 336 | _fill_hits<event::SADCHit>( e, _eventCounter%3 , "NCAL1" ); | ||
| 337 | _fill_hits<event::SADCHit>( e, _eventCounter%5 - 2 , "NCAL2" ); | ||
| 338 | _fill_hits<event::SADCHit>( e, _eventCounter%3 - 1 , "NCBL1" ); | ||
| 339 | _fill_hits<event::APVHit>( e, _eventCounter%5 - 1 , "TRCK01" ); | ||
| 340 | } else { | ||
| 341 | // run #2 | ||
| 342 | _ch.set_run_no(2); // has to cause re-caching of all subscribers | ||
| 343 | _fill_hits<event::SADCHit>( e, _eventCounter%5 , "NCAL01" ); | ||
| 344 | _fill_hits<event::APVHit>( e, _eventCounter%3 - 1 , "TRCK01__" ); | ||
| 345 | _fill_hits<event::APVHit>( e, _eventCounter%10 , "TRDK01__" ); | ||
| 346 | _fill_hits<event::APVHit>( e, _eventCounter%10- 5 , "TRDK02__" ); | ||
| 347 | } | ||
| 348 | // Expected counts: | ||
| 349 | // NCAL1 : 100 + 49 = 149 | ||
| 350 | // NCAL2 : 30 | ||
| 351 | // NCBL1 : 16 | ||
| 352 | // TRCK01 : 60 + 17 = 77 | ||
| 353 | // TRDK01 : 225 | ||
| 354 | // TRDK02 : 50 | ||
| 355 | return (++_eventCounter) <= 100; | ||
| 356 | } | ||
| 357 | }; | ||
| 358 | |||
| 359 | struct MockHandlerStats { | ||
| 360 | size_t nHits | ||
| 361 | , nHitsInEvent; | ||
| 362 | std::map<DetID_t, size_t> nHitsByDet; | ||
| 363 | std::set<na64ee::EventNumericID> eventIDs; | ||
| 364 | |||
| 365 | MockHandlerStats() : nHits(0) {} | ||
| 366 | }; | ||
| 367 | |||
| 368 | // A mock hits processing handler template | ||
| 369 | // Gathers statistics of hits passed by. | ||
| 370 | template<typename HitT> | ||
| 371 | class MockHandler : public AbstractHitHandler<HitT> | ||
| 372 | , public MockHandlerStats { | ||
| 373 | protected: | ||
| 374 | bool _removeOdd; | ||
| 375 | public: | ||
| 376 | MockHandler( iCalibHandle * ch | ||
| 377 | , const std::string & only="" | ||
| 378 | , bool removeOdd=false ) | ||
| 379 | : AbstractHitHandler<HitT>(ch, only) | ||
| 380 | , _removeOdd(removeOdd) {} | ||
| 381 | |||
| 382 | virtual AbstractHandler::ProcRes process_event( Event * e ) override { | ||
| 383 | nHitsInEvent = 0; | ||
| 384 | na64ee::UEventID ueID = { .chunklessLayout = e->id }; | ||
| 385 | auto it = eventIDs.find(ueID.numeric); | ||
| 386 | EXPECT_EQ( it, eventIDs.end() ); // assure events are unique | ||
| 387 | eventIDs.insert(ueID.numeric); | ||
| 388 | return AbstractHitHandler<HitT>::process_event(e); | ||
| 389 | } | ||
| 390 | |||
| 391 | virtual bool process_hit( na64ee::AbsEventID eventID | ||
| 392 | , DetID_t detID | ||
| 393 | , HitT & hit ) override { | ||
| 394 | // increase general hits counters | ||
| 395 | ++nHits; | ||
| 396 | ++nHitsInEvent; | ||
| 397 | // increase by-detector hit counter | ||
| 398 | auto ir = nHitsByDet.emplace(detID, 1); | ||
| 399 | if( ! ir.second ) { // insertion failed because of existing element | ||
| 400 | ++ (ir.first->second); | ||
| 401 | } | ||
| 402 | if( _removeOdd && nHits%2 ) { | ||
| 403 | this->_set_hit_erase_flag(); | ||
| 404 | } | ||
| 405 | return true; | ||
| 406 | } | ||
| 407 | }; | ||
| 408 | |||
| 409 | TEST(Pipeline, HitProcessorRecachingLogic) { | ||
| 410 | // This string keys will be used to identify the mock SADC detectors | ||
| 411 | const char sadcDetNames[][8] = { "NCAL1", "NCAL01" | ||
| 412 | , "NCAL2" | ||
| 413 | , "NCBL01" | ||
| 414 | }; | ||
| 415 | // This string keys will be used to identify mock APV detectors | ||
| 416 | const char apvDetNames[][8] = { "TRCK01" | ||
| 417 | , "TRDK01" | ||
| 418 | , "TRDK02" | ||
| 419 | }; | ||
| 420 | // This array will be filled with ptrs to handlers for checks | ||
| 421 | MockHandlerStats * stats[7], ** cStat = stats; | ||
| 422 | // Hit banks is an important object for data source and handlers. It | ||
| 423 | // provides pre-allocated memory for fast event modifications -- imposing | ||
| 424 | // hits in event structure by source, and derived data by handlers. | ||
| 425 | HitBanks banks; | ||
| 426 | // Calibration handle is another important object providing calibration | ||
| 427 | // data, detector name mappings and so on. | ||
| 428 | MockCalibHandle ch; | ||
| 429 | // Create the pipeline | ||
| 430 | Pipeline p; | ||
| 431 | |||
| 432 | MockHandler<SADCHit> * h1, * h3; | ||
| 433 | MockHandler<APVHit> * h2, * h4; | ||
| 434 | // Insert some handlers in pipeline | ||
| 435 | { // - This one will accept all the SADC hits | ||
| 436 | auto hPtr = h1 = new MockHandler<SADCHit>( &ch ); | ||
| 437 | p.push_back( hPtr ); | ||
| 438 | *(cStat++) = hPtr; | ||
| 439 | } | ||
| 440 | { // - This one will accept all the APV hits | ||
| 441 | auto hPtr = h2 = new MockHandler<APVHit>( &ch ); | ||
| 442 | p.push_back( hPtr ); | ||
| 443 | *(cStat++) = hPtr; | ||
| 444 | } | ||
| 445 | { // - This one shall trait only NCAL1 (NCAL01 for run #2) detector | ||
| 446 | auto hPtr = h3 = new MockHandler<SADCHit>( &ch | ||
| 447 | , "NCAL == kin && 1 == number" | ||
| 448 | , true ); | ||
| 449 | p.push_back( hPtr ); | ||
| 450 | *(cStat++) = hPtr; | ||
| 451 | } | ||
| 452 | { // - This one shall trait only TRCK01 detector | ||
| 453 | auto hPtr = h4 = new MockHandler<APVHit>( &ch | ||
| 454 | , "TRCK == kin && 1 == number" | ||
| 455 | , true ); | ||
| 456 | p.push_back( hPtr ); | ||
| 457 | *(cStat++) = hPtr; | ||
| 458 | } | ||
| 459 | { // - This one will accept all the SADC hits (after removal) | ||
| 460 | auto hPtr = h1 = new MockHandler<SADCHit>( &ch ); | ||
| 461 | p.push_back( hPtr ); | ||
| 462 | *(cStat++) = hPtr; | ||
| 463 | } | ||
| 464 | #if 0 | ||
| 465 | { // - This one will accept all the APV hits (after removal) | ||
| 466 | auto hPtr = h2 = new MockHandler<APVHit>( &ch ); | ||
| 467 | p.push_back( hPtr ); | ||
| 468 | *(cStat++) = hPtr; | ||
| 469 | } | ||
| 470 | #endif | ||
| 471 | *(cStat++) = nullptr; | ||
| 472 | // Create the source | ||
| 473 | MockEventSource src( banks, ch ); | ||
| 474 | // Create reentrant event instance (owned by thread) | ||
| 475 | Event e(banks); | ||
| 476 | EXPECT_EQ( &banks.bankSADC, &e.sadcHits.pool() ); | ||
| 477 | EXPECT_EQ( &banks.bankAPV, &e.apvHits.pool() ); | ||
| 478 | // Process events from source with pipeline | ||
| 479 | while(src.read(e)) { | ||
| 480 | EXPECT_EQ( &banks.bankSADC, &e.sadcHits.pool() ); | ||
| 481 | EXPECT_EQ( &banks.bankAPV, &e.apvHits.pool() ); | ||
| 482 | p.process(e); | ||
| 483 | e.clear(); | ||
| 484 | banks.clear(); | ||
| 485 | } | ||
| 486 | // Check the results | ||
| 487 | // - at least one event is present on handler #1 | ||
| 488 | ASSERT_FALSE( stats[0]->eventIDs.empty() ); | ||
| 489 | // - 100 events were passed through all the handlers, and check total | ||
| 490 | // number of hits accepted by each of the handlers | ||
| 491 | const size_t expectedHitCounts[] = { | ||
| 492 | 100 + 49 + 30 + 16, /* SADC overall */ | ||
| 493 | 60 + 17 + 225 + 50, /* APV overall */ | ||
| 494 | 100 + 49, /* NCAL1/NCAL01 */ | ||
| 495 | 60 + 17, /* TRCK01 */ | ||
| 496 | (100+49)/2+30+16, /* SADC overall, after discriminating odd NCAL1/NCAL01 */ | ||
| 497 | (60+17)/2+225+50, /* APV overall, after discriminating odd TRCK01 */ | ||
| 498 | }; | ||
| 499 | const size_t * expectedCountPtr = expectedHitCounts; | ||
| 500 | for( MockHandlerStats ** cStat = stats | ||
| 501 | ; *cStat | ||
| 502 | ; ++cStat, ++expectedCountPtr ) { | ||
| 503 | EXPECT_EQ( 100, (*cStat)->eventIDs.size() ); | ||
| 504 | if( *expectedCountPtr ) { | ||
| 505 | EXPECT_EQ( *expectedCountPtr, (*cStat)->nHits ) | ||
| 506 | << " at handler #" | ||
| 507 | << cStat - stats; | ||
| 508 | } | ||
| 509 | } | ||
| 510 | } | ||
| 511 | |||
| 512 | #endif | ||
| 513 | |||
| 514 | } // namespace na64dp::test | ||
| 515 | } // namespace na64dp | ||
| 516 |