Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1422 lines
42 KiB

  1. //
  2. // The following tests need to be added:
  3. //
  4. // - Run the bad-shutdown test on an empty log (forcing a special path
  5. // in CalcLogInfo).
  6. //
  7. #include "pch.cxx"
  8. #pragma hdrstop
  9. #define TRKDATA_ALLOCATE
  10. #include "trkwks.hxx"
  11. BOOL g_fNotified = FALSE;
  12. extern ULONG g_Debug;
  13. BOOL g_fTLogDebug = FALSE;
  14. CTrkWksConfiguration g_cTrkWksConfiguration;
  15. CWorkManager g_WorkManager;
  16. CTestLog g_cTestLog( &g_cTrkWksConfiguration, &g_WorkManager );
  17. inline void TestRaise( HRESULT hr, TCHAR *ptszMessage, va_list Arguments )
  18. {
  19. CHAR szHR[8];
  20. sprintf( szHR, "%#08X", hr );
  21. if( NULL != ptszMessage )
  22. TrkLogErrorRoutineInternal( TRKDBG_ERROR, szHR, ptszMessage, Arguments );
  23. RaiseException( hr, 0, 0, NULL );
  24. }
  25. inline void TestRaiseException( HRESULT hr, TCHAR *ptszMessage = NULL, ... )
  26. {
  27. va_list Arguments;
  28. va_start( Arguments, ptszMessage );
  29. TestRaise( hr, ptszMessage, Arguments );
  30. }
  31. class CTestLogCallback : public PLogCallback
  32. {
  33. void OnEntriesAvailable();
  34. };
  35. void
  36. CTestLogCallback::OnEntriesAvailable()
  37. {
  38. g_fNotified = TRUE;
  39. }
  40. CTestLog::CTestLog( CTrkWksConfiguration *pTrkWksConfiguration, CWorkManager *pWorkManager )
  41. {
  42. _pTrkWksConfiguration = pTrkWksConfiguration;
  43. _pWorkManager = pWorkManager;
  44. *_tszLogFile = TEXT('\0');
  45. } // CTestLog::CTestLog
  46. void
  47. CTestLog::ReInitialize()
  48. {
  49. _cLogFile.UnInitialize();
  50. DeleteFile( _tszLogFile );
  51. _cLogFile.Initialize( _tszLogFile, _pTrkWksConfiguration, &_cSimpleTimer );
  52. _cLog.Initialize( NULL, _pTrkWksConfiguration, &_cLogFile );
  53. }
  54. void
  55. CTestLog::GenerateLogName()
  56. {
  57. DWORD dw;
  58. TCHAR tszRootPath[ MAX_PATH + 1 ];
  59. DWORD cSectorsPerCluster, cNumberOfFreeClusters, cTotalNumberOfClusters;
  60. if( TEXT('\0') != *_tszLogFile )
  61. return;
  62. // Generate a log file name
  63. if( !GetCurrentDirectory( sizeof(_tszLogFile), _tszLogFile ))
  64. {
  65. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't get the current directory") ));
  66. TrkRaiseLastError( );
  67. }
  68. if( TEXT('\\') != _tszLogFile[ _tcslen(_tszLogFile) ] )
  69. _tcscat( _tszLogFile, TEXT("\\") );
  70. _tcscat( _tszLogFile, TEXT("TLog.log") );
  71. // Calculate the sector size
  72. TrkAssert( TEXT(':') == _tszLogFile[1] );
  73. _tcsncpy( tszRootPath, _tszLogFile, sizeof("a:\\") - 1 );
  74. tszRootPath[ sizeof("a:\\") - 1 ] = TEXT('\0');
  75. if( !GetDiskFreeSpace( tszRootPath,
  76. &cSectorsPerCluster, &_cbSector,
  77. &cNumberOfFreeClusters, &cTotalNumberOfClusters ))
  78. {
  79. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't get bytes-per-sector value on %s"), tszRootPath ));
  80. TrkRaiseLastError( );
  81. }
  82. } // CTestLog::GenerateLogName()
  83. const TCHAR*
  84. CTestLog::LogFileName()
  85. {
  86. return( _tszLogFile );
  87. }
  88. ULONG
  89. CTestLog::DataSectorOffset() const
  90. {
  91. return( _cLogFile._header.NumSectors() * CBSector() );
  92. }
  93. void
  94. CTestLog::CreateLog( PLogCallback *pLogCallback, BOOL fValidate )
  95. {
  96. TCHAR tszLogFile[ MAX_PATH + 1 ];
  97. GenerateLogName();
  98. DeleteFile( _tszLogFile );
  99. _pWorkManager->Initialize();
  100. _cSimpleTimer.Initialize( this, _pWorkManager, 0, 0, NULL );
  101. _cLogFile.Initialize( _tszLogFile, _pTrkWksConfiguration, &_cSimpleTimer );
  102. _cLog.Initialize( pLogCallback, _pTrkWksConfiguration, &_cLogFile );
  103. StartTestWorkerThread(_pWorkManager);
  104. if( fValidate )
  105. ValidateLog();
  106. } // CTestLog::CreateLog()
  107. void
  108. CTestLog::Timer( DWORD dwTimerId )
  109. {
  110. _cLog.Flush( FLUSH_TO_CACHE );
  111. _cLogFile.SetShutdown( TRUE );
  112. _cLogFile.Flush( FLUSH_THROUGH_CACHE );
  113. _cLogFile.OnLogCloseTimer();
  114. }
  115. void
  116. CTestLog::OpenLog( PLogCallback *pLogCallback, BOOL fValidate )
  117. {
  118. GenerateLogName();
  119. _pWorkManager->Initialize();
  120. _cSimpleTimer.Initialize( this, _pWorkManager, 0, 0, NULL );
  121. _cLogFile.Initialize( _tszLogFile, _pTrkWksConfiguration, &_cSimpleTimer );
  122. _cLog.Initialize( pLogCallback, _pTrkWksConfiguration, &_cLogFile );
  123. StartTestWorkerThread(_pWorkManager);
  124. if( fValidate )
  125. ValidateLog();
  126. } // CTestLog::CreateLog()
  127. void
  128. CTestLog::CloseLog()
  129. {
  130. _pWorkManager->StopWorkerThread();
  131. WaitTestThreadExit();
  132. _cLog.Flush( FLUSH_TO_CACHE );
  133. _cLogFile.SetShutdown( TRUE );
  134. _cLogFile.Flush( FLUSH_THROUGH_CACHE );
  135. _cLogFile.UnInitialize();
  136. _cSimpleTimer.UnInitialize();
  137. _pWorkManager->UnInitialize();
  138. }
  139. void
  140. CTestLog::Append( ULONG cMoves, const TRKSVR_MOVE_NOTIFICATION rgNotifications[] )
  141. {
  142. LogMoveNotification lmn;
  143. SequenceNumber seqOriginal, seqFinal;
  144. if( _cLog.IsEmpty() )
  145. seqOriginal = -1;
  146. else
  147. {
  148. _cLogFile.ReadMoveNotification( _cLog._loginfo.ilogLast, &lmn );
  149. seqOriginal = lmn.seq;
  150. }
  151. g_fNotified = FALSE;
  152. for( ULONG i = 0; i < cMoves; i++ )
  153. {
  154. _cLog.Append( rgNotifications[i].droidCurrent,
  155. rgNotifications[i].droidNew,
  156. rgNotifications[i].droidBirth );
  157. }
  158. _cLogFile.ReadMoveNotification( _cLog._loginfo.ilogLast, &lmn );
  159. seqFinal = lmn.seq;
  160. if( seqFinal != (SequenceNumber)(seqOriginal + cMoves) )
  161. TestRaiseException( E_FAIL, TEXT("Incorrect sequence numbers after Append (%d + %d = %d?)\n"),
  162. seqOriginal, cMoves, seqFinal );
  163. if( !g_fNotified )
  164. TestRaiseException( E_FAIL, TEXT("Didn't receive a notification during an append\n") );
  165. } // CTestLog::Append()
  166. ULONG
  167. CTestLog::Read( ULONG cRead, TRKSVR_MOVE_NOTIFICATION rgNotifications[], SequenceNumber *pseqFirst )
  168. {
  169. _cLog.Read( rgNotifications, pseqFirst, &cRead );
  170. return( cRead );
  171. } // CTestLog::ReadLog()
  172. void
  173. CTestLog::ReadExtendedHeader( ULONG iOffset, void *pv, ULONG cb )
  174. {
  175. _cLogFile.ReadExtendedHeader( iOffset, pv, cb );
  176. }
  177. void
  178. CTestLog::WriteExtendedHeader( ULONG iOffset, const void *pv, ULONG cb )
  179. {
  180. _cLogFile.WriteExtendedHeader( iOffset, pv, cb );
  181. }
  182. void
  183. CTestLog::ReadAndValidate( ULONG cToRead, ULONG cExpected,
  184. const TRKSVR_MOVE_NOTIFICATION rgNotificationsExpected[],
  185. TRKSVR_MOVE_NOTIFICATION rgNotificationsRead[],
  186. SequenceNumber seqExpected )
  187. {
  188. ULONG cLogEntriesRead = 0;
  189. SequenceNumber seq;
  190. memset( rgNotificationsRead, 0, sizeof(*rgNotificationsRead) * cExpected );
  191. cLogEntriesRead = Read( cToRead, rgNotificationsRead, &seq );
  192. if( cLogEntriesRead != cExpected )
  193. {
  194. TestRaiseException( E_FAIL, TEXT("Bad read from log; expected %d entries, got %d\n"),
  195. cExpected, cLogEntriesRead );
  196. }
  197. if( seq != seqExpected
  198. &&
  199. 0 != cExpected
  200. )
  201. {
  202. TestRaiseException( E_FAIL, TEXT("Invalid sequence number from log (got %d, expected %d)\n"),
  203. seq, seqExpected );
  204. }
  205. if( 0 != cExpected )
  206. {
  207. for( ULONG i = 0; i < cExpected; i++ )
  208. if( memcmp( &rgNotificationsExpected[i], &rgNotificationsRead[i], sizeof(rgNotificationsRead[i]) ))
  209. {
  210. TestRaiseException( E_FAIL, TEXT("Log entries read don't match that which was expected\n") );
  211. }
  212. }
  213. } // CTestLog::ReadAndValidate()
  214. SequenceNumber
  215. CTestLog::GetNextSeqNumber( )
  216. {
  217. return( _cLog.GetNextSeqNumber() );
  218. } // CTestLog::GetLatestSeqNumber()
  219. BOOL
  220. CTestLog::Search( const CDomainRelativeObjId &droid, TRKSVR_MOVE_NOTIFICATION *pNotification )
  221. {
  222. pNotification->droidCurrent = droid;
  223. return( _cLog.Search( pNotification->droidCurrent,
  224. &pNotification->droidNew,
  225. &pNotification->droidBirth ) );
  226. } // CTestLog::Search()
  227. void
  228. CTestLog::Seek( SequenceNumber seq )
  229. {
  230. SequenceNumber seqOriginal;
  231. LogIndex ilogOriginal;
  232. LogMoveNotification lmn;
  233. ilogOriginal = _cLog._loginfo.ilogRead;
  234. if( ilogOriginal != _cLog._loginfo.ilogWrite )
  235. {
  236. _cLogFile.ReadMoveNotification( _cLog._loginfo.ilogRead, &lmn );
  237. seqOriginal = lmn.seq;
  238. }
  239. g_fNotified = FALSE;
  240. _cLog.Seek( seq );
  241. if( seq != _cLog._loginfo.seqNext )
  242. {
  243. _cLogFile.ReadMoveNotification( _cLog._loginfo.ilogRead, &lmn );
  244. if( ilogOriginal == _cLog._loginfo.ilogWrite
  245. ||
  246. seqOriginal > lmn.seq
  247. )
  248. {
  249. if( !g_fNotified && !_cLog.IsEmpty() )
  250. {
  251. TrkLog(( TRKDBG_ERROR, TEXT("Didn't receive a notification after a backwards seek") ));
  252. TrkRaiseException( E_FAIL );
  253. }
  254. }
  255. }
  256. } // CTestLog::Seek( SequenceNumber ... )
  257. void
  258. CTestLog::Seek( int origin, int iSeek )
  259. {
  260. SequenceNumber seqOriginal;
  261. LogMoveNotification lmn;
  262. _cLogFile.ReadMoveNotification( _cLog._loginfo.ilogRead, &lmn );
  263. seqOriginal = _cLog._loginfo.ilogRead == _cLog._loginfo.ilogWrite
  264. ? _cLog._loginfo.seqNext
  265. : lmn.seq;
  266. g_fNotified = FALSE;
  267. _cLog.Seek( origin, iSeek );
  268. _cLogFile.ReadMoveNotification( _cLog._loginfo.ilogRead, &lmn );
  269. if( !_cLog.IsRead()
  270. &&
  271. seqOriginal > lmn.seq
  272. )
  273. {
  274. if( !g_fNotified && !_cLog.IsEmpty() )
  275. TestRaiseException( E_FAIL, TEXT("Didn't receive a notification after a backwards seek") );
  276. }
  277. } // CTestLog::Seek( origin ... )
  278. void
  279. CTestLog::ValidateLog()
  280. {
  281. ULONG cEntries = _cLogFile.NumEntriesInFile();
  282. LogIndex ilogEntry, i, j;
  283. ULONG *rgiNext = NULL;
  284. ULONG *rgiPrev = NULL;
  285. __try
  286. {
  287. rgiNext = (ULONG*) new ULONG[ cEntries ];
  288. rgiPrev = (ULONG*) new ULONG[ cEntries ];
  289. for( ilogEntry = 0; ilogEntry < cEntries; ilogEntry++ )
  290. {
  291. rgiNext[ ilogEntry ] = _cLogFile._sector.GetLogEntry( ilogEntry )->ilogNext;
  292. rgiPrev[ ilogEntry ] = _cLogFile._sector.GetLogEntry( ilogEntry )->ilogPrevious;
  293. }
  294. for( i = 0; i < cEntries; i++ )
  295. {
  296. // Validate that the entry pointed to by i->next, points
  297. // back to i with its prev pointer.
  298. if( rgiPrev[ rgiNext[i] ] != i )
  299. TestRaiseException( E_FAIL, TEXT("Two entries don't point to each other: %d, %d, %d\n"),
  300. i, rgiNext[i], rgiPrev[ rgiNext[i] ] );
  301. // Verify that noone else's next/prev pointers point to
  302. // i's next/prev pointers.
  303. for( j = i+1; j < cEntries; j++ )
  304. {
  305. if( rgiNext[i] == rgiNext[j] )
  306. TestRaiseException( E_FAIL, TEXT("Two entries in the log have the same next pointer: %d and %d (point to %d)\n"),
  307. i, j, rgiNext[i] );
  308. if( rgiPrev[i] == rgiPrev[j] )
  309. TestRaiseException( E_FAIL, TEXT("Two entries in the log have the same prev pointer: %d and %d (point to %d)\n"),
  310. i, j, rgiPrev[i] );
  311. }
  312. }
  313. }
  314. __finally
  315. {
  316. delete[] rgiNext;
  317. delete[] rgiPrev;
  318. }
  319. } // CTestLog::ValidateLog()
  320. ULONG
  321. CTestLog::GetCbLog()
  322. {
  323. return( _cLogFile._cbLogFile );
  324. }
  325. void
  326. CTestLog::DelayUntilClose()
  327. {
  328. _tprintf( TEXT(" Sleeping so that the log auto-closes\n") );
  329. Sleep( 1500 * _pTrkWksConfiguration->GetLogFileOpenTime() );
  330. if( _cLogFile.IsOpen() )
  331. {
  332. TrkLog(( TRKDBG_ERROR, TEXT("After delaying, log file did not close") ));
  333. TrkRaiseException( E_FAIL );
  334. }
  335. }
  336. void
  337. CTestLog::MakeEntryOld()
  338. {
  339. _cLogFile._sector.GetLogEntry( _cLog._loginfo.ilogStart )->move.DateWritten
  340. -= _pTrkWksConfiguration->_dwLogOverwriteAge + 1;
  341. _cLogFile.Flush( FLUSH_UNCONDITIONALLY );
  342. } // CTestLog::MakeStartOld()
  343. ULONG
  344. CTestLog::GetNumEntries()
  345. {
  346. return( _cLogFile.NumEntriesInFile() );
  347. } // CTestLog::GetNumEntries()
  348. LogIndex
  349. CTestLog::GetStartIndex()
  350. {
  351. return( _cLog._loginfo.ilogStart );
  352. }
  353. LogIndex
  354. CTestLog::GetEndIndex()
  355. {
  356. return( _cLog._loginfo.ilogEnd );
  357. }
  358. LogIndex
  359. CTestLog::GetReadIndex()
  360. {
  361. return( _cLog._loginfo.ilogRead );
  362. }
  363. void
  364. CTestLog::SetReadIndex( LogIndex ilogRead )
  365. {
  366. _cLog._loginfo.ilogRead = ilogRead;
  367. _cLog.RefreshHeader();
  368. _cLogFile.Flush();
  369. }
  370. BOOL
  371. CTestLog::IsEmpty()
  372. {
  373. BOOL fReturn;
  374. fReturn = _cLog.IsEmpty();
  375. return( fReturn );
  376. }
  377. ULONG
  378. CTestLog::NumEntriesInFile( )
  379. {
  380. ULONG cSectors = _cLogFile._cbLogFile / _cbSector - NUM_HEADER_SECTORS;
  381. ULONG cEntriesPerSector = (_cbSector-sizeof(LogEntryHeader)) / sizeof(LogEntry);
  382. return( cSectors * cEntriesPerSector );
  383. }
  384. ULONG
  385. CTestLog::NumEntriesPerSector()
  386. {
  387. return( ( _cbSector-sizeof(LogEntryHeader) ) / sizeof(LogEntry) );
  388. }
  389. ULONG
  390. CTestLog::NumEntriesPerKB()
  391. {
  392. return( (1024 / _cbSector) * NumEntriesPerSector() );
  393. }
  394. ULONG
  395. CTestLog::CBSector() const
  396. {
  397. return( _cbSector );
  398. }
  399. void ReadTest( ULONG cEntries,
  400. TRKSVR_MOVE_NOTIFICATION rgNotificationsExpected[],
  401. TRKSVR_MOVE_NOTIFICATION rgNotificationsRead[],
  402. SequenceNumber seqExpected )
  403. {
  404. g_cTestLog.ReadAndValidate( cEntries + 1, cEntries,
  405. rgNotificationsExpected, rgNotificationsRead,
  406. seqExpected );
  407. g_cTestLog.ReadAndValidate( cEntries, cEntries,
  408. rgNotificationsExpected, rgNotificationsRead,
  409. seqExpected );
  410. if( cEntries > 1 )
  411. {
  412. g_cTestLog.ReadAndValidate( cEntries - 1, cEntries - 1,
  413. rgNotificationsExpected, rgNotificationsRead,
  414. seqExpected );
  415. g_cTestLog.ReadAndValidate( 1, 1,
  416. rgNotificationsExpected, rgNotificationsRead,
  417. seqExpected );
  418. }
  419. }
  420. void
  421. ExerciseLog( ULONG cEntries, SequenceNumber seqFirst,
  422. TRKSVR_MOVE_NOTIFICATION rgNotificationsExpected[],
  423. TRKSVR_MOVE_NOTIFICATION rgNotificationsRead[] )
  424. {
  425. SequenceNumber seqExpected = seqFirst;
  426. SequenceNumber seqRead;
  427. ULONG cRead;
  428. ULONG iReadOriginal = g_cTestLog.GetReadIndex();
  429. ReadTest( cEntries, rgNotificationsExpected, rgNotificationsRead, seqExpected );
  430. if( 0 != cEntries )
  431. {
  432. // Skip forward by one entry
  433. g_cTestLog.Seek( SEEK_CUR, 1 );
  434. seqExpected++;
  435. ReadTest( cEntries-1, &rgNotificationsExpected[1], &rgNotificationsRead[1], seqExpected );
  436. if( cEntries > 1 )
  437. {
  438. // Skip forward by one entry, but using an absolute seek.
  439. g_cTestLog.Seek( SEEK_SET, 2 );
  440. seqExpected++;
  441. ReadTest( cEntries-2, &rgNotificationsExpected[2], &rgNotificationsRead[2], seqExpected );
  442. // Do a relative seek back in the log.
  443. g_cTestLog.Seek( SEEK_CUR, -1 );
  444. seqExpected--;
  445. ReadTest( cEntries-1, &rgNotificationsExpected[1], &rgNotificationsRead[1], seqExpected );
  446. }
  447. // Do a relative seek back to the beginning of the log
  448. g_cTestLog.Seek( SEEK_CUR, -1000 );
  449. seqExpected--;
  450. ReadTest( cEntries, &rgNotificationsExpected[0], &rgNotificationsRead[0], seqExpected );
  451. // Skip forward by the remaining entries
  452. g_cTestLog.Seek( SEEK_CUR, cEntries );
  453. seqExpected += cEntries;
  454. cRead = g_cTestLog.Read( 1, rgNotificationsRead, &seqRead );
  455. if( 0 != cRead )
  456. TestRaiseException( E_FAIL, TEXT("Shouldn't have been able to read an already-read log\n") );
  457. // Seek to the end (which is where the read index already is), to ensure
  458. // that nothing happens.
  459. g_fNotified = FALSE;
  460. g_cTestLog.Seek( seqFirst + cEntries );
  461. if( g_fNotified )
  462. TestRaiseException( E_FAIL, TEXT("A seek-to-current shouldn't have caused a notification") );
  463. cRead = g_cTestLog.Read( 1, rgNotificationsRead, &seqRead );
  464. if( 0 != cRead )
  465. TestRaiseException( E_FAIL, TEXT("Shouldn't have been able to read an already-read log\n") );
  466. // Over-seek to the end.
  467. g_fNotified = FALSE;
  468. g_cTestLog.Seek( SEEK_CUR, 1000 );
  469. if( g_fNotified )
  470. TestRaiseException( E_FAIL, TEXT("A seek-to-current shouldn't have caused a notification") );
  471. cRead = g_cTestLog.Read( 1, rgNotificationsRead, &seqRead );
  472. if( 0 != cRead )
  473. TestRaiseException( E_FAIL, TEXT("Shouldn't have been able to read an already-read log\n") );
  474. }
  475. // Seek to the start of the log
  476. g_cTestLog.Seek( seqFirst );
  477. seqExpected = seqFirst;
  478. ReadTest( cEntries, rgNotificationsExpected, rgNotificationsRead, seqExpected );
  479. if( 0 != cEntries )
  480. {
  481. // Seek to the end of the log
  482. seqExpected = seqFirst + (ULONG)(cEntries - 1);
  483. g_cTestLog.Seek( seqExpected );
  484. ReadTest( 1, &rgNotificationsExpected[cEntries-1], &rgNotificationsRead[cEntries-1], seqExpected );
  485. g_cTestLog.Seek( SEEK_CUR, 1 );
  486. }
  487. // Search for each of the log entries
  488. for( ULONG i = 0; i < cEntries; i++ )
  489. {
  490. if( !g_cTestLog.Search( rgNotificationsExpected[i].droidCurrent,
  491. rgNotificationsRead ))
  492. {
  493. TestRaiseException( E_FAIL, TEXT("Search failed to find entry") );
  494. }
  495. if( memcmp( &rgNotificationsExpected[i], rgNotificationsRead, sizeof(*rgNotificationsRead) ))
  496. TestRaiseException( E_FAIL, TEXT("Search failed on entry %d"), i );
  497. }
  498. g_cTestLog.SetReadIndex( iReadOriginal );
  499. } // ExerciseLog()
  500. void
  501. FillAndExerciseLog( ULONG cEntriesOriginal, ULONG cEntriesTotal, SequenceNumber seqFirst,
  502. TRKSVR_MOVE_NOTIFICATION rgNotificationsWrite[],
  503. TRKSVR_MOVE_NOTIFICATION rgNotificationsRead[] )
  504. {
  505. // Test the log as-is
  506. ExerciseLog( cEntriesOriginal, seqFirst, rgNotificationsWrite, rgNotificationsRead );
  507. // Add an entry to the log and re-test
  508. g_cTestLog.Append( 1, &rgNotificationsWrite[ cEntriesOriginal ] );
  509. ExerciseLog( cEntriesOriginal + 1, seqFirst,
  510. rgNotificationsWrite, rgNotificationsRead );
  511. // Test a full log
  512. g_cTestLog.Append( cEntriesTotal - cEntriesOriginal - 2,
  513. &rgNotificationsWrite[ cEntriesOriginal + 1] );
  514. ExerciseLog( cEntriesTotal - 1, seqFirst,
  515. rgNotificationsWrite, rgNotificationsRead );
  516. }
  517. ULONG
  518. LogIndex2SectorIndex( ULONG cbSector, LogIndex ilog )
  519. {
  520. ULONG cEntriesPerSector = ( cbSector - sizeof(LogEntryHeader) ) / sizeof(LogEntry);
  521. return( ilog / cEntriesPerSector + NUM_HEADER_SECTORS );
  522. }
  523. void
  524. ReadLogSector( HANDLE hFile, LogIndex ilog, ULONG cbSector, BYTE rgbSector[] )
  525. {
  526. ULONG iSector = LogIndex2SectorIndex( cbSector, ilog );
  527. ULONG cb;
  528. if( 0xFFFFFFFF == SetFilePointer(hFile, iSector * cbSector, NULL, FILE_BEGIN ))
  529. {
  530. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't seek file to %lu (in test)"), iSector*cbSector ));
  531. TrkRaiseLastError( );
  532. }
  533. if( !ReadFile( hFile, rgbSector, cbSector, &cb, NULL )
  534. ||
  535. cbSector != cb
  536. )
  537. {
  538. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't read from logfile (in test), cbRead = %d"), cb ));
  539. TrkRaiseLastError( );
  540. }
  541. }
  542. void
  543. WriteLogSector( HANDLE hFile, LogIndex ilog, ULONG cbSector, BYTE rgbSector[] )
  544. {
  545. ULONG iSector = LogIndex2SectorIndex( cbSector, ilog );
  546. ULONG cb;
  547. if( 0xFFFFFFFF == SetFilePointer(hFile, iSector * cbSector, NULL, FILE_BEGIN ))
  548. {
  549. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't seek file to %lu (in test)"), iSector*cbSector ));
  550. TrkRaiseLastError( );
  551. }
  552. if( !WriteFile( hFile, rgbSector, cbSector, &cb, NULL )
  553. ||
  554. cbSector != cb
  555. )
  556. {
  557. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't write to logfile (in test), cbWritten = %d"), cb ));
  558. TrkRaiseLastError( );
  559. }
  560. }
  561. void
  562. CreateNewLog( CTestLogCallback *pcTestLogCallback, ULONG *pcLogEntries, ULONG *piNotifications,
  563. SequenceNumber *pseqFirst)
  564. {
  565. _tprintf( TEXT(" Creating a log") );
  566. g_cTrkWksConfiguration._dwMinLogKB = 1;
  567. g_cTrkWksConfiguration._dwMaxLogKB = 1;
  568. g_cTestLog.CreateLog( pcTestLogCallback );
  569. *pcLogEntries = g_cTestLog.NumEntriesInFile();
  570. *piNotifications = 0;
  571. *pseqFirst = 0;
  572. if( 0 != g_cTestLog.GetNextSeqNumber( ))
  573. {
  574. TrkLog(( TRKDBG_ERROR, TEXT("Next sequence number should be zero after a create") ));
  575. TrkRaiseException( E_FAIL );
  576. }
  577. _tprintf( TEXT(" (%d entries)\n"), *pcLogEntries );
  578. }
  579. EXTERN_C void __cdecl _tmain( int argc, TCHAR *argv[] )
  580. {
  581. CTestLogCallback cTestLogCallback;
  582. TRKSVR_MOVE_NOTIFICATION rgNotificationsWritten[ 50 ];
  583. TRKSVR_MOVE_NOTIFICATION rgNotificationsRead[ 50 ];
  584. TRKSVR_MOVE_NOTIFICATION tempNotificationWrite, tempNotificationRead;
  585. __try
  586. {
  587. ULONG cLogEntries = 0;
  588. ULONG i;
  589. DWORD dw;
  590. ULONG cRead, cb, cbFile;
  591. SequenceNumber seqFirst = 0;
  592. BOOL fAppendFailed;
  593. HANDLE hFile = INVALID_HANDLE_VALUE;
  594. BYTE rgbSector[ 2048 ];
  595. LogHeader *plogheader = NULL;
  596. LogEntry *plogentry = NULL;
  597. ULONG iNotifications = 0;
  598. BYTE rgbExtendedHeaderWrite[ 16 ];
  599. BYTE rgbExtendedHeaderRead[ 16 ];
  600. LogIndex ilogStart, ilogEnd;
  601. // --------------
  602. // Initialization
  603. // --------------
  604. _tprintf( TEXT("\nCLog Unit Test\n") );
  605. _tprintf( TEXT( "==============\n\n") );
  606. if( argc > 1 )
  607. {
  608. if( !_tcscmp( TEXT("/D"), argv[1] )
  609. ||
  610. !_tcscmp( TEXT("/d"), argv[1] )
  611. ||
  612. !_tcscmp( TEXT("-D"), argv[1] )
  613. ||
  614. !_tcscmp( TEXT("-d"), argv[1] )
  615. )
  616. {
  617. g_fTLogDebug = TRUE;
  618. }
  619. } // if( argc > 1 )
  620. TrkDebugCreate( TRK_DBG_FLAGS_WRITE_TO_DBG | (g_fTLogDebug ? TRK_DBG_FLAGS_WRITE_TO_STDOUT : 0), "TLog" );
  621. g_cTrkWksConfiguration.Initialize();
  622. g_cTrkWksConfiguration._dwMinLogKB = 1;
  623. g_cTrkWksConfiguration._dwMaxLogKB = 1;
  624. g_cTrkWksConfiguration._dwLogDeltaKB = 1;
  625. g_cTrkWksConfiguration._dwLogOverwriteAge = 10;
  626. g_cTrkWksConfiguration._dwLogFileOpenTime = 10;
  627. g_cTrkWksConfiguration._dwDebugFlags = (0xFFFFFFFF & ~TRKDBG_WORKMAN);
  628. g_Debug = g_cTrkWksConfiguration._dwDebugFlags;
  629. for( i = 0; i < sizeof(rgNotificationsWritten); i++ )
  630. ((BYTE*) rgNotificationsWritten)[ i ] = (BYTE) i;
  631. // -----------
  632. // Basic Tests
  633. // -----------
  634. _tprintf( TEXT("Basic exercises\n") );
  635. CreateNewLog( &cTestLogCallback, &cLogEntries, &iNotifications, &seqFirst );
  636. // Test the initial log
  637. FillAndExerciseLog( 0, cLogEntries, seqFirst, rgNotificationsWritten, rgNotificationsRead );
  638. // Seek to a non-existent entry in the log
  639. g_cTestLog.Seek( 1 );
  640. g_cTestLog.Seek( -1 );
  641. ExerciseLog( cLogEntries-1, 0,
  642. &rgNotificationsWritten[ iNotifications ],
  643. &rgNotificationsRead[ iNotifications ] );
  644. // Cause the log to expand. Note that in this case, the start/end indices are
  645. // currently at the start/end of the file.
  646. _tprintf( TEXT("Cause the log to expand") );
  647. g_cTrkWksConfiguration._dwLogDeltaKB = 1;
  648. g_cTrkWksConfiguration._dwMaxLogKB = g_cTrkWksConfiguration._dwMaxLogKB + 1;
  649. g_cTestLog.Append( 1, &rgNotificationsWritten[ cLogEntries - 1] );
  650. _tprintf( TEXT(" (%d entries)\n"), g_cTestLog.NumEntriesInFile() );
  651. g_cTestLog.DelayUntilClose();
  652. FillAndExerciseLog( cLogEntries,
  653. g_cTestLog.NumEntriesInFile(),
  654. seqFirst,
  655. &rgNotificationsWritten[ iNotifications ],
  656. &rgNotificationsRead[ iNotifications ] );
  657. cLogEntries = g_cTestLog.NumEntriesInFile();
  658. // Close and re-open the log
  659. _tprintf( TEXT("Close and re-open the log\n") );
  660. g_cTestLog.CloseLog();
  661. g_cTestLog.OpenLog( &cTestLogCallback );
  662. ExerciseLog( cLogEntries - 1, seqFirst,
  663. &rgNotificationsWritten[ iNotifications ],
  664. &rgNotificationsRead[ iNotifications ] );
  665. // Ensure that we can't add to a full log (where the log can't be expanded,
  666. // the start entry isn't old enough to throw away, and the start entry
  667. // hasn't yet been read).
  668. __try
  669. {
  670. fAppendFailed = FALSE;
  671. TrkLog(( TRKDBG_ERROR, TEXT("TLog Unit Test: Causing an intentional Append exception") ));
  672. g_cTestLog.Seek( SEEK_SET, 0 ); // Make the start entry un-read
  673. g_cTestLog.Append( 1, rgNotificationsWritten );
  674. }
  675. __except( BreakOnAccessViolation() )
  676. {
  677. if( GetExceptionCode() != STATUS_LOG_FILE_FULL )
  678. TestRaiseException( GetExceptionCode(), TEXT("Wrong exception raised when attempting to write to a full log") );
  679. fAppendFailed = TRUE;
  680. }
  681. if( !fAppendFailed )
  682. TestRaiseException( E_FAIL, TEXT("Append to a full log should have failed") );
  683. // Overwrite an entry in the log that's overwritable since it's been read already.
  684. _tprintf( TEXT("Try to add to a max log (the start entry's been read)\n") );
  685. g_cTestLog.Seek( SEEK_SET, 1 );
  686. g_cTestLog.Append( 1, &rgNotificationsWritten[ cLogEntries - 1 ] );
  687. seqFirst++;
  688. iNotifications++;
  689. ExerciseLog( cLogEntries-1, seqFirst,
  690. &rgNotificationsWritten[ iNotifications ],
  691. &rgNotificationsRead[ iNotifications ] );
  692. g_cTestLog.ValidateLog();
  693. // Overwrite an old entry in the log
  694. _tprintf( TEXT("Try to add to a max log (the start entry's old)\n") );
  695. g_cTestLog.Seek( SEEK_SET, 0 );
  696. g_cTestLog.MakeEntryOld();
  697. g_cTestLog.Append( 1, &rgNotificationsWritten[cLogEntries] );
  698. seqFirst++;
  699. iNotifications++;
  700. ExerciseLog( cLogEntries-1, seqFirst,
  701. &rgNotificationsWritten[ iNotifications ],
  702. &rgNotificationsRead[ iNotifications ] );
  703. g_cTestLog.ValidateLog();
  704. // Grow again (note that this time, the start/end indices are in the middle of
  705. // the file). Also, this time, we show that the log can grow to up to the max
  706. // size, even if it means we can't grow an entire delta.
  707. _tprintf( TEXT("Cause the log to expand again") );
  708. g_cTrkWksConfiguration._dwLogDeltaKB = 10;
  709. g_cTrkWksConfiguration._dwMaxLogKB = g_cTrkWksConfiguration._dwMaxLogKB + 1;
  710. g_cTestLog.Append( 1, &rgNotificationsWritten[ cLogEntries+1 ] );
  711. if( g_cTestLog.NumEntriesInFile()
  712. >
  713. cLogEntries + g_cTestLog.NumEntriesPerKB()
  714. )
  715. {
  716. TrkLog(( TRKDBG_ERROR, TEXT("Log grew by more than the max allowable") ));
  717. TrkRaiseWin32Error( E_FAIL );
  718. }
  719. _tprintf( TEXT(" (%d entries)\n"), g_cTestLog.NumEntriesInFile() );
  720. FillAndExerciseLog( cLogEntries, g_cTestLog.NumEntriesInFile(),
  721. seqFirst,
  722. &rgNotificationsWritten[ iNotifications ],
  723. &rgNotificationsRead[ iNotifications ] );
  724. cLogEntries = g_cTestLog.NumEntriesInFile();
  725. g_cTestLog.ValidateLog();
  726. // --------------
  727. // Extended Tests
  728. // --------------
  729. // Test the extended header
  730. _tprintf( TEXT("Extended header area\n") );
  731. for( i = 0; i < sizeof(rgbExtendedHeaderWrite); i++ )
  732. rgbExtendedHeaderWrite[ i ] = (BYTE)i;
  733. g_cTestLog.WriteExtendedHeader( 32, (void*) rgbExtendedHeaderWrite, sizeof(rgbExtendedHeaderWrite) );
  734. g_cTestLog.ReadExtendedHeader( 32, (void*) rgbExtendedHeaderRead, sizeof(rgbExtendedHeaderRead) );
  735. for( i = 0; i < sizeof(rgbExtendedHeaderWrite); i++ )
  736. rgbExtendedHeaderWrite[ i ] = (BYTE)(i + 1);
  737. g_cTestLog.WriteExtendedHeader( 32, (void*) rgbExtendedHeaderWrite, sizeof(rgbExtendedHeaderWrite) );
  738. g_cTestLog.DelayUntilClose();
  739. g_cTestLog.ReadExtendedHeader( 32, (void*) rgbExtendedHeaderRead, sizeof(rgbExtendedHeaderRead) );
  740. if( memcmp( rgbExtendedHeaderWrite, rgbExtendedHeaderRead, sizeof(rgbExtendedHeaderWrite) ))
  741. {
  742. TrkLog(( TRKDBG_ERROR, TEXT("Extended header information couldn't be written/read") ));
  743. TrkRaiseWin32Error( E_FAIL );
  744. }
  745. // Make the log look abnormally shutdown, then open it.
  746. _tprintf( TEXT("Make log look abnormally shut down\n") );
  747. g_cTestLog.CloseLog();
  748. hFile = CreateFile( g_cTestLog.LogFileName(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ,
  749. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  750. if( INVALID_HANDLE_VALUE == hFile )
  751. {
  752. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open the logfile from the test") ));
  753. TrkRaiseLastError( );
  754. }
  755. if( !ReadFile( hFile, rgbSector, g_cTestLog.CBSector(), &cb, NULL )
  756. ||
  757. g_cTestLog.CBSector() != cb
  758. )
  759. {
  760. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't read from logfile (in test), cbRead = %d"), cb ));
  761. TrkRaiseLastError( );
  762. }
  763. plogheader = (LogHeader*) rgbSector;
  764. plogheader->fProperShutdown = FALSE;
  765. if( 0xFFFFFFFF == SetFilePointer( hFile, 0, NULL, FILE_BEGIN ))
  766. {
  767. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't seek logfile (in test)") ));
  768. TrkRaiseLastError( );
  769. }
  770. if( !WriteFile( hFile, rgbSector, g_cTestLog.CBSector(), &cb, NULL )
  771. ||
  772. g_cTestLog.CBSector() != cb
  773. )
  774. {
  775. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't write to logfile (in test), cbWritten = %d"), cb ));
  776. TrkRaiseLastError( );
  777. }
  778. CloseHandle( hFile );
  779. hFile = INVALID_HANDLE_VALUE;
  780. plogheader = NULL;
  781. g_cTestLog.OpenLog( &cTestLogCallback );
  782. ExerciseLog( cLogEntries - 1, seqFirst,
  783. &rgNotificationsWritten[ iNotifications ],
  784. &rgNotificationsRead[ iNotifications ] );
  785. // Make the log look like it crashed during an expansion.
  786. _tprintf( TEXT("Expansion crash recovery\n") );
  787. ilogStart = g_cTestLog.GetStartIndex();
  788. ilogEnd = g_cTestLog.GetEndIndex();
  789. g_cTestLog.CloseLog();
  790. hFile = CreateFile( g_cTestLog.LogFileName(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ,
  791. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  792. if( INVALID_HANDLE_VALUE == hFile )
  793. {
  794. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open the logfile from the test") ));
  795. TrkRaiseLastError( );
  796. }
  797. cbFile = GetFileSize( hFile, NULL );
  798. if( 0xffffffff == cbFile )
  799. {
  800. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't get log file size (in test)") ));
  801. TrkRaiseLastError( );
  802. }
  803. if( !ReadFile( hFile, rgbSector, g_cTestLog.CBSector(), &cb, NULL )
  804. ||
  805. g_cTestLog.CBSector() != cb
  806. )
  807. {
  808. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't read from logfile (in test), cbRead = %d"), cb ));
  809. TrkRaiseLastError( );
  810. }
  811. plogheader = (LogHeader*) rgbSector;
  812. plogheader->fProperShutdown = FALSE;
  813. plogheader->expand.cbFile = cbFile;
  814. plogheader->expand.ilogStart = ilogStart;
  815. plogheader->expand.ilogEnd = ilogEnd;
  816. if( 0xFFFFFFFF == SetFilePointer( hFile, 0, NULL, FILE_BEGIN ))
  817. {
  818. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't seek logfile (in test)") ));
  819. TrkRaiseLastError( );
  820. }
  821. if( !WriteFile( hFile, rgbSector, g_cTestLog.CBSector(), &cb, NULL )
  822. ||
  823. g_cTestLog.CBSector() != cb
  824. )
  825. {
  826. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't write to logfile (in test), cbWritten = %d"), cb ));
  827. TrkRaiseLastError( );
  828. }
  829. ReadLogSector( hFile, ilogStart, g_cTestLog.CBSector(), rgbSector );
  830. plogentry = &( (LogEntry*)rgbSector )[ ilogStart % (g_cTestLog.CBSector()/sizeof(LogEntry)) ];
  831. plogentry->ilogPrevious = -1;
  832. WriteLogSector( hFile, ilogStart, g_cTestLog.CBSector(), rgbSector );
  833. ReadLogSector( hFile, ilogEnd, g_cTestLog.CBSector(), rgbSector );
  834. plogentry = &( (LogEntry*)rgbSector )[ ilogEnd % (g_cTestLog.CBSector()/sizeof(LogEntry)) ];
  835. plogentry->ilogNext = -1;
  836. WriteLogSector( hFile, ilogEnd, g_cTestLog.CBSector(), rgbSector );
  837. cbFile += g_cTestLog.CBSector();
  838. if ( 0xFFFFFFFF == SetFilePointer(hFile, cbFile, NULL, FILE_BEGIN)
  839. ||
  840. !SetEndOfFile(hFile) )
  841. {
  842. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't reset log file size to %lu (in test)"), cbFile ));
  843. TrkRaiseLastError( );
  844. }
  845. CloseHandle( hFile );
  846. hFile = INVALID_HANDLE_VALUE;
  847. plogheader = NULL;
  848. g_cTestLog.OpenLog( &cTestLogCallback );
  849. ExerciseLog( cLogEntries - 1, seqFirst,
  850. &rgNotificationsWritten[ iNotifications ],
  851. &rgNotificationsRead[ iNotifications ] );
  852. // Corrupt the log header, but in a way that is recoverable.
  853. _tprintf( TEXT("Make log look corrupted (recoverable)\n") );
  854. g_cTestLog.CloseLog();
  855. hFile = CreateFile( g_cTestLog.LogFileName(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ,
  856. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  857. if( INVALID_HANDLE_VALUE == hFile )
  858. {
  859. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open the logfile from the test") ));
  860. TrkRaiseLastError( );
  861. }
  862. if( !ReadFile( hFile, rgbSector, g_cTestLog.CBSector(), &cb, NULL )
  863. ||
  864. g_cTestLog.CBSector() != cb
  865. )
  866. {
  867. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't read from logfile (in test), cbRead = %d"), cb ));
  868. TrkRaiseLastError( );
  869. }
  870. plogheader = (LogHeader*) rgbSector;
  871. plogheader->fProperShutdown = FALSE;
  872. memset( &reinterpret_cast<BYTE*>(plogheader)[CLOG_LOGINFO_START], 0, CLOG_LOGINFO_LENGTH );
  873. if( 0xFFFFFFFF == SetFilePointer( hFile, 0, NULL, FILE_BEGIN ))
  874. {
  875. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't seek logfile (in test)") ));
  876. TrkRaiseLastError( );
  877. }
  878. if( !WriteFile( hFile, rgbSector, g_cTestLog.CBSector(), &cb, NULL )
  879. ||
  880. g_cTestLog.CBSector() != cb
  881. )
  882. {
  883. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't write to logfile (in test), cbWritten = %d"), cb ));
  884. TrkRaiseLastError( );
  885. }
  886. CloseHandle( hFile );
  887. hFile = INVALID_HANDLE_VALUE;
  888. plogheader = NULL;
  889. g_cTestLog.OpenLog( &cTestLogCallback );
  890. if( g_cTestLog.IsEmpty() )
  891. {
  892. TrkLog(( TRKDBG_ERROR, TEXT("We got a new log file after what should have been a recoverable corruption") ));
  893. TrkRaiseWin32Error( E_FAIL );
  894. }
  895. ExerciseLog( cLogEntries - 1, seqFirst,
  896. &rgNotificationsWritten[ iNotifications ],
  897. &rgNotificationsRead[ iNotifications ] );
  898. // Make the log look corrupted and un-recoverable in the header
  899. _tprintf( TEXT("Make log header look corrupted (un-recoverable)\n") );
  900. g_cTestLog.CloseLog();
  901. hFile = CreateFile( g_cTestLog.LogFileName(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ,
  902. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  903. if( INVALID_HANDLE_VALUE == hFile )
  904. {
  905. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open the logfile from the test") ));
  906. TrkRaiseLastError( );
  907. }
  908. if( !ReadFile( hFile, rgbSector, g_cTestLog.CBSector(), &cb, NULL )
  909. ||
  910. g_cTestLog.CBSector() != cb
  911. )
  912. {
  913. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't read from logfile (in test), cbRead = %d"), cb ));
  914. TrkRaiseLastError( );
  915. }
  916. plogheader = (LogHeader*) rgbSector;
  917. plogheader->fProperShutdown = FALSE;
  918. plogheader->ulSignature = 0;
  919. if( 0xFFFFFFFF == SetFilePointer( hFile, 0, NULL, FILE_BEGIN ))
  920. {
  921. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't seek logfile (in test)") ));
  922. TrkRaiseLastError( );
  923. }
  924. if( !WriteFile( hFile, rgbSector, g_cTestLog.CBSector(), &cb, NULL )
  925. ||
  926. g_cTestLog.CBSector() != cb
  927. )
  928. {
  929. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't write to logfile (in test), cbWritten = %d"), cb ));
  930. TrkRaiseLastError( );
  931. }
  932. CloseHandle( hFile );
  933. hFile = INVALID_HANDLE_VALUE;
  934. plogheader = NULL;
  935. g_cTestLog.OpenLog( &cTestLogCallback );
  936. if( !g_cTestLog.IsEmpty() )
  937. {
  938. TrkLog(( TRKDBG_ERROR,TEXT("After opening a corrupt log, we should have a new log file") ));
  939. TrkRaiseWin32Error( E_FAIL );
  940. }
  941. // Make the log look corrupted and un-recoverable in the sectors
  942. _tprintf( TEXT("Make log sectors look corrupted (un-recoverable)\n") );
  943. g_cTestLog.CloseLog();
  944. CreateNewLog( &cTestLogCallback, &cLogEntries, &iNotifications, &seqFirst );
  945. FillAndExerciseLog( 0, cLogEntries, seqFirst, rgNotificationsWritten, rgNotificationsRead );
  946. g_cTestLog.CloseLog();
  947. hFile = CreateFile( g_cTestLog.LogFileName(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ,
  948. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  949. if( INVALID_HANDLE_VALUE == hFile )
  950. {
  951. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open the logfile from the test") ));
  952. TrkRaiseLastError( );
  953. }
  954. if( 0xFFFFFFFF == SetFilePointer( hFile,
  955. g_cTestLog.DataSectorOffset(),
  956. NULL, FILE_BEGIN ))
  957. {
  958. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't seek logfile to start of first sector (in test)") ));
  959. TrkRaiseLastError( );
  960. }
  961. if( !ReadFile( hFile, rgbSector, g_cTestLog.CBSector(), &cb, NULL )
  962. ||
  963. g_cTestLog.CBSector() != cb
  964. )
  965. {
  966. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't read from logfile (in test), cbRead = %d"), cb ));
  967. TrkRaiseLastError( );
  968. }
  969. memset( rgbSector, 0, sizeof(rgbSector) );
  970. if( 0xFFFFFFFF == SetFilePointer( hFile,
  971. g_cTestLog.DataSectorOffset(),
  972. NULL, FILE_BEGIN ))
  973. {
  974. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't re-seek logfile to start of first sector (in test)") ));
  975. TrkRaiseLastError( );
  976. }
  977. if( !WriteFile( hFile, rgbSector, g_cTestLog.CBSector(), &cb, NULL )
  978. ||
  979. g_cTestLog.CBSector() != cb
  980. )
  981. {
  982. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't write to logfile (in test), cbWritten = %d"), cb ));
  983. TrkRaiseLastError( );
  984. }
  985. CloseHandle( hFile );
  986. hFile = INVALID_HANDLE_VALUE;
  987. BOOL fExceptionRaised = FALSE;
  988. __try
  989. {
  990. TrkLog(( TRKDBG_ERROR, TEXT("About to open a corrupted log (this should raise)") ));
  991. // The open should succeed
  992. g_cTestLog.OpenLog( &cTestLogCallback,
  993. FALSE // => Don't validate
  994. );
  995. // This should raise
  996. ExerciseLog( cLogEntries - 1, seqFirst,
  997. &rgNotificationsWritten[ iNotifications ],
  998. &rgNotificationsRead[ iNotifications ] );
  999. }
  1000. __except( EXCEPTION_EXECUTE_HANDLER )
  1001. {
  1002. fExceptionRaised = TRUE;
  1003. if( GetExceptionCode() != TRK_E_CORRUPT_LOG )
  1004. {
  1005. TrkLog(( TRKDBG_ERROR, TEXT("After corrupting a sector, Open should have raised TRK_E_CORRUPT_LOG") ));
  1006. TrkRaiseException( GetExceptionCode() );
  1007. }
  1008. }
  1009. if( !fExceptionRaised )
  1010. {
  1011. TrkLog(( TRKDBG_ERROR, TEXT("We should have gotten an exception after corrupting log sectors") ));
  1012. TrkRaiseWin32Error( E_FAIL );
  1013. }
  1014. g_cTestLog.ReInitialize();
  1015. if( !g_cTestLog.IsEmpty() )
  1016. {
  1017. TrkLog(( TRKDBG_ERROR, TEXT("After opening a corrupt log, we should have a new log file") ));
  1018. TrkRaiseWin32Error( E_FAIL );
  1019. }
  1020. cLogEntries = g_cTestLog.NumEntriesInFile();
  1021. iNotifications = 0;
  1022. seqFirst = 0;
  1023. FillAndExerciseLog( 0, cLogEntries, seqFirst, rgNotificationsWritten, rgNotificationsRead );
  1024. // Test that tunneling works correctly (if there are duplicate entries, we should
  1025. // get the most recent).
  1026. _tprintf( TEXT("Test tunneling\n") );
  1027. tempNotificationWrite = rgNotificationsWritten[0];
  1028. g_cTestLog.Append( 1, &tempNotificationWrite );
  1029. strncpy( (LPSTR) &tempNotificationWrite.droidBirth, "abcdefghijklmnopqrstuvwxyznowiknowmyabcsnexttimewontyousingwithme",
  1030. sizeof(tempNotificationWrite.droidBirth) );
  1031. g_cTestLog.Append( 1, &tempNotificationWrite );
  1032. g_cTestLog.Search( tempNotificationWrite.droidCurrent, &tempNotificationRead );
  1033. if( memcmp( &tempNotificationWrite, &tempNotificationRead, sizeof(tempNotificationWrite) ))
  1034. {
  1035. TrkLog(( TRKDBG_ERROR, TEXT("Didn't get the tunneled move notification") ));
  1036. TrkRaiseWin32Error( E_FAIL );
  1037. }
  1038. _tprintf( TEXT("\nTests Passed\n") );
  1039. g_cTestLog.CloseLog();
  1040. } // __try
  1041. __finally
  1042. {
  1043. }
  1044. } // _tmain()