comparison test/db_test_base.py @ 6332:6a6b4651be1f

Use server-side cursor for postgres in some cases In filter, filter_iter, and _materialize_multilinks, use named cursor with postgresql. This turns of client-side cursor handling and avoids *large* roundup process (or wsgi process) in case of large results. Fixes issue2551114.
author Ralf Schlatterbeck <rsc@runtux.com>
date Thu, 04 Mar 2021 12:55:21 +0100
parents 778a9f455067
children 0db59cc2cd37
comparison
equal deleted inserted replaced
6331:c547e05d7a54 6332:6a6b4651be1f
175 self.open_database() 175 self.open_database()
176 setupSchema(self.db, 1, self.module) 176 setupSchema(self.db, 1, self.module)
177 177
178 def iterSetup(self, classname='issue'): 178 def iterSetup(self, classname='issue'):
179 cls = getattr(self.db, classname) 179 cls = getattr(self.db, classname)
180 def filt_iter(*args, **kw): 180 def filt_iter_list(*args, **kw):
181 """ for checking equivalence of filter and filter_iter """ 181 """ for checking equivalence of filter and filter_iter """
182 return list(cls.filter_iter(*args, **kw)) 182 return list(cls.filter_iter(*args, **kw))
183 return self.assertEqual, cls.filter, filt_iter 183 def filter_test_iterator():
184 """ yield all filter variants with config settings changed
185 appropriately
186 """
187 self.db.config.RDBMS_SERVERSIDE_CURSOR = False
188 yield (cls.filter)
189 yield (filt_iter_list)
190 self.db.config.RDBMS_SERVERSIDE_CURSOR = True
191 yield (cls.filter)
192 yield (filt_iter_list)
193 return self.assertEqual, filter_test_iterator
184 194
185 def filteringSetupTransitiveSearch(self, classname='issue'): 195 def filteringSetupTransitiveSearch(self, classname='issue'):
186 u_m = {} 196 u_m = {}
187 k = 30 197 k = 30
188 for user in ( 198 for user in (
491 if commit: self.db.commit() 501 if commit: self.db.commit()
492 self.assertEqual(self.db.issue.get(nid, "deadline"), None) 502 self.assertEqual(self.db.issue.get(nid, "deadline"), None)
493 503
494 def testDateSort(self): 504 def testDateSort(self):
495 d1 = date.Date('.') 505 d1 = date.Date('.')
496 ae, filter, filter_iter = self.filteringSetup() 506 ae, iiter = self.filteringSetup()
497 nid = self.db.issue.create(title="nodeadline", status='1') 507 nid = self.db.issue.create(title="nodeadline", status='1')
498 self.db.commit() 508 self.db.commit()
499 for filt in filter, filter_iter: 509 for filt in iiter():
500 ae(filt(None, {}, ('+','deadline')), ['5', '2', '1', '3', '4']) 510 ae(filt(None, {}, ('+','deadline')), ['5', '2', '1', '3', '4'])
501 ae(filt(None, {}, ('+','id'), ('+', 'deadline')), 511 ae(filt(None, {}, ('+','id'), ('+', 'deadline')),
502 ['5', '2', '1', '3', '4']) 512 ['5', '2', '1', '3', '4'])
503 ae(filt(None, {}, ('-','id'), ('-', 'deadline')), 513 ae(filt(None, {}, ('-','id'), ('-', 'deadline')),
504 ['4', '3', '1', '2', '5']) 514 ['4', '3', '1', '2', '5'])
505 515
506 def testDateSortMultilink(self): 516 def testDateSortMultilink(self):
507 d1 = date.Date('.') 517 d1 = date.Date('.')
508 ae, filter, filter_iter = self.filteringSetup() 518 ae, iiter = self.filteringSetup()
509 nid = self.db.issue.create(title="nodeadline", status='1') 519 nid = self.db.issue.create(title="nodeadline", status='1')
510 self.db.commit() 520 self.db.commit()
511 ae(sorted(self.db.issue.get('1','nosy')), []) 521 ae(sorted(self.db.issue.get('1','nosy')), [])
512 ae(sorted(self.db.issue.get('2','nosy')), []) 522 ae(sorted(self.db.issue.get('2','nosy')), [])
513 ae(sorted(self.db.issue.get('3','nosy')), ['1','2']) 523 ae(sorted(self.db.issue.get('3','nosy')), ['1','2'])
516 ae(self.db.user.get('1','username'), 'admin') 526 ae(self.db.user.get('1','username'), 'admin')
517 ae(self.db.user.get('2','username'), 'fred') 527 ae(self.db.user.get('2','username'), 'fred')
518 ae(self.db.user.get('3','username'), 'bleep') 528 ae(self.db.user.get('3','username'), 'bleep')
519 # filter_iter currently doesn't work for Multilink sort 529 # filter_iter currently doesn't work for Multilink sort
520 # so testing only filter 530 # so testing only filter
521 ae(filter(None, {}, ('+', 'id'), ('+','nosy')), 531 for f in iiter():
522 ['1', '2', '5', '4', '3']) 532 if f.__name__ != 'filter':
523 ae(filter(None, {}, ('+','deadline'), ('+', 'nosy')), 533 continue
524 ['5', '2', '1', '4', '3']) 534 ae(f(None, {}, ('+', 'id'), ('+','nosy')),
525 ae(filter(None, {}, ('+','nosy'), ('+', 'deadline')), 535 ['1', '2', '5', '4', '3'])
526 ['5', '2', '1', '3', '4']) 536 ae(f(None, {}, ('+','deadline'), ('+', 'nosy')),
537 ['5', '2', '1', '4', '3'])
538 ae(f(None, {}, ('+','nosy'), ('+', 'deadline')),
539 ['5', '2', '1', '3', '4'])
527 540
528 # Interval 541 # Interval
529 def testIntervalChange(self): 542 def testIntervalChange(self):
530 self.assertRaises(TypeError, self.db.issue.create, 543 self.assertRaises(TypeError, self.db.issue.create,
531 title='spam', foo=1) 544 title='spam', foo=1)
1563 got = self.db.issue.find(status={'1':1}) 1576 got = self.db.issue.find(status={'1':1})
1564 got.sort() 1577 got.sort()
1565 self.assertEqual(got, [one, three]) 1578 self.assertEqual(got, [one, three])
1566 1579
1567 def testFindRevLinkMultilink(self): 1580 def testFindRevLinkMultilink(self):
1568 ae, filter, filter_iter = self.filteringSetupTransitiveSearch('user') 1581 ae, dummy = self.filteringSetupTransitiveSearch('user')
1569 ni = 'nosy_issues' 1582 ni = 'nosy_issues'
1570 self.db.issue.set('6', nosy=['3', '4', '5']) 1583 self.db.issue.set('6', nosy=['3', '4', '5'])
1571 self.db.issue.set('7', nosy=['5']) 1584 self.db.issue.set('7', nosy=['5'])
1572 # After this setup we have the following values for nosy: 1585 # After this setup we have the following values for nosy:
1573 # issue assignedto nosy 1586 # issue assignedto nosy
1706 self.db.issue.create(**issue) 1719 self.db.issue.create(**issue)
1707 self.db.commit() 1720 self.db.commit()
1708 return self.iterSetup(classname) 1721 return self.iterSetup(classname)
1709 1722
1710 def testFilteringID(self): 1723 def testFilteringID(self):
1711 ae, filter, filter_iter = self.filteringSetup() 1724 ae, iiter = self.filteringSetup()
1712 for filt in filter, filter_iter: 1725 for filt in iiter():
1713 ae(filt(None, {'id': '1'}, ('+','id'), (None,None)), ['1']) 1726 ae(filt(None, {'id': '1'}, ('+','id'), (None,None)), ['1'])
1714 ae(filt(None, {'id': '2'}, ('+','id'), (None,None)), ['2']) 1727 ae(filt(None, {'id': '2'}, ('+','id'), (None,None)), ['2'])
1715 ae(filt(None, {'id': '100'}, ('+','id'), (None,None)), []) 1728 ae(filt(None, {'id': '100'}, ('+','id'), (None,None)), [])
1716 1729
1717 def testFilteringBoolean(self): 1730 def testFilteringBoolean(self):
1718 ae, filter, filter_iter = self.filteringSetup('user') 1731 ae, iiter = self.filteringSetup('user')
1719 a = 'assignable' 1732 a = 'assignable'
1720 for filt in filter, filter_iter: 1733 for filt in iiter():
1721 ae(filt(None, {a: '1'}, ('+','id'), (None,None)), ['3','4']) 1734 ae(filt(None, {a: '1'}, ('+','id'), (None,None)), ['3','4'])
1722 ae(filt(None, {a: '0'}, ('+','id'), (None,None)), ['5']) 1735 ae(filt(None, {a: '0'}, ('+','id'), (None,None)), ['5'])
1723 ae(filt(None, {a: ['1']}, ('+','id'), (None,None)), ['3','4']) 1736 ae(filt(None, {a: ['1']}, ('+','id'), (None,None)), ['3','4'])
1724 ae(filt(None, {a: ['0']}, ('+','id'), (None,None)), ['5']) 1737 ae(filt(None, {a: ['0']}, ('+','id'), (None,None)), ['5'])
1725 ae(filt(None, {a: ['0','1']}, ('+','id'), (None,None)), 1738 ae(filt(None, {a: ['0','1']}, ('+','id'), (None,None)),
1741 ae(filt(None, {a: [False]}, ('+','id'), (None,None)), ['5']) 1754 ae(filt(None, {a: [False]}, ('+','id'), (None,None)), ['5'])
1742 ae(filt(None, {a: [False,True]}, ('+','id'), (None,None)), 1755 ae(filt(None, {a: [False,True]}, ('+','id'), (None,None)),
1743 ['3','4','5']) 1756 ['3','4','5'])
1744 1757
1745 def testFilteringNumber(self): 1758 def testFilteringNumber(self):
1746 ae, filter, filter_iter = self.filteringSetup('user') 1759 ae, iiter = self.filteringSetup('user')
1747 for filt in filter, filter_iter: 1760 for filt in iiter():
1748 ae(filt(None, {'age': '1'}, ('+','id'), (None,None)), ['3']) 1761 ae(filt(None, {'age': '1'}, ('+','id'), (None,None)), ['3'])
1749 ae(filt(None, {'age': '1.5'}, ('+','id'), (None,None)), ['4']) 1762 ae(filt(None, {'age': '1.5'}, ('+','id'), (None,None)), ['4'])
1750 ae(filt(None, {'age': '2'}, ('+','id'), (None,None)), ['5']) 1763 ae(filt(None, {'age': '2'}, ('+','id'), (None,None)), ['5'])
1751 ae(filt(None, {'age': ['1','2']}, ('+','id'), (None,None)), 1764 ae(filt(None, {'age': ['1','2']}, ('+','id'), (None,None)),
1752 ['3','5']) 1765 ['3','5'])
1753 ae(filt(None, {'age': 2}, ('+','id'), (None,None)), ['5']) 1766 ae(filt(None, {'age': 2}, ('+','id'), (None,None)), ['5'])
1754 ae(filt(None, {'age': [1,2]}, ('+','id'), (None,None)), ['3','5']) 1767 ae(filt(None, {'age': [1,2]}, ('+','id'), (None,None)), ['3','5'])
1755 1768
1756 def testFilteringString(self): 1769 def testFilteringString(self):
1757 ae, filter, filter_iter = self.filteringSetup() 1770 ae, iiter = self.filteringSetup()
1758 for filt in filter, filter_iter: 1771 for filt in iiter():
1759 ae(filt(None, {'title': ['one']}, ('+','id'), (None,None)), ['1']) 1772 ae(filt(None, {'title': ['one']}, ('+','id'), (None,None)), ['1'])
1760 ae(filt(None, {'title': ['issue one']}, ('+','id'), (None,None)), 1773 ae(filt(None, {'title': ['issue one']}, ('+','id'), (None,None)),
1761 ['1']) 1774 ['1'])
1762 ae(filt(None, {'title': ['issue', 'one']}, ('+','id'), (None,None)), 1775 ae(filt(None, {'title': ['issue', 'one']}, ('+','id'), (None,None)),
1763 ['1']) 1776 ['1'])
1769 def testFilteringStringCase(self): 1782 def testFilteringStringCase(self):
1770 """ 1783 """
1771 Similar to testFilteringString except the search parameters 1784 Similar to testFilteringString except the search parameters
1772 have different capitalization. 1785 have different capitalization.
1773 """ 1786 """
1774 ae, filter, filter_iter = self.filteringSetup() 1787 ae, iiter = self.filteringSetup()
1775 for filt in filter, filter_iter: 1788 for filt in iiter():
1776 ae(filt(None, {'title': ['One']}, ('+','id'), (None,None)), ['1']) 1789 ae(filt(None, {'title': ['One']}, ('+','id'), (None,None)), ['1'])
1777 ae(filt(None, {'title': ['Issue One']}, ('+','id'), (None,None)), 1790 ae(filt(None, {'title': ['Issue One']}, ('+','id'), (None,None)),
1778 ['1']) 1791 ['1'])
1779 ae(filt(None, {'title': ['ISSUE', 'ONE']}, ('+','id'), (None,None)), 1792 ae(filt(None, {'title': ['ISSUE', 'ONE']}, ('+','id'), (None,None)),
1780 ['1']) 1793 ['1'])
1782 ['1','2','3']) 1795 ['1','2','3'])
1783 ae(filt(None, {'title': ['One', 'Two']}, ('+','id'), (None,None)), 1796 ae(filt(None, {'title': ['One', 'Two']}, ('+','id'), (None,None)),
1784 []) 1797 [])
1785 1798
1786 def testFilteringStringExactMatch(self): 1799 def testFilteringStringExactMatch(self):
1787 ae, filter, filter_iter = self.filteringSetup() 1800 ae, iiter = self.filteringSetup()
1788 # Change title of issue2 to 'issue' so we can test substring 1801 # Change title of issue2 to 'issue' so we can test substring
1789 # search vs exact search 1802 # search vs exact search
1790 self.db.issue.set('2', title='issue') 1803 self.db.issue.set('2', title='issue')
1791 #self.db.commit() 1804 #self.db.commit()
1792 for filt in filter, filter_iter: 1805 for filt in iiter():
1793 ae(filt(None, {}, exact_match_spec = 1806 ae(filt(None, {}, exact_match_spec =
1794 {'title': ['one']}), []) 1807 {'title': ['one']}), [])
1795 ae(filt(None, {}, exact_match_spec = 1808 ae(filt(None, {}, exact_match_spec =
1796 {'title': ['issue one']}), ['1']) 1809 {'title': ['issue one']}), ['1'])
1797 ae(filt(None, {}, exact_match_spec = 1810 ae(filt(None, {}, exact_match_spec =
1818 1831
1819 def testFilteringSpecialChars(self): 1832 def testFilteringSpecialChars(self):
1820 """ Special characters in SQL search are '%' and '_', some used 1833 """ Special characters in SQL search are '%' and '_', some used
1821 to lead to a traceback. 1834 to lead to a traceback.
1822 """ 1835 """
1823 ae, filter, filter_iter = self.filteringSetup() 1836 ae, iiter = self.filteringSetup()
1824 self.db.issue.set('1', title="With % symbol") 1837 self.db.issue.set('1', title="With % symbol")
1825 self.db.issue.set('2', title="With _ symbol") 1838 self.db.issue.set('2', title="With _ symbol")
1826 self.db.issue.set('3', title="With \\ symbol") 1839 self.db.issue.set('3', title="With \\ symbol")
1827 self.db.issue.set('4', title="With ' symbol") 1840 self.db.issue.set('4', title="With ' symbol")
1828 d = dict (status = '1') 1841 d = dict (status = '1')
1829 for filt in filter, filter_iter: 1842 for filt in iiter():
1830 ae(filt(None, dict(title='%'), ('+','id'), (None,None)), ['1']) 1843 ae(filt(None, dict(title='%'), ('+','id'), (None,None)), ['1'])
1831 ae(filt(None, dict(title='_'), ('+','id'), (None,None)), ['2']) 1844 ae(filt(None, dict(title='_'), ('+','id'), (None,None)), ['2'])
1832 ae(filt(None, dict(title='\\'), ('+','id'), (None,None)), ['3']) 1845 ae(filt(None, dict(title='\\'), ('+','id'), (None,None)), ['3'])
1833 ae(filt(None, dict(title="'"), ('+','id'), (None,None)), ['4']) 1846 ae(filt(None, dict(title="'"), ('+','id'), (None,None)), ['4'])
1834 1847
1835 def testFilteringLink(self): 1848 def testFilteringLink(self):
1836 ae, filter, filter_iter = self.filteringSetup() 1849 ae, iiter = self.filteringSetup()
1837 a = 'assignedto' 1850 a = 'assignedto'
1838 grp = (None, None) 1851 grp = (None, None)
1839 for filt in filter, filter_iter: 1852 for filt in iiter():
1840 ae(filt(None, {'status': '1'}, ('+','id'), grp), ['2','3']) 1853 ae(filt(None, {'status': '1'}, ('+','id'), grp), ['2','3'])
1841 ae(filt(None, {a: '-1'}, ('+','id'), grp), ['3','4']) 1854 ae(filt(None, {a: '-1'}, ('+','id'), grp), ['3','4'])
1842 ae(filt(None, {a: None}, ('+','id'), grp), ['3','4']) 1855 ae(filt(None, {a: None}, ('+','id'), grp), ['3','4'])
1843 ae(filt(None, {a: [None]}, ('+','id'), grp), ['3','4']) 1856 ae(filt(None, {a: [None]}, ('+','id'), grp), ['3','4'])
1844 ae(filt(None, {a: ['-1', None]}, ('+','id'), grp), ['3','4']) 1857 ae(filt(None, {a: ['-1', None]}, ('+','id'), grp), ['3','4'])
1845 ae(filt(None, {a: ['1', None]}, ('+','id'), grp), ['1', '3','4']) 1858 ae(filt(None, {a: ['1', None]}, ('+','id'), grp), ['1', '3','4'])
1846 1859
1847 def testFilteringRevLink(self): 1860 def testFilteringRevLink(self):
1848 ae, filter, filter_iter = self.filteringSetupTransitiveSearch('user') 1861 ae, iiter = self.filteringSetupTransitiveSearch('user')
1849 # We have 1862 # We have
1850 # issue assignedto 1863 # issue assignedto
1851 # 1: 6 1864 # 1: 6
1852 # 2: 6 1865 # 2: 6
1853 # 3: 7 1866 # 3: 7
1854 # 4: 8 1867 # 4: 8
1855 # 5: 9 1868 # 5: 9
1856 # 6: 10 1869 # 6: 10
1857 # 7: 10 1870 # 7: 10
1858 # 8: 10 1871 # 8: 10
1859 for filt in filter, filter_iter: 1872 for filt in iiter():
1860 ae(filt(None, {'issues': ['3', '4']}), ['7', '8']) 1873 ae(filt(None, {'issues': ['3', '4']}), ['7', '8'])
1861 ae(filt(None, {'issues': ['1', '4', '8']}), ['6', '8', '10']) 1874 ae(filt(None, {'issues': ['1', '4', '8']}), ['6', '8', '10'])
1862 ae(filt(None, {'issues.title': ['ts2']}), ['6']) 1875 ae(filt(None, {'issues.title': ['ts2']}), ['6'])
1863 ae(filt(None, {'issues': ['-1']}), ['1', '2', '3', '4', '5']) 1876 ae(filt(None, {'issues': ['-1']}), ['1', '2', '3', '4', '5'])
1864 ae(filt(None, {'issues': '-1'}), ['1', '2', '3', '4', '5']) 1877 ae(filt(None, {'issues': '-1'}), ['1', '2', '3', '4', '5'])
1872 # Now retire some linked-to issues and retry 1885 # Now retire some linked-to issues and retry
1873 self.db.issue.retire('6') 1886 self.db.issue.retire('6')
1874 self.db.issue.retire('2') 1887 self.db.issue.retire('2')
1875 self.db.issue.retire('3') 1888 self.db.issue.retire('3')
1876 self.db.commit() 1889 self.db.commit()
1877 for filt in filter, filter_iter: 1890 for filt in iiter():
1878 ae(filt(None, {'issues': ['3', '4']}), ['8']) 1891 ae(filt(None, {'issues': ['3', '4']}), ['8'])
1879 ae(filt(None, {'issues': ['1', '4', '8']}), ['6', '8', '10']) 1892 ae(filt(None, {'issues': ['1', '4', '8']}), ['6', '8', '10'])
1880 ae(filt(None, {'issues.title': ['ts2']}), []) 1893 ae(filt(None, {'issues.title': ['ts2']}), [])
1881 ae(filt(None, {'issues': ['-1']}), ['1', '2', '3', '4', '5', '7']) 1894 ae(filt(None, {'issues': ['-1']}), ['1', '2', '3', '4', '5', '7'])
1882 ae(filt(None, {'issues': '-1'}), ['1', '2', '3', '4', '5', '7']) 1895 ae(filt(None, {'issues': '-1'}), ['1', '2', '3', '4', '5', '7'])
1883 self.assertEqual(ls(self.db.user.get('6', 'issues')), ['1']) 1896 self.assertEqual(ls(self.db.user.get('6', 'issues')), ['1'])
1884 self.assertEqual(ls(self.db.user.get('7', 'issues')), []) 1897 self.assertEqual(ls(self.db.user.get('7', 'issues')), [])
1885 self.assertEqual(ls(self.db.user.get('10', 'issues')), ['7', '8']) 1898 self.assertEqual(ls(self.db.user.get('10', 'issues')), ['7', '8'])
1886 1899
1887 def testFilteringLinkSortSearchMultilink(self): 1900 def testFilteringLinkSortSearchMultilink(self):
1888 ae, filter, filter_iter = self.filteringSetup() 1901 ae, iiter = self.filteringSetup()
1889 a = 'assignedto' 1902 a = 'assignedto'
1890 grp = (None, None) 1903 grp = (None, None)
1891 for filt in filter, filter_iter: 1904 for filt in iiter():
1892 ae(filt(None, {'status.mls': '1'}, ('+','status')), ['2','3']) 1905 ae(filt(None, {'status.mls': '1'}, ('+','status')), ['2','3'])
1893 ae(filt(None, {'status.mls': '2'}, ('+','status')), ['2','3']) 1906 ae(filt(None, {'status.mls': '2'}, ('+','status')), ['2','3'])
1894 1907
1895 def testFilteringMultilinkAndGroup(self): 1908 def testFilteringMultilinkAndGroup(self):
1896 """testFilteringMultilinkAndGroup: 1909 """testFilteringMultilinkAndGroup:
1897 See roundup Bug 1541128: apparently grouping by something and 1910 See roundup Bug 1541128: apparently grouping by something and
1898 searching a Multilink failed with MySQL 5.0 1911 searching a Multilink failed with MySQL 5.0
1899 """ 1912 """
1900 ae, filter, filter_iter = self.filteringSetup() 1913 ae, iiter = self.filteringSetup()
1901 for f in filter, filter_iter: 1914 for f in iiter():
1902 ae(f(None, {'files': '1'}, ('-','activity'), ('+','status')), ['4']) 1915 ae(f(None, {'files': '1'}, ('-','activity'), ('+','status')), ['4'])
1903 1916
1904 def testFilteringRetired(self): 1917 def testFilteringRetired(self):
1905 ae, filter, filter_iter = self.filteringSetup() 1918 ae, iiter = self.filteringSetup()
1906 self.db.issue.retire('2') 1919 self.db.issue.retire('2')
1907 for f in filter, filter_iter: 1920 for f in iiter():
1908 ae(f(None, {'status': '1'}, ('+','id'), (None,None)), ['3']) 1921 ae(f(None, {'status': '1'}, ('+','id'), (None,None)), ['3'])
1909 1922
1910 def testFilteringMultilink(self): 1923 def testFilteringMultilink(self):
1911 ae, filter, filter_iter = self.filteringSetup() 1924 ae, iiter = self.filteringSetup()
1912 for filt in filter, filter_iter: 1925 for filt in iiter():
1913 ae(filt(None, {'nosy': '3'}, ('+','id'), (None,None)), ['4']) 1926 ae(filt(None, {'nosy': '3'}, ('+','id'), (None,None)), ['4'])
1914 ae(filt(None, {'nosy': '-1'}, ('+','id'), (None,None)), ['1', '2']) 1927 ae(filt(None, {'nosy': '-1'}, ('+','id'), (None,None)), ['1', '2'])
1915 ae(filt(None, {'nosy': ['1','2']}, ('+', 'status'), 1928 ae(filt(None, {'nosy': ['1','2']}, ('+', 'status'),
1916 ('-', 'deadline')), ['4', '3']) 1929 ('-', 'deadline')), ['4', '3'])
1917 1930
1918 def testFilteringRevMultilink(self): 1931 def testFilteringRevMultilink(self):
1919 ae, filter, filter_iter = self.filteringSetupTransitiveSearch('user') 1932 ae, iiter = self.filteringSetupTransitiveSearch('user')
1920 ni = 'nosy_issues' 1933 ni = 'nosy_issues'
1921 self.db.issue.set('6', nosy=['3', '4', '5']) 1934 self.db.issue.set('6', nosy=['3', '4', '5'])
1922 self.db.issue.set('7', nosy=['5']) 1935 self.db.issue.set('7', nosy=['5'])
1923 # After this setup we have the following values for nosy: 1936 # After this setup we have the following values for nosy:
1924 # issue nosy 1937 # issue nosy
1928 # 4: 1941 # 4:
1929 # 5: 1942 # 5:
1930 # 6: 3, 4, 5 1943 # 6: 3, 4, 5
1931 # 7: 5 1944 # 7: 5
1932 # 8: 1945 # 8:
1933 for filt in filter, filter_iter: 1946 for filt in iiter():
1934 ae(filt(None, {ni: ['1', '2']}), ['4', '5']) 1947 ae(filt(None, {ni: ['1', '2']}), ['4', '5'])
1935 ae(filt(None, {ni: ['6','7']}), ['3', '4', '5']) 1948 ae(filt(None, {ni: ['6','7']}), ['3', '4', '5'])
1936 ae(filt(None, {'nosy_issues.title': ['ts2']}), ['5']) 1949 ae(filt(None, {'nosy_issues.title': ['ts2']}), ['5'])
1937 ae(filt(None, {ni: ['-1']}), ['1', '2', '6', '7', '8', '9', '10']) 1950 ae(filt(None, {ni: ['-1']}), ['1', '2', '6', '7', '8', '9', '10'])
1938 ae(filt(None, {ni: '-1'}), ['1', '2', '6', '7', '8', '9', '10']) 1951 ae(filt(None, {ni: '-1'}), ['1', '2', '6', '7', '8', '9', '10'])
1944 self.assertEqual(ls(n.nosy_issues), ['1', '6']) 1957 self.assertEqual(ls(n.nosy_issues), ['1', '6'])
1945 # Now retire some linked-to issues and retry 1958 # Now retire some linked-to issues and retry
1946 self.db.issue.retire('2') 1959 self.db.issue.retire('2')
1947 self.db.issue.retire('6') 1960 self.db.issue.retire('6')
1948 self.db.commit() 1961 self.db.commit()
1949 for filt in filter, filter_iter: 1962 for filt in iiter():
1950 ae(filt(None, {ni: ['1', '2']}), ['4']) 1963 ae(filt(None, {ni: ['1', '2']}), ['4'])
1951 ae(filt(None, {ni: ['6','7']}), ['5']) 1964 ae(filt(None, {ni: ['6','7']}), ['5'])
1952 ae(filt(None, {'nosy_issues.title': ['ts2']}), []) 1965 ae(filt(None, {'nosy_issues.title': ['ts2']}), [])
1953 ae(filt(None, {ni: ['-1']}), 1966 ae(filt(None, {ni: ['-1']}),
1954 ['1', '2', '3', '6', '7', '8', '9', '10']) 1967 ['1', '2', '3', '6', '7', '8', '9', '10'])
1956 ['1', '2', '3', '6', '7', '8', '9', '10']) 1969 ['1', '2', '3', '6', '7', '8', '9', '10'])
1957 self.assertEqual(ls(self.db.user.get('4', ni)), ['1']) 1970 self.assertEqual(ls(self.db.user.get('4', ni)), ['1'])
1958 self.assertEqual(ls(self.db.user.get('5', ni)), ['7']) 1971 self.assertEqual(ls(self.db.user.get('5', ni)), ['7'])
1959 1972
1960 def testFilteringMany(self): 1973 def testFilteringMany(self):
1961 ae, filter, filter_iter = self.filteringSetup() 1974 ae, iiter = self.filteringSetup()
1962 for f in filter, filter_iter: 1975 for f in iiter():
1963 ae(f(None, {'nosy': '2', 'status': '1'}, ('+','id'), (None,None)), 1976 ae(f(None, {'nosy': '2', 'status': '1'}, ('+','id'), (None,None)),
1964 ['3']) 1977 ['3'])
1965 1978
1966 def testFilteringRangeBasic(self): 1979 def testFilteringRangeBasic(self):
1967 ae, filter, filter_iter = self.filteringSetup() 1980 ae, iiter = self.filteringSetup()
1968 d = 'deadline' 1981 d = 'deadline'
1969 for f in filter, filter_iter: 1982 for f in iiter():
1970 ae(f(None, {d: 'from 2003-02-10 to 2003-02-23'}), ['1','3']) 1983 ae(f(None, {d: 'from 2003-02-10 to 2003-02-23'}), ['1','3'])
1971 ae(f(None, {d: '2003-02-10; 2003-02-23'}), ['1','3']) 1984 ae(f(None, {d: '2003-02-10; 2003-02-23'}), ['1','3'])
1972 ae(f(None, {d: '; 2003-02-16'}), ['2']) 1985 ae(f(None, {d: '; 2003-02-16'}), ['2'])
1973 1986
1974 def testFilteringRangeTwoSyntaxes(self): 1987 def testFilteringRangeTwoSyntaxes(self):
1975 ae, filter, filter_iter = self.filteringSetup() 1988 ae, iiter = self.filteringSetup()
1976 for filt in filter, filter_iter: 1989 for filt in iiter():
1977 ae(filt(None, {'deadline': 'from 2003-02-16'}), ['1', '3', '4']) 1990 ae(filt(None, {'deadline': 'from 2003-02-16'}), ['1', '3', '4'])
1978 ae(filt(None, {'deadline': '2003-02-16;'}), ['1', '3', '4']) 1991 ae(filt(None, {'deadline': '2003-02-16;'}), ['1', '3', '4'])
1979 1992
1980 def testFilteringRangeYearMonthDay(self): 1993 def testFilteringRangeYearMonthDay(self):
1981 ae, filter, filter_iter = self.filteringSetup() 1994 ae, iiter = self.filteringSetup()
1982 for filt in filter, filter_iter: 1995 for filt in iiter():
1983 ae(filt(None, {'deadline': '2002'}), []) 1996 ae(filt(None, {'deadline': '2002'}), [])
1984 ae(filt(None, {'deadline': '2003'}), ['1', '2', '3']) 1997 ae(filt(None, {'deadline': '2003'}), ['1', '2', '3'])
1985 ae(filt(None, {'deadline': '2004'}), ['4']) 1998 ae(filt(None, {'deadline': '2004'}), ['4'])
1986 ae(filt(None, {'deadline': '2003-02-16'}), ['1']) 1999 ae(filt(None, {'deadline': '2003-02-16'}), ['1'])
1987 ae(filt(None, {'deadline': '2003-02-17'}), []) 2000 ae(filt(None, {'deadline': '2003-02-17'}), [])
1988 2001
1989 def testFilteringRangeMonths(self): 2002 def testFilteringRangeMonths(self):
1990 ae, filter, filter_iter = self.filteringSetup() 2003 ae, iiter = self.filteringSetup()
1991 for month in range(1, 13): 2004 for month in range(1, 13):
1992 for n in range(1, month+1): 2005 for n in range(1, month+1):
1993 i = self.db.issue.create(title='%d.%d'%(month, n), 2006 i = self.db.issue.create(title='%d.%d'%(month, n),
1994 deadline=date.Date('2001-%02d-%02d.00:00'%(month, n))) 2007 deadline=date.Date('2001-%02d-%02d.00:00'%(month, n)))
1995 self.db.commit() 2008 self.db.commit()
1996 2009
1997 for month in range(1, 13): 2010 for month in range(1, 13):
1998 for filt in filter, filter_iter: 2011 for filt in iiter():
1999 r = filt(None, dict(deadline='2001-%02d'%month)) 2012 r = filt(None, dict(deadline='2001-%02d'%month))
2000 assert len(r) == month, 'month %d != length %d'%(month, len(r)) 2013 assert len(r) == month, 'month %d != length %d'%(month, len(r))
2001 2014
2002 def testFilteringDateRangeMulti(self): 2015 def testFilteringDateRangeMulti(self):
2003 ae, filter, filter_iter = self.filteringSetup() 2016 ae, iiter = self.filteringSetup()
2004 self.db.issue.create(title='no deadline') 2017 self.db.issue.create(title='no deadline')
2005 self.db.commit() 2018 self.db.commit()
2006 for filt in filter, filter_iter: 2019 for filt in iiter():
2007 r = filt (None, dict(deadline='-')) 2020 r = filt (None, dict(deadline='-'))
2008 self.assertEqual(r, ['5']) 2021 self.assertEqual(r, ['5'])
2009 r = filt (None, dict(deadline=';2003-02-01,2004;')) 2022 r = filt (None, dict(deadline=';2003-02-01,2004;'))
2010 self.assertEqual(r, ['2', '4']) 2023 self.assertEqual(r, ['2', '4'])
2011 r = filt (None, dict(deadline='-,;2003-02-01,2004;')) 2024 r = filt (None, dict(deadline='-,;2003-02-01,2004;'))
2012 self.assertEqual(r, ['2', '4', '5']) 2025 self.assertEqual(r, ['2', '4', '5'])
2013 2026
2014 def testFilteringRangeInterval(self): 2027 def testFilteringRangeInterval(self):
2015 ae, filter, filter_iter = self.filteringSetup() 2028 ae, iiter = self.filteringSetup()
2016 for filt in filter, filter_iter: 2029 for filt in iiter():
2017 ae(filt(None, {'foo': 'from 0:50 to 2:00'}), ['1']) 2030 ae(filt(None, {'foo': 'from 0:50 to 2:00'}), ['1'])
2018 ae(filt(None, {'foo': 'from 0:50 to 1d 2:00'}), ['1', '2']) 2031 ae(filt(None, {'foo': 'from 0:50 to 1d 2:00'}), ['1', '2'])
2019 ae(filt(None, {'foo': 'from 5:50'}), ['2']) 2032 ae(filt(None, {'foo': 'from 5:50'}), ['2'])
2020 ae(filt(None, {'foo': 'to 0:05'}), []) 2033 ae(filt(None, {'foo': 'to 0:05'}), [])
2021 2034
2022 def testFilteringRangeGeekInterval(self): 2035 def testFilteringRangeGeekInterval(self):
2023 ae, filter, filter_iter = self.filteringSetup() 2036 ae, iiter = self.filteringSetup()
2024 # Note: When querying, create date one minute later than the 2037 # Note: When querying, create date one minute later than the
2025 # timespan later queried to avoid race conditions where the 2038 # timespan later queried to avoid race conditions where the
2026 # creation of the deadline is more than a second ago when 2039 # creation of the deadline is more than a second ago when
2027 # queried -- in that case we wouldn't get the expected result. 2040 # queried -- in that case we wouldn't get the expected result.
2028 # By extending the interval by a minute we would need a very 2041 # By extending the interval by a minute we would need a very
2031 { 'deadline': date.Date('. -2d') + date.Interval ('00:01')}, 2044 { 'deadline': date.Date('. -2d') + date.Interval ('00:01')},
2032 { 'deadline': date.Date('. -1d') + date.Interval ('00:01')}, 2045 { 'deadline': date.Date('. -1d') + date.Interval ('00:01')},
2033 { 'deadline': date.Date('. -8d') + date.Interval ('00:01')}, 2046 { 'deadline': date.Date('. -8d') + date.Interval ('00:01')},
2034 ): 2047 ):
2035 self.db.issue.create(**issue) 2048 self.db.issue.create(**issue)
2036 for filt in filter, filter_iter: 2049 for filt in iiter():
2037 ae(filt(None, {'deadline': '-2d;'}), ['5', '6']) 2050 ae(filt(None, {'deadline': '-2d;'}), ['5', '6'])
2038 ae(filt(None, {'deadline': '-1d;'}), ['6']) 2051 ae(filt(None, {'deadline': '-1d;'}), ['6'])
2039 ae(filt(None, {'deadline': '-1w;'}), ['5', '6']) 2052 ae(filt(None, {'deadline': '-1w;'}), ['5', '6'])
2040 ae(filt(None, {'deadline': '. -2d;'}), ['5', '6']) 2053 ae(filt(None, {'deadline': '. -2d;'}), ['5', '6'])
2041 ae(filt(None, {'deadline': '. -1d;'}), ['6']) 2054 ae(filt(None, {'deadline': '. -1d;'}), ['6'])
2044 def testFilteringIntervalSort(self): 2057 def testFilteringIntervalSort(self):
2045 # 1: '1:10' 2058 # 1: '1:10'
2046 # 2: '1d' 2059 # 2: '1d'
2047 # 3: None 2060 # 3: None
2048 # 4: '0:10' 2061 # 4: '0:10'
2049 ae, filter, filter_iter = self.filteringSetup() 2062 ae, iiter = self.filteringSetup()
2050 for filt in filter, filter_iter: 2063 for filt in iiter():
2051 # ascending should sort None, 1:10, 1d 2064 # ascending should sort None, 1:10, 1d
2052 ae(filt(None, {}, ('+','foo'), (None,None)), ['3', '4', '1', '2']) 2065 ae(filt(None, {}, ('+','foo'), (None,None)), ['3', '4', '1', '2'])
2053 # descending should sort 1d, 1:10, None 2066 # descending should sort 1d, 1:10, None
2054 ae(filt(None, {}, ('-','foo'), (None,None)), ['2', '1', '4', '3']) 2067 ae(filt(None, {}, ('-','foo'), (None,None)), ['2', '1', '4', '3'])
2055 2068
2056 def testFilteringStringSort(self): 2069 def testFilteringStringSort(self):
2057 # 1: 'issue one' 2070 # 1: 'issue one'
2058 # 2: 'issue two' 2071 # 2: 'issue two'
2059 # 3: 'issue three' 2072 # 3: 'issue three'
2060 # 4: 'non four' 2073 # 4: 'non four'
2061 ae, filter, filter_iter = self.filteringSetup() 2074 ae, iiter = self.filteringSetup()
2062 for filt in filter, filter_iter: 2075 for filt in iiter():
2063 ae(filt(None, {}, ('+','title')), ['1', '3', '2', '4']) 2076 ae(filt(None, {}, ('+','title')), ['1', '3', '2', '4'])
2064 ae(filt(None, {}, ('-','title')), ['4', '2', '3', '1']) 2077 ae(filt(None, {}, ('-','title')), ['4', '2', '3', '1'])
2065 # Test string case: For now allow both, w/wo case matching. 2078 # Test string case: For now allow both, w/wo case matching.
2066 # 1: 'issue one' 2079 # 1: 'issue one'
2067 # 2: 'issue two' 2080 # 2: 'issue two'
2068 # 3: 'Issue three' 2081 # 3: 'Issue three'
2069 # 4: 'non four' 2082 # 4: 'non four'
2070 self.db.issue.set('3', title='Issue three') 2083 self.db.issue.set('3', title='Issue three')
2071 for filt in filter, filter_iter: 2084 for filt in iiter():
2072 ae(filt(None, {}, ('+','title')), ['1', '3', '2', '4']) 2085 ae(filt(None, {}, ('+','title')), ['1', '3', '2', '4'])
2073 ae(filt(None, {}, ('-','title')), ['4', '2', '3', '1']) 2086 ae(filt(None, {}, ('-','title')), ['4', '2', '3', '1'])
2074 # Obscure bug in anydbm backend trying to convert to number 2087 # Obscure bug in anydbm backend trying to convert to number
2075 # 1: '1st issue' 2088 # 1: '1st issue'
2076 # 2: '2' 2089 # 2: '2'
2077 # 3: 'Issue three' 2090 # 3: 'Issue three'
2078 # 4: 'non four' 2091 # 4: 'non four'
2079 self.db.issue.set('1', title='1st issue') 2092 self.db.issue.set('1', title='1st issue')
2080 self.db.issue.set('2', title='2') 2093 self.db.issue.set('2', title='2')
2081 for filt in filter, filter_iter: 2094 for filt in iiter():
2082 ae(filt(None, {}, ('+','title')), ['1', '2', '3', '4']) 2095 ae(filt(None, {}, ('+','title')), ['1', '2', '3', '4'])
2083 ae(filt(None, {}, ('-','title')), ['4', '3', '2', '1']) 2096 ae(filt(None, {}, ('-','title')), ['4', '3', '2', '1'])
2084 2097
2085 def testFilteringMultilinkSort(self): 2098 def testFilteringMultilinkSort(self):
2086 # 1: [] Reverse: 1: [] 2099 # 1: [] Reverse: 1: []
2090 # Note the sort order for the multilink doen't change when 2103 # Note the sort order for the multilink doen't change when
2091 # reversing the sort direction due to the re-sorting of the 2104 # reversing the sort direction due to the re-sorting of the
2092 # multilink! 2105 # multilink!
2093 # Note that we don't test filter_iter here, Multilink sort-order 2106 # Note that we don't test filter_iter here, Multilink sort-order
2094 # isn't defined for that. 2107 # isn't defined for that.
2095 ae, filt, dummy = self.filteringSetup() 2108 ae, iiter = self.filteringSetup()
2096 ae(filt(None, {}, ('+','nosy'), (None,None)), ['1', '2', '4', '3']) 2109 for filt in iiter():
2097 ae(filt(None, {}, ('-','nosy'), (None,None)), ['4', '3', '1', '2']) 2110 if filt.__name__ != 'filter':
2111 continue
2112 ae(filt(None, {}, ('+','nosy'), (None,None)), ['1', '2', '4', '3'])
2113 ae(filt(None, {}, ('-','nosy'), (None,None)), ['4', '3', '1', '2'])
2098 2114
2099 def testFilteringMultilinkSortGroup(self): 2115 def testFilteringMultilinkSortGroup(self):
2100 # 1: status: 2 "in-progress" nosy: [] 2116 # 1: status: 2 "in-progress" nosy: []
2101 # 2: status: 1 "unread" nosy: [] 2117 # 2: status: 1 "unread" nosy: []
2102 # 3: status: 1 "unread" nosy: ['admin','fred'] 2118 # 3: status: 1 "unread" nosy: ['admin','fred']
2103 # 4: status: 3 "testing" nosy: ['admin','bleep','fred'] 2119 # 4: status: 3 "testing" nosy: ['admin','bleep','fred']
2104 # Note that we don't test filter_iter here, Multilink sort-order 2120 # Note that we don't test filter_iter here, Multilink sort-order
2105 # isn't defined for that. 2121 # isn't defined for that.
2106 ae, filt, dummy = self.filteringSetup() 2122 ae, iiter = self.filteringSetup()
2107 ae(filt(None, {}, ('+','nosy'), ('+','status')), ['1', '4', '2', '3']) 2123 for filt in iiter():
2108 ae(filt(None, {}, ('-','nosy'), ('+','status')), ['1', '4', '3', '2']) 2124 if filt.__name__ != 'filter':
2109 ae(filt(None, {}, ('+','nosy'), ('-','status')), ['2', '3', '4', '1']) 2125 continue
2110 ae(filt(None, {}, ('-','nosy'), ('-','status')), ['3', '2', '4', '1']) 2126 ae(filt(None, {}, ('+','nosy'), ('+','status')),
2111 ae(filt(None, {}, ('+','status'), ('+','nosy')), ['1', '2', '4', '3']) 2127 ['1', '4', '2', '3'])
2112 ae(filt(None, {}, ('-','status'), ('+','nosy')), ['2', '1', '4', '3']) 2128 ae(filt(None, {}, ('-','nosy'), ('+','status')),
2113 ae(filt(None, {}, ('+','status'), ('-','nosy')), ['4', '3', '1', '2']) 2129 ['1', '4', '3', '2'])
2114 ae(filt(None, {}, ('-','status'), ('-','nosy')), ['4', '3', '2', '1']) 2130 ae(filt(None, {}, ('+','nosy'), ('-','status')),
2131 ['2', '3', '4', '1'])
2132 ae(filt(None, {}, ('-','nosy'), ('-','status')),
2133 ['3', '2', '4', '1'])
2134 ae(filt(None, {}, ('+','status'), ('+','nosy')),
2135 ['1', '2', '4', '3'])
2136 ae(filt(None, {}, ('-','status'), ('+','nosy')),
2137 ['2', '1', '4', '3'])
2138 ae(filt(None, {}, ('+','status'), ('-','nosy')),
2139 ['4', '3', '1', '2'])
2140 ae(filt(None, {}, ('-','status'), ('-','nosy')),
2141 ['4', '3', '2', '1'])
2115 2142
2116 def testFilteringLinkSortGroup(self): 2143 def testFilteringLinkSortGroup(self):
2117 # 1: status: 2 -> 'i', priority: 3 -> 1 2144 # 1: status: 2 -> 'i', priority: 3 -> 1
2118 # 2: status: 1 -> 'u', priority: 3 -> 1 2145 # 2: status: 1 -> 'u', priority: 3 -> 1
2119 # 3: status: 1 -> 'u', priority: 2 -> 3 2146 # 3: status: 1 -> 'u', priority: 2 -> 3
2120 # 4: status: 3 -> 't', priority: 2 -> 3 2147 # 4: status: 3 -> 't', priority: 2 -> 3
2121 ae, filter, filter_iter = self.filteringSetup() 2148 ae, iiter = self.filteringSetup()
2122 for filt in filter, filter_iter: 2149 for filt in iiter():
2123 ae(filt(None, {}, ('+','status'), ('+','priority')), 2150 ae(filt(None, {}, ('+','status'), ('+','priority')),
2124 ['1', '2', '4', '3']) 2151 ['1', '2', '4', '3'])
2125 ae(filt(None, {'priority':'2'}, ('+','status'), ('+','priority')), 2152 ae(filt(None, {'priority':'2'}, ('+','status'), ('+','priority')),
2126 ['4', '3']) 2153 ['4', '3'])
2127 ae(filt(None, {'priority.order':'3'}, ('+','status'), 2154 ae(filt(None, {'priority.order':'3'}, ('+','status'),
2134 def testFilteringDateSort(self): 2161 def testFilteringDateSort(self):
2135 # '1': '2003-02-16.22:50' 2162 # '1': '2003-02-16.22:50'
2136 # '2': '2003-01-01.00:00' 2163 # '2': '2003-01-01.00:00'
2137 # '3': '2003-02-18' 2164 # '3': '2003-02-18'
2138 # '4': '2004-03-08' 2165 # '4': '2004-03-08'
2139 ae, filter, filter_iter = self.filteringSetup() 2166 ae, iiter = self.filteringSetup()
2140 for f in filter, filter_iter: 2167 for f in iiter():
2141 # ascending 2168 # ascending
2142 ae(f(None, {}, ('+','deadline'), (None,None)), ['2', '1', '3', '4']) 2169 ae(f(None, {}, ('+','deadline'), (None,None)), ['2', '1', '3', '4'])
2143 # descending 2170 # descending
2144 ae(f(None, {}, ('-','deadline'), (None,None)), ['4', '3', '1', '2']) 2171 ae(f(None, {}, ('-','deadline'), (None,None)), ['4', '3', '1', '2'])
2145 2172
2146 def testFilteringDateSortPriorityGroup(self): 2173 def testFilteringDateSortPriorityGroup(self):
2147 # '1': '2003-02-16.22:50' 1 => 2 2174 # '1': '2003-02-16.22:50' 1 => 2
2148 # '2': '2003-01-01.00:00' 3 => 1 2175 # '2': '2003-01-01.00:00' 3 => 1
2149 # '3': '2003-02-18' 2 => 3 2176 # '3': '2003-02-18' 2 => 3
2150 # '4': '2004-03-08' 1 => 2 2177 # '4': '2004-03-08' 1 => 2
2151 ae, filter, filter_iter = self.filteringSetup() 2178 ae, iiter = self.filteringSetup()
2152 2179
2153 for filt in filter, filter_iter: 2180 for filt in iiter():
2154 # ascending 2181 # ascending
2155 ae(filt(None, {}, ('+','deadline'), ('+','priority')), 2182 ae(filt(None, {}, ('+','deadline'), ('+','priority')),
2156 ['2', '1', '3', '4']) 2183 ['2', '1', '3', '4'])
2157 ae(filt(None, {}, ('-','deadline'), ('+','priority')), 2184 ae(filt(None, {}, ('-','deadline'), ('+','priority')),
2158 ['1', '2', '4', '3']) 2185 ['1', '2', '4', '3'])
2161 ['3', '4', '2', '1']) 2188 ['3', '4', '2', '1'])
2162 ae(filt(None, {}, ('-','deadline'), ('-','priority')), 2189 ae(filt(None, {}, ('-','deadline'), ('-','priority')),
2163 ['4', '3', '1', '2']) 2190 ['4', '3', '1', '2'])
2164 2191
2165 def testFilteringTransitiveLinkUser(self): 2192 def testFilteringTransitiveLinkUser(self):
2166 ae, filter, filter_iter = self.filteringSetupTransitiveSearch('user') 2193 ae, iiter = self.filteringSetupTransitiveSearch('user')
2167 for f in filter, filter_iter: 2194 for f in iiter():
2168 ae(f(None, {'supervisor.username': 'ceo'}, ('+','username')), 2195 ae(f(None, {'supervisor.username': 'ceo'}, ('+','username')),
2169 ['4', '5']) 2196 ['4', '5'])
2170 ae(f(None, {'supervisor.supervisor.username': 'ceo'}, 2197 ae(f(None, {'supervisor.supervisor.username': 'ceo'},
2171 ('+','username')), ['6', '7', '8', '9', '10']) 2198 ('+','username')), ['6', '7', '8', '9', '10'])
2172 ae(f(None, {'supervisor.supervisor': '3'}, ('+','username')), 2199 ae(f(None, {'supervisor.supervisor': '3'}, ('+','username')),
2182 ['8', '9', '10']) 2209 ['8', '9', '10'])
2183 ae(f(None, {'supervisor.supervisor': '3', 'supervisor': '4'}, 2210 ae(f(None, {'supervisor.supervisor': '3', 'supervisor': '4'},
2184 ('+','username')), ['6', '7']) 2211 ('+','username')), ['6', '7'])
2185 2212
2186 def testFilteringTransitiveLinkUserLimit(self): 2213 def testFilteringTransitiveLinkUserLimit(self):
2187 ae, filter, filter_iter = self.filteringSetupTransitiveSearch('user') 2214 ae, iiter = self.filteringSetupTransitiveSearch('user')
2188 for f in filter, filter_iter: 2215 for f in iiter():
2189 ae(f(None, {'supervisor.username': 'ceo'}, ('+','username'), 2216 ae(f(None, {'supervisor.username': 'ceo'}, ('+','username'),
2190 limit=1), ['4']) 2217 limit=1), ['4'])
2191 ae(f(None, {'supervisor.supervisor.username': 'ceo'}, 2218 ae(f(None, {'supervisor.supervisor.username': 'ceo'},
2192 ('+','username'), limit=4), ['6', '7', '8', '9']) 2219 ('+','username'), limit=4), ['6', '7', '8', '9'])
2193 ae(f(None, {'supervisor.supervisor': '3'}, ('+','username'), 2220 ae(f(None, {'supervisor.supervisor': '3'}, ('+','username'),
2201 limit=4, offset=3), []) 2228 limit=4, offset=3), [])
2202 ae(f(None, {'supervisor.supervisor': '3', 'supervisor': '4'}, 2229 ae(f(None, {'supervisor.supervisor': '3', 'supervisor': '4'},
2203 ('+','username'), limit=1, offset=5), []) 2230 ('+','username'), limit=1, offset=5), [])
2204 2231
2205 def testFilteringTransitiveLinkSort(self): 2232 def testFilteringTransitiveLinkSort(self):
2206 ae, filter, filter_iter = self.filteringSetupTransitiveSearch() 2233 ae, iiter = self.filteringSetupTransitiveSearch()
2207 ae, ufilter, ufilter_iter = self.iterSetup('user') 2234 ae, uiter = self.iterSetup('user')
2208 # Need to make ceo his own (and first two users') supervisor, 2235 # Need to make ceo his own (and first two users') supervisor,
2209 # otherwise we will depend on sorting order of NULL values. 2236 # otherwise we will depend on sorting order of NULL values.
2210 # Leave that to a separate test. 2237 # Leave that to a separate test.
2211 self.db.user.set('1', supervisor = '3') 2238 self.db.user.set('1', supervisor = '3')
2212 self.db.user.set('2', supervisor = '3') 2239 self.db.user.set('2', supervisor = '3')
2213 self.db.user.set('3', supervisor = '3') 2240 self.db.user.set('3', supervisor = '3')
2214 for ufilt in ufilter, ufilter_iter: 2241 for ufilt in uiter():
2215 ae(ufilt(None, {'supervisor':'3'}, []), ['1', '2', '3', '4', '5']) 2242 ae(ufilt(None, {'supervisor':'3'}, []), ['1', '2', '3', '4', '5'])
2216 ae(ufilt(None, {}, [('+','supervisor.supervisor.supervisor'), 2243 ae(ufilt(None, {}, [('+','supervisor.supervisor.supervisor'),
2217 ('+','supervisor.supervisor'), ('+','supervisor'), 2244 ('+','supervisor.supervisor'), ('+','supervisor'),
2218 ('+','username')]), 2245 ('+','username')]),
2219 ['1', '3', '2', '4', '5', '6', '7', '8', '9', '10']) 2246 ['1', '3', '2', '4', '5', '6', '7', '8', '9', '10'])
2220 ae(ufilt(None, {}, [('+','supervisor.supervisor.supervisor'), 2247 ae(ufilt(None, {}, [('+','supervisor.supervisor.supervisor'),
2221 ('-','supervisor.supervisor'), ('-','supervisor'), 2248 ('-','supervisor.supervisor'), ('-','supervisor'),
2222 ('+','username')]), 2249 ('+','username')]),
2223 ['8', '9', '10', '6', '7', '1', '3', '2', '4', '5']) 2250 ['8', '9', '10', '6', '7', '1', '3', '2', '4', '5'])
2224 for f in filter, filter_iter: 2251 for f in iiter():
2225 ae(f(None, {}, [('+','assignedto.supervisor.supervisor.supervisor'), 2252 ae(f(None, {}, [('+','assignedto.supervisor.supervisor.supervisor'),
2226 ('+','assignedto.supervisor.supervisor'), 2253 ('+','assignedto.supervisor.supervisor'),
2227 ('+','assignedto.supervisor'), ('+','assignedto')]), 2254 ('+','assignedto.supervisor'), ('+','assignedto')]),
2228 ['1', '2', '3', '4', '5', '6', '7', '8']) 2255 ['1', '2', '3', '4', '5', '6', '7', '8'])
2229 ae(f(None, {}, [('+','assignedto.supervisor.supervisor.supervisor'), 2256 ae(f(None, {}, [('+','assignedto.supervisor.supervisor.supervisor'),
2255 ('-','assignedto.supervisor'), ('+','assignedto'), 2282 ('-','assignedto.supervisor'), ('+','assignedto'),
2256 ('+','status')]), ['4', '5', '1', '2', '3']) 2283 ('+','status')]), ['4', '5', '1', '2', '3'])
2257 2284
2258 def testFilteringTransitiveLinkSortNull(self): 2285 def testFilteringTransitiveLinkSortNull(self):
2259 """Check sorting of NULL values""" 2286 """Check sorting of NULL values"""
2260 ae, filter, filter_iter = self.filteringSetupTransitiveSearch() 2287 ae, iiter = self.filteringSetupTransitiveSearch()
2261 ae, ufilter, ufilter_iter = self.iterSetup('user') 2288 ae, uiter = self.iterSetup('user')
2262 for ufilt in ufilter, ufilter_iter: 2289 for ufilt in uiter():
2263 ae(ufilt(None, {}, [('+','supervisor.supervisor.supervisor'), 2290 ae(ufilt(None, {}, [('+','supervisor.supervisor.supervisor'),
2264 ('+','supervisor.supervisor'), ('+','supervisor'), 2291 ('+','supervisor.supervisor'), ('+','supervisor'),
2265 ('+','username')]), 2292 ('+','username')]),
2266 ['1', '3', '2', '4', '5', '6', '7', '8', '9', '10']) 2293 ['1', '3', '2', '4', '5', '6', '7', '8', '9', '10'])
2267 ae(ufilt(None, {}, [('+','supervisor.supervisor.supervisor'), 2294 ae(ufilt(None, {}, [('+','supervisor.supervisor.supervisor'),
2268 ('-','supervisor.supervisor'), ('-','supervisor'), 2295 ('-','supervisor.supervisor'), ('-','supervisor'),
2269 ('+','username')]), 2296 ('+','username')]),
2270 ['8', '9', '10', '6', '7', '4', '5', '1', '3', '2']) 2297 ['8', '9', '10', '6', '7', '4', '5', '1', '3', '2'])
2271 for f in filter, filter_iter: 2298 for f in iiter():
2272 ae(f(None, {}, [('+','assignedto.supervisor.supervisor.supervisor'), 2299 ae(f(None, {}, [('+','assignedto.supervisor.supervisor.supervisor'),
2273 ('+','assignedto.supervisor.supervisor'), 2300 ('+','assignedto.supervisor.supervisor'),
2274 ('+','assignedto.supervisor'), ('+','assignedto')]), 2301 ('+','assignedto.supervisor'), ('+','assignedto')]),
2275 ['1', '2', '3', '4', '5', '6', '7', '8']) 2302 ['1', '2', '3', '4', '5', '6', '7', '8'])
2276 ae(f(None, {}, [('+','assignedto.supervisor.supervisor.supervisor'), 2303 ae(f(None, {}, [('+','assignedto.supervisor.supervisor.supervisor'),
2277 ('+','assignedto.supervisor.supervisor'), 2304 ('+','assignedto.supervisor.supervisor'),
2278 ('-','assignedto.supervisor'), ('+','assignedto')]), 2305 ('-','assignedto.supervisor'), ('+','assignedto')]),
2279 ['4', '5', '6', '7', '8', '1', '2', '3']) 2306 ['4', '5', '6', '7', '8', '1', '2', '3'])
2280 2307
2281 def testFilteringTransitiveLinkIssue(self): 2308 def testFilteringTransitiveLinkIssue(self):
2282 ae, filter, filter_iter = self.filteringSetupTransitiveSearch() 2309 ae, iiter = self.filteringSetupTransitiveSearch()
2283 for filt in filter, filter_iter: 2310 for filt in iiter():
2284 ae(filt(None, {'assignedto.supervisor.username': 'grouplead1'}, 2311 ae(filt(None, {'assignedto.supervisor.username': 'grouplead1'},
2285 ('+','id')), ['1', '2', '3']) 2312 ('+','id')), ['1', '2', '3'])
2286 ae(filt(None, {'assignedto.supervisor.username': 'grouplead2'}, 2313 ae(filt(None, {'assignedto.supervisor.username': 'grouplead2'},
2287 ('+','id')), ['4', '5', '6', '7', '8']) 2314 ('+','id')), ['4', '5', '6', '7', '8'])
2288 ae(filt(None, {'assignedto.supervisor.username': 'grouplead2', 2315 ae(filt(None, {'assignedto.supervisor.username': 'grouplead2',
2293 'status': '2'}, ('+','id')), ['5', '7']) 2320 'status': '2'}, ('+','id')), ['5', '7'])
2294 ae(filt(None, {'assignedto.supervisor': ['4', '5'], 'status': '2'}, 2321 ae(filt(None, {'assignedto.supervisor': ['4', '5'], 'status': '2'},
2295 ('+','id')), ['1', '3', '5', '7']) 2322 ('+','id')), ['1', '3', '5', '7'])
2296 2323
2297 def testFilteringTransitiveMultilink(self): 2324 def testFilteringTransitiveMultilink(self):
2298 ae, filter, filter_iter = self.filteringSetupTransitiveSearch() 2325 ae, iiter = self.filteringSetupTransitiveSearch()
2299 for filt in filter, filter_iter: 2326 for filt in iiter():
2300 ae(filt(None, {'messages.author.username': 'grouplead1'}, 2327 ae(filt(None, {'messages.author.username': 'grouplead1'},
2301 ('+','id')), []) 2328 ('+','id')), [])
2302 ae(filt(None, {'messages.author': '6'}, 2329 ae(filt(None, {'messages.author': '6'},
2303 ('+','id')), ['1', '2']) 2330 ('+','id')), ['1', '2'])
2304 ae(filt(None, {'messages.author.id': '6'}, 2331 ae(filt(None, {'messages.author.id': '6'},
2330 'messages': ['5', '7']}, ('+','id')), ['5', '8']) 2357 'messages': ['5', '7']}, ('+','id')), ['5', '8'])
2331 2358
2332 def testFilteringTransitiveMultilinkSort(self): 2359 def testFilteringTransitiveMultilinkSort(self):
2333 # Note that we don't test filter_iter here, Multilink sort-order 2360 # Note that we don't test filter_iter here, Multilink sort-order
2334 # isn't defined for that. 2361 # isn't defined for that.
2335 ae, filt, dummy = self.filteringSetupTransitiveSearch() 2362 ae, iiter = self.filteringSetupTransitiveSearch()
2336 ae(filt(None, {}, [('+','messages.author')]), 2363 for filt in iiter():
2337 ['1', '2', '3', '4', '5', '8', '6', '7']) 2364 if filt.__name__ != 'filter':
2338 ae(filt(None, {}, [('-','messages.author')]), 2365 continue
2339 ['8', '6', '7', '5', '4', '3', '1', '2']) 2366 ae(filt(None, {}, [('+','messages.author')]),
2340 ae(filt(None, {}, [('+','messages.date')]), 2367 ['1', '2', '3', '4', '5', '8', '6', '7'])
2341 ['6', '7', '8', '5', '4', '3', '1', '2']) 2368 ae(filt(None, {}, [('-','messages.author')]),
2342 ae(filt(None, {}, [('-','messages.date')]), 2369 ['8', '6', '7', '5', '4', '3', '1', '2'])
2343 ['1', '2', '3', '4', '8', '5', '6', '7']) 2370 ae(filt(None, {}, [('+','messages.date')]),
2344 ae(filt(None, {}, [('+','messages.author'),('+','messages.date')]), 2371 ['6', '7', '8', '5', '4', '3', '1', '2'])
2345 ['1', '2', '3', '4', '5', '8', '6', '7']) 2372 ae(filt(None, {}, [('-','messages.date')]),
2346 ae(filt(None, {}, [('-','messages.author'),('+','messages.date')]), 2373 ['1', '2', '3', '4', '8', '5', '6', '7'])
2347 ['8', '6', '7', '5', '4', '3', '1', '2']) 2374 ae(filt(None, {}, [('+','messages.author'),('+','messages.date')]),
2348 ae(filt(None, {}, [('+','messages.author'),('-','messages.date')]), 2375 ['1', '2', '3', '4', '5', '8', '6', '7'])
2349 ['1', '2', '3', '4', '5', '8', '6', '7']) 2376 ae(filt(None, {}, [('-','messages.author'),('+','messages.date')]),
2350 ae(filt(None, {}, [('-','messages.author'),('-','messages.date')]), 2377 ['8', '6', '7', '5', '4', '3', '1', '2'])
2351 ['8', '6', '7', '5', '4', '3', '1', '2']) 2378 ae(filt(None, {}, [('+','messages.author'),('-','messages.date')]),
2352 ae(filt(None, {}, [('+','messages.author'),('+','assignedto')]), 2379 ['1', '2', '3', '4', '5', '8', '6', '7'])
2353 ['1', '2', '3', '4', '5', '8', '6', '7']) 2380 ae(filt(None, {}, [('-','messages.author'),('-','messages.date')]),
2354 ae(filt(None, {}, [('+','messages.author'), 2381 ['8', '6', '7', '5', '4', '3', '1', '2'])
2355 ('-','assignedto.supervisor'),('-','assignedto')]), 2382 ae(filt(None, {}, [('+','messages.author'),('+','assignedto')]),
2356 ['1', '2', '3', '4', '5', '8', '6', '7']) 2383 ['1', '2', '3', '4', '5', '8', '6', '7'])
2357 ae(filt(None, {}, 2384 ae(filt(None, {}, [('+','messages.author'),
2358 [('+','messages.author.supervisor.supervisor.supervisor'), 2385 ('-','assignedto.supervisor'),('-','assignedto')]),
2359 ('+','messages.author.supervisor.supervisor'), 2386 ['1', '2', '3', '4', '5', '8', '6', '7'])
2360 ('+','messages.author.supervisor'), ('+','messages.author')]), 2387 ae(filt(None, {},
2361 ['1', '2', '3', '4', '5', '6', '7', '8']) 2388 [('+','messages.author.supervisor.supervisor.supervisor'),
2389 ('+','messages.author.supervisor.supervisor'),
2390 ('+','messages.author.supervisor'), ('+','messages.author')]),
2391 ['1', '2', '3', '4', '5', '6', '7', '8'])
2362 self.db.user.setorderprop('age') 2392 self.db.user.setorderprop('age')
2363 self.db.msg.setorderprop('date') 2393 self.db.msg.setorderprop('date')
2364 ae(filt(None, {}, [('+','messages'), ('+','messages.author')]), 2394 for filt in iiter():
2365 ['6', '7', '8', '5', '4', '3', '1', '2']) 2395 if filt.__name__ != 'filter':
2366 ae(filt(None, {}, [('+','messages.author'), ('+','messages')]), 2396 continue
2367 ['6', '7', '8', '5', '4', '3', '1', '2']) 2397 ae(filt(None, {}, [('+','messages'), ('+','messages.author')]),
2398 ['6', '7', '8', '5', '4', '3', '1', '2'])
2399 ae(filt(None, {}, [('+','messages.author'), ('+','messages')]),
2400 ['6', '7', '8', '5', '4', '3', '1', '2'])
2368 self.db.msg.setorderprop('author') 2401 self.db.msg.setorderprop('author')
2369 # Orderprop is a Link/Multilink: 2402 for filt in iiter():
2370 # messages are sorted by orderprop().labelprop(), i.e. by 2403 if filt.__name__ != 'filter':
2371 # author.username, *not* by author.orderprop() (author.age)! 2404 continue
2372 ae(filt(None, {}, [('+','messages')]), 2405 # Orderprop is a Link/Multilink:
2373 ['1', '2', '3', '4', '5', '8', '6', '7']) 2406 # messages are sorted by orderprop().labelprop(), i.e. by
2374 ae(filt(None, {}, [('+','messages.author'), ('+','messages')]), 2407 # author.username, *not* by author.orderprop() (author.age)!
2375 ['6', '7', '8', '5', '4', '3', '1', '2']) 2408 ae(filt(None, {}, [('+','messages')]),
2376 # The following will sort by 2409 ['1', '2', '3', '4', '5', '8', '6', '7'])
2377 # author.supervisor.username and then by 2410 ae(filt(None, {}, [('+','messages.author'), ('+','messages')]),
2378 # author.username 2411 ['6', '7', '8', '5', '4', '3', '1', '2'])
2379 # I've resited the tempation to implement recursive orderprop 2412 # The following will sort by
2380 # here: There could even be loops if several classes specify a 2413 # author.supervisor.username and then by
2381 # Link or Multilink as the orderprop... 2414 # author.username
2382 # msg: 4: worker1 (id 5) : grouplead1 (id 4) ceo (id 3) 2415 # I've resited the tempation to implement recursive orderprop
2383 # msg: 5: worker2 (id 7) : grouplead1 (id 4) ceo (id 3) 2416 # here: There could even be loops if several classes specify a
2384 # msg: 6: worker3 (id 8) : grouplead2 (id 5) ceo (id 3) 2417 # Link or Multilink as the orderprop...
2385 # msg: 7: worker4 (id 9) : grouplead2 (id 5) ceo (id 3) 2418 # msg: 4: worker1 (id 5) : grouplead1 (id 4) ceo (id 3)
2386 # msg: 8: worker5 (id 10) : grouplead2 (id 5) ceo (id 3) 2419 # msg: 5: worker2 (id 7) : grouplead1 (id 4) ceo (id 3)
2387 # issue 1: messages 4 sortkey:[[grouplead1], [worker1], 1] 2420 # msg: 6: worker3 (id 8) : grouplead2 (id 5) ceo (id 3)
2388 # issue 2: messages 4 sortkey:[[grouplead1], [worker1], 2] 2421 # msg: 7: worker4 (id 9) : grouplead2 (id 5) ceo (id 3)
2389 # issue 3: messages 5 sortkey:[[grouplead1], [worker2], 3] 2422 # msg: 8: worker5 (id 10) : grouplead2 (id 5) ceo (id 3)
2390 # issue 4: messages 6 sortkey:[[grouplead2], [worker3], 4] 2423 # issue 1: messages 4 sortkey:[[grouplead1], [worker1], 1]
2391 # issue 5: messages 7 sortkey:[[grouplead2], [worker4], 5] 2424 # issue 2: messages 4 sortkey:[[grouplead1], [worker1], 2]
2392 # issue 6: messages 8 sortkey:[[grouplead2], [worker5], 6] 2425 # issue 3: messages 5 sortkey:[[grouplead1], [worker2], 3]
2393 # issue 7: messages 8 sortkey:[[grouplead2], [worker5], 7] 2426 # issue 4: messages 6 sortkey:[[grouplead2], [worker3], 4]
2394 # issue 8: messages 7,8 sortkey:[[grouplead2, grouplead2], ...] 2427 # issue 5: messages 7 sortkey:[[grouplead2], [worker4], 5]
2428 # issue 6: messages 8 sortkey:[[grouplead2], [worker5], 6]
2429 # issue 7: messages 8 sortkey:[[grouplead2], [worker5], 7]
2430 # issue 8: messages 7,8 sortkey:[[grouplead2, grouplead2], ...]
2395 self.db.user.setorderprop('supervisor') 2431 self.db.user.setorderprop('supervisor')
2396 ae(filt(None, {}, [('+','messages.author'), ('-','messages')]), 2432 for filt in iiter():
2397 ['3', '1', '2', '6', '7', '5', '4', '8']) 2433 if filt.__name__ != 'filter':
2434 continue
2435 ae(filt(None, {}, [('+','messages.author'), ('-','messages')]),
2436 ['3', '1', '2', '6', '7', '5', '4', '8'])
2398 2437
2399 def testFilteringSortId(self): 2438 def testFilteringSortId(self):
2400 ae, filter, filter_iter = self.filteringSetupTransitiveSearch('user') 2439 ae, iiter = self.filteringSetupTransitiveSearch('user')
2401 for filt in filter, filter_iter: 2440 for filt in iiter():
2402 ae(filt(None, {}, ('+','id')), 2441 ae(filt(None, {}, ('+','id')),
2403 ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']) 2442 ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'])
2404 2443
2405 def testFilteringRetiredString(self): 2444 def testFilteringRetiredString(self):
2406 ae, filter, filter_iter = self.filteringSetup() 2445 ae, iiter = self.filteringSetup()
2407 self.db.issue.retire('1') 2446 self.db.issue.retire('1')
2408 self.db.commit() 2447 self.db.commit()
2409 r = { None: (['1'], ['1'], ['1'], ['1', '2', '3'], []) 2448 r = { None: (['1'], ['1'], ['1'], ['1', '2', '3'], [])
2410 , True: (['1'], ['1'], ['1'], ['1'], []) 2449 , True: (['1'], ['1'], ['1'], ['1'], [])
2411 , False: ([], [], [], ['2', '3'], []) 2450 , False: ([], [], [], ['2', '3'], [])
2412 } 2451 }
2413 for filt in filter, filter_iter: 2452 for filt in iiter():
2414 for retire in True, False, None: 2453 for retire in True, False, None:
2415 ae(filt(None, {'title': ['one']}, ('+','id'), 2454 ae(filt(None, {'title': ['one']}, ('+','id'),
2416 retired=retire), r[retire][0]) 2455 retired=retire), r[retire][0])
2417 ae(filt(None, {'title': ['issue one']}, ('+','id'), 2456 ae(filt(None, {'title': ['issue one']}, ('+','id'),
2418 retired=retire), r[retire][1]) 2457 retired=retire), r[retire][1])
2436 self.db = self.module.Database(config, 'admin') 2475 self.db = self.module.Database(config, 'admin')
2437 setupSchema(self.db, 0, self.module) 2476 setupSchema(self.db, 0, self.module)
2438 2477
2439 def testImportExport(self): 2478 def testImportExport(self):
2440 # use the filtering setup to create a bunch of items 2479 # use the filtering setup to create a bunch of items
2441 ae, dummy1, dummy2 = self.filteringSetup() 2480 ae, dummy = self.filteringSetup()
2442 # Get some stuff into the journal for testing import/export of 2481 # Get some stuff into the journal for testing import/export of
2443 # journal data: 2482 # journal data:
2444 self.db.user.set('4', password = password.Password('xyzzy')) 2483 self.db.user.set('4', password = password.Password('xyzzy'))
2445 self.db.user.set('4', age = 3) 2484 self.db.user.set('4', age = 3)
2446 self.db.user.set('4', assignable = True) 2485 self.db.user.set('4', assignable = True)
2549 # test import/export via admin interface 2588 # test import/export via admin interface
2550 def testAdminImportExport(self): 2589 def testAdminImportExport(self):
2551 import roundup.admin 2590 import roundup.admin
2552 import csv 2591 import csv
2553 # use the filtering setup to create a bunch of items 2592 # use the filtering setup to create a bunch of items
2554 ae, dummy1, dummy2 = self.filteringSetup() 2593 ae, dummy = self.filteringSetup()
2555 # create large field 2594 # create large field
2556 self.db.priority.create(name = 'X' * 500) 2595 self.db.priority.create(name = 'X' * 500)
2557 self.db.config.CSV_FIELD_SIZE = 400 2596 self.db.config.CSV_FIELD_SIZE = 400
2558 self.db.commit() 2597 self.db.commit()
2559 output = [] 2598 output = []
2601 # test props from args parsing 2640 # test props from args parsing
2602 def testAdminOtherCommands(self): 2641 def testAdminOtherCommands(self):
2603 import roundup.admin 2642 import roundup.admin
2604 2643
2605 # use the filtering setup to create a bunch of items 2644 # use the filtering setup to create a bunch of items
2606 ae, dummy1, dummy2 = self.filteringSetup() 2645 ae, dummy = self.filteringSetup()
2607 # create large field 2646 # create large field
2608 self.db.priority.create(name = 'X' * 500) 2647 self.db.priority.create(name = 'X' * 500)
2609 self.db.config.CSV_FIELD_SIZE = 400 2648 self.db.config.CSV_FIELD_SIZE = 400
2610 self.db.commit() 2649 self.db.commit()
2611 2650
3226 self.assertEqual(self.db.sql_index_exists('_issue', '_issue_id_idx'), 1) 3265 self.assertEqual(self.db.sql_index_exists('_issue', '_issue_id_idx'), 1)
3227 self.assertEqual(self.db.sql_index_exists('_issue', '_issue_x_idx'), 0) 3266 self.assertEqual(self.db.sql_index_exists('_issue', '_issue_x_idx'), 0)
3228 3267
3229 class FilterCacheTest(commonDBTest): 3268 class FilterCacheTest(commonDBTest):
3230 def testFilteringTransitiveLinkCache(self): 3269 def testFilteringTransitiveLinkCache(self):
3231 ae, filter, filter_iter = self.filteringSetupTransitiveSearch() 3270 ae, dummy = self.filteringSetupTransitiveSearch()
3232 ae, ufilter, ufilter_iter = self.iterSetup('user') 3271 ae, dummy = self.iterSetup('user')
3233 # Need to make ceo his own (and first two users') supervisor 3272 # Need to make ceo his own (and first two users') supervisor
3234 self.db.user.set('1', supervisor = '3') 3273 self.db.user.set('1', supervisor = '3')
3235 self.db.user.set('2', supervisor = '3') 3274 self.db.user.set('2', supervisor = '3')
3236 self.db.user.set('3', supervisor = '3') 3275 self.db.user.set('3', supervisor = '3')
3237 # test bool value 3276 # test bool value

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