source: products/quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testBugs.py @ 3225

Last change on this file since 3225 was 3225, checked in by vmaksymiv, 13 years ago

fixed ICanonicalLink adapter test for v4.0.6

File size: 13.0 KB
Line 
1import urllib
2from cStringIO import StringIO
3
4from OFS.interfaces import ITraversable
5
6from zope.component import getGlobalSiteManager
7from zope.component import queryAdapter, getMultiAdapter
8from zope.interface import directlyProvides
9from zope.viewlet.interfaces import IViewlet, IViewletManager
10
11from quintagroup.seoptimizer.browser.interfaces import IPloneSEOLayer
12from quintagroup.seoptimizer.browser.seo_configlet import ISEOConfigletSchema
13from quintagroup.canonicalpath.interfaces import ICanonicalLink
14from quintagroup.canonicalpath.adapters import DefaultCanonicalLinkAdapter
15
16from quintagroup.seoptimizer.tests.base import FunctionalTestCase
17from Products.PloneTestCase.PloneTestCase import portal_owner, \
18    default_password
19import re
20from Products.Five import zcml
21from Products.CMFCore.utils import getToolByName
22
23
24class TestBugs(FunctionalTestCase):
25
26    def afterSetUp(self):
27        self.basic_auth = ':'.join((portal_owner, default_password))
28        self.loginAsPortalOwner()
29        # prepare test document
30        self.portal.invokeFactory('Document', id='my_doc')
31        self.my_doc = self.portal['my_doc']
32        self.mydoc_path = "/%s" % self.my_doc.absolute_url(1)
33
34    def set_title(self, title='', title_override=0, comment='',
35                  comment_override=0):
36        """ Set seo title """
37        portal = self.portal
38        fp = portal['front-page']
39        request = portal.REQUEST
40        view = portal.restrictedTraverse('@@plone')
41        manager = getMultiAdapter((fp, request, view), IViewletManager,
42                        name=u'plone.htmlhead')
43
44        directlyProvides(request, IPloneSEOLayer)
45        viewlet = getMultiAdapter((fp, request, view, manager), IViewlet,
46                        name=u'plone.htmlhead.title')
47
48        form_data = {'seo_title': title,
49                     'seo_title_override:int': title_override,
50                     'seo_html_comment': comment,
51                     'seo_html_comment_override:int': comment_override,
52                     'form.button.Save': "Save",
53                     'form.submitted:int': 1}
54
55        self.publish(path=fp.absolute_url(1) + '/@@seo-context-properties',
56                     basic=self.basic_auth, request_method='POST',
57                     stdin=StringIO(urllib.urlencode(form_data)))
58        viewlet.update()
59        seo_title_comment = viewlet.render()
60        return seo_title_comment
61
62    def test_seo_title(self):
63        """ Test changing title """
64        title = "New Title"
65        new_title = u'<title>%s</title>' % title
66        seo_title = self.set_title(title=title, title_override=1)
67        self.assertEqual(new_title, seo_title)
68
69    def test_seo_comment(self):
70        """ Test changing comment """
71        comment = "New Comment"
72        seo_title_comment = self.set_title(comment=comment, comment_override=1)
73        self.assert_(seo_title_comment.endswith("<!--%s-->" % comment))
74
75    def test_seo_title_comment(self):
76        """ Test changing title and comment """
77        title = "New Title"
78        comment = "New Comment"
79        new_title = u'<title>%s</title>\n<!--%s-->' % (title, comment)
80        seo_title_comment = self.set_title(title=title, title_override=1,
81                                           comment=comment, comment_override=1)
82        self.assertEqual(new_title, seo_title_comment)
83
84    def test_modification_date(self):
85        """ Modification date changing on SEO properties edit """
86        form_data = {'seo_title': 'New Title',
87                     'seo_title_override:int': 1,
88                     'form.button.Save': "Save",
89                     'form.submitted:int': 1}
90
91        md_before = self.my_doc.modification_date
92        self.publish(path=self.mydoc_path + '/@@seo-context-properties',
93                     basic=self.basic_auth, request_method='POST',
94                     stdin=StringIO(urllib.urlencode(form_data)))
95        md_after = self.my_doc.modification_date
96
97        self.assertNotEqual(md_before, md_after)
98
99    def test_bug_20_at_plone_org(self):
100        portal = self.portal
101        fp = portal['front-page']
102        request = portal.REQUEST
103        view = portal.restrictedTraverse('@@plone')
104
105        manager = getMultiAdapter((fp, request, view), IViewletManager,
106                        name=u'plone.htmlhead')
107        viewlet = getMultiAdapter((fp, request, view, manager), IViewlet,
108                        name=u'plone.htmlhead.title')
109        viewlet.update()
110        old_title = viewlet.render()
111
112        # add IPloneSEOLayer
113        directlyProvides(request, IPloneSEOLayer)
114
115        viewlet = getMultiAdapter((fp, request, view, manager), IViewlet,
116                        name=u'plone.htmlhead.title')
117        viewlet.update()
118        new_title = viewlet.render()
119
120        self.assertEqual(old_title, new_title)
121
122    def test_bug_22_at_plone_org(self):
123        """If ICanonicalLink adapter is not found for the context object
124           - page rendering should not break, but only canonical link
125           should disappear.
126        """
127        # XXX: in 4.0.6 version we has quick fix bug #33
128        # http://plone.org/products/plone-seo/issues/33
129        # so this test hasn't any sense at 4.0.6 version
130        qi = getToolByName(self.getPortal(), "portal_quickinstaller")
131        seo_version = qi.getProductVersion('quintagroup.seoptimizer')
132        if seo_version is not None and seo_version.startswith("4.0.6"):
133            return
134
135        curl = re.compile('<link\srel\s*=\s*"canonical"\s+' \
136                          '[^>]*href\s*=\s*\"([^\"]*)\"[^>]*>', re.S | re.M)
137        # When adapter registered for the object - canoncal link
138        # present on the page
139        self.assertNotEqual(queryAdapter(self.my_doc, ICanonicalLink), None)
140
141        res = self.publish(path=self.mydoc_path, basic=self.basic_auth)
142        self.assertNotEqual(curl.search(res.getBody()), None)
143
144        # Now remove adapter from the registry -> this should :
145        #     - not break page on rendering;
146        #     - canonical link will be absent on the page
147        gsm = getGlobalSiteManager()
148        gsm.unregisterAdapter(DefaultCanonicalLinkAdapter, [ITraversable, ],
149                              ICanonicalLink)
150        self.assertEqual(queryAdapter(self.my_doc, ICanonicalLink), None)
151
152        res = self.publish(path=self.mydoc_path, basic=self.basic_auth)
153        self.assertEqual(curl.search(res.getBody()), None)
154
155        # register adapter back in the global site manager
156        gsm.registerAdapter(DefaultCanonicalLinkAdapter, [ITraversable, ],
157                            ICanonicalLink)
158
159    def test_bug_19_23_at_plone_org(self):
160        """overrides.zcml should present in the root of the package"""
161        import quintagroup.seoptimizer
162        try:
163            zcml.load_config('overrides.zcml', quintagroup.seoptimizer)
164        except IOError:
165            self.fail("overrides.zcml removed from the package root")
166
167    def test_escape_characters_title(self):
168        """Change escape characters in title of SEO properties
169           Bug url http://plone.org/products/plone-seo/issues/31
170        """
171        from cgi import escape
172        title = 'New <i>Title</i>'
173        form_data = {'seo_title': title,
174                     'seo_title_override:int': 1,
175                     'form.button.Save': "Save",
176                     'form.submitted:int': 1}
177
178        self.publish(path=self.mydoc_path + '/@@seo-context-properties',
179                     basic=self.basic_auth, request_method='POST',
180                     stdin=StringIO(urllib.urlencode(form_data)))
181        html = self.publish(self.mydoc_path, self.basic_auth).getBody()
182        m = re.match('.*<title>\\s*%s\\s*</title>' % escape(title), html,
183                     re.S | re.M)
184        self.assert_(m, 'Title is not escaped properly.')
185
186    def test_escape_characters_comment(self):
187        """Change escape characters in comment of SEO properties
188        """
189        from cgi import escape
190        comment = 'New <i>comment</i>'
191        form_data = {'seo_title': 'New Title',
192                     'seo_title_override:int': 1,
193                     'seo_html_comment': comment,
194                     'seo_html_comment_override:int': 1,
195                     'form.button.Save': "Save",
196                     'form.submitted:int': 1}
197
198        self.publish(path=self.mydoc_path + '/@@seo-context-properties',
199                     basic=self.basic_auth, request_method='POST',
200                     stdin=StringIO(urllib.urlencode(form_data)))
201        html = self.publish(self.mydoc_path, self.basic_auth).getBody()
202        m = re.match('.*<!--\\s*%s\\s*-->' % escape(comment), html,
203                     re.S | re.M)
204        self.assert_(m, 'Comment is not escaped properly.')
205
206    def test_bug_custom_metatags_update(self):
207        # Prepare a page for the test
208        page = self.portal["front-page"]
209        request = self.portal.REQUEST
210        directlyProvides(request, IPloneSEOLayer)
211        seo_context_props = getMultiAdapter((page, request),
212                                            name="seo-context-properties")
213        # Set default custom meta tag without default value (tag name only)
214        self.gseo = queryAdapter(self.portal, ISEOConfigletSchema)
215        self.gseo.default_custom_metatags = ["test_tag", ]
216        try:
217            # Breakage on updating custom metatag
218            # with seo-context-properties view
219            seo_context_props.updateSEOCustomMetaTagsProperties([])
220        except IndexError:
221            self.fail("Error in calculating of default tag value, when only "\
222                      "tag name set in default_custom_metatags property of "\
223                      "the configlet.")
224
225
226class TestBug24AtPloneOrg(FunctionalTestCase):
227
228    def afterSetUp(self):
229        # Add test users: member, editor
230        member_id = 'test_member'
231        editor_id = 'test_editor'
232        test_pswd = 'pswd'
233        uf = self.portal.acl_users
234        uf.userFolderAddUser(member_id, test_pswd,
235                        ['Member'], [])
236        uf.userFolderAddUser(editor_id, test_pswd,
237                        ['Member', 'Editor'], [])
238
239        self.member_auth = '%s:%s' % (member_id, test_pswd)
240        self.editor_auth = '%s:%s' % (editor_id, test_pswd)
241        self.portal_url = '/'.join(self.portal.getPhysicalPath())
242
243    def test_not_break(self):
244        """Default portal page should not breaks for any user"""
245        # Anonymous
246        resp = self.publish(path=self.portal_url)
247        self.assertEqual(resp.getStatus(), 200)
248        # Member
249        resp = self.publish(path=self.portal_url, basic=self.member_auth)
250        self.assertEqual(resp.getStatus(), 200)
251        # Editor: this fails, althought must pass
252        resp = self.publish(path=self.portal_url, basic=self.editor_auth)
253        self.assertEqual(resp.getStatus(), 200)
254
255    def test_tab_visibility(self):
256        """Only Editor can view seo tab"""
257        rexp = re.compile('<a\s+[^>]*' \
258               'href="[a-zA-Z0-9\:\/_-]*/@@seo-context-properties"[^>]*>'\
259               '\s*SEO Properties\s*</a>', re.I | re.S)
260        # Anonymous: NO SEO Properties link
261        res = self.publish(path=self.portal_url).getBody()
262        self.assertEqual(rexp.search(res), None)
263        # Member: NO 'SEO Properties' link
264        res = self.publish(path=self.portal_url,
265                           basic=self.member_auth).getBody()
266        self.assertEqual(rexp.search(res), None)
267        # Editor: PRESENT 'SEO Properties' link
268        res = self.publish(path=self.portal_url,
269                           basic=self.editor_auth).getBody()
270        self.assertNotEqual(rexp.search(res), None)
271
272    def test_tab_access(self):
273        """Only Editor can access 'SEO Properties' tab"""
274        test_url = self.portal_url + '/front-page/@@seo-context-properties'
275        # Anonymous: can NOT ACCESS
276        headers = self.publish(path=test_url).headers
277        self.assert_('Unauthorized' in headers.get('bobo-exception-type', ""),
278                     "No 'Unauthorized' exception rised for Anonymous on " \
279                     "'@@seo-context-properties' view")
280        # Member: can NOT ACCESS
281        self.publish(path=test_url, basic=self.member_auth).headers
282        self.assert_('Unauthorized' in headers.get('bobo-exception-type', ""),
283                     "No 'Unauthorized' exception rised for Member on " \
284                     "'@@seo-context-properties' view")
285        # Editor: CAN Access
286        res = self.publish(path=test_url, basic=self.editor_auth)
287        self.assertEqual(res.status, 200)
288
289    def test_tab_edit(self):
290        """Editor can change SEO Properties"""
291        test_url = self.portal_url + '/front-page/@@seo-context-properties'
292        form_data = {'seo_title': 'New Title',
293                     'seo_title_override:int': 1,
294                     'form.submitted:int': 1}
295        res = self.publish(path=test_url, basic=self.editor_auth,
296                           request_method='POST',
297                           stdin=StringIO(urllib.urlencode(form_data)))
298        self.assertNotEqual(res.status, 200)
299
300
301def test_suite():
302    from unittest import TestSuite, makeSuite
303    suite = TestSuite()
304    suite.addTest(makeSuite(TestBugs))
305    suite.addTest(makeSuite(TestBug24AtPloneOrg))
306    return suite
Note: See TracBrowser for help on using the repository browser.