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