def test_redirect_suppression(self): """The document view shouldn't redirect when passed redirect=no.""" redirect, _ = doc_rev('REDIRECT [[http://smoo/]]') response = self.client.get( redirect.get_absolute_url() + '?redirect=no', follow=True) self.assertContains(response, 'REDIRECT ')
def test_form_save_section(self): d, r = doc_rev( """ <h1 id="s1">s1</h1> <p>test</p> <p>test</p> <h1 id="s2">s2</h1> <p>test</p> <p>test</p> <h1 id="s3">s3</h1> <p>test</p> <p>test</p> """ ) replace_content = """ <h1 id="s2">New stuff</h1> <p>new stuff</p> """ expected = """ <h1 id="s1">s1</h1> <p>test</p> <p>test</p> <h1 id="s2">New stuff</h1> <p>new stuff</p> <h1 id="s3">s3</h1> <p>test</p> <p>test</p> """ rev_form = RevisionForm({"content": replace_content}, instance=r, section_id="s2") new_rev = rev_form.save(r.creator, d) eq_(normalize_html(expected), normalize_html(new_rev.content))
def test_raw_section_source(self): """The raw source for a document section can be requested""" client = LocalizingClient() client.login(username='******', password='******') d, r = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) expected = """ <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> """ response = client.get('%s?section=s2&raw=true' % reverse('wiki.document', args=[d.slug])) eq_(normalize_html(expected), normalize_html(response.content))
def test_form_loaded_with_section(self): """RevisionForm given section_id should load initial content for only one section""" d, r = doc_rev( """ <h1 id="s1">s1</h1> <p>test</p> <p>test</p> <h1 id="s2">s2</h1> <p>test</p> <p>test</p> <h1 id="s3">s3</h1> <p>test</p> <p>test</p> """ ) expected = """ <h1 id="s2">s2</h1> <p>test</p> <p>test</p> """ rev_form = RevisionForm(instance=r, section_id="s2") eq_(normalize_html(expected), normalize_html(rev_form.initial["content"]))
def test_raw_with_editing_links_source(self): """The raw source for a document can be requested, with section editing links""" client = LocalizingClient() client.login(username='******', password='******') d, r = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) expected = """ <h1 id="s1"><a class="edit-section" data-section-id="s1" data-section-src-url="/en-US/docs/%(slug)s?raw=true&section=s1" href="/en-US/docs/%(slug)s$edit?section=s1&edit_links=true" title="Edit section">Edit</a>Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2"><a class="edit-section" data-section-id="s2" data-section-src-url="/en-US/docs/%(slug)s?raw=true&section=s2" href="/en-US/docs/%(slug)s$edit?section=s2&edit_links=true" title="Edit section">Edit</a>Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3"><a class="edit-section" data-section-id="s3" data-section-src-url="/en-US/docs/%(slug)s?raw=true&section=s3" href="/en-US/docs/%(slug)s$edit?section=s3&edit_links=true" title="Edit section">Edit</a>Head 3</h1> <p>test</p> <p>test</p> """ % {'slug': d.slug} response = client.get('%s?raw=true&edit_links=true' % reverse('wiki.document', args=[d.slug])) eq_(normalize_html(expected), normalize_html(response.content))
def setUp(self): super(DeferredRenderingTests, self).setUp() self.rendered_content = 'THIS IS RENDERED' self.raw_content = 'THIS IS NOT RENDERED CONTENT' self.d1, self.r1 = doc_rev('Doc 1') constance.config.KUMA_DOCUMENT_RENDER_TIMEOUT = 600.0 constance.config.KUMA_DOCUMENT_FORCE_DEFERRED_TIMEOUT = 7.0
def test_form_onload_attr_filter(self): """RevisionForm should strip out any harmful onload attributes from input markup""" d, r = doc_rev(""" <svg><circle onload=confirm(3)> """) rev_form = RevisionForm(instance=r) ok_('onload' not in rev_form.initial['content'])
def test_unapproved_revision_not_updates_html(self): """Creating an unapproved revision does not update document.html""" d, _ = doc_rev('Here to stay') assert 'Here to stay' in d.html, '"Here to stay" not in %s' % d.html # Creating another approved revision keeps initial content r = revision(document=d, content='Fail to replace html') r.save() assert 'Here to stay' in d.html, '"Here to stay" not in %s' % d.html
def test_approved_revision_updates_html(self): """Creating an approved revision updates document.html""" d, _ = doc_rev("Replace document html") assert "Replace document html" in d.html, '"Replace document html" not in %s' % d.html # Creating another approved revision replaces it again r = revision(document=d, content="Replace html again", is_approved=True) r.save() assert "Replace html again" in d.html, '"Replace html again" not in %s' % d.html
def test_retitling(self): """When the title of an article is edited, a redirect is made.""" # Not testing slug changes separately; the model tests cover those plus # slug+title changes. If title changes work in the view, the rest # should also. new_title = "Some New Title" d, r = doc_rev() old_title = d.title data = new_document_data() data.update({"title": new_title, "slug": d.slug, "form": "doc"}) self.client.post(reverse("wiki.edit_document", args=[d.slug]), data) eq_(new_title, Document.uncached.get(slug=d.slug).title) assert Document.uncached.get(title=old_title).redirect_url()
def test_changing_products(self): """Changing products works as expected.""" d, r = doc_rev() data = new_document_data() data.update({'products': ['desktop', 'sync'], 'form': 'doc'}) self.client.post(reverse('wiki.edit_document', args=[d.slug]), data) tags_eq(d, ['desktop', 'sync']) data.update({'products': ['mobile'], 'form': 'doc'}) self.client.post(reverse('wiki.edit_document', args=[data['slug']]), data) tags_eq(d, ['mobile'])
def test_changing_products(self): """Changing products works as expected.""" client = LocalizingClient() client.login(username='******', password='******') d, r = doc_rev() data = new_document_data() data.update({'products': ['desktop', 'sync'], 'form': 'doc'}) client.post(reverse('wiki.edit_document', args=[d.slug]), data) tags_eq(d, ['desktop', 'sync']) data.update({'products': ['mobile'], 'form': 'doc'}) client.post(reverse('wiki.edit_document', args=[data['slug']]), data) tags_eq(d, ['mobile'])
def test_retitling_ignored_for_iframe(self): """When the title of an article is edited in an iframe, the change is ignored.""" client = LocalizingClient() client.login(username='******', password='******') new_title = 'Some New Title' d, r = doc_rev() old_title = d.title data = new_document_data() data.update({'title': new_title, 'slug': d.slug, 'form': 'rev'}) client.post('%s?iframe=1' % reverse('wiki.edit_document', args=[d.slug]), data) eq_(old_title, Document.uncached.get(slug=d.slug).title) assert "REDIRECT" not in Document.uncached.get(title=old_title).html
def test_raw_section_edit(self): client = LocalizingClient() client.login(username='******', password='******') d, r = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) replace = """ <h1 id="s2">Replace</h1> <p>replace</p> """ expected = """ <h1 id="s2">Replace</h1> <p>replace</p> """ response = client.post('%s?section=s2&raw=true' % reverse('wiki.edit_document', args=[d.slug]), {"form": "rev", "content": replace}, follow=True) eq_(normalize_html(expected), normalize_html(response.content)) expected = """ <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Replace</h1> <p>replace</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """ response = client.get('%s?raw=true' % reverse('wiki.document', args=[d.slug])) eq_(normalize_html(expected), normalize_html(response.content))
def test_show_toc(self): """Setting show_toc appropriately affects the Document's show_toc property.""" d, r = doc_rev('Toggle table of contents.') assert r.show_toc assert d.show_toc r = revision(document=d, content=r.content, show_toc=False, is_approved=True) r.save() assert not d.show_toc r = revision(document=d, content=r.content, show_toc=True, is_approved=True) r.save() assert d.show_toc
def test_retitling(self): """When the title of an article is edited, a redirect is made.""" # Not testing slug changes separately; the model tests cover those plus # slug+title changes. If title changes work in the view, the rest # should also. client = LocalizingClient() client.login(username='******', password='******') new_title = 'Some New Title' d, r = doc_rev() old_title = d.title data = new_document_data() data.update({'title': new_title, 'slug': d.slug, 'form': 'doc'}) client.post(reverse('wiki.edit_document', args=[d.slug]), data) eq_(new_title, Document.uncached.get(slug=d.slug).title) assert Document.uncached.get(title=old_title).redirect_url()
def test_changing_metadata(self): """Changing metadata works as expected.""" client = LocalizingClient() client.login(username='******', password='******') d, r = doc_rev() data = new_document_data() data.update({'firefox_versions': [1, 2, 3], 'operating_systems': [1, 3], 'form': 'doc'}) client.post(reverse('wiki.edit_document', args=[d.slug]), data) eq_(3, d.firefox_versions.count()) eq_(2, d.operating_systems.count()) data.update({'firefox_versions': [1, 2], 'operating_systems': [2], 'form': 'doc'}) client.post(reverse('wiki.edit_document', args=[data['slug']]), data) eq_(2, d.firefox_versions.count()) eq_(1, d.operating_systems.count())
def test_revert(self): """Reverting to a specific revision.""" d, r = doc_rev('Test reverting') old_id = r.id time.sleep(1) r2 = revision(document=d, title='Test reverting', content='An edit to revert', comment='This edit gets reverted', is_approved=True) r.save() time.sleep(1) reverted = d.revert(r, r.creator) ok_('Revert to' in reverted.comment) ok_('Test reverting' == reverted.content) ok_(old_id != reverted.id)
def test_revision_tags(self): """Change tags on Document by creating Revisions""" d, _ = doc_rev('Sample document') eq_(0, Document.objects.filter(tags__name='foo').count()) eq_(0, Document.objects.filter(tags__name='alpha').count()) r = revision(document=d, content='Update to document', is_approved=True, tags="foo, bar, baz") r.save() eq_(1, Document.objects.filter(tags__name='foo').count()) eq_(0, Document.objects.filter(tags__name='alpha').count()) r = revision(document=d, content='Another update', is_approved=True, tags="alpha, beta, gamma") r.save() eq_(0, Document.objects.filter(tags__name='foo').count()) eq_(1, Document.objects.filter(tags__name='alpha').count())
def test_changing_products(self): """Changing products works as expected.""" d, r = doc_rev() prod_desktop = product(title=u"desktop", save=True) prod_mobile = product(title=u"mobile", save=True) data = new_document_data() data.update({"products": [prod_desktop.id, prod_mobile.id], "title": d.title, "slug": d.slug, "form": "doc"}) self.client.post(reverse("wiki.edit_document", args=[d.slug]), data) eq_( sorted(Document.uncached.get(slug=d.slug).products.values_list("id", flat=True)), sorted([prod.id for prod in [prod_desktop, prod_mobile]]), ) data.update({"products": [prod_desktop.id], "form": "doc"}) self.client.post(reverse("wiki.edit_document", args=[data["slug"]]), data) eq_( sorted(Document.uncached.get(slug=d.slug).products.values_list("id", flat=True)), sorted([prod.id for prod in [prod_desktop]]), )
def test_trans_lock_workflow(self): """End to end test of locking on a translated document.""" doc, _ = doc_rev() u = user(save=True, password='******') # Create a new translation of doc() using the translation view self.client.login(username=u.username, password='******') trans_url = reverse('wiki.translate', locale='es', args=[doc.slug]) data = { 'title': 'Un Test Articulo', 'slug': 'un-test-articulo', 'keywords': 'keyUno, keyDos, keyTres', 'summary': 'lipsumo', 'content': 'loremo ipsumo doloro sito ameto'} r = self.client.post(trans_url, data) eq_(r.status_code, 302) # Now run the test. edit_url = reverse('wiki.edit_document', locale='es', args=[data['slug']]) es_doc = Document.objects.get(slug=data['slug']) eq_(es_doc.locale, 'es') self._lock_workflow(es_doc, edit_url)
def test_trans_lock_workflow(self): """End to end test of locking on a translated document.""" doc, _ = doc_rev() u = user(save=True, password="******") # Create a new translation of doc() using the translation view self.client.login(username=u.username, password="******") trans_url = reverse("wiki.translate", locale="es", args=[doc.slug]) data = { "title": "Un Test Articulo", "slug": "un-test-articulo", "keywords": "keyUno, keyDos, keyTres", "summary": "lipsumo", "content": "loremo ipsumo doloro sito ameto", } r = self.client.post(trans_url, data) eq_(r.status_code, 302) # Now run the test. edit_url = reverse("wiki.edit_document", locale="es", args=[data["slug"]]) es_doc = Document.objects.get(slug=data["slug"]) eq_(es_doc.locale, "es") self._lock_workflow(es_doc, edit_url)
def test_changing_products(self): """Changing products works as expected.""" d, r = doc_rev() prod_desktop = product(title=u'desktop', save=True) prod_mobile = product(title=u'mobile', save=True) data = new_document_data() data.update({'products': [prod_desktop.id, prod_mobile.id], 'title': d.title, 'slug': d.slug, 'form': 'doc'}) self.client.post(reverse('wiki.edit_document', args=[d.slug]), data) eq_(sorted(Document.uncached.get(slug=d.slug).products.values_list( 'id', flat=True)), sorted([prod.id for prod in [prod_desktop, prod_mobile]])) data.update({'products': [prod_desktop.id], 'form': 'doc'}) self.client.post(reverse('wiki.edit_document', args=[data['slug']]), data) eq_(sorted(Document.uncached.get(slug=d.slug).products.values_list( 'id', flat=True)), sorted([prod.id for prod in [prod_desktop]]))
def test_revision_unicode(self): """Revision containing unicode characters is saved successfully.""" str = u'Firefox informa\xe7\xf5es \u30d8\u30eb' _, r = doc_rev(str) eq_(str, r.content)
def setUp(self): self.d, self.r = doc_rev() self.old_title = self.d.title self.old_slug = self.d.slug
def test_link_annotation(self): d, r = doc_rev("This document exists") d.save() r.save() d2 = document(title=u"Héritée", locale=u"fr", slug=u"CSS/Héritage", save=True) base_url = u"http://testserver/" vars = dict( base_url=base_url, exist_url=d.get_absolute_url(), exist_url_with_base=urljoin(base_url, d.get_absolute_url()), uilocale_url=u"/en-US/docs/%s/%s" % (d.locale, d.slug), noexist_url=u"/en-US/docs/no-such-doc", noexist_url_with_base=urljoin(base_url, u"/en-US/docs/no-such-doc"), noexist_uilocale_url=u"/en-US/docs/en-US/blah-blah-blah", nonen_slug="/fr/docs/CSS/H%c3%a9ritage", tag_url="/en-US/docs/tag/foo", feed_url="/en-US/docs/feeds/atom/all", templates_url="/en-US/docs/templates", ) doc_src = ( u""" <li><a href="%(nonen_slug)s">Héritée</a></li> <li><a href="%(exist_url)s">This doc should exist</a></li> <li><a href="%(exist_url)s#withanchor">This doc should exist</a></li> <li><a href="%(exist_url_with_base)s">This doc should exist</a></li> <li><a href="%(exist_url_with_base)s#withanchor">This doc should exist</a></li> <li><a href="%(uilocale_url)s">This doc should exist</a></li> <li><a class="foobar" href="%(exist_url)s">This doc should exist, and its class should be left alone.</a></li> <li><a href="%(noexist_url)s#withanchor">This doc should NOT exist</a></li> <li><a href="%(noexist_url)s">This doc should NOT exist</a></li> <li><a href="%(noexist_url_with_base)s">This doc should NOT exist</a></li> <li><a href="%(noexist_url_with_base)s#withanchor">This doc should NOT exist</a></li> <li><a href="%(noexist_uilocale_url)s">This doc should NOT exist</a></li> <li><a class="foobar" href="%(noexist_url)s">This doc should NOT exist, and its class should be altered</a></li> <li><a href="http://mozilla.org/">This is an external link</a></li> <li><a class="foobar" name="quux">A lack of href should not cause a problem.</a></li> <li><a>In fact, a "link" with no attributes should be no problem as well.</a></li> <a href="%(tag_url)s">Tag link</a> <a href="%(feed_url)s">Feed link</a> <a href="%(templates_url)s">Templates link</a> """ % vars ) expected = ( u""" <li><a href="%(nonen_slug)s">Héritée</a></li> <li><a href="%(exist_url)s">This doc should exist</a></li> <li><a href="%(exist_url)s#withanchor">This doc should exist</a></li> <li><a href="%(exist_url_with_base)s">This doc should exist</a></li> <li><a href="%(exist_url_with_base)s#withanchor">This doc should exist</a></li> <li><a href="%(uilocale_url)s">This doc should exist</a></li> <li><a class="foobar" href="%(exist_url)s">This doc should exist, and its class should be left alone.</a></li> <li><a class="new" href="%(noexist_url)s#withanchor">This doc should NOT exist</a></li> <li><a class="new" href="%(noexist_url)s">This doc should NOT exist</a></li> <li><a class="new" href="%(noexist_url_with_base)s">This doc should NOT exist</a></li> <li><a class="new" href="%(noexist_url_with_base)s#withanchor">This doc should NOT exist</a></li> <li><a class="new" href="%(noexist_uilocale_url)s">This doc should NOT exist</a></li> <li><a class="foobar new" href="%(noexist_url)s">This doc should NOT exist, and its class should be altered</a></li> <li><a class="external" href="http://mozilla.org/">This is an external link</a></li> <li><a class="foobar" name="quux">A lack of href should not cause a problem.</a></li> <li><a>In fact, a "link" with no attributes should be no problem as well.</a></li> <a href="%(tag_url)s">Tag link</a> <a href="%(feed_url)s">Feed link</a> <a href="%(templates_url)s">Templates link</a> """ % vars ) # Split the markup into lines, to better see failures doc_lines = doc_src.strip().split("\n") expected_lines = expected.strip().split("\n") for idx in range(0, len(doc_lines)): doc_line = doc_lines[idx] expected_line = expected_lines[idx] result_line = wiki.content.parse(doc_line).annotateLinks(base_url=vars["base_url"]).serialize() eq_(normalize_html(expected_line), normalize_html(result_line))
def test_link_annotation(self): d, r = doc_rev("This document exists") d.save() r.save() d2 = document(title=u'Héritée', locale=u'fr', slug=u'CSS/Héritage', save=True) base_url = u'http://testserver/' vars = dict( base_url=base_url, exist_url=d.get_absolute_url(), exist_url_with_base=urljoin(base_url, d.get_absolute_url()), uilocale_url=u'/en-US/docs/%s/%s' % (d.locale, d.slug), noexist_url=u'/en-US/docs/no-such-doc', noexist_url_with_base=urljoin(base_url, u'/en-US/docs/no-such-doc'), noexist_uilocale_url=u'/en-US/docs/en-US/blah-blah-blah', nonen_slug='/fr/docs/CSS/H%c3%a9ritage', ) doc_src = u""" <li><a href="%(nonen_slug)s">Héritée</a></li> <li><a href="%(exist_url)s">This doc should exist</a></li> <li><a href="%(exist_url)s#withanchor">This doc should exist</a></li> <li><a href="%(exist_url_with_base)s">This doc should exist</a></li> <li><a href="%(exist_url_with_base)s#withanchor">This doc should exist</a></li> <li><a href="%(uilocale_url)s">This doc should exist</a></li> <li><a class="foobar" href="%(exist_url)s">This doc should exist, and its class should be left alone.</a></li> <li><a href="%(noexist_url)s#withanchor">This doc should NOT exist</a></li> <li><a href="%(noexist_url)s">This doc should NOT exist</a></li> <li><a href="%(noexist_url_with_base)s">This doc should NOT exist</a></li> <li><a href="%(noexist_url_with_base)s#withanchor">This doc should NOT exist</a></li> <li><a href="%(noexist_uilocale_url)s">This doc should NOT exist</a></li> <li><a class="foobar" href="%(noexist_url)s">This doc should NOT exist, and its class should be altered</a></li> <li><a href="http://mozilla.org/">This is an external link</a></li> <li><a class="foobar" name="quux">A lack of href should not cause a problem.</a></li> <li><a>In fact, a "link" with no attributes should be no problem as well.</a></li> """ % vars expected = u""" <li><a href="%(nonen_slug)s">Héritée</a></li> <li><a href="%(exist_url)s">This doc should exist</a></li> <li><a href="%(exist_url)s#withanchor">This doc should exist</a></li> <li><a href="%(exist_url_with_base)s">This doc should exist</a></li> <li><a href="%(exist_url_with_base)s#withanchor">This doc should exist</a></li> <li><a href="%(uilocale_url)s">This doc should exist</a></li> <li><a class="foobar" href="%(exist_url)s">This doc should exist, and its class should be left alone.</a></li> <li><a class="new" href="%(noexist_url)s#withanchor">This doc should NOT exist</a></li> <li><a class="new" href="%(noexist_url)s">This doc should NOT exist</a></li> <li><a class="new" href="%(noexist_url_with_base)s">This doc should NOT exist</a></li> <li><a class="new" href="%(noexist_url_with_base)s#withanchor">This doc should NOT exist</a></li> <li><a class="new" href="%(noexist_uilocale_url)s">This doc should NOT exist</a></li> <li><a class="foobar new" href="%(noexist_url)s">This doc should NOT exist, and its class should be altered</a></li> <li><a class="external" href="http://mozilla.org/">This is an external link</a></li> <li><a class="foobar" name="quux">A lack of href should not cause a problem.</a></li> <li><a>In fact, a "link" with no attributes should be no problem as well.</a></li> """ % vars # Split the markup into lines, to better see failures doc_lines = doc_src.strip().split("\n") expected_lines = expected.strip().split("\n") for idx in range(0, len(doc_lines)): doc_line = doc_lines[idx] expected_line = expected_lines[idx] result_line = (wiki.content.parse(doc_line).annotateLinks( base_url=vars['base_url']).serialize()) eq_(normalize_html(expected_line), normalize_html(result_line))
def test_revision_unicode(self): """Revision containing unicode characters is saved successfully.""" str = u' \r\nFirefox informa\xe7\xf5es \u30d8\u30eb' _, r = doc_rev(str) eq_(str, r.content)
def test_midair_section_merge(self): """If a page was changed while someone was editing, but the changes didn't affect the specific section being edited, then ignore the midair warning""" client = LocalizingClient() client.login(username='******', password='******') doc, rev = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) replace_1 = """ <h1 id="s1">replace</h1> <p>replace</p> """ replace_2 = """ <h1 id="s2">replace</h1> <p>replace</p> """ expected = """ <h1 id="s1">replace</h1> <p>replace</p> <h1 id="s2">replace</h1> <p>replace</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """ data = {'form': 'rev', 'content': rev.content} # Edit #1 starts... resp = client.get('%s?section=s1' % reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id1 = page.find('input[name="current_rev"]').attr('value') # Edit #2 starts... resp = client.get('%s?section=s2' % reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id2 = page.find('input[name="current_rev"]').attr('value') # Edit #2 submits successfully data.update({ 'form': 'rev', 'content': replace_2, 'current_rev': rev_id2 }) resp = client.post( '%s?section=s2&raw=true' % reverse('wiki.edit_document', args=[doc.slug]), data) eq_(302, resp.status_code) # Edit #1 submits, but since it's a different section, there's no # mid-air collision data.update({ 'form': 'rev', 'content': replace_1, 'current_rev': rev_id1 }) resp = client.post( '%s?section=s1&raw=true' % reverse('wiki.edit_document', args=[doc.slug]), data) # No conflict, but we should get a 205 Reset as an indication that the # page needs a refresh. eq_(205, resp.status_code) # Finally, make sure that all the edits landed response = client.get('%s?raw=true' % reverse('wiki.document', args=[doc.slug])) eq_(normalize_html(expected), normalize_html(response.content)) # Also, ensure that the revision is slipped into the headers eq_(unicode(Document.uncached.get(slug=doc.slug).current_revision.id), unicode(response['x-kuma-revision']))
def test_roundtrip(self): # Create some documents and revisions here, rather than use a fixture d1, r1 = doc_rev('Doc 1') d2, r2 = doc_rev('Doc 2') d3, r3 = doc_rev('Doc 3') d4, r4 = doc_rev('Doc 4') d5, r5 = doc_rev('Doc 5') # Since this happens in dev sometimes, break a doc by deleting its # current revision and leaving it with none. d5.current_revision = None d5.save() r5.delete() # The same creator will be used for all the revs, so let's also get a # non-creator user for the upload. creator = r1.creator uploader = User.objects.exclude(pk=creator.id).all()[0] # Count docs (with revisions) and revisions in DB doc_cnt_db = (Document.objects .filter(current_revision__isnull=False) .count()) rev_cnt_db = (Revision.objects.count()) # Do the dump, capture it, parse the JSON fin = StringIO() Document.objects.dump_json(Document.objects.all(), fin) data_json = fin.getvalue() data = json.loads(data_json) # No objects should come with non-null primary keys for x in data: ok_(not x['pk']) # Count the documents in JSON vs the DB doc_cnt_json = len([x for x in data if x['model'] == 'wiki.document']) eq_(doc_cnt_db, doc_cnt_json, "DB and JSON document counts should match") # Count the revisions in JSON vs the DB rev_cnt_json = len([x for x in data if x['model'] == 'wiki.revision']) eq_(rev_cnt_db, rev_cnt_json, "DB and JSON revision counts should match") # For good measure, ensure no documents missing revisions in the dump. doc_no_rev = (Document.objects .filter(current_revision__isnull=True))[0] no_rev_cnt = len([x for x in data if x['model'] == 'wiki.document' and x['fields']['slug'] == doc_no_rev.slug and x['fields']['locale'] == doc_no_rev.locale]) eq_(0, no_rev_cnt, "There should be no document exported without revision") # Upload the data as JSON, assert that all objects were loaded loaded_cnt = Document.objects.load_json(uploader, StringIO(data_json)) eq_(len(data), loaded_cnt) # Ensure the current revisions of the documents have changed, and that # the creator matches the uploader. for d_orig in (d1, d2, d3, d4): d_curr = Document.uncached.get(pk=d_orig.pk) eq_(2, d_curr.revisions.count()) ok_(d_orig.current_revision.id != d_curr.current_revision.id) ok_(d_orig.current_revision.creator_id != d_curr.current_revision.creator_id) eq_(uploader.id, d_curr.current_revision.creator_id) # Everyone out of the pool! Document.objects.all().delete() Revision.objects.all().delete() # Try reloading the data on an empty DB loaded_cnt = Document.objects.load_json(uploader, StringIO(data_json)) eq_(len(data), loaded_cnt) # Count docs (with revisions) and revisions in DB. The imported objects # should have beeen doc/rev pairs. eq_(loaded_cnt / 2, Document.objects.count()) eq_(loaded_cnt / 2, Revision.objects.count()) # The originals should be gone, now. for d_orig in (d1, d2, d3, d4): # The original primary key should have gone away. try: d_curr = Document.uncached.get(pk=d_orig.pk) ok_(False, "This should have been an error") except Document.DoesNotExist: pass # Should be able to fetch document with the original natural key key = d_orig.natural_key() d_curr = Document.objects.get_by_natural_key(*key) eq_(1, d_curr.revisions.count()) eq_(uploader.id, d_curr.current_revision.creator_id)
def test_midair_section_collision(self): """If both a revision and the edited section has changed, then a section edit is a collision.""" client = LocalizingClient() client.login(username='******', password='******') doc, rev = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) replace_1 = """ <h1 id="s2">replace</h1> <p>replace</p> """ replace_2 = """ <h1 id="s2">first replace</h1> <p>first replace</p> """ data = { 'form': 'rev', 'content': rev.content } # Edit #1 starts... resp = client.get('%s?section=s2' % reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id1 = page.find('input[name="current_rev"]').attr('value') # Edit #2 starts... resp = client.get('%s?section=s2' % reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id2 = page.find('input[name="current_rev"]').attr('value') # Edit #2 submits successfully data.update({ 'form': 'rev', 'content': replace_2, 'current_rev': rev_id2 }) resp = client.post('%s?section=s2&raw=true' % reverse('wiki.edit_document', args=[doc.slug]), data) eq_(302, resp.status_code) # Edit #1 submits, but since it's the same section, there's a collision data.update({ 'form': 'rev', 'content': replace_1, 'current_rev': rev_id1 }) resp = client.post('%s?section=s2&raw=true' % reverse('wiki.edit_document', args=[doc.slug]), data) # With the raw API, we should get a 409 Conflict on collision. eq_(409, resp.status_code)
def test_doc_lock_workflow(self): """End to end test of locking on an english document.""" doc, rev = doc_rev() url = reverse('wiki.edit_document', args=[doc.slug], locale='en-US') self._lock_workflow(doc, url)
def test_midair_section_collision(self): """If both a revision and the edited section has changed, then a section edit is a collision.""" client = LocalizingClient() client.login(username='******', password='******') doc, rev = doc_rev(""" <h1 id="s1">Head 1</h1> <p>test</p> <p>test</p> <h1 id="s2">Head 2</h1> <p>test</p> <p>test</p> <h1 id="s3">Head 3</h1> <p>test</p> <p>test</p> """) replace_1 = """ <h1 id="s2">replace</h1> <p>replace</p> """ replace_2 = """ <h1 id="s2">first replace</h1> <p>first replace</p> """ data = {'form': 'rev', 'content': rev.content} # Edit #1 starts... resp = client.get('%s?section=s2' % reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id1 = page.find('input[name="current_rev"]').attr('value') # Edit #2 starts... resp = client.get('%s?section=s2' % reverse('wiki.edit_document', args=[doc.slug])) page = pq(resp.content) rev_id2 = page.find('input[name="current_rev"]').attr('value') # Edit #2 submits successfully data.update({ 'form': 'rev', 'content': replace_2, 'current_rev': rev_id2 }) resp = client.post( '%s?section=s2&raw=true' % reverse('wiki.edit_document', args=[doc.slug]), data) eq_(302, resp.status_code) # Edit #1 submits, but since it's the same section, there's a collision data.update({ 'form': 'rev', 'content': replace_1, 'current_rev': rev_id1 }) resp = client.post( '%s?section=s2&raw=true' % reverse('wiki.edit_document', args=[doc.slug]), data) # With the raw API, we should get a 409 Conflict on collision. eq_(409, resp.status_code)
def test_link_annotation(self): d, r = doc_rev("This document exists") d.save() r.save() document(title=u'Héritée', locale=u'fr', slug=u'CSS/Héritage', save=True) document(title=u'DOM/StyleSheet', locale=u'en-US', slug=u'DOM/StyleSheet', save=True) base_url = u'http://testserver/' vars = dict( base_url=base_url, exist_url=d.get_absolute_url(), exist_url_with_base=urljoin(base_url, d.get_absolute_url()), uilocale_url=u'/en-US/docs/%s/%s' % (d.locale, d.slug), noexist_url=u'/en-US/docs/no-such-doc', noexist_url_with_base=urljoin(base_url, u'/en-US/docs/no-such-doc'), noexist_uilocale_url=u'/en-US/docs/en-US/blah-blah-blah', nonen_slug='/fr/docs/CSS/H%c3%a9ritage', tag_url='/en-US/docs/tag/foo', feed_url='/en-US/docs/feeds/atom/all', templates_url='/en-US/docs/templates', ) doc_src = u""" <li><a href="%(nonen_slug)s">Héritée</a></li> <li><a href="%(exist_url)s">This doc should exist</a></li> <li><a href="%(exist_url)s#withanchor">This doc should exist</a></li> <li><a href="%(exist_url_with_base)s">This doc should exist</a></li> <li><a href="%(exist_url_with_base)s#withanchor">This doc should exist</a></li> <li><a href="%(uilocale_url)s">This doc should exist</a></li> <li><a class="foobar" href="%(exist_url)s">This doc should exist, and its class should be left alone.</a></li> <li><a href="%(noexist_url)s#withanchor">This doc should NOT exist</a></li> <li><a href="%(noexist_url)s">This doc should NOT exist</a></li> <li><a href="%(noexist_url_with_base)s">This doc should NOT exist</a></li> <li><a href="%(noexist_url_with_base)s#withanchor">This doc should NOT exist</a></li> <li><a href="%(noexist_uilocale_url)s">This doc should NOT exist</a></li> <li><a class="foobar" href="%(noexist_url)s">This doc should NOT exist, and its class should be altered</a></li> <li><a href="http://mozilla.org/">This is an external link</a></li> <li><a class="foobar" name="quux">A lack of href should not cause a problem.</a></li> <li><a>In fact, a "link" with no attributes should be no problem as well.</a></li> <a href="%(tag_url)s">Tag link</a> <a href="%(feed_url)s">Feed link</a> <a href="%(templates_url)s">Templates link</a> <a href="/en-US/docs/DOM/stylesheet">Case sensitive 1</a> <a href="/en-US/docs/DOM/Stylesheet">Case sensitive 1</a> <a href="/en-US/docs/DOM/StyleSheet">Case sensitive 1</a> <a href="/en-us/docs/dom/StyleSheet">Case sensitive 1</a> <a href="/en-US/docs/dom/Styles">For good measure</a> """ % vars expected = u""" <li><a href="%(nonen_slug)s">Héritée</a></li> <li><a href="%(exist_url)s">This doc should exist</a></li> <li><a href="%(exist_url)s#withanchor">This doc should exist</a></li> <li><a href="%(exist_url_with_base)s">This doc should exist</a></li> <li><a href="%(exist_url_with_base)s#withanchor">This doc should exist</a></li> <li><a href="%(uilocale_url)s">This doc should exist</a></li> <li><a class="foobar" href="%(exist_url)s">This doc should exist, and its class should be left alone.</a></li> <li><a class="new" href="%(noexist_url)s#withanchor">This doc should NOT exist</a></li> <li><a class="new" href="%(noexist_url)s">This doc should NOT exist</a></li> <li><a class="new" href="%(noexist_url_with_base)s">This doc should NOT exist</a></li> <li><a class="new" href="%(noexist_url_with_base)s#withanchor">This doc should NOT exist</a></li> <li><a class="new" href="%(noexist_uilocale_url)s">This doc should NOT exist</a></li> <li><a class="foobar new" href="%(noexist_url)s">This doc should NOT exist, and its class should be altered</a></li> <li><a class="external" href="http://mozilla.org/">This is an external link</a></li> <li><a class="foobar" name="quux">A lack of href should not cause a problem.</a></li> <li><a>In fact, a "link" with no attributes should be no problem as well.</a></li> <a href="%(tag_url)s">Tag link</a> <a href="%(feed_url)s">Feed link</a> <a href="%(templates_url)s">Templates link</a> <a href="/en-US/docs/DOM/stylesheet">Case sensitive 1</a> <a href="/en-US/docs/DOM/Stylesheet">Case sensitive 1</a> <a href="/en-US/docs/DOM/StyleSheet">Case sensitive 1</a> <a href="/en-us/docs/dom/StyleSheet">Case sensitive 1</a> <a class="new" href="/en-US/docs/dom/Styles">For good measure</a> """ % vars # Split the markup into lines, to better see failures doc_lines = doc_src.strip().split("\n") expected_lines = expected.strip().split("\n") for idx in range(0, len(doc_lines)): doc_line = doc_lines[idx] expected_line = expected_lines[idx] result_line = (wiki.content.parse(doc_line) .annotateLinks(base_url=vars['base_url']) .serialize()) eq_(normalize_html(expected_line), normalize_html(result_line))
def test_roundtrip(self): # Create some documents and revisions here, rather than use a fixture d1, r1 = doc_rev('Doc 1') d2, r2 = doc_rev('Doc 2') d3, r3 = doc_rev('Doc 3') d4, r4 = doc_rev('Doc 4') d5, r5 = doc_rev('Doc 5') # Since this happens in dev sometimes, break a doc by deleting its # current revision and leaving it with none. d5.current_revision = None d5.save() r5.delete() # The same creator will be used for all the revs, so let's also get a # non-creator user for the upload. creator = r1.creator uploader = User.objects.exclude(pk=creator.id).all()[0] # Count docs (with revisions) and revisions in DB doc_cnt_db = (Document.objects.filter( current_revision__isnull=False).count()) rev_cnt_db = (Revision.objects.count()) # Do the dump, capture it, parse the JSON fin = StringIO() Document.objects.dump_json(Document.objects.all(), fin) data_json = fin.getvalue() data = json.loads(data_json) # No objects should come with non-null primary keys for x in data: ok_(not x['pk']) # Count the documents in JSON vs the DB doc_cnt_json = len([x for x in data if x['model'] == 'wiki.document']) eq_(doc_cnt_db, doc_cnt_json, "DB and JSON document counts should match") # Count the revisions in JSON vs the DB rev_cnt_json = len([x for x in data if x['model'] == 'wiki.revision']) eq_(rev_cnt_db, rev_cnt_json, "DB and JSON revision counts should match") # For good measure, ensure no documents missing revisions in the dump. doc_no_rev = (Document.objects.filter( current_revision__isnull=True))[0] no_rev_cnt = len([ x for x in data if x['model'] == 'wiki.document' and x['fields']['slug'] == doc_no_rev.slug and x['fields']['locale'] == doc_no_rev.locale ]) eq_(0, no_rev_cnt, "There should be no document exported without revision") # Upload the data as JSON, assert that all objects were loaded loaded_cnt = Document.objects.load_json(uploader, StringIO(data_json)) eq_(len(data), loaded_cnt) # Ensure the current revisions of the documents have changed, and that # the creator matches the uploader. for d_orig in (d1, d2, d3, d4): d_curr = Document.uncached.get(pk=d_orig.pk) eq_(2, d_curr.revisions.count()) ok_(d_orig.current_revision.id != d_curr.current_revision.id) ok_(d_orig.current_revision.creator_id != d_curr.current_revision.creator_id) eq_(uploader.id, d_curr.current_revision.creator_id) # Everyone out of the pool! Document.objects.all().delete() Revision.objects.all().delete() # Try reloading the data on an empty DB loaded_cnt = Document.objects.load_json(uploader, StringIO(data_json)) eq_(len(data), loaded_cnt) # Count docs (with revisions) and revisions in DB. The imported objects # should have beeen doc/rev pairs. eq_(loaded_cnt / 2, Document.objects.count()) eq_(loaded_cnt / 2, Revision.objects.count()) # The originals should be gone, now. for d_orig in (d1, d2, d3, d4): # The original primary key should have gone away. try: d_curr = Document.uncached.get(pk=d_orig.pk) ok_(False, "This should have been an error") except Document.DoesNotExist: pass # Should be able to fetch document with the original natural key key = d_orig.natural_key() d_curr = Document.objects.get_by_natural_key(*key) eq_(1, d_curr.revisions.count()) eq_(uploader.id, d_curr.current_revision.creator_id)