Transaction handling and duplicates
-----------------------------------

This tests transaction handling when indexing in Solr, or more specifically
properly aborting a transaction.  To do this we'll try to create some content
and fake a `ConflictError` shortly before the transaction completes.  The
publisher will catch it and retry, but while doing so the object will get a
different UID than the first time.  Without being able to abort the
transaction Solr would receive two sets of data and consequently return two
results when searching for this particular piece of content later on.

We'll use a testbrowser test this, but first we need to activate Solr support
and reindex the site's content:

  >>> from collective.solr.testing import activateAndReindex
  >>> from plone.app.testing import TEST_USER_ID
  >>> from plone.app.testing import TEST_USER_NAME
  >>> from plone.app.testing import TEST_USER_PASSWORD
  >>> from plone.app.testing import setRoles
  >>> from plone.testing.z2 import Browser
  >>> from transaction import commit
  >>> setRoles(layer['portal'], TEST_USER_ID, ['Manager'])
  >>> commit()
  >>> browser = Browser(layer['app'])
  >>> browser.open('http://nohost/plone/login_form')
  >>> browser.getControl(name='__ac_name').value = TEST_USER_NAME
  >>> browser.getControl(name='__ac_password').value = TEST_USER_PASSWORD
  >>> browser.getControl(name='submit').click()

  >>> activateAndReindex(layer['portal'])
  >>> commit()
  >>> browser.open('http://nohost/plone/')
  >>> browser.getLink('Page').click()
  >>> browser.getControl('Title').value = 'Foo'

Before we actually click "Save" in order to create the content, we need to
add a monkey-patch which will raise the `ConflictError` we'd like to see.  We
also keep track of the generated UIDs in order to make sure the exception was
indeed raised:

  >>> uids = []
  >>> from ZODB.POSException import ConflictError
  >>> from Products.Archetypes.BaseObject import BaseObject
  >>> original = BaseObject.at_post_create_script
  >>> def at_post_create_script(self):
  ...   first = not bool(uids)
  ...   uids.append(self.UID())
  ...   if first:
  ...     raise ConflictError()   # trigger a retry (once)
  >>> BaseObject.at_post_create_script = at_post_create_script
  >>> from App.config import getConfiguration
  >>> getConfiguration().conflict_error_log_level = 0

Now we go ahead and actually create the content item, after which we can check
Solr's index by searching for the title:

  >>> browser.getControl('Save').click()

  >>> len(uids)
  2
  >>> from collective.solr.dispatcher import solrSearchResults
  >>> len(solrSearchResults(SearchableText='Foo'))
  1

In the end we need to clean up our changes to avoid having ill effects on
other tests:

  >>> BaseObject.at_post_create_script = original   # remove the monkey
