2
Copyright (c) 2010 Sérgio Martins <iamsergio@gmail.com>
4
This library is free software; you can redistribute it and/or modify it
5
under the terms of the GNU Library General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or (at your
7
option) any later version.
9
This library is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12
License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to the
16
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20
#include <calendarsupport/utils.h>
21
#include <calendarsupport/calendar.h>
22
#include <calendarsupport/calendarmodel.h>
23
#include <calendarsupport/next/incidencechanger2.h>
25
#include <Akonadi/ChangeRecorder>
26
#include <Akonadi/Session>
27
#include <Akonadi/ItemFetchScope>
28
#include <akonadi/entitydisplayattribute.h>
29
#include <akonadi/agentinstance.h>
30
#include <akonadi/agentmanager.h>
31
#include <akonadi/collection.h>
32
#include <akonadi/collectionstatistics.h>
33
#include <akonadi/control.h>
34
#include <akonadi/itemcreatejob.h>
35
#include <akonadi/itemmodifyjob.h>
36
#include <akonadi/itemdeletejob.h>
37
#include <akonadi/collectionfetchjob.h>
38
#include <akonadi/collectionfetchscope.h>
39
#include <akonadi/qtest_akonadi.h>
41
#include <Akonadi/Item>
42
#include <Akonadi/Collection>
44
#include <KCalCore/Event>
45
#include <KCalCore/Journal>
46
#include <KCalCore/Todo>
48
#include <KSystemTimeZone>
50
#include <QtCore/QObject>
51
#include <QPushButton>
53
using namespace Akonadi;
54
using namespace KCalCore;
55
using namespace CalendarSupport;
57
class IncidenceChangerTest : public QObject
60
Collection mCollection;
61
CalendarModel *mCalendarModel;
62
CalendarSupport::Calendar *mCalendar;
64
// List of incidence uids.
65
QStringList mPendingInsertsInETM;
66
QStringList mPendingUpdatesInETM;
67
QStringList mPendingDeletesInETM;
69
bool mWaitingForIncidenceChangerSignals;
70
IncidenceChanger2::ResultCode mExpectedResult;
71
IncidenceChanger2 *mChanger;
73
QSet<int> mKnownChangeIds;
78
mWaitingForIncidenceChangerSignals = false;
79
mExpectedResult = IncidenceChanger2::ResultCodeSuccess;
80
//Control::start(); //TODO: uncomment when using testrunner
81
qRegisterMetaType<CalendarSupport::IncidenceChanger2::ResultCode>("CalendarSupport::IncidenceChanger2::ResultCode");
82
CollectionFetchJob *job = new CollectionFetchJob( Collection::root(),
83
CollectionFetchJob::Recursive,
85
// Get list of collections
86
job->fetchScope().setContentMimeTypes( QStringList() << "application/x-vnd.akonadi.calendar.event" );
89
// Find our collection
90
Collection::List collections = job->collections();
91
foreach( Collection collection, collections ) {
92
if ( collection.name().startsWith( QLatin1String( "akonadi_ical_resource" ) ) ) {
93
mCollection = collection;
98
QVERIFY( mCollection.isValid() );
101
Akonadi::Session *session = new Akonadi::Session( "KOrganizerETM", this );
102
Akonadi::ChangeRecorder *monitor = new Akonadi::ChangeRecorder( this );
103
Akonadi::ItemFetchScope scope;
104
scope.fetchFullPayload( true );
105
scope.fetchAttribute<Akonadi::EntityDisplayAttribute>();
106
monitor->setSession( session );
107
monitor->setCollectionMonitored( Akonadi::Collection::root() );
108
monitor->fetchCollection( true );
109
monitor->setItemFetchScope( scope );
110
monitor->setMimeTypeMonitored( "text/calendar", true );
111
monitor->setMimeTypeMonitored( KCalCore::Event::eventMimeType(), true );
112
monitor->setMimeTypeMonitored( KCalCore::Todo::todoMimeType(), true );
113
monitor->setMimeTypeMonitored( KCalCore::Journal::journalMimeType(), true );
114
mCalendarModel = new CalendarSupport::CalendarModel( monitor, this );
116
mCalendar = new CalendarSupport::Calendar( mCalendarModel,
118
KSystemTimeZones::local() );
120
mChanger = new IncidenceChanger2();
121
mChanger->setShowDialogsOnError( false );
123
connect( mChanger, SIGNAL(createFinished(int,Akonadi::Item,CalendarSupport::IncidenceChanger2::ResultCode,QString)),
124
SLOT(createFinished(int,Akonadi::Item,CalendarSupport::IncidenceChanger2::ResultCode,QString)) );
126
connect( mChanger, SIGNAL(deleteFinished(int,QVector<Akonadi::Item::Id>,CalendarSupport::IncidenceChanger2::ResultCode,QString)),
127
SLOT(deleteFinished(int,QVector<Akonadi::Item::Id>,CalendarSupport::IncidenceChanger2::ResultCode,QString)) );
129
connect( mChanger,SIGNAL(modifyFinished(int,Akonadi::Item,CalendarSupport::IncidenceChanger2::ResultCode,QString)),
130
SLOT(modifyFinished(int,Akonadi::Item,CalendarSupport::IncidenceChanger2::ResultCode,QString)) );
132
connect( mCalendarModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
133
SLOT(rowsInserted(QModelIndex,int,int)) );
135
connect( mCalendarModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
136
SLOT(dataChanged(QModelIndex,QModelIndex)) );
138
connect( mCalendarModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
139
SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)) );
146
{ // Create 5 incidences, wait for the signal.
147
for ( int i = 0; i < 5; ++i ) {
148
const QString uid( "uid" + QString::number( i ) );
149
const QString summary( "summary" + QString::number( i ) );
150
Incidence::Ptr incidence( new Event() );
151
incidence->setUid( uid );
152
incidence->setSummary( summary );
153
mPendingInsertsInETM.append( uid );
154
changeId = mChanger->createIncidence( incidence,
156
QVERIFY( changeId != -1 );
157
mKnownChangeIds.insert( changeId );
162
{ // Invalid parameters
163
changeId = mChanger->createIncidence( Incidence::Ptr(), // Invalid payload
165
QVERIFY( changeId == -1 );
166
mKnownChangeIds.insert( changeId );
169
{ // Invalid collections
180
const Item::List incidences = mCalendar->rawIncidences();
182
{ // Delete 5 incidences, previously created
183
foreach( const Item &item, incidences ) {
184
mPendingDeletesInETM.append( item.payload<Incidence::Ptr>()->uid() );
186
changeId = mChanger->deleteIncidences( incidences );
187
mKnownChangeIds.insert( changeId );
188
QVERIFY( changeId != -1 );
192
{ // Delete something already deleted
193
mWaitingForIncidenceChangerSignals = true;
194
changeId = mChanger->deleteIncidences( incidences );
195
mKnownChangeIds.insert( changeId );
196
QVERIFY( changeId != -1 );
197
mExpectedResult = IncidenceChanger2::ResultCodeAlreadyDeleted;
201
{ // If we provide an empty list, a job won't be created
202
changeId = mChanger->deleteIncidences( Item::List() );
203
mKnownChangeIds.insert( changeId );
204
QVERIFY( changeId == -1 );
207
{ // If we provide a list with at least one invalid item, a job won't be created
210
changeId = mChanger->deleteIncidences( list );
211
QVERIFY( changeId == -1 );
220
// First create an incidence
221
const QString uid( "uid");
222
const QString summary( "summary");
223
Incidence::Ptr incidence( new Event() );
224
incidence->setUid( uid );
225
incidence->setSummary( summary );
226
mPendingInsertsInETM.append( uid );
227
changeId = mChanger->createIncidence( incidence,
229
QVERIFY( changeId != -1 );
230
mKnownChangeIds.insert( changeId );
233
{ // Just a summary change
234
Item item = mCalendar->itemForIncidenceUid( uid );
235
QVERIFY( item.isValid() );
236
item.payload<Incidence::Ptr>()->setSummary( "summary2" );
237
mPendingUpdatesInETM.append( uid );
238
changeId = mChanger->modifyIncidence( item );
239
QVERIFY( changeId != -1 );
240
mKnownChangeIds.insert( changeId );
242
item = mCalendar->itemForIncidenceUid( uid );
243
QVERIFY( item.isValid() );
244
QVERIFY( item.payload<Incidence::Ptr>()->summary() == "summary2" );
248
changeId = mChanger->modifyIncidence( Item() );
249
QVERIFY( changeId == -1 );
252
{ // Delete it and try do modify it, should result in error
253
Item item = mCalendar->itemForIncidenceUid( uid );
254
QVERIFY( item.isValid() );
255
mPendingDeletesInETM.append( uid );
256
changeId = mChanger->deleteIncidence( item );
257
QVERIFY( changeId != -1 );
258
mKnownChangeIds.insert( changeId );
261
mWaitingForIncidenceChangerSignals = true;
262
changeId = mChanger->modifyIncidence( item );
263
mKnownChangeIds.insert( changeId );
264
mExpectedResult = IncidenceChanger2::ResultCodeAlreadyDeleted;
265
QVERIFY( changeId != -1 );
270
void testMassModifyForConflicts()
274
// First create an incidence
275
const QString uid( "uid");
276
const QString summary( "summary");
277
Incidence::Ptr incidence( new Event() );
278
incidence->setUid( uid );
279
incidence->setSummary( summary );
280
mPendingInsertsInETM.append( uid );
281
changeId = mChanger->createIncidence( incidence,
283
QVERIFY( changeId != -1 );
284
mKnownChangeIds.insert( changeId );
287
kDebug() << "Doing 30 modifications, but waiting for jobs to end before starting a new one.";
288
const int LIMIT = 30;
289
for ( int i = 0; i < LIMIT; ++i ) {
290
mWaitingForIncidenceChangerSignals = true;
291
mPendingUpdatesInETM.append( uid );
292
Item item = mCalendar->itemForIncidenceUid( uid );
293
QVERIFY( item.isValid() );
294
item.payload<Incidence::Ptr>()->setSummary( QString::number( i ) );
295
int changeId = mChanger->modifyIncidence( item );
296
QVERIFY( changeId > -1 );
297
mKnownChangeIds.insert( changeId );
301
Item item = mCalendar->itemForIncidenceUid( uid );
302
QVERIFY( item.isValid() );
304
kDebug() << "Doing 30 modifications, and not for jobs to end before starting a new one.";
306
for ( int i = 0; i < LIMIT; ++i ) {
307
item.payload<Incidence::Ptr>()->setSummary( QString::number( i ) );
308
const int changeId = mChanger->modifyIncidence( item );
309
QVERIFY( changeId > -1 );
310
mKnownChangeIds.insert( changeId );
312
if ( i == LIMIT-1 ) {
313
// Let's catch the last signal, so we don't exit our test with jobs still running
314
mWaitingForIncidenceChangerSignals = true;
320
// Cleanup, delete the incidence
321
item = mCalendar->itemForIncidenceUid( uid );
322
QVERIFY( item.isValid() );
323
mPendingDeletesInETM.append( uid );
324
changeId = mChanger->deleteIncidence( item );
325
QVERIFY( changeId != -1 );
326
mKnownChangeIds.insert( changeId );
332
void waitForSignals()
334
while ( !mPendingInsertsInETM.isEmpty() ||
335
!mPendingUpdatesInETM.isEmpty() ||
336
!mPendingDeletesInETM.isEmpty() ||
337
mWaitingForIncidenceChangerSignals ) {
338
QTest::qWait( 1000 );
342
void rowsInserted( const QModelIndex &index, int start, int end )
344
Item::List list = itemsFromModel( mCalendarModel, index, start, end );
346
foreach( const Item &item, list ) {
347
Incidence::Ptr incidence = CalendarSupport::incidence( item );
348
if ( incidence && mPendingInsertsInETM.contains( incidence->uid() ) )
349
mPendingInsertsInETM.removeAll( incidence->uid() );
353
void dataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight )
355
Q_ASSERT( topLeft.row() <= bottomRight.row() );
356
const int endRow = bottomRight.row();
357
QModelIndex i( topLeft );
359
while ( row <= endRow ) {
360
const Akonadi::Item item = itemFromIndex( i );
361
if ( item.isValid() ) {
362
Incidence::Ptr incidence = CalendarSupport::incidence( item );
363
if ( incidence && mPendingUpdatesInETM.contains( incidence->uid() ) )
364
mPendingUpdatesInETM.removeAll( incidence->uid() );
367
i = i.sibling( row, topLeft.column() );
371
void rowsAboutToBeRemoved( const QModelIndex &index, int start, int end )
373
Item::List list = itemsFromModel( mCalendarModel, index, start, end );
374
foreach( const Item &item, list ) {
375
Incidence::Ptr incidence = CalendarSupport::incidence( item );
376
if ( incidence && mPendingDeletesInETM.contains( incidence->uid() ) )
377
mPendingDeletesInETM.removeAll( incidence->uid() );
381
void deleteFinished( int changeId,
382
const QVector<Akonadi::Item::Id> &deletedIds,
383
CalendarSupport::IncidenceChanger2::ResultCode resultCode,
384
const QString &errorMessage )
386
Q_UNUSED( deletedIds );
387
QVERIFY( mKnownChangeIds.contains( changeId ) );
388
QVERIFY( changeId != -1 );
390
if ( resultCode != IncidenceChanger2::ResultCodeSuccess ) {
391
kDebug() << "Error string is " << errorMessage;
393
QVERIFY( !deletedIds.isEmpty() );
394
foreach( Akonadi::Item::Id id , deletedIds ) {
399
QVERIFY( resultCode == mExpectedResult );
400
mExpectedResult = IncidenceChanger2::ResultCodeSuccess;
401
mWaitingForIncidenceChangerSignals = false;
404
void createFinished( int changeId,
405
const Akonadi::Item &item,
406
CalendarSupport::IncidenceChanger2::ResultCode resultCode,
407
const QString &errorString )
409
QVERIFY( mKnownChangeIds.contains( changeId ) );
410
QVERIFY( changeId != -1 );
412
if ( resultCode == IncidenceChanger2::ResultCodeSuccess ) {
413
QVERIFY( item.isValid() );
414
QVERIFY( item.parentCollection().isValid() );
416
kDebug() << "Error string is " << errorString;
419
QVERIFY( resultCode == mExpectedResult );
420
mExpectedResult = IncidenceChanger2::ResultCodeSuccess;
421
mWaitingForIncidenceChangerSignals = false;
424
void modifyFinished( int changeId,
425
const Akonadi::Item &item,
426
CalendarSupport::IncidenceChanger2::ResultCode resultCode,
427
const QString &errorString )
430
QVERIFY( mKnownChangeIds.contains( changeId ) );
431
QVERIFY( changeId != -1 );
433
if ( resultCode == IncidenceChanger2::ResultCodeSuccess )
434
QVERIFY( item.isValid() );
436
kDebug() << "Error string is " << errorString;
438
QVERIFY( resultCode == mExpectedResult );
440
mExpectedResult = IncidenceChanger2::ResultCodeSuccess;
441
mWaitingForIncidenceChangerSignals = false;
445
QTEST_AKONADIMAIN( IncidenceChangerTest, NoGUI )
447
#include "incidencechangertest.moc"