comparison test/test_cgi.py @ 6083:f74d078cfd9a

issue2551019 needs to be handled in the action code itself, not the WSGI handler for Python 3 we always need to encode the output in the client character set
author Christof Meerwald <cmeerw@cmeerw.org>
date Sat, 08 Feb 2020 00:29:13 +0000
parents 54d0080769f9
children 15fd91fd3c4c
comparison
equal deleted inserted replaced
6082:a3221c686736 6083:f74d078cfd9a
7 # This module is distributed in the hope that it will be useful, 7 # This module is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 10
11 from __future__ import print_function 11 from __future__ import print_function
12 import unittest, os, shutil, errno, sys, difflib, cgi, re 12 import unittest, os, shutil, errno, sys, difflib, cgi, re, io
13 13
14 import pytest 14 import pytest
15 15
16 from roundup.cgi import client, actions, exceptions 16 from roundup.cgi import client, actions, exceptions
17 from roundup.cgi.exceptions import FormError, NotFound, Redirect 17 from roundup.cgi.exceptions import FormError, NotFound, Redirect
18 from roundup.exceptions import UsageError, Reject 18 from roundup.exceptions import UsageError, Reject
19 from roundup.cgi.templating import HTMLItem, HTMLRequest, NoTemplate 19 from roundup.cgi.templating import HTMLItem, HTMLRequest, NoTemplate
20 from roundup.cgi.templating import HTMLProperty, _HTMLItem, anti_csrf_nonce 20 from roundup.cgi.templating import HTMLProperty, _HTMLItem, anti_csrf_nonce
21 from roundup.cgi.form_parser import FormParser 21 from roundup.cgi.form_parser import FormParser
22 from roundup import init, instance, password, hyperdb, date 22 from roundup import init, instance, password, hyperdb, date
23 from roundup.anypy.strings import StringIO, u2s, b2s 23 from roundup.anypy.strings import u2s, b2s, s2b
24 24
25 from time import sleep 25 from time import sleep
26 26
27 # For testing very simple rendering 27 # For testing very simple rendering
28 from roundup.cgi.engine_zopetal import RoundupPageTemplate 28 from roundup.cgi.engine_zopetal import RoundupPageTemplate
1785 key_id1=self.db.keyword.create(name='keyword1') 1785 key_id1=self.db.keyword.create(name='keyword1')
1786 key_id2=self.db.keyword.create(name='keyword2') 1786 key_id2=self.db.keyword.create(name='keyword2')
1787 self.db.issue.create(title='foo1', status='2', assignedto='4', nosy=['3',demo_id]) 1787 self.db.issue.create(title='foo1', status='2', assignedto='4', nosy=['3',demo_id])
1788 self.db.issue.create(title='bar2', status='1', assignedto='3', keyword=[key_id1,key_id2]) 1788 self.db.issue.create(title='bar2', status='1', assignedto='3', keyword=[key_id1,key_id2])
1789 self.db.issue.create(title='baz32', status='4') 1789 self.db.issue.create(title='baz32', status='4')
1790 output = StringIO() 1790 output = io.BytesIO()
1791 cl.request = MockNull() 1791 cl.request = MockNull()
1792 cl.request.wfile = output 1792 cl.request.wfile = output
1793 # call export version that outputs names 1793 # call export version that outputs names
1794 actions.ExportCSVAction(cl).handle() 1794 actions.ExportCSVAction(cl).handle()
1795 #print(output.getvalue()) 1795 #print(output.getvalue())
1796 should_be=('id,title,status,keyword,assignedto,nosy\r\n' 1796 should_be=(s2b('id,title,status,keyword,assignedto,nosy\r\n'
1797 '1,foo1,deferred,,"Contrary, Mary","Bork, Chef;Contrary, Mary;demo"\r\n' 1797 '1,foo1,deferred,,"Contrary, Mary","Bork, Chef;Contrary, Mary;demo"\r\n'
1798 '2,bar2,unread,keyword1;keyword2,"Bork, Chef","Bork, Chef"\r\n' 1798 '2,bar2,unread,keyword1;keyword2,"Bork, Chef","Bork, Chef"\r\n'
1799 '3,baz32,need-eg,,,\r\n') 1799 '3,baz32,need-eg,,,\r\n'))
1800 #print(should_be) 1800 #print(should_be)
1801 #print(output.getvalue()) 1801 #print(output.getvalue())
1802 self.assertEqual(output.getvalue(), should_be) 1802 self.assertEqual(output.getvalue(), should_be)
1803 output = StringIO() 1803 output = io.BytesIO()
1804 cl.request = MockNull() 1804 cl.request = MockNull()
1805 cl.request.wfile = output 1805 cl.request.wfile = output
1806 # call export version that outputs id numbers 1806 # call export version that outputs id numbers
1807 actions.ExportCSVWithIdAction(cl).handle() 1807 actions.ExportCSVWithIdAction(cl).handle()
1808 print(output.getvalue()) 1808 print(output.getvalue())
1809 self.assertEqual('id,title,status,keyword,assignedto,nosy\r\n' 1809 self.assertEqual(s2b('id,title,status,keyword,assignedto,nosy\r\n'
1810 "1,foo1,2,[],4,\"['3', '4', '5']\"\r\n" 1810 "1,foo1,2,[],4,\"['3', '4', '5']\"\r\n"
1811 "2,bar2,1,\"['1', '2']\",3,['3']\r\n" 1811 "2,bar2,1,\"['1', '2']\",3,['3']\r\n"
1812 '3,baz32,4,[],None,[]\r\n', 1812 '3,baz32,4,[],None,[]\r\n'),
1813 output.getvalue()) 1813 output.getvalue())
1814
1815 def testCSVExportCharset(self):
1816 cl = self._make_client(
1817 {'@columns': 'id,title,status,keyword,assignedto,nosy'},
1818 nodeid=None, userid='1')
1819 cl.classname = 'issue'
1820
1821 demo_id=self.db.user.create(username='demo', address='demo@test.test',
1822 roles='User', realname='demo')
1823 self.db.issue.create(title=b2s(b'foo1\xc3\xa4'), status='2', assignedto='4', nosy=['3',demo_id])
1824
1825 output = io.BytesIO()
1826 cl.request = MockNull()
1827 cl.request.wfile = output
1828 # call export version that outputs names
1829 actions.ExportCSVAction(cl).handle()
1830 should_be=(b'id,title,status,keyword,assignedto,nosy\r\n'
1831 b'1,foo1\xc3\xa4,deferred,,"Contrary, Mary","Bork, Chef;Contrary, Mary;demo"\r\n')
1832 self.assertEqual(output.getvalue(), should_be)
1833
1834 output = io.BytesIO()
1835 cl.request = MockNull()
1836 cl.request.wfile = output
1837 # call export version that outputs id numbers
1838 actions.ExportCSVWithIdAction(cl).handle()
1839 print(output.getvalue())
1840 self.assertEqual(b'id,title,status,keyword,assignedto,nosy\r\n'
1841 b"1,foo1\xc3\xa4,2,[],4,\"['3', '4', '5']\"\r\n",
1842 output.getvalue())
1843
1844 # again with ISO-8859-1 client charset
1845 cl.charset = 'iso8859-1'
1846 output = io.BytesIO()
1847 cl.request = MockNull()
1848 cl.request.wfile = output
1849 # call export version that outputs names
1850 actions.ExportCSVAction(cl).handle()
1851 should_be=(b'id,title,status,keyword,assignedto,nosy\r\n'
1852 b'1,foo1\xe4,deferred,,"Contrary, Mary","Bork, Chef;Contrary, Mary;demo"\r\n')
1853 self.assertEqual(output.getvalue(), should_be)
1854
1855 output = io.BytesIO()
1856 cl.request = MockNull()
1857 cl.request.wfile = output
1858 # call export version that outputs id numbers
1859 actions.ExportCSVWithIdAction(cl).handle()
1860 print(output.getvalue())
1861 self.assertEqual(b'id,title,status,keyword,assignedto,nosy\r\n'
1862 b"1,foo1\xe4,2,[],4,\"['3', '4', '5']\"\r\n",
1863 output.getvalue())
1814 1864
1815 def testCSVExportBadColumnName(self): 1865 def testCSVExportBadColumnName(self):
1816 cl = self._make_client({'@columns': 'falseid,name'}, nodeid=None, 1866 cl = self._make_client({'@columns': 'falseid,name'}, nodeid=None,
1817 userid='1') 1867 userid='1')
1818 cl.classname = 'status' 1868 cl.classname = 'status'
1819 output = StringIO() 1869 output = io.BytesIO()
1820 cl.request = MockNull() 1870 cl.request = MockNull()
1821 cl.request.wfile = output 1871 cl.request.wfile = output
1822 self.assertRaises(exceptions.NotFound, 1872 self.assertRaises(exceptions.NotFound,
1823 actions.ExportCSVAction(cl).handle) 1873 actions.ExportCSVAction(cl).handle)
1824 1874
1825 def testCSVExportFailPermissionBadColumn(self): 1875 def testCSVExportFailPermissionBadColumn(self):
1826 cl = self._make_client({'@columns': 'id,email,password'}, nodeid=None, 1876 cl = self._make_client({'@columns': 'id,email,password'}, nodeid=None,
1827 userid='2') 1877 userid='2')
1828 cl.classname = 'user' 1878 cl.classname = 'user'
1829 output = StringIO() 1879 output = io.BytesIO()
1830 cl.request = MockNull() 1880 cl.request = MockNull()
1831 cl.request.wfile = output 1881 cl.request.wfile = output
1832 # used to be self.assertRaises(exceptions.Unauthorised, 1882 # used to be self.assertRaises(exceptions.Unauthorised,
1833 # but not acting like the column name is not found 1883 # but not acting like the column name is not found
1834 # see issue2550755 - should this return Unauthorised? 1884 # see issue2550755 - should this return Unauthorised?
1843 roles='User', realname='demo', 1893 roles='User', realname='demo',
1844 password=passwd) 1894 password=passwd)
1845 cl = self._make_client({'@columns': 'id,username,address,password'}, 1895 cl = self._make_client({'@columns': 'id,username,address,password'},
1846 nodeid=None, userid=demo_id) 1896 nodeid=None, userid=demo_id)
1847 cl.classname = 'user' 1897 cl.classname = 'user'
1848 output = StringIO() 1898 output = io.BytesIO()
1849 cl.request = MockNull() 1899 cl.request = MockNull()
1850 cl.request.wfile = output 1900 cl.request.wfile = output
1851 # used to be self.assertRaises(exceptions.Unauthorised, 1901 # used to be self.assertRaises(exceptions.Unauthorised,
1852 # but not acting like the column name is not found 1902 # but not acting like the column name is not found
1853 1903
1854 actions.ExportCSVAction(cl).handle() 1904 actions.ExportCSVAction(cl).handle()
1855 #print(output.getvalue()) 1905 #print(output.getvalue())
1856 self.assertEqual('id,username,address,password\r\n' 1906 self.assertEqual(s2b('id,username,address,password\r\n'
1857 '1,admin,[hidden],[hidden]\r\n' 1907 '1,admin,[hidden],[hidden]\r\n'
1858 '2,anonymous,[hidden],[hidden]\r\n' 1908 '2,anonymous,[hidden],[hidden]\r\n'
1859 '3,Chef,[hidden],[hidden]\r\n' 1909 '3,Chef,[hidden],[hidden]\r\n'
1860 '4,mary,[hidden],[hidden]\r\n' 1910 '4,mary,[hidden],[hidden]\r\n'
1861 '5,demo,demo@test.test,%s\r\n'%(passwd), 1911 '5,demo,demo@test.test,%s\r\n'%(passwd)),
1862 output.getvalue()) 1912 output.getvalue())
1863 1913
1864 def testCSVExportWithId(self): 1914 def testCSVExportWithId(self):
1865 cl = self._make_client({'@columns': 'id,name'}, nodeid=None, 1915 cl = self._make_client({'@columns': 'id,name'}, nodeid=None,
1866 userid='1') 1916 userid='1')
1867 cl.classname = 'status' 1917 cl.classname = 'status'
1868 output = StringIO() 1918 output = io.BytesIO()
1869 cl.request = MockNull() 1919 cl.request = MockNull()
1870 cl.request.wfile = output 1920 cl.request.wfile = output
1871 actions.ExportCSVWithIdAction(cl).handle() 1921 actions.ExportCSVWithIdAction(cl).handle()
1872 self.assertEqual('id,name\r\n1,unread\r\n2,deferred\r\n3,chatting\r\n' 1922 self.assertEqual(s2b('id,name\r\n1,unread\r\n2,deferred\r\n3,chatting\r\n'
1873 '4,need-eg\r\n5,in-progress\r\n6,testing\r\n7,done-cbb\r\n' 1923 '4,need-eg\r\n5,in-progress\r\n6,testing\r\n7,done-cbb\r\n'
1874 '8,resolved\r\n', 1924 '8,resolved\r\n'),
1875 output.getvalue()) 1925 output.getvalue())
1876 1926
1877 def testCSVExportWithIdBadColumnName(self): 1927 def testCSVExportWithIdBadColumnName(self):
1878 cl = self._make_client({'@columns': 'falseid,name'}, nodeid=None, 1928 cl = self._make_client({'@columns': 'falseid,name'}, nodeid=None,
1879 userid='1') 1929 userid='1')
1880 cl.classname = 'status' 1930 cl.classname = 'status'
1881 output = StringIO() 1931 output = io.BytesIO()
1882 cl.request = MockNull() 1932 cl.request = MockNull()
1883 cl.request.wfile = output 1933 cl.request.wfile = output
1884 self.assertRaises(exceptions.NotFound, 1934 self.assertRaises(exceptions.NotFound,
1885 actions.ExportCSVWithIdAction(cl).handle) 1935 actions.ExportCSVWithIdAction(cl).handle)
1886 1936
1887 def testCSVExportWithIdFailPermissionBadColumn(self): 1937 def testCSVExportWithIdFailPermissionBadColumn(self):
1888 cl = self._make_client({'@columns': 'id,email,password'}, nodeid=None, 1938 cl = self._make_client({'@columns': 'id,email,password'}, nodeid=None,
1889 userid='2') 1939 userid='2')
1890 cl.classname = 'user' 1940 cl.classname = 'user'
1891 output = StringIO() 1941 output = io.BytesIO()
1892 cl.request = MockNull() 1942 cl.request = MockNull()
1893 cl.request.wfile = output 1943 cl.request.wfile = output
1894 # used to be self.assertRaises(exceptions.Unauthorised, 1944 # used to be self.assertRaises(exceptions.Unauthorised,
1895 # but not acting like the column name is not found 1945 # but not acting like the column name is not found
1896 # see issue2550755 - should this return Unauthorised? 1946 # see issue2550755 - should this return Unauthorised?
1901 1951
1902 def testCSVExportWithIdFailPermissionValidColumn(self): 1952 def testCSVExportWithIdFailPermissionValidColumn(self):
1903 cl = self._make_client({'@columns': 'id,address,password'}, nodeid=None, 1953 cl = self._make_client({'@columns': 'id,address,password'}, nodeid=None,
1904 userid='2') 1954 userid='2')
1905 cl.classname = 'user' 1955 cl.classname = 'user'
1906 output = StringIO() 1956 output = io.BytesIO()
1907 cl.request = MockNull() 1957 cl.request = MockNull()
1908 cl.request.wfile = output 1958 cl.request.wfile = output
1909 # used to be self.assertRaises(exceptions.Unauthorised, 1959 # used to be self.assertRaises(exceptions.Unauthorised,
1910 # but not acting like the column name is not found 1960 # but not acting like the column name is not found
1911 self.assertRaises(exceptions.Unauthorised, 1961 self.assertRaises(exceptions.Unauthorised,

Roundup Issue Tracker: http://roundup-tracker.org/