1 /* 2 * Copyright (C) 2009, 2010 Nicolas Bonnefon and other contributors 3 * 4 * This file is part of glogg. 5 * 6 * glogg is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * glogg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with glogg. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <QSignalSpy> 21 #include <QMutexLocker> 22 #include <QFile> 23 24 #include "testlogdata.h" 25 #include "logdata.h" 26 27 #if QT_VERSION < 0x040500 28 #define QBENCHMARK 29 #endif 30 31 #if !defined( TMPDIR ) 32 #define TMPDIR "/tmp" 33 #endif 34 35 static const qint64 VBL_NB_LINES = 4999999LL; 36 static const int VBL_LINE_PER_PAGE = 70; 37 static const char* vbl_format="LOGDATA is a part of glogg, we are going to test it thoroughly, this is line\t\t%07d\n"; 38 static const int VBL_LINE_LENGTH = (76+2+7) ; // Without the final '\n' ! 39 static const int VBL_VISIBLE_LINE_LENGTH = (76+8+4+7); // Without the final '\n' ! 40 41 static const qint64 SL_NB_LINES = 5000LL; 42 static const int SL_LINE_PER_PAGE = 70; 43 static const char* sl_format="LOGDATA is a part of glogg, we are going to test it thoroughly, this is line %06d\n"; 44 static const int SL_LINE_LENGTH = 83; // Without the final '\n' ! 45 46 static const char* partial_line_begin = "123... beginning of line."; 47 static const char* partial_line_end = " end of line 123.\n"; 48 49 void TestLogData::initTestCase() 50 { 51 QVERIFY( generateDataFiles() ); 52 } 53 54 void TestLogData::simpleLoad() 55 { 56 LogData logData; 57 QSignalSpy progressSpy( &logData, SIGNAL( loadingProgressed( int ) ) ); 58 59 // Register for notification file is loaded 60 connect( &logData, SIGNAL( loadingFinished( bool ) ), 61 this, SLOT( loadingFinished() ) ); 62 63 QBENCHMARK { 64 logData.attachFile( TMPDIR "/verybiglog.txt" ); 65 // Wait for the loading to be done 66 { 67 QApplication::exec(); 68 } 69 } 70 QCOMPARE( (qint64) progressSpy.count(), logData.getFileSize() / (5LL*1024*1024) + 2 ); 71 // Blocks of 5 MiB + 1 for the start notification (0%) 72 QCOMPARE( logData.getNbLine(), VBL_NB_LINES ); 73 QCOMPARE( logData.getMaxLength(), VBL_VISIBLE_LINE_LENGTH ); 74 QCOMPARE( logData.getLineLength( 123 ), VBL_VISIBLE_LINE_LENGTH ); 75 QCOMPARE( logData.getFileSize(), VBL_NB_LINES * (VBL_LINE_LENGTH+1LL) ); 76 77 // Disconnect all signals 78 disconnect( &logData, 0 ); 79 } 80 81 void TestLogData::multipleLoad() 82 { 83 LogData logData; 84 QSignalSpy finishedSpy( &logData, SIGNAL( loadingFinished( bool ) ) ); 85 86 // Register for notification file is loaded 87 connect( &logData, SIGNAL( loadingFinished( bool ) ), 88 this, SLOT( loadingFinished() ) ); 89 90 // Start loading the VBL 91 logData.attachFile( TMPDIR "/verybiglog.txt" ); 92 93 // Immediately interrupt the loading 94 logData.interruptLoading(); 95 96 // and wait for the signal 97 QApplication::exec(); 98 99 // Check we have an empty file 100 QCOMPARE( finishedSpy.count(), 1 ); 101 // TODO: check loadingFinished arg == false 102 QCOMPARE( logData.getNbLine(), 0LL ); 103 QCOMPARE( logData.getMaxLength(), 0 ); 104 QCOMPARE( logData.getFileSize(), 0LL ); 105 106 // Restart the VBL 107 logData.attachFile( TMPDIR "/verybiglog.txt" ); 108 109 // Ensure the counting has started 110 { 111 QMutex mutex; 112 QWaitCondition sleep; 113 // sleep.wait( &mutex, 10 ); 114 } 115 116 // Load the SL (should block until VBL is fully indexed) 117 logData.attachFile( TMPDIR "/smalllog.txt" ); 118 119 // and wait for the 2 signals (one for each file) 120 QApplication::exec(); 121 QApplication::exec(); 122 123 // Check we have the small log loaded 124 QCOMPARE( finishedSpy.count(), 3 ); 125 QCOMPARE( logData.getNbLine(), SL_NB_LINES ); 126 QCOMPARE( logData.getMaxLength(), SL_LINE_LENGTH ); 127 QCOMPARE( logData.getFileSize(), SL_NB_LINES * (SL_LINE_LENGTH+1LL) ); 128 129 // Restart the VBL again 130 logData.attachFile( TMPDIR "/verybiglog.txt" ); 131 132 // Immediately interrupt the loading 133 logData.interruptLoading(); 134 135 // and wait for the signal 136 QApplication::exec(); 137 138 // Check the small log has been restored 139 QCOMPARE( finishedSpy.count(), 4 ); 140 QCOMPARE( logData.getNbLine(), SL_NB_LINES ); 141 QCOMPARE( logData.getMaxLength(), SL_LINE_LENGTH ); 142 QCOMPARE( logData.getFileSize(), SL_NB_LINES * (SL_LINE_LENGTH+1LL) ); 143 144 // Disconnect all signals 145 disconnect( &logData, 0 ); 146 } 147 148 void TestLogData::changingFile() 149 { 150 char newLine[90]; 151 LogData logData; 152 153 QSignalSpy finishedSpy( &logData, SIGNAL( loadingFinished( bool ) ) ); 154 QSignalSpy progressSpy( &logData, SIGNAL( loadingProgressed( int ) ) ); 155 QSignalSpy changedSpy( &logData, 156 SIGNAL( fileChanged( LogData::MonitoredFileStatus ) ) ); 157 158 // Register for notification file is loaded 159 connect( &logData, SIGNAL( loadingFinished( bool ) ), 160 this, SLOT( loadingFinished() ) ); 161 162 // Generate a small file 163 QFile file( TMPDIR "/changingfile.txt" ); 164 if ( file.open( QIODevice::WriteOnly ) ) { 165 for (int i = 0; i < 200; i++) { 166 snprintf(newLine, 89, sl_format, i); 167 file.write( newLine, qstrlen(newLine) ); 168 } 169 } 170 file.close(); 171 172 // Start loading it 173 logData.attachFile( TMPDIR "/changingfile.txt" ); 174 175 // and wait for the signal 176 QApplication::exec(); 177 178 // Check we have the small file 179 QCOMPARE( finishedSpy.count(), 1 ); 180 QCOMPARE( logData.getNbLine(), 200LL ); 181 QCOMPARE( logData.getMaxLength(), SL_LINE_LENGTH ); 182 QCOMPARE( logData.getFileSize(), 200 * (SL_LINE_LENGTH+1LL) ); 183 184 // Add some data to it 185 if ( file.open( QIODevice::Append ) ) { 186 for (int i = 0; i < 200; i++) { 187 snprintf(newLine, 89, sl_format, i); 188 file.write( newLine, qstrlen(newLine) ); 189 } 190 // To test the edge case when the final line is not complete 191 file.write( partial_line_begin, qstrlen( partial_line_begin ) ); 192 } 193 file.close(); 194 195 // and wait for the signals 196 QApplication::exec(); 197 198 // Check we have a bigger file 199 QCOMPARE( changedSpy.count(), 1 ); 200 QCOMPARE( finishedSpy.count(), 2 ); 201 QCOMPARE( logData.getNbLine(), 401LL ); 202 QCOMPARE( logData.getMaxLength(), SL_LINE_LENGTH ); 203 QCOMPARE( logData.getFileSize(), (qint64) (400 * (SL_LINE_LENGTH+1LL) 204 + strlen( partial_line_begin ) ) ); 205 206 // Add a couple more lines, including the end of the unfinished one. 207 if ( file.open( QIODevice::Append ) ) { 208 file.write( partial_line_end, qstrlen( partial_line_end ) ); 209 for (int i = 0; i < 20; i++) { 210 snprintf(newLine, 89, sl_format, i); 211 file.write( newLine, qstrlen(newLine) ); 212 } 213 } 214 file.close(); 215 216 // and wait for the signals 217 QApplication::exec(); 218 219 // Check we have a bigger file 220 QCOMPARE( changedSpy.count(), 2 ); 221 QCOMPARE( finishedSpy.count(), 3 ); 222 QCOMPARE( logData.getNbLine(), 421LL ); 223 QCOMPARE( logData.getMaxLength(), SL_LINE_LENGTH ); 224 QCOMPARE( logData.getFileSize(), (qint64) ( 420 * (SL_LINE_LENGTH+1LL) 225 + strlen( partial_line_begin ) + strlen( partial_line_end ) ) ); 226 227 // Truncate the file 228 QVERIFY( file.open( QIODevice::WriteOnly ) ); 229 file.close(); 230 231 // and wait for the signals 232 QApplication::exec(); 233 234 // Check we have an empty file 235 QCOMPARE( changedSpy.count(), 3 ); 236 QCOMPARE( finishedSpy.count(), 4 ); 237 QCOMPARE( logData.getNbLine(), 0LL ); 238 QCOMPARE( logData.getMaxLength(), 0 ); 239 QCOMPARE( logData.getFileSize(), 0LL ); 240 } 241 242 void TestLogData::sequentialRead() 243 { 244 LogData logData; 245 246 // Register for notification file is loaded 247 connect( &logData, SIGNAL( loadingFinished( bool ) ), 248 this, SLOT( loadingFinished() ) ); 249 250 logData.attachFile( TMPDIR "/verybiglog.txt" ); 251 252 // Wait for the loading to be done 253 { 254 QApplication::exec(); 255 } 256 257 // Read all lines sequentially 258 QString s; 259 QBENCHMARK { 260 for (int i = 0; i < VBL_NB_LINES; i++) { 261 s = logData.getLineString(i); 262 } 263 } 264 QCOMPARE( s.length(), VBL_LINE_LENGTH ); 265 266 } 267 268 void TestLogData::sequentialReadExpanded() 269 { 270 LogData logData; 271 272 // Register for notification file is loaded 273 connect( &logData, SIGNAL( loadingFinished( bool ) ), 274 this, SLOT( loadingFinished() ) ); 275 276 logData.attachFile( TMPDIR "/verybiglog.txt" ); 277 278 // Wait for the loading to be done 279 { 280 QApplication::exec(); 281 } 282 283 // Read all expanded lines sequentially 284 QString s; 285 QBENCHMARK { 286 for (int i = 0; i < VBL_NB_LINES; i++) { 287 s = logData.getExpandedLineString(i); 288 } 289 } 290 QCOMPARE( s.length(), VBL_VISIBLE_LINE_LENGTH ); 291 } 292 293 void TestLogData::randomPageRead() 294 { 295 LogData logData; 296 297 // Register for notification file is loaded 298 connect( &logData, SIGNAL( loadingFinished( bool ) ), 299 this, SLOT( loadingFinished() ) ); 300 301 logData.attachFile( TMPDIR "/verybiglog.txt" ); 302 // Wait for the loading to be done 303 { 304 QApplication::exec(); 305 } 306 307 QWARN("Starting random page read test"); 308 309 // Read page by page from the beginning and the end, using the QStringList 310 // function 311 QStringList list; 312 QBENCHMARK { 313 for (int page = 0; page < (VBL_NB_LINES/VBL_LINE_PER_PAGE)-1; page++) 314 { 315 list = logData.getLines( page*VBL_LINE_PER_PAGE, VBL_LINE_PER_PAGE ); 316 QCOMPARE(list.count(), VBL_LINE_PER_PAGE); 317 int page_from_end = (VBL_NB_LINES/VBL_LINE_PER_PAGE) - page - 1; 318 list = logData.getLines( page_from_end*VBL_LINE_PER_PAGE, VBL_LINE_PER_PAGE ); 319 QCOMPARE(list.count(), VBL_LINE_PER_PAGE); 320 } 321 } 322 323 } 324 325 void TestLogData::randomPageReadExpanded() 326 { 327 LogData logData; 328 329 // Register for notification file is loaded 330 connect( &logData, SIGNAL( loadingFinished( bool ) ), 331 this, SLOT( loadingFinished() ) ); 332 333 logData.attachFile( TMPDIR "/verybiglog.txt" ); 334 // Wait for the loading to be done 335 { 336 QApplication::exec(); 337 } 338 339 QWARN("Starting random page read test (expanded lines)"); 340 341 // Read page by page from the beginning and the end, using the QStringList 342 // function 343 QStringList list; 344 QBENCHMARK { 345 for (int page = 0; page < (VBL_NB_LINES/VBL_LINE_PER_PAGE)-1; page++) 346 { 347 list = logData.getExpandedLines( page*VBL_LINE_PER_PAGE, VBL_LINE_PER_PAGE ); 348 QCOMPARE(list.count(), VBL_LINE_PER_PAGE); 349 int page_from_end = (VBL_NB_LINES/VBL_LINE_PER_PAGE) - page - 1; 350 list = logData.getExpandedLines( page_from_end*VBL_LINE_PER_PAGE, VBL_LINE_PER_PAGE ); 351 QCOMPARE(list.count(), VBL_LINE_PER_PAGE); 352 } 353 } 354 } 355 356 // 357 // Private functions 358 // 359 void TestLogData::loadingFinished() 360 { 361 QApplication::quit(); 362 } 363 364 bool TestLogData::generateDataFiles() 365 { 366 char newLine[90]; 367 368 QFile file( TMPDIR "/verybiglog.txt" ); 369 if ( file.open( QIODevice::WriteOnly ) ) { 370 for (int i = 0; i < VBL_NB_LINES; i++) { 371 snprintf(newLine, 89, vbl_format, i); 372 file.write( newLine, qstrlen(newLine) ); 373 } 374 } 375 else { 376 return false; 377 } 378 file.close(); 379 380 file.setFileName( TMPDIR "/smalllog.txt" ); 381 if ( file.open( QIODevice::WriteOnly ) ) { 382 for (int i = 0; i < SL_NB_LINES; i++) { 383 snprintf(newLine, 89, sl_format, i); 384 file.write( newLine, qstrlen(newLine) ); 385 } 386 } 387 else { 388 return false; 389 } 390 file.close(); 391 392 return true; 393 } 394