TestingSyncSource+CalDAV: added "delete all" API call
During testing, removing all items is done via a special call in TestingSyncSource. It used to be an utility method which fell back to the normal SyncSource API. This patch changes several things - Reversed order in which items are deleted in that utility method, because removing children (= longer IDs) first tends to be supported better by servers (bug in CalDAV server, but still...). - Allow backends to implement their own removeAllItems(). - Implement that in CalDAV + MapSyncSource as removing the merged items directly, instead of using a sequence of PUT+final DELETE. Found while testing with Bedework CalDAV server. Makes testing more robust and efficient.
This commit is contained in:
parent
a7f7c8eacf
commit
765ed0f833
|
@ -858,6 +858,48 @@ std::string CalDAVSource::removeSubItem(const string &davLUID, const std::string
|
|||
}
|
||||
}
|
||||
|
||||
void CalDAVSource::removeMergedItem(const std::string &davLUID)
|
||||
{
|
||||
EventCache::iterator it = m_cache.find(davLUID);
|
||||
if (it == m_cache.end()) {
|
||||
// gone already, no need to do anything
|
||||
SE_LOG_DEBUG(this, NULL, "%s: ignoring request to delete non-existent item",
|
||||
davLUID.c_str());
|
||||
return;
|
||||
}
|
||||
// use item as it is, load only if it is not going to be removed entirely
|
||||
Event &event = *it->second;
|
||||
|
||||
// remove entire merged item, nothing will be left after removal
|
||||
try {
|
||||
removeItem(event.m_DAVluid);
|
||||
} catch (const TransportStatusException &ex) {
|
||||
if (ex.syncMLStatus() == 404) {
|
||||
// Someone must have created a detached recurrence on
|
||||
// the server without the master event - or the
|
||||
// item was already removed while the sync ran.
|
||||
// Let's log the problem and ignore it.
|
||||
Exception::log();
|
||||
} else if (ex.syncMLStatus() == 409 &&
|
||||
strstr(ex.what(), "Can't delete a recurring event")) {
|
||||
// Google CalDAV:
|
||||
// HTTP/1.1 409 Can't delete a recurring event except on its organizer's calendar
|
||||
//
|
||||
// Workaround: use the workarounds from removeSubItem()
|
||||
std::set<std::string> subids = event.m_subids;
|
||||
for (std::set<std::string>::reverse_iterator it = subids.rbegin();
|
||||
it != subids.rend();
|
||||
++it) {
|
||||
removeSubItem(davLUID, *it);
|
||||
}
|
||||
} else {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
m_cache.erase(davLUID);
|
||||
}
|
||||
|
||||
void CalDAVSource::flushItem(const string &davLUID)
|
||||
{
|
||||
// TODO: currently we always flush immediately, so no need to send data here
|
||||
|
|
|
@ -42,6 +42,7 @@ class CalDAVSource : public WebDAVSource,
|
|||
const std::string &item);
|
||||
virtual void readSubItem(const std::string &uid, const std::string &subid, std::string &item);
|
||||
virtual std::string removeSubItem(const string &uid, const std::string &subid);
|
||||
virtual void removeMergedItem(const std::string &luid);
|
||||
virtual void flushItem(const string &uid);
|
||||
virtual std::string getSubDescription(const string &uid, const string &subid);
|
||||
|
||||
|
|
|
@ -351,4 +351,13 @@ std::pair<std::string, std::string> MapSyncSource::splitLUID(const std::string &
|
|||
|
||||
StringEscape MapSyncSource::m_escape('%', "/");
|
||||
|
||||
void MapSyncSource::removeAllItems()
|
||||
{
|
||||
BOOST_FOREACH(const SubRevisionMap_t::value_type &entry,
|
||||
m_revisions) {
|
||||
m_sub->removeMergedItem(entry.first);
|
||||
}
|
||||
m_revisions.clear();
|
||||
}
|
||||
|
||||
SE_END_CXX
|
||||
|
|
|
@ -166,6 +166,11 @@ class SubSyncSource : virtual public SyncSourceBase
|
|||
*/
|
||||
virtual std::string removeSubItem(const string &mainid, const std::string &subid) = 0;
|
||||
|
||||
/**
|
||||
* Remove all sub-items belonging to mainid.
|
||||
*/
|
||||
virtual void removeMergedItem(const std::string &mainid) = 0;
|
||||
|
||||
/**
|
||||
* Called whenever this class thinks that the item may no longer be
|
||||
* needed. Might be wrong...
|
||||
|
@ -265,6 +270,9 @@ class MapSyncSource :
|
|||
virtual std::string getDescription(sysync::KeyH aItemKey) { return dynamic_cast<SyncSourceLogging &>(*m_sub).getDescription(aItemKey); }
|
||||
virtual std::string getDescription(const string &luid);
|
||||
|
||||
/* TestingSyncSource */
|
||||
virtual void removeAllItems();
|
||||
|
||||
private:
|
||||
boost::shared_ptr<SubSyncSource> m_sub;
|
||||
/** escape / in uid with %2F, so that splitMainIDValue() and splitLUID() can use / as separator */
|
||||
|
|
|
@ -1388,5 +1388,20 @@ void SyncSourceBlob::init(SyncSource::Operations &ops,
|
|||
_1, _2);
|
||||
}
|
||||
|
||||
void TestingSyncSource::removeAllItems()
|
||||
{
|
||||
// remove longest luids first:
|
||||
// for luid=UID[+RECURRENCE-ID] that will
|
||||
// remove children from a merged event first,
|
||||
// which is better supported by certain servers
|
||||
Items_t items = getAllItems();
|
||||
for (Items_t::reverse_iterator it = items.rbegin();
|
||||
it != items.rend();
|
||||
++it) {
|
||||
deleteItem(*it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SE_END_CXX
|
||||
|
||||
|
|
|
@ -2081,11 +2081,7 @@ class TestingSyncSource : public SyncSource,
|
|||
|
||||
virtual SourceType getSourceType() const { return SyncSourceConfig::getSourceType(); }
|
||||
|
||||
void removeAllItems() {
|
||||
BOOST_FOREACH(const string &luid, getAllItems()) {
|
||||
deleteItem(luid);
|
||||
}
|
||||
}
|
||||
virtual void removeAllItems();
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue