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