changeset 5110:87b0358790ed

Adding some tests for admin.py. Specifically for issue2550572: setting nosy=+foo on multiple issues gives them all the same exact nosy list. To make this work had to change the admin.py code to use "sys.stdout.write" in place of "print". In the test I now hijack stdout.write following an existing example of this for admin's import/export command that hijacks sys.stderr.write. Also I corrected a misspelling in security.py. The word "everything" was misspelled. It is not inside _() markers so I don't think it's going to affect translation and grepping the locale subdir doesn't show the original string.
author John Rouillard <rouilj@ieee.org>
date Wed, 29 Jun 2016 18:35:19 -0400
parents 43a1f7fe39f5
children 1c94afabb2cb
files roundup/admin.py roundup/security.py test/db_test_base.py
diffstat 3 files changed, 134 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/roundup/admin.py	Tue Jun 28 15:39:38 2016 +1000
+++ b/roundup/admin.py	Wed Jun 29 18:35:19 2016 -0400
@@ -107,7 +107,7 @@
         """
         if message:
             message = _('Problem: %(message)s\n\n')%locals()
-        print _("""%(message)sUsage: roundup-admin [options] [<command> <arguments>]
+        sys.stdout.write( _("""%(message)sUsage: roundup-admin [options] [<command> <arguments>]
 
 Options:
  -i instance home  -- specify the issue tracker "home directory" to administer
@@ -128,13 +128,13 @@
  roundup-admin help                       -- this help
  roundup-admin help <command>             -- command-specific help
  roundup-admin help all                   -- all available help
-""")%locals()
+""")%locals())
         self.help_commands()
 
     def help_commands(self):
         """List the commands available with their help summary.
         """
-        print _('Commands:'),
+        sys.stdout.write( _('Commands: '))
         commands = ['']
         for command in self.commands.itervalues():
             h = _(command.__doc__).split('\n')[0]
@@ -143,8 +143,7 @@
         commands.append(_(
 """Commands may be abbreviated as long as the abbreviation
 matches only one command, e.g. l == li == lis == list."""))
-        print '\n'.join(commands)
-        print
+        sys.stdout.write('\n'.join(commands) + '\n\n')
 
     def help_commands_html(self, indent_re=re.compile(r'^(\s+)\S+')):
         """ Produce an HTML command list.
@@ -736,9 +735,9 @@
         for key in cl.properties:
             value = cl.properties[key]
             if keyprop == key:
-                print _('%(key)s: %(value)s (key property)')%locals()
+                sys.stdout.write( _('%(key)s: %(value)s (key property)\n')%locals() )
             else:
-                print _('%(key)s: %(value)s')%locals()
+                sys.stdout.write( _('%(key)s: %(value)s\n')%locals() )
 
     def do_display(self, args):
         ''"""Usage: display designator[,designator]*
@@ -829,7 +828,7 @@
 
         # do the actual create
         try:
-            print cl.create(**props)
+            sys.stdout.write(cl.create(**props) + '\n')
         except (TypeError, IndexError, ValueError), message:
             raise UsageError(message)
         self.db_uncommitted = True
@@ -1354,34 +1353,34 @@
             try:
                 roles = [(args[0], self.db.security.role[args[0]])]
             except KeyError:
-                print _('No such Role "%(role)s"')%locals()
+                sys.stdout.write( _('No such Role "%(role)s"\n')%locals() )
                 return 1
         else:
             roles = list(self.db.security.role.items())
             role = self.db.config.NEW_WEB_USER_ROLES
             if ',' in role:
-                print _('New Web users get the Roles "%(role)s"')%locals()
+                sys.stdout.write( _('New Web users get the Roles "%(role)s"\n')%locals() )
             else:
-                print _('New Web users get the Role "%(role)s"')%locals()
+                sys.stdout.write( _('New Web users get the Role "%(role)s"\n')%locals() )
             role = self.db.config.NEW_EMAIL_USER_ROLES
             if ',' in role:
-                print _('New Email users get the Roles "%(role)s"')%locals()
+                sys.stdout.write( _('New Email users get the Roles "%(role)s"\n')%locals() )
             else:
-                print _('New Email users get the Role "%(role)s"')%locals()
+                sys.stdout.write( _('New Email users get the Role "%(role)s"\n')%locals() )
         roles.sort()
         for rolename, role in roles:
-            print _('Role "%(name)s":')%role.__dict__
+            sys.stdout.write( _('Role "%(name)s":\n')%role.__dict__ )
             for permission in role.permissions:
                 d = permission.__dict__
                 if permission.klass:
                     if permission.properties:
-                        print _(' %(description)s (%(name)s for "%(klass)s"'
-                          ': %(properties)s only)')%d
+                        sys.stdout.write( _(' %(description)s (%(name)s for "%(klass)s"' +
+                          ': %(properties)s only)\n')%d )
                     else:
-                        print _(' %(description)s (%(name)s for "%(klass)s" '
-                            'only)')%d
+                        sys.stdout.write( _(' %(description)s (%(name)s for "%(klass)s" ' +
+                            'only)\n')%d )
                 else:
-                    print _(' %(description)s (%(name)s)')%d
+                    sys.stdout.write( _(' %(description)s (%(name)s)\n')%d )
         return 0
 
 
--- a/roundup/security.py	Tue Jun 28 15:39:38 2016 +1000
+++ b/roundup/security.py	Wed Jun 29 18:35:19 2016 -0400
@@ -128,7 +128,7 @@
         # default permissions - Admin may do anything
         for p in 'create edit retire view'.split():
             p = self.addPermission(name=p.title(),
-                description="User may %s everthing"%p)
+                description="User may %s everything"%p)
             self.addPermissionToRole('Admin', p)
 
         # initialise the permissions and roles needed for the UIs
--- a/test/db_test_base.py	Tue Jun 28 15:39:38 2016 +1000
+++ b/test/db_test_base.py	Wed Jun 29 18:35:19 2016 -0400
@@ -25,7 +25,7 @@
     Interval, DatabaseError, Boolean, Number, Node, Integer
 from roundup.mailer import Mailer
 from roundup import date, password, init, instance, configuration, \
-    roundupdb, i18n
+    roundupdb, i18n, hyperdb
 from roundup.cgi.templating import HTMLItem
 
 from mocknull import MockNull
@@ -1959,6 +1959,120 @@
             roundup.admin.sys = sys
             shutil.rmtree('_test_export')
 
+    # test props from args parsing
+    def testAdminOtherCommands(self):
+        import roundup.admin
+        from roundup.exceptions import UsageError
+
+        # use the filtering setup to create a bunch of items
+        ae, dummy1, dummy2 = self.filteringSetup()
+        # create large field
+        self.db.priority.create(name = 'X' * 500)
+        self.db.config.CSV_FIELD_SIZE = 400
+        self.db.commit()
+
+        eoutput = [] # stderr output
+        soutput = [] # stdout output
+
+        def stderrwrite(s):
+            eoutput.append(s)
+        def stdoutwrite(s):
+            soutput.append(s)
+        roundup.admin.sys = MockNull ()
+        try:
+            roundup.admin.sys.stderr.write = stderrwrite
+            roundup.admin.sys.stdout.write = stdoutwrite
+
+            tool = roundup.admin.AdminTool()
+            home = '.'
+            tool.tracker_home = home
+            tool.db = self.db
+            tool.verbose = False
+            tool.separator = "\n"
+            tool.print_designator = True
+
+            # test props_from_args
+            self.assertRaises(UsageError, tool.props_from_args, "fullname") # invalid propname
+
+            self.assertEqual(tool.props_from_args("="), {'': None}) # not sure this desired, I'd expect UsageError
+            
+            props = tool.props_from_args(["fullname=robert", "friends=+rouilj,+other", "key="])
+            self.assertEqual(props, {'fullname': 'robert', 'friends': '+rouilj,+other', 'key': None})
+
+            # test get_class()
+            self.assertRaises(UsageError, tool.get_class, "bar") # invalid class
+
+            # This writes to stdout, need to figure out how to redirect to a variable.
+            # classhandle = tool.get_class("user") # valid class
+            # FIXME there should be some test here
+ 
+            issue_class_spec = tool.do_specification(["issue"])
+            self.assertEqual(soutput, ['files: <roundup.hyperdb.Multilink to "file">\n',
+                                       'status: <roundup.hyperdb.Link to "status">\n',
+                                       'feedback: <roundup.hyperdb.Link to "msg">\n',
+                                       'spam: <roundup.hyperdb.Multilink to "msg">\n',
+                                       'nosy: <roundup.hyperdb.Multilink to "user">\n',
+                                       'title: <roundup.hyperdb.String>\n',
+                                       'messages: <roundup.hyperdb.Multilink to "msg">\n',
+                                       'priority: <roundup.hyperdb.Link to "priority">\n',
+                                       'assignedto: <roundup.hyperdb.Link to "user">\n',
+                                       'deadline: <roundup.hyperdb.Date>\n',
+                                       'foo: <roundup.hyperdb.Interval>\n',
+                                       'superseder: <roundup.hyperdb.Multilink to "issue">\n'])
+
+            #userclassprop=tool.do_list(["mls"])
+            #tool.print_designator = False
+            #userclassprop=tool.do_get(["realname","user1"])
+
+            # test do_create
+            soutput[:] = [] # empty for next round of output
+            userclass=tool.do_create(["issue", "title='title1 title'", "nosy=1,3"]) # should be issue 5
+            userclass=tool.do_create(["issue", "title='title2 title'", "nosy=2,3"]) # should be issue 6
+            self.assertEqual(soutput, ['5\n', '6\n'])
+            # verify nosy setting
+            props=self.db.issue.get('5', "nosy")
+            self.assertEqual(props, ['1','3'])
+
+            # test do_set using newly created issues
+            # remove user 3 from issues
+            # verifies issue2550572
+            userclass=tool.do_set(["issue5,issue6", "nosy=-3"])
+            # verify proper result
+            props=self.db.issue.get('5', "nosy")
+            self.assertEqual(props, ['1'])
+            props=self.db.issue.get('6', "nosy")
+            self.assertEqual(props, ['2'])
+
+            # basic usage test. TODO add full output verification
+            soutput[:] = [] # empty for next round of output
+            tool.usage(message="Hello World")
+            self.failUnless(soutput[0].startswith('Problem: Hello World'), None)
+
+            # check security output
+            soutput[:] = [] # empty for next round of output
+            tool.do_security("Admin")
+            self.assertEqual(soutput, [ 'New Web users get the Role "User"\n',
+                                       'New Email users get the Role "User"\n',
+                                       'Role "admin":\n',
+                                       ' User may create everything (Create)\n',
+                                       ' User may edit everything (Edit)\n',
+                                       ' User may retire everything (Retire)\n',
+                                       ' User may view everything (View)\n',
+                                       ' User may access the web interface (Web Access)\n',
+                                       ' User may manipulate user Roles through the web (Web Roles)\n',
+                                       ' User may use the email interface (Email Access)\n',
+                                       'Role "anonymous":\n', 'Role "user":\n',
+                                       ' User is allowed to access msg (View for "msg" only)\n'])
+
+
+            self.nukeAndCreate()
+            tool = roundup.admin.AdminTool()
+            tool.tracker_home = home
+            tool.db = self.db
+            tool.verbose = False
+        finally:
+            roundup.admin.sys = sys
+
     def testAddProperty(self):
         self.db.issue.create(title="spam", status='1')
         self.db.commit()

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