/** @short Check that the STATUS processing does not break offline "sync" */ void OfflineTest::testStatusVsExistsCached() { QString mailbox = QLatin1String("a"); // Push the data to the cache existsA = 10; uidNextA = 11; uidValidityA = 666; SyncState sync; sync.setExists(existsA); sync.setUidValidity(uidValidityA); sync.setUidNext(uidNextA); for (uint i = 1; i <= existsA; ++i) uidMapA << i; model->cache()->setMailboxSyncState(mailbox, sync); model->cache()->setUidMapping(mailbox, uidMapA); // Request the STATUS command to see how many messages are in there. This is not a synchronization, though // -- Trojita is *not* opening that mailbox, so the previously cached data remain. QCOMPARE(idxA.data(RoleTotalMessageCount).toInt(), 0); cClient(t.mk("STATUS a (MESSAGES UNSEEN RECENT)\r\n")); cServer("* STATUS a (MESSAGES 42 UNSEEN 2 RECENT 3)\r\n" + t.last("OK status\r\n")); QCOMPARE(idxA.data(RoleTotalMessageCount).toInt(), 42); LibMailboxSync::setModelNetworkPolicy(model, NETWORK_OFFLINE); cClient(t.mk("LOGOUT\r\n")); cServer(t.last("OK logged out\r\n") + "* BYE see ya\r\n"); model->resyncMailbox(idxA); for (int i = 0; i < 10; ++i) QCoreApplication::processEvents(); QCOMPARE(model->rowCount(msgListA), static_cast<int>(existsA)); helperVerifyUidMapA(); helperCheckCache(); }
/** @short Helper: verify that values recorded in the cache are valid */ void LibMailboxSync::helperCheckCache(bool ignoreUidNext) { using namespace Imap::Mailbox; // Check the cache SyncState syncState = model->cache()->mailboxSyncState(QLatin1String("a")); QCOMPARE(syncState.exists(), existsA); QCOMPARE(syncState.isUsableForSyncing(), true); if (!ignoreUidNext) { QCOMPARE(syncState.uidNext(), uidNextA); } QCOMPARE(syncState.uidValidity(), uidValidityA); QCOMPARE(model->cache()->uidMapping(QLatin1String("a")), uidMapA); QCOMPARE(static_cast<uint>(uidMapA.size()), existsA); SyncState ssFromTree = model->findMailboxByName(QLatin1String("a"))->syncState; SyncState ssFromCache = syncState; if (ignoreUidNext) { ssFromTree.setUidNext(0); ssFromCache.setUidNext(0); } QCOMPARE(ssFromCache, ssFromTree); if (model->isNetworkAvailable()) { // when offline, calling cEmpty would assert fail cEmpty(); } QVERIFY(errorSpy->isEmpty()); }
void Dispatcher::Did_SyncLog_StateChange_Execute(SyncStateMsgPtr stateMsg) { int size = stateMsg->state_size(); int index = 0; // iterate and fetch the actions for (; index < size; index++) { SyncState state = stateMsg->state(index); if (state.has_old_seq() && state.has_seq()) { uint64_t oldSeq = state.old_seq(); uint64_t newSeq = state.seq(); Name userName(reinterpret_cast<const unsigned char*>(state.name().c_str()), state.name().size()); // fetch actions with oldSeq + 1 to newSeq (inclusive) Name actionNameBase = Name("/")(userName)(CHRONOSHARE_APP)("action")(m_sharedFolder); m_actionFetcher->Enqueue(userName, actionNameBase, std::max<uint64_t>(oldSeq + 1, 1), newSeq, FetchManager::PRIORITY_HIGH); } } }
void SyncStateUpdater::UpdateSyncState(MojSignal<>::SlotRef slot, const SyncState& syncState, bool clearSyncState) { m_doneSignal.connect(slot); MojErr err; MojObject batchPayload; MojObject batchOperations; // Delete old sync state MojObject delPayload; MojDbQuery query; err = query.from(SyncStateAdapter::SYNC_STATE_KIND); ErrorToException(err); MojString capabilityProvider; capabilityProvider.assign(m_capabilityProvider.c_str()); err = query.where(SyncStateAdapter::CAPABILITY_PROVIDER, MojDbQuery::OpEq, capabilityProvider); ErrorToException(err); err = query.where(SyncStateAdapter::ACCOUNT_ID, MojDbQuery::OpEq, syncState.GetAccountId()); ErrorToException(err); err = query.where(SyncStateAdapter::COLLECTION_ID, MojDbQuery::OpEq, syncState.GetCollectionId()); ErrorToException(err); MojObject queryObj; err = query.toObject(queryObj); ErrorToException(err); err = delPayload.put("query", queryObj); ErrorToException(err); MojObject delOperation; err = delOperation.putString("method", "del"); ErrorToException(err); err = delOperation.put("params", delPayload); ErrorToException(err); err = batchOperations.push(delOperation); ErrorToException(err); if(!clearSyncState) { // Store new sync state MojObject putPayload; MojObject syncStateObj; SyncStateAdapter::SerializeToDatabaseObject(syncState, syncStateObj, m_capabilityProvider.c_str(), m_busAddress.c_str()); MojObject objects; err = objects.push(syncStateObj); ErrorToException(err); err = putPayload.put("objects", objects); ErrorToException(err); MojObject putOperation; err = putOperation.putString("method", "put"); ErrorToException(err); err = putOperation.put("params", putPayload); ErrorToException(err); err = batchOperations.push(putOperation); ErrorToException(err); } err = batchPayload.put("operations", batchOperations); ErrorToException(err); // Note: batch operations are not atomic, this is just for convenience and performance m_busClient.SendRequest(m_updateSlot, "com.palm.tempdb", "batch", batchPayload); }
/** @short Check that cached mailboxes do not send away STATUS when they are going to be immediately replaced anyway */ void ImapModelListChildMailboxesTest::testNoStatusForCachedItems() { using namespace Imap::Mailbox; // Remember two mailboxes model->cache()->setChildMailboxes(QString(), QList<MailboxMetadata>() << MailboxMetadata(QStringLiteral("a"), QStringLiteral("."), QStringList()) << MailboxMetadata(QStringLiteral("b"), QStringLiteral("."), QStringList()) ); // ... and the numbers for the first of them SyncState s; s.setExists(10); s.setRecent(1); s.setUnSeenCount(2); QVERIFY(s.isUsableForNumbers()); model->cache()->setMailboxSyncState(QStringLiteral("b"), s); // touch the network QCOMPARE(model->rowCount(QModelIndex()), 1); cClient(t.mk("LIST \"\" \"%\"\r\n")); // ...but the data gets refreshed from cache immediately QCOMPARE(model->rowCount(QModelIndex()), 3); // just settings up indexes idxA = model->index(1, 0, QModelIndex()); QVERIFY(idxA.isValid()); QCOMPARE(idxA.data(RoleMailboxName).toString(), QString::fromUtf8("a")); idxB = model->index(2, 0, QModelIndex()); QVERIFY(idxB.isValid()); QCOMPARE(idxB.data(RoleMailboxName).toString(), QString::fromUtf8("b")); // Request message counts; this should not lead to network activity even though the actual number // is not stored in the cache for mailbox "a", simply because the whole mailbox will get replaced // after the LIST finishes anyway QCOMPARE(idxA.data(RoleTotalMessageCount), QVariant()); QCOMPARE(idxA.data(RoleMailboxNumbersFetched).toBool(), false); QCOMPARE(idxB.data(RoleTotalMessageCount).toInt(), 10); QCOMPARE(idxB.data(RoleMailboxNumbersFetched).toBool(), false); cEmpty(); cServer("* LIST (\\HasNoChildren) \".\" a\r\n" "* LIST (\\HasNoChildren) \".\" b\r\n" + t.last("OK listed\r\n")); cEmpty(); // The mailboxes are replaced now -> rebuild the indexes QVERIFY(!idxA.isValid()); QVERIFY(!idxB.isValid()); idxA = model->index(1, 0, QModelIndex()); QVERIFY(idxA.isValid()); QCOMPARE(idxA.data(RoleMailboxName).toString(), QString::fromUtf8("a")); idxB = model->index(2, 0, QModelIndex()); QVERIFY(idxB.isValid()); QCOMPARE(idxB.data(RoleMailboxName).toString(), QString::fromUtf8("b")); // Ask for the numbers again QCOMPARE(idxA.data(RoleTotalMessageCount), QVariant()); QCOMPARE(idxB.data(RoleTotalMessageCount), QVariant()); QByteArray c1 = t.mk("STATUS a (MESSAGES UNSEEN RECENT)\r\n"); QByteArray r1 = t.last("OK status\r\n"); QByteArray c2 = t.mk("STATUS b (MESSAGES UNSEEN RECENT)\r\n"); QByteArray r2 = t.last("OK status\r\n"); cClient(c1 + c2); cServer("* STATUS a (MESSAGES 1 RECENT 2 UNSEEN 3)\r\n" "* STATUS b (MESSAGES 666 RECENT 33 UNSEEN 2)\r\n"); QCOMPARE(idxA.data(RoleTotalMessageCount).toInt(), 1); QCOMPARE(idxA.data(RoleMailboxNumbersFetched).toBool(), true); QCOMPARE(idxB.data(RoleTotalMessageCount).toInt(), 666); QCOMPARE(idxB.data(RoleMailboxNumbersFetched).toBool(), true); QCOMPARE(model->cache()->mailboxSyncState(QLatin1String("a")).unSeenCount(), 3u); QCOMPARE(model->cache()->mailboxSyncState(QLatin1String("a")).recent(), 2u); // the "EXISTS" is missing, though QVERIFY(!model->cache()->mailboxSyncState(QLatin1String("a")).isUsableForNumbers()); QCOMPARE(model->cache()->mailboxSyncState(QLatin1String("b")).unSeenCount(), 2u); QCOMPARE(model->cache()->mailboxSyncState(QLatin1String("b")).recent(), 33u); // The mailbox state for mailbox "b" must be preserved QCOMPARE(model->cache()->mailboxSyncState(QLatin1String("b")).exists(), 10u); QVERIFY(model->cache()->mailboxSyncState(QLatin1String("b")).isUsableForNumbers()); cServer(r2 + r1); cEmpty(); }