xref: /glogg/tests/testlogdata.cpp (revision 5f12ccbaee05305bc6aceae31f9948fd33f8c5f4)
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