/*
* Copyright (C) 2009, 2010 Nicolas Bonnefon and other contributors
*
* This file is part of glogg.
*
* glogg is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* glogg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with glogg. If not, see .
*/
#include
#include
#include
#include "testlogdata.h"
#include "logdata.h"
#if QT_VERSION < 0x040500
#define QBENCHMARK
#endif
#if !defined( TMPDIR )
#define TMPDIR "/tmp"
#endif
static const qint64 VBL_NB_LINES = 4999999LL;
static const int VBL_LINE_PER_PAGE = 70;
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";
static const int VBL_LINE_LENGTH = (76+2+7) ; // Without the final '\n' !
static const int VBL_VISIBLE_LINE_LENGTH = (76+8+4+7); // Without the final '\n' !
static const qint64 SL_NB_LINES = 5000LL;
static const int SL_LINE_PER_PAGE = 70;
static const char* sl_format="LOGDATA is a part of glogg, we are going to test it thoroughly, this is line %06d\n";
static const int SL_LINE_LENGTH = 83; // Without the final '\n' !
static const char* partial_line_begin = "123... beginning of line.";
static const char* partial_line_end = " end of line 123.\n";
void TestLogData::initTestCase()
{
QVERIFY( generateDataFiles() );
}
void TestLogData::simpleLoad()
{
LogData logData;
QSignalSpy progressSpy( &logData, SIGNAL( loadingProgressed( int ) ) );
// Register for notification file is loaded
connect( &logData, SIGNAL( loadingFinished( bool ) ),
this, SLOT( loadingFinished() ) );
QBENCHMARK {
logData.attachFile( TMPDIR "/verybiglog.txt" );
// Wait for the loading to be done
{
QApplication::exec();
}
}
QCOMPARE( (qint64) progressSpy.count(), logData.getFileSize() / (5LL*1024*1024) + 2 );
// Blocks of 5 MiB + 1 for the start notification (0%)
QCOMPARE( logData.getNbLine(), VBL_NB_LINES );
QCOMPARE( logData.getMaxLength(), VBL_VISIBLE_LINE_LENGTH );
QCOMPARE( logData.getLineLength( 123 ), VBL_VISIBLE_LINE_LENGTH );
QCOMPARE( logData.getFileSize(), VBL_NB_LINES * (VBL_LINE_LENGTH+1LL) );
// Disconnect all signals
disconnect( &logData, 0 );
}
void TestLogData::multipleLoad()
{
LogData logData;
QSignalSpy finishedSpy( &logData, SIGNAL( loadingFinished( bool ) ) );
// Register for notification file is loaded
connect( &logData, SIGNAL( loadingFinished( bool ) ),
this, SLOT( loadingFinished() ) );
// Start loading the VBL
logData.attachFile( TMPDIR "/verybiglog.txt" );
// Immediately interrupt the loading
logData.interruptLoading();
// and wait for the signal
QApplication::exec();
// Check we have an empty file
QCOMPARE( finishedSpy.count(), 1 );
// TODO: check loadingFinished arg == false
QCOMPARE( logData.getNbLine(), 0LL );
QCOMPARE( logData.getMaxLength(), 0 );
QCOMPARE( logData.getFileSize(), 0LL );
// Restart the VBL
logData.attachFile( TMPDIR "/verybiglog.txt" );
// Ensure the counting has started
{
QMutex mutex;
QWaitCondition sleep;
// sleep.wait( &mutex, 10 );
}
// Load the SL (should block until VBL is fully indexed)
logData.attachFile( TMPDIR "/smalllog.txt" );
// and wait for the 2 signals (one for each file)
QApplication::exec();
QApplication::exec();
// Check we have the small log loaded
QCOMPARE( finishedSpy.count(), 3 );
QCOMPARE( logData.getNbLine(), SL_NB_LINES );
QCOMPARE( logData.getMaxLength(), SL_LINE_LENGTH );
QCOMPARE( logData.getFileSize(), SL_NB_LINES * (SL_LINE_LENGTH+1LL) );
// Restart the VBL again
logData.attachFile( TMPDIR "/verybiglog.txt" );
// Immediately interrupt the loading
logData.interruptLoading();
// and wait for the signal
QApplication::exec();
// Check the small log has been restored
QCOMPARE( finishedSpy.count(), 4 );
QCOMPARE( logData.getNbLine(), SL_NB_LINES );
QCOMPARE( logData.getMaxLength(), SL_LINE_LENGTH );
QCOMPARE( logData.getFileSize(), SL_NB_LINES * (SL_LINE_LENGTH+1LL) );
// Disconnect all signals
disconnect( &logData, 0 );
}
void TestLogData::changingFile()
{
char newLine[90];
LogData logData;
QSignalSpy finishedSpy( &logData, SIGNAL( loadingFinished( bool ) ) );
QSignalSpy progressSpy( &logData, SIGNAL( loadingProgressed( int ) ) );
QSignalSpy changedSpy( &logData,
SIGNAL( fileChanged( LogData::MonitoredFileStatus ) ) );
// Register for notification file is loaded
connect( &logData, SIGNAL( loadingFinished( bool ) ),
this, SLOT( loadingFinished() ) );
// Generate a small file
QFile file( TMPDIR "/changingfile.txt" );
if ( file.open( QIODevice::WriteOnly ) ) {
for (int i = 0; i < 200; i++) {
snprintf(newLine, 89, sl_format, i);
file.write( newLine, qstrlen(newLine) );
}
}
file.close();
// Start loading it
logData.attachFile( TMPDIR "/changingfile.txt" );
// and wait for the signal
QApplication::exec();
// Check we have the small file
QCOMPARE( finishedSpy.count(), 1 );
QCOMPARE( logData.getNbLine(), 200LL );
QCOMPARE( logData.getMaxLength(), SL_LINE_LENGTH );
QCOMPARE( logData.getFileSize(), 200 * (SL_LINE_LENGTH+1LL) );
// Add some data to it
if ( file.open( QIODevice::Append ) ) {
for (int i = 0; i < 200; i++) {
snprintf(newLine, 89, sl_format, i);
file.write( newLine, qstrlen(newLine) );
}
// To test the edge case when the final line is not complete
file.write( partial_line_begin, qstrlen( partial_line_begin ) );
}
file.close();
// and wait for the signals
QApplication::exec();
// Check we have a bigger file
QCOMPARE( changedSpy.count(), 1 );
QCOMPARE( finishedSpy.count(), 2 );
QCOMPARE( logData.getNbLine(), 401LL );
QCOMPARE( logData.getMaxLength(), SL_LINE_LENGTH );
QCOMPARE( logData.getFileSize(), 400 * (SL_LINE_LENGTH+1LL)
+ strlen( partial_line_begin ) );
// Add a couple more lines, including the end of the unfinished one.
if ( file.open( QIODevice::Append ) ) {
file.write( partial_line_end, qstrlen( partial_line_end ) );
for (int i = 0; i < 20; i++) {
snprintf(newLine, 89, sl_format, i);
file.write( newLine, qstrlen(newLine) );
}
}
file.close();
// and wait for the signals
QApplication::exec();
// Check we have a bigger file
QCOMPARE( changedSpy.count(), 2 );
QCOMPARE( finishedSpy.count(), 3 );
QCOMPARE( logData.getNbLine(), 421LL );
QCOMPARE( logData.getMaxLength(), SL_LINE_LENGTH );
QCOMPARE( logData.getFileSize(), 420 * (SL_LINE_LENGTH+1LL)
+ strlen( partial_line_begin ) + strlen( partial_line_end ) );
// Truncate the file
QVERIFY( file.open( QIODevice::WriteOnly ) );
file.close();
// and wait for the signals
QApplication::exec();
// Check we have an empty file
QCOMPARE( changedSpy.count(), 3 );
QCOMPARE( finishedSpy.count(), 4 );
QCOMPARE( logData.getNbLine(), 0LL );
QCOMPARE( logData.getMaxLength(), 0 );
QCOMPARE( logData.getFileSize(), 0LL );
}
void TestLogData::sequentialRead()
{
LogData logData;
// Register for notification file is loaded
connect( &logData, SIGNAL( loadingFinished( bool ) ),
this, SLOT( loadingFinished() ) );
logData.attachFile( TMPDIR "/verybiglog.txt" );
// Wait for the loading to be done
{
QApplication::exec();
}
// Read all lines sequentially
QString s;
QBENCHMARK {
for (int i = 0; i < VBL_NB_LINES; i++) {
s = logData.getLineString(i);
}
}
QCOMPARE( s.length(), VBL_LINE_LENGTH );
}
void TestLogData::sequentialReadExpanded()
{
LogData logData;
// Register for notification file is loaded
connect( &logData, SIGNAL( loadingFinished( bool ) ),
this, SLOT( loadingFinished() ) );
logData.attachFile( TMPDIR "/verybiglog.txt" );
// Wait for the loading to be done
{
QApplication::exec();
}
// Read all expanded lines sequentially
QString s;
QBENCHMARK {
for (int i = 0; i < VBL_NB_LINES; i++) {
s = logData.getExpandedLineString(i);
}
}
QCOMPARE( s.length(), VBL_VISIBLE_LINE_LENGTH );
}
void TestLogData::randomPageRead()
{
LogData logData;
// Register for notification file is loaded
connect( &logData, SIGNAL( loadingFinished( bool ) ),
this, SLOT( loadingFinished() ) );
logData.attachFile( TMPDIR "/verybiglog.txt" );
// Wait for the loading to be done
{
QApplication::exec();
}
QWARN("Starting random page read test");
// Read page by page from the beginning and the end, using the QStringList
// function
QStringList list;
QBENCHMARK {
for (int page = 0; page < (VBL_NB_LINES/VBL_LINE_PER_PAGE)-1; page++)
{
list = logData.getLines( page*VBL_LINE_PER_PAGE, VBL_LINE_PER_PAGE );
QCOMPARE(list.count(), VBL_LINE_PER_PAGE);
int page_from_end = (VBL_NB_LINES/VBL_LINE_PER_PAGE) - page - 1;
list = logData.getLines( page_from_end*VBL_LINE_PER_PAGE, VBL_LINE_PER_PAGE );
QCOMPARE(list.count(), VBL_LINE_PER_PAGE);
}
}
}
void TestLogData::randomPageReadExpanded()
{
LogData logData;
// Register for notification file is loaded
connect( &logData, SIGNAL( loadingFinished( bool ) ),
this, SLOT( loadingFinished() ) );
logData.attachFile( TMPDIR "/verybiglog.txt" );
// Wait for the loading to be done
{
QApplication::exec();
}
QWARN("Starting random page read test (expanded lines)");
// Read page by page from the beginning and the end, using the QStringList
// function
QStringList list;
QBENCHMARK {
for (int page = 0; page < (VBL_NB_LINES/VBL_LINE_PER_PAGE)-1; page++)
{
list = logData.getExpandedLines( page*VBL_LINE_PER_PAGE, VBL_LINE_PER_PAGE );
QCOMPARE(list.count(), VBL_LINE_PER_PAGE);
int page_from_end = (VBL_NB_LINES/VBL_LINE_PER_PAGE) - page - 1;
list = logData.getExpandedLines( page_from_end*VBL_LINE_PER_PAGE, VBL_LINE_PER_PAGE );
QCOMPARE(list.count(), VBL_LINE_PER_PAGE);
}
}
}
//
// Private functions
//
void TestLogData::loadingFinished()
{
QApplication::quit();
}
bool TestLogData::generateDataFiles()
{
char newLine[90];
QFile file( TMPDIR "/verybiglog.txt" );
if ( file.open( QIODevice::WriteOnly ) ) {
for (int i = 0; i < VBL_NB_LINES; i++) {
snprintf(newLine, 89, vbl_format, i);
file.write( newLine, qstrlen(newLine) );
}
}
else {
return false;
}
file.close();
file.setFileName( TMPDIR "/smalllog.txt" );
if ( file.open( QIODevice::WriteOnly ) ) {
for (int i = 0; i < SL_NB_LINES; i++) {
snprintf(newLine, 89, sl_format, i);
file.write( newLine, qstrlen(newLine) );
}
}
else {
return false;
}
file.close();
return true;
}